ボイストラベラー 音声認識や周波数周りの技術選定の話
Baplisca(@sooooouls) です。
先日、技育展で「ボイストラベラー」という音声認識と周波数取得を組合せた世界初のゲームを紹介しました。
内容や感想はこちらの記事で書きました。
ゲーム内では、音声認識をするパートと周波数取得するパートに別れています。
この2つの機能をどの様に実装したか書いていきます。
はじめに
ゲームを作ってから結構時間が経っており、あいまいなところがあると思うので注意してください。
よって適宜調べながら、補完するのを推奨します。
それと、Unityの基礎的な話はここでは書きません。
技術選定の話
ゲームという性質上、高速な相互作用が必要です。
そこで基本指針としては、ユーザー目線に立った操作性と安定性と低遅延性を心がけました。
音声区間検出
音声認識と周波数取得、両方に共通するのは音声区間検出(VAD)です。
音声区間検出は、実際に取り出したい信号区間のみを検出し、雑音のみの信号区間を除去します。
これにより、音声認識と周波数取得の精度が上がります。
実装では、パワースペクトルとゼロ交差数を用いました。
パワースペクトルで、ある閾値以上の音を有声と判断します。
ゼロ交差数で、ある閾値以上の値を雑音として判断します。
この2つの技術で、音声区間検出を実現しています。
もっと詳しい説明を見つけたので紹介します。
音声認識
使用技術の変遷は、UnityEngine.Windows.Speech → Julius(モジュールモード)→ Julius(ネイティブプラグイン)です。
UnityEngine.Windows.Speechは、Unityの音声認識APIなので手軽に実装できたので採用しました。しかし、実装してみると認識遅延が発生して、ゲームとしては使えませんでした。
Julius(モジュールモード)は、Juliusを裏で実行し、ソケット通信を行うのですが、頻繁にソケットエラーが起き、安定しませんでした。
Julius(ネイティブプラグイン)は、メインスレッドであるC#側から、C++で書かれたJuliusの処理を呼び出し、音声認識を実現しています。両者の欠点(遅延と安定性)をうまく補えたので採用しました。
周波数取得
初めは、AMDF(Average Magnitude Difference Function)で、自己相関関数を利用して周波数を取得してました。ほぼリアルタイムで周波数は取得できるのですが、精度があまり良くなかったです。例えば音階A4(440Hz)の信号を流し込むと、倍音のA5(880Hz)で判定されるケースがありました。
試行錯誤の末、最終的には、高速フーリエ変換(FFT)を用いました。リアルタイムで精度もかなり高いです。
終わりに
「ボイストラベラー」は、現在Windows(exe版)のみを作成してます。UnityはMacやAndroid、ブラウザ(WebGL)などのマルチプラットフォームに対応しているので、他プラットフォームでの公開も検討してます。