跳慮跋考

興味も思考も行先不明

声帯の数値シミュレーションによる音声生成

初音ミク嬢を筆頭として音声サンプルの編集による音声合成は随分栄華を誇っていますが、力学モデルのシミュレーションによる音声合成はどうも人気が無い様ですね。私が世情に疎いだけかも知れませんけれど。
実用程度*1ならそうした経験的帰納的な手法も使えるでしょうが、完璧を求めるならば、整然とした理論モデルによる演繹的アプローチが必要不可欠だと私は思っています。そしてそれは声以外でも。

モデル

で、何をしたかというと、石坂とFlanaganによる声帯の二質量モデル*2を実装してみました。簡単に言うと、声帯を発条で振動する二つの壁の組み合わせとしてモデル化したものです。
もっと発展した研究の論文*3を参考にしたので、元の論文よりはLsを無視してたり声道をもっと細かくしたりしています。それと声道のパラメタの式が納得いかなかったので修正したところも。
あと電気的等価回路については、これ(pdf)を見るとちょっと分かるかもですね。
声道断面積関数については色々ネットでデータを探して、MRIによる計測データ*4があったのでこれを使いました。

実装

んで微分方程式をプログラムに解かせる訳です。最初は連立一階常微分方程式を表すラムダ式とパラメタによって解を求めていくクラスを作ったんですが、声道の各要素に対応するラムダ式を簡単に書けず、Boost.Preprocessor などという黒魔法にも手を出してみましたがどうもきもちよくないので結局 GSL のを使いました。そしたら全ての変数を纏めて扱う ℝⁿ→ℝⁿ 函数みたいな設計になってて、なんかもうあっはいって感じですね。

兎に角そうして実装したのがこのコード(Gist)です。パラメタまで色々ハードコードしてるのは気にしないで下さい。C++ よく分かんないので適当に const つけまくったりしてますが意味あるんでしょうかね。なんか速くなったりしませんか?
論文に"The time derivative of the mouth volume velocity (i.e., through the radiation load) is good approximation to the radiated sound pressure."(p.1248)とあるので、dydt の最後の要素の値である dUO/dt が最終的な音声波形出力(放射音圧)と看做せます。
途中に書いてありますが、y の中身は { H1: 質量1の変位, V1: 質量1の速度, H2: 質量2の変位, V2: 質量2の変位, Ug: 声門内で平均した体積速度, U1, ..., Un: 声道の各要素での体積速度, P1, ..., Pn: 声道の各要素での圧力, Uo: 口での体積速度 } となっています。U1,V1,U2,V2,...にした方がいい気もしますが面倒な割に御利益が無い気もしますね。
本当はパラメタとか最初に全部出力してますが省略。

さて実装で何が困ったって、普通に計算させると発散するんですよね。変位が小さくなると体積速度が上がる、体積速度が上がると変位速度が上がる、という感じの循環が起きてるってことだと思うんですが。
でどうしたかって、まぁ現実に照らし合わせれば数μmの隙間を物凄い勢いで風が通る訳がないので、変位に下限値(コード中の Hmin)を設定してやりました。何ともびみょーですがまず動かなくては仕様がありません。
論文に全然書いてないからもしかしたら私の実装した式が間違ってるかも知れないんですが……。

出力

g++ ならば最低限 -std=gnu++0x -lgsl -lgslcblas -lm あたりのコンパイラオプションつければ大丈夫だと思います。あとは最適化とか。
声道に/a/を選んで(上のコードは/o/ですが)、引数(初期値)を 0.018 0 0.018 0 0 にして実行すると以下の波形を得ます。上から二つの声門面積、声門内の平均体積速度、放射音圧です。
面積が負の方に行き過ぎだったり(質量が剛体として"衝突"するモデルではないので負になるの自体はいいのですが)体積速度がギザギザし過ぎだったりする気もしますが大体は再現できていますね。
f:id:quinoh:20130707011626p:plain

それで波形が出来たのはいいのですが、テキストファイルだから .wav か何かにしないと聴けませんので、適当な変換プログラム(Gist)を書きました。本当に適当なので多少サンプリングレートが狂いますがまぁ聴いても分からないでしょう。最大値くらいは自動で計算すべきかも。
斯くして漸く出来たのがこれ(TwitSound)。結構「あ」っぽいと思いますがどうでしょう? 「あいうえお」全部繋げてみるとこんな感じ(TwitSound)になって「い」「え」とかはもっと不自然だったりするので、この辺りは声道面積の値次第なのかどうなのかという感じですね。スペクトルとかを観察すると「不自然さ」が定量できるのでしょうか。

取り敢えずこれで音声を生成する為のフレームワーク的なものは出来た訳ですので、これをどう自然な声に近づけるかというところが次の問題になります。
筋肉の緊張度を入力パラメータとして声道断面積を制御する事で波形を自然な声に制限したり発声を学習したり逆に音声認識の為の符号化で使えないか……など色々あるのですが、なかなかどれも大変そう。まぁまず声がどんなものかを知らねばなりませんかね。
それから計算速度が遅いのも困りものです。どうにか1秒を1秒以下で計算して欲しいところですが、これより時間刻みを大きくしても発散したりしてどうしたものか。
それとここまで頑張ったところでアレですが、「本質を簡潔に」モデル化するという観点からすると声道をバラバラにしてシミュレートしているのはちょっと泥臭過ぎる嫌いもあります。そうした考えを貫くならば、声道を音響フィルタと看做す「音響フィルタ理論」などを使った方が良いのかも知れません。複雑なモデルほど実装も操作も難しいので。

*1:「程度」なんて言うと色々な人に殺されそうですね

*2:Ishizaka, K.; Flanagan, J. L. "Synthesis of Voiced Sounds From a Two-Mass Model of the Vocal Cords". Bell System Tech. J. 1972, Vol. 51, No. 6, p. 1233-1268. [pdf]

*3:古賀博之; 中川匡弘. "カオス音声生成モデル". 電子情報通信学会技術研究報告. NLP, 非線形問題. 1998, Vol. 98, No. 343, p. 25-32. [CiNii]

*4:Story, Brad H.; Titze, Ingo R. "Vocal tract area functions from magnetic resonance imaging". J. Acoust. Soc. Am. 1996, Vol. 100, No. 1, p. 537-554. [ResearchGate]