Q3〜10月前半の開発記録

7月の作業記録は別途書いてあって、8月の作業記録はMIDI 2.0本の告知がだいぶ持っていってしまったのですが、他のこともちょろちょろとあったので、最近までの自分用開発記録をまとめておきます。時系列は順不同です。

ADLplug/VST3 on LinuxとJUCE6+LV2

JUCEが 6.0でようやくLinux対応したので、ADLplugのようなJUCEベースのオーディオプラグインがまた本家JUCEだけでもビルドできるようになったのですが、ADLplugは独自にLV2対応を進めていたこともあって、JUCE6へのアップデートは行われていません。

このままだとVST3版は永久に出てこないことになって、LV2版を使っている自分としては特に困らない予定だったのですが、いま自分のaugeneプロジェクトでMML + tracktion_engineを使った打ち込み環境に全面移行を図っていて、そこではまだLV2サポートをホスト側で統合できていないので、VST3版が必要になってしまいました。

本家JUCEに切り替えた上でLV2サポートを切り捨ててビルドしても良いのですが、毎回ビルド切り替えのためにJUCEブランチを切り替えるのも面倒なので、とりあえずADLplugで使われているLV2サポート付きのJUCEをJUCE6にアップグレードしました。

github.com

これをもとに更新したADLplugも公開してあります。

github.com

ひとつ問題になっているのが、JUCE6にアップグレードした段階でVST2 SDKの代替として機能するVeSTigeが、既存のコードだけではJUCEのVST2 Wrapperを十分にビルドできなくなってしまったため、VST2サポートが切り落とされてしまっていることです。VeSTige、もともとはLMMSの一部なのですが、いろんなところで改良版?が作られているので、どこに使えるバージョンがあるのかよくわからないんですよね…。そういうわけでコレを使う限り & 本家VST2 SDKを使わない限り、VST2ビルドは失敗します。

あとVST3版にするとマルチチャンネルで使う時にプログラムチェンジが正しく処理されないという問題があって、これはアプリの問題ではなくVST3の仕様レベルでの問題っぽいというのが現時点での評価です。この問題があるのとJUCE6アップデートに上記の副作用があるのとで、本家にはマージされない可能性が大いにあります。作者もFM音源からは割と足を洗ってsfizzに集中しているそうですし。

fmbank

OPNplugは音色を定義して使えないとあまり意味がありません(プリセットで満足するタイプならそれでも良いのですが、わたしは他人の作ったFM音色を探すことに意義を見出せないので…)。そういうわけで、大昔にFM音源をいじっていた頃に自作していたOPNのFM音色をつかうわけですが、OPNplugなどで使えるフォーマットが全然違うので、まずはOSSでよく使われていそうなopm形式のテキストデータにしてgithubで公開しました。

github.com

FM音色データとして流通?しているものにもいくつかのフォーマットがあって、OPNplugでサポートされているのはwopnというバイナリのフォーマットのみです。この辺のフォーマットの変換にはOPN2BankEditorというプロジェクトが便利です。古いMMLデータ形式から新しいmml2vgm形式(やmucom88形式とかも)、それと各種FM音色エディタの形式がサポートされています。

github.com

ただ、エディタ上にコピペしてペーストするような作業になるので、大量に音色がある場合はコンバーターを頑張って作ったほうが良いかもしれません。わたしはコンバーターを書く時間のうちに手作業で変換が終えられてしまいそうなので手作業でやっつけました…。あとちょっと変換処理に問題があったので修正して反映してもらったりしていました。

この辺のツールの使い方は時間が無限に使えるようになったらmusilあたりに書いていきたいと思っています。

sfizz on AAP

sfzサウンドフォントをオーディオプラグインとして使えるsfizzを、Android assetsから読み込むアプローチをとりあえず一旦放棄して、ローカルファイルとして格納するようにしたら、無事プラグインとしてロードして動作するようになりました。ただなぜかホストに依存するようで、JUCE AudioPluginHostからだとどうもうまくいかないのでまだ検証が必要なやつです。

最近この辺をちょいちょいいじりながら本家のバグを見つけてプルリクなどを送ったりDiscordの開発コミュニティに顔を出したりしていたら、大して貢献しているわけでもないのにcontributorsリストに名前が載ってしまったので、もうちょっとsfzが広まるようにやっていくか…みたいなモードになっています(安い釣り針だ)。ARIA UIの実装実験もAndroidプラグインも既に彼らに知られていたので、その辺が大きかったのかもしれません。協力できるところは協力していこうと思っています。UI Standard GuitarのKSOPとかUI Metal GTXが使えるところまではもっていきたいですし(そこまで手を出せる技術知は今のところありませんが)。

ちなみにsfizzではlibsndfileに依存している部分を置き換える作業も行われていたりするので、これが通るとファイルシステム依存部分が減ってassetからのロードが無理なく実現できるようになるかもしれないので、現時点では今のコードに無理にassetサポートを追加しない方針で様子見です。(libsndfileはFluidsynthでもsf3サポートのために使われているので、libsndfileのファイル名を指定するAPIに依存しないアプリケーションコードを書くことも可能なはずではありますが。)

