https://adventar.org/calendars/3353 の9日目エントリーです。
ソフトウェアMIDIシンセサイザー
fluidsynthはクロスプラットフォームで動作するソフトウェアMIDIシンセサイザーです。主にLinux(ALSA/Jack/PulseAudioなど)、Mac(CoreAudio)、Windows(WinMM)で動作します。音源としてサウンドフォント(sf2形式/sf3形式)を使用するので、理屈としてはサウンドフォントとして表現できるどのようなサンプリング音源であってもMIDI楽器として表現できることになります。
fluidsynthと同様にサウンドフォントを利用しているソフトウェアMIDIシンセサイザーとしてtimidity++が挙げられます。timidityのほうが歴史が長いですが、現在でもアクティブに開発されているのはfluidsynthのほうでしょう。他には最近だとwildmidiというものもあるのですが、使っているという声を見ないのでとりあえず今回はスキップします。
ソフトウェアMIDIシンセサイザーは今では音楽制作で使われる場面はあまり無いと思いますが、Roland音源ベースのWindows GS Wavetable SynthやYamaha XG Soft Synthesizerを使ってSMFファイル(*.mid
ファイル)を再生したという人も多いのではないでしょうか。これがLinux環境になると大抵timidity++かfluidsynthになります。
fluidsynthそのものは実行可能ファイルであり主な用途は単体で実行してOS上の仮想MIDIデバイスとして登録して任意のMIDIクライアントアプリケーションから使用できるようにするものですが、ライブラリとしても使うことができます。モバイル環境ではこのアプローチで使われていることが多いようです。このエントリーでは主にこの方面で解説します。
なお、サウンドフォントについては日を改めて書きます。
オーディオドライバー
fluidsynthはクロスプラットフォームで動作するように設計されています。これを実現しているのが、オーディオドライバーとMIDIドライバーの抽象化です。ソースツリーの中ではdrivers
というディレクトリにまとめられており、fluid_adriver.c
に既知のオーディオドライバーが、fluid_mdriver.c
に既知のMIDIドライバーが、それぞれ登録されています。
もし現在サポートされていないオーディオAPIのサポートを追加しようと思ったら、専用のドライバーを作成して、fluidsynthのソースコードに組み込むことで実現できます。筆者はAndroid環境用にOpenSLESとOboeのサポートを追加したバージョンを公開しています(本家にもpull requestを送ってあるのですが、ビルドが複雑怪奇になっているのでまだ取り込める状態にはなっていません)。
OS固有のオーディオI/OとMIDIデバイスドライバーとしての登録処理以外は、ほぼクロスプラットフォームで実現できるコードです。スレッド処理などにはglibのgthreadが(今のところ)用いられています。glib依存は割とビルド過程で面倒なので、筆者としては将来どうにかならないかなあ…とも思っているところです…
fluidsynthはOS環境次第でMIDIデバイスとしても利用できます。ALSA MIDIやCoreMIDI、WinMMはサポートしているようです。
libfluidsynth API
fluidsynthの面白いところは、Cで実装されていて、そのAPIも公開されているということです。CでAPIが公開されているライブラリは、他の言語のバインディングが比較的容易に作成できます。libfluidsynthにはPythonやRubyやHaskellのバインディングが存在しているようです。筆者もnfluidsynthというC#のバインディングを公開しています。
libfluidsynthでは、内部処理の割と詳細な部分が公開されています。たとえばfluid_synth_noteon()
という関数を使うと、引数で指定したチャンネルにMIDIノートオンのメッセージを送ることができます。
これを応用すると、MIDIメッセージを処理するライブラリで、その出力先にlibfluidsynthを使うこともできます。筆者はmanaged-midiというクロスプラットフォームのMIDIライブラリをC#で作成しているのですが、この出力先にALSAやWinMMやCoreMIDIだけでなくFluidsynthを使用した使用例も作成して、先のnfluidsynthに含めています。