simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:音声合成でリアルタイムにコンピュータにしゃべってもらう

Windows PC 環境で動作するライブラリしかありませんが
Webカメラのマイクやヘッドセットマイクなどの音声入力を拾って
かなり高精度に日本語を認識するプログラムが作れる、動作することを確認しました。

simplestar-tech.hatenablog.com

Intel RealSense には音声合成もまた用意されていますが
サンプルアセットがUnity4対応で更新が止まっているのでUnity5ではクラッシュしてしまいます。

タイムリーにも Unity with VOCALOID というものが先週公開されたそうではないですか
business.vocaloid.com

Unityサンプルをダウンロードして再生してみると
確かに音声が流れた

コードを追ってみると .vsqx ファイルをロードして再生しているだけだった。

.vsqx ファイルは VOCALOID のエディタから出力する xml 形式のファイルです。

VOCALOID にはそこまで興味はなく
リアルタイムでテキストを読み上げてくれればそれで良かったのですが

マニュアルを呼んでもそれが全然わからなくて、困った。

HelloVOCALOID_1.0.1.0.unitypackage

をインポートして RealTime シーンを実行してみた。
これはわかりやすい。
日本語と鍵盤の組み合わせでユニティちゃんがしゃべってくれます。

もう少し詳細を追ってみます。
たとえばキーボードをおした時、どのコードを実行するのか見てみます。

あー、大体のことがつかめてきました。
次のコードを見てください。

        void OnAudioFilterRead(Single[] data, Int32 channels)
        {
            if (!ready)
            {
                return;
            }
            UInt32 numBufferdSamples = YVF.YVFRealtimeGetAudioNumData();

            Int32 numOutSamples = data.Length / channels;
            if (numBufferdSamples < numOutSamples)
            {
                numOutSamples = (Int32)numBufferdSamples;
            }

            // リアルタイム合成の結果をYVFから受け取る.
            if (renderData.Length < numOutSamples)
            {
                renderData = new Int16[numOutSamples];
            }
            YVF.YVFRealtimePopAudio(renderData, numOutSamples);

            // 合成結果をAudioClipに書き込む.
            for (int i = 0; i < numOutSamples; ++i)
            {
                Single value = renderData[i] / 32768.0f;	// convert uint16_t (-32768 ~ 32767) to float (-1.0 ~ 1.0)
                int index = i * channels;
                for (int j = index; j < index + channels; ++j)
                {
                    data[j] = value;
                }
            }

            // 不足した場合はゼロで埋める.
            for (int i = numOutSamples * channels; i < data.Length; ++i)
            {
                data[i] = 0;
            }
        }

Unity の仕様で OnAudioFilterRead が MonoBehaviour に書かれていると、これを呼び続けるという動きをします。
もしその時引数の Single[] data に波形データでも書き込んだものなら、その波形をオーディオ機器に流して物理的に音が鳴るそうです。

音声合成エンジンである今回の VOCALOID はどこかの処理で波形を生み出す計算をしていて
今回は何かの合図があったときに、エンジン内にその波形を作り出し、ここに晒すような作りになっています。

実際ボタンをおした時にエンジン側に送る命令はこれだけ

			// ノートオンを送信する.
			YVF.YVFRealtimeAddMidi(YVF.YVFMIDIEventType.NoteOn, noteNumber);
			YVF.YVFRealtimeCommitMidi();

ノートオンをすると、カレントの発音記号に対して noteNumber の音を与えて波形を構築
Unity はその波形をただ流すだけという、そういうものになっています。

今回私が求めているものは、テキストを渡してそれを読み上げるものなので
歌まで歌わなくて良いという観点からは、ここまで自由度は高くなくて良いという意見を持ちました。

"テスト" みたいな文字列を渡して、発声ボタンを押すと "テスト" としゃべるシステムが
簡易に用意できない、またはそこを自分で作らなければいけない、という雰囲気をつかめたので、調べて良かったです。

次に試してみたいと思っているのは CeVIO なので
VOCALOID の調査はここまでにします。

続きは次の記事に書きます。

simplestar-tech.hatenablog.com