aria2webのスクショを見てわかる人はわかると思いますが、sfizzはKontaktの次の時代を作るOSSとして発展できるポテンシャルは十分にあると思います(SforzandoがOSSになってLinux対応できればそれでもいいのですが)。Kontakt、Komplete 13でもVST3版が出ることはなかったですし、この辺は世代交代を期待したいところです(とはいえVST3には前述の問題もあるのでVST2が使われ続けることになるのかも…それはそれで不幸な話なのですが)。現状sfzをサポートするOSSはopcodes実装がSforzandoに遠く及ばないとされていたのが、sfizzがえらい勢いで進化しているので、しばらく経つとこの辺の勢力図が変わってくるのではないかと思います。

tracktion_engine app on Android

しばらく前からaugeneというMML => MIDI + AudioPluginHost (filtergraph) => tracktion(edit) という流れのツールチェインを構築していて、最近ようやくMMLからOPNplugやsfizzでギター音源sfzの奏法をMMLで指定して演奏できるところまで実現できたので、次はこれをAndroidに移植する作業を進めていました。

tracktion_engine自体はStepSequencerDemoを動かしたことがあるので*1、基本的には移植で困ることは多分ありません。多分、というのは、StepSequencerDemo以外で使われている機能については使ってみないとわからないためです。実際、Editをファイルからロードして演奏する処理については、Android用にassetsからロードする仕組みはNDKにもJUCEにも無いので、sfizzと同様にローカルファイルストレージにいったんコピーしてからロードするというやっつけ工程が必要になりました。

あとJUCE6がCMakeに対応したので、外部ライブラリに依存しているaugeneもCMake化したほうが楽だと思って移行したのですが、Androidサポートについては、Projucerで行われているプロジェクトファイル生成はCMakeでは全くサポートされていないので、自前でテンプレートを用意するかどうかで試行錯誤した結果、とりあえず従来のProjucer方式でプロジェクトを生成しています。aap-juceのビルドシステムがProjucer前提で組まれているのが最大の理由です。CMake前提のビルドに書き換えようとも思ったのですが、移植対象のアプリがそもそもCMakeに書き換わっていない(そして古いアプリもあるので多分書き換わらない)ので、10月中は無理だと判断しました(この辺をいじっていた頃はM3出展を視野に入れていたのです)。

audio plugin portabilityの問題

Linuxデスクトップ上でMMLで打ち込んで生成したtracktioneditと、Androidに移植したtracktion_engineアプリがあれば完結するかと思われたこの課題ですが、本当の(そして現在進行系の)課題は、複数の環境をまたいで編集・再生できるポータブルな楽曲編集環境を構築するところにあります。

AAPはVST3をサポートできないので(そもそもvst3sdkがまだAndroid NDKでビルドできないので)、VST3でビルドした音源を使った楽曲がAndroid上でシームレスに演奏できることを期待するのはちょっと無理があります。正確には、音源そのものはJUCEでビルドされていてaap-juceでビルドできるのですが、AudioPluginHostで編集したfiltergraph上にはプラグインのstateが生バイナリをbase64変換して保存されており、この生バイナリのデータが他のプラグインフォーマットとは共有できません。つまり、ユーザーが打ち込んだデータのクロスプラグインフレームワーク互換性の問題です。

これは別に自分のプロジェクト固有の問題ではなくて、オーディオプラグインの世界全体の問題です。たとえばRoland Sound Canvas VAをVSTで打ち込んでいたものをAUに置き換えても互換性が無いことになっています。

本当にstateデータを共有できないのかどうか試してみたのですが、JUCEのVST3サポートの実装ではVST3固有の情報を出力に含めていて無理でした(OPNplugの実装でいえば、stateのXMLのroot要素判定に"VST3PluginState"が渡される)。手作業で回避コードを書くこともできるのですが、課題はADLplugという個別のプラグインを動かすことでもなければJUCEベースのプラグインのみパッチ対応することでもないので、そういう対応は現状考えていません。

現状で一番現実的に可能そうなのはtracktion_engineをLV2サポート付きのJUCEでビルドしてAudioPluginHostもaugeneもLV2を使って制作して、それをaap-lv2でビルドしたプラグインを使って再生する、といったところです。JUCEのLV2サポートもホスト側(juce_audio_processors)について実装されている必要があり、現状ではjlv2というモジュールしか見当たりません。ADLplugのLV2サポートなど大半のLV2サポートブランチはjuce_audio_plugin_clientのみなのです。

この問題をどう解決するか、については、そもそも音楽制作環境におけるクロスプラットフォーム・クロスプラグイン環境をどう実現すべきか?という課題について整理して別の機会にまとめたいと思っています。進展があればgithubの自分のプロジェクトである程度まとめていくかもしれません。

*1:ちなみにStepSequencerDemoはjuce_emscriptenを使ってWeb上で動作していて、tracktion_engineの開発者にも知られています