https://adventar.org/calendars/3353 の15日目エントリーです。
music-synthesizer-for-android (is not only for Android)
music-synthesizer-for-androidは、こう聞くとびっくりするかもしれませんが、Google公式リポジトリで配布されているYAMAHA DX7互換のソフトウェアFMシンセサイザーです。music-synthesizer-for-androidという名前は長いので、この界隈(?)ではよくMSFAと略されます。
名前だけ見ると完全にAndroid専用ですが、実態は単なるC++ライブラリなので、オーディオ出力と繋ぎ合わせると、およそC++コードからコンパイルして実行できるどんな環境でも動作します。いくつか派生プロジェクトを挙げると…
- dexed: MSFAをJUCEによってオーディオプラグイン化してGUIを追加したもの、に加えて他のソフトウェアFMシンセサイザーなどもサポートしたもの(そういうわけでMSFAだけではないものです) https://github.com/asb2m10/dexed
- webdx7: WebAudioModulesを使ってMSFAを動かせるようにしたもの https://github.com/webaudiomodules/webdx7
実機からの録音データを利用した完全に近いパラメーター調整
DX7というFM音源は多数のシンセサイザー開発者の興味を引くものであるようで、商用製品ならNative InstrumentsのFM8、OSSでもHexterなどがDX7互換音源というかたちで公開されています。MSFAのドキュメントによると、これらはまだ再現度が低いようです(とは言ってもこれが書かれたのはまだcode.google.comがあった頃なのですが)。FM音源の互換チップやシンセサイザーで重要なのは、同じパラメーターを渡した時に実機と同じ音が発生することなので、再現度の高さが重要です。
MSFAが面白いのは、MSFAを作るにあたって、DX7の実機にMIDIメッセージを送信して得られた音と、エミュレーションで再現した音をRoland Quad-Captureで録音して、ほぼビットレベルまで同一になるところまでunit testでチェックしていたことです。DX7の内部で使用されているYM21290とYM21280をリバースエンジニアリングして音色を再現するのはそれほど難しくなかった、というような話がwikiページ…だったものとして残されているドキュメント…にまとめられており、これ自体がだいぶ面白い読み物です。
使い方
DX7はMIDIメッセージを受け取ることで演奏できます。とは言っても、波形を合成した結果は自分のアプリケーション側で取得して、適宜音声出力に流してやる必要があります。プログラム側がやることは
- RingBufferを用意する
- そのRingBufferをコンストラクターに渡してSynthUnitのインスタンスを作る
- Synth.init(sampleRate)で初期化する
- RingBufferにMIDIメッセージを書き込む
- Synth.getSamples()で合成結果を取得する
- 取得したサンプルデータをオーディオI/OのAPIなどで出力する(あるいはwavなどに保存する)
これだけです。MIDIメッセージとしては、まずシステムエクスクルーシブで音色定義を送信してやる必要があり、これを手作業で適切に行うためにはDX7のMIDI実装を知っている必要があるのですが、実際にはDexed Cartなど既知の音源集から音色を選んでそのファイル内容をそのまま送ってやれば良いようです。あとはノートオン/オフなどの命令も含め、MIDI音源と同じように操作すればよいでしょう。