フェルマータ

個人用のメモ。ソフトウェアの導入とかが多くなる予定。

いまさら WORLD の合成部分の薄い C++ ラッパー作った

ポエム

世間が何かと騒がしく外に出るのもままならなくなった反面、在宅勤務で体力が回復してきたので忘れていたコーディングをし直している。とりあえず勘を取り戻そうかと表題の通り音声合成でもやってみる。本職は web エンジニアだったはずなんだがどうにもこういうもののが書きやすいのは変わらないようだ。

やりたいこと

WORLD は C のインタフェースとしてとても優秀でオフライン合成であれば(※)割とさっくり分析・合成ができるのだが、抽象度あげようとするとどうしても C の構文がぼくの頭には難しいので少し抽象度上げたかった。また久しく C++ やっていなかったので弱った脳みそでもなんとかなる合成部分だけやることにした。やりたいことは下記。 (※:オンライン合成もサンプルがあってたぶん便利なのだろうけど使ったことがないので使い勝手はわからない。)

  • 時刻を言うと F0 を返事してくれる人がいる
  • 時刻を言うとそのときのスペクトルを返事してくれる人がいる
  • このとき上の 2 つの人の言うことを聞きながらいい感じの合成音声を再生成したい

まんまこれがインタフェースなのでそのまま実装すればいいのだが、再生成部分のインタフェースが何言ってんのかわからずにかわいくなくなりそうだったので、再生成は以下の 2 つの人に役割を分ける。

  • ある時刻のスペクトル(精確には周期性成分のスペクトルと非周期性成分のスペクトル)を言うとそのスペクトルのインパルスレスポンスを返事してくれる人
  • インパルスレスポンスをいい感じに並べて一連の音声にしてくれる人

これで難しいことはなにもない。数学?今回は全部 WORLD に任せるよ。

作った

github.com (どうでもいいけどアメノウズメさんから名前借りたけど、芸術の神というより宴会芸の神のイメージが強いから名前違うほうがいいかしら、まあプロトタイプだしなんでもいいか)

    int fftSize = 1024;
    int f0Length = 1000;
    NaiveSpectrogram spectrogram((unsigned int)f0Length, (unsigned int)fftSize, /* msFramePeriod = */ 1.0);

    /* Analyze and create WORLD spectrogram here. */

    int waveLength = 44100;
    int samplingFrequency = 44100;
    double *wave = new double[waveLength];
    for(int i = 0; i < waveLength; i++) {
        wave[i] = 0.0;
    }

    SynthesizeImpulseResponseWithWORLD irs(spectrogram.fftSize(), samplingFrequency);
    SynthesizePhraseWithWORLD synthesize(&irs, /* f0Floor = */ 71.0, /* f0Default = */ 500.0);

    PhraseSignal s(wave, /* indexMin = */ 0, /* indexMax = */ waveLength, samplingFrequency);
    PhraseParameters p(&spectrogram, /* startPhase = */ 0.0, /* startFractionalTimeShift = */ 0.0);

    synthesize(&s, &p);

    /* Save wave as wav file here. */

最初の 2 つの F0 とスペクトルのお返事をするクラスが class NaiveSpectrogram final : public Spectrogram さん、インパルスレスポンスをお返事する人が class SynthesizeImpulseResponseWithWORLD final : public SynthesizeImpulseResponse さん、お返事まとめて音声にしてくれる人が class SynthesizePhraseWithWORLD final : public SynthesizePhrase さん。クラスの名前は長いがこんな感じで合成部分は synthesize(&s, &p); にまとまる。ここまで書くのに二週間弱くらい。趣味をやらんくなる寸前までこの部分やれなくて四苦八苦してたので当時よりはいくぶんか成長はしたようだ。DIO, CheapTrick, , D4C, StoneMask で分析したデータを spectrogram に突っ込んでおけばよしなに再合成してくれる動作確認はしたがテストは書いていない、というかバイナリのテストの書き方がわからんのでお手上げという感じ。一応テスタブルには書いてあるので頑張ればなんとかなるけど趣味だしまあ。