6月の作業記録

このシリーズのタイトル使うのひさしぶりなんですが、先月書いたaria2webも実質的に作業記録みたいなものなんで、掘り起こして復活させた、みたいな感じではありません…。

6月の、と書き出してしまいましたが、前回からの差分だけにしておきます。3週間くらい?

designing Audio Plugin Framework for Android @ COSCUP 2020

台湾の大規模コミュニティカンファレンスCOSCUPで2年ぶりにしゃべることにしました。内容は今開発しているAndroid向けオーディオプラグインフレームワークの設計アプローチについて、ということになります。7月はその準備作業に着手する予定です。

2018年もlanguage server protocolについてのセッションで、かなり.NET色を排除した内容だったのですが(それまではMonoDevelop -> Monoランタイム -> .NET Coreだった)、今回は完全に過去を切り捨ててオーディオの話をします。どっちも単独で引っ張るとまあまあ素人なのですが、複合領域だからな…!

AndroidiOSもなのですが、モバイルOSは実行可能なコードの制約が強く、プロセス分離から逃げられないので、それを踏まえたオーディオプラグイン機構が必要になります(この話題ここではしょっちゅう出してますが)。オーディオはリアルタイム処理も考慮しないといけないので無理ゲーなのでは…!?となってしまいますが、Android 8.1で「Realtime IPC Binderが実装された<折返し>か!?」みたいな状況になっていたりする…など無駄に深入りした話などを交えつつ、基本的にはどういう設計が求められるかという上澄みの話をする予定です。

プラグインUIの仕組みなども実装しておきたいのですが、時間的に厳しそう…(30分しかないし)。実装基盤もガタガタなので、おそらくその辺を強化して終わりでしょう。

ちなみに台湾のカンファレンスのスピーカーといっても、それだけで業務出張になるわけではないので、渡航資格が発生するわけではありません。そんなわけで日本からのオンラインセッションとなる予定です。準備というのはだいたいそっちの練習という感じです。やってみないとわからないですしね。基本的には会場のネットワークに繋いでビデオ通話するだけなのですが、もしかしたら日本からでも見えるようになるかもしれません。現状何もわかっていません。

aap-sfizz

今月の上旬に書きましたが、ARIAのUIをWebViewで表示できるようになって、sfizzとも組み合わせてオーディオプラグインとして使えるようになったので、今度はこれをAndroidで動かそうと思ったわけですが、LV2プラグインの移植はmda-lv2しか実績がなく、その土台を整備する作業が必要になりました。JUCEのプラグインならほぼProjucerのプロジェクトがあるわけですが、LV2プラグインはプロジェクトによる感じです。

sfizzはCMakeのプロジェクトなので、プロジェクトファイルを取り込むという意味では難易度がやや低いのですが、Android用のLV2開発ライブラリをパッケージとして参照解決できる状態にはなっていません。理想を言えば、aarを参照に追加するだけで解決したいところです。

この目的ではAndroid Studio 4.0に新規追加されたPrefabフォーマットのサポート(4月に書いたやつ)が解決することが期待されたのですが、全くうまくいく様子がなく、AGPのソースを追っかけてもそもそもprefabツールがセットアップされる様子もなく、Prefabパッケージの妥当性を検証する機構が全く無いので(こっちはLV2で使われているwafのビルド結果を手作業でバンドルするしかない)、まだまともに動作させるのは無理だという結論になりました。この辺の機能は今のAndroid NDKのプロジェクトリーダーが仕切っているっぽいのですが、どうも中途半端な機能を無理やりリリースにねじ込んでいる感が否めません…

ともあれ、Prefabは使えないので、これまで通りwafとcerberoのビルド結果をaarに取り込みつつ、参照側でもPkgConfigのパスなどをよろしく解決できるhackに頼るという方向性で、sfizzのCMakeLists.txtにパッチを当ててなんとかビルドしました。

sfizzはそれでビルドまではできたのですが、実際にsfzファイルをロードするところまではまだ実現できていません。それほど難しくはないはずなのですが、続く2つのタスクが先だと判断して先送りしています。

aap-lv2モジュールの切り離しとmda-lv2の再構成

sfizzの移植は、当初は独立リポジトリで行っていたのですが、LV2プラグイン移植の依存関係にフレームワーク本体を追加しないといけない状態はしんどいなあ…と考えていました。

また一方で、そもそもプラグインフレームワーク自体にLV2は必須のものではありません。LV2依存部分がビルドの難易度を爆上げしていた側面はあります。(これは実際にはそこまで大したことはなく、当初lv2リポジトリのサンプルプラグインまでビルドしていた関係でlibsndfileやcairoまでビルドしていたことが原因なのですが、それらを除外してもmda-lv2ではlibsndfileが必須でした。)

mda-lv2はもともとLV2プラグインをビルドする際に必須ではないですし、これだけはGPLv3なのでビルドから切り離しておきたかったこともあって、LV2まわりのビルドを根本的に見直すことにしました。最終的には、aap-lv2というリポジトリが誕生し、プラグイン本体はaap-juceを切り離した時のようにスッキリしました。

いったんLV2依存部分を切り離すと、ここにLV2プラグインの移植を放り込むことでビルドスクリプトの負担がかなり下がったので、sfizz移植はここに追加しました。mda-lv2はLV2サポートのリファレンス実装としてモジュールを再整備されています。

いずれprefabが安定的に使えるようになってaarがMaven経由で使える程度に安定化してきたら、単独の移植プロジェクトでフレームワークを参照するのも平易になるでしょう。(aap-lv2リポジトリ自体はLV2バックエンドの開発とdogfoodingのために現状のままが良いですが。)

Guitarixの移植

前述の4月のエントリーでも言及したのですが、sfizzでインストゥルメントプラグインを実現して、Guitarixで実用的なエフェクターを取り入れることができれば(といってもどれだけ実践的なのかは正直サンプル以上のことはわかりませんが)、とりあえず「波形合成のおもちゃ」以上の、まともな音源で作られた楽曲を再生できる期待値は上がります。

そういうわけでいよいよGuitarixを取り込むことにしたのですが、Guitarixもwafを使ってビルドするので、LV2モジュールをAndroidようにビルドする仕組みを再利用できるようにすることにしました。今後LV2プラグインを誰でも移植できるようにするためには、自分で道を作っておかないといけないわけです。

ビルドスクリプトそのものは再利用がそれほど難しいわけではないはずだったのですが、LV2リポジトリのビルドはautowaf、Guitarixは手書きのwafなので(wafはpythonスクリプトなので何でも書けてしまう)、再利用できる部品だけ再利用しました。同じことを移植作業では毎回気にしないといけないことでしょう…

Guitarixの最難関はハードな依存関係です。glibmm、その依存関係にあるlibsigc++、glibなどが基本にあって、さらにlibsndfile, fftw3, eigen、zita-convolver, zita-resamplerといったものをすべてCerberoでビルドできるようにしました(zita-*は必要なかったので無駄足になってしまいましたが…)。

ネイティブライブラリのビルドシステムのオーバーホールの一環として、Cerberoを置き換えることも検討したのですが(何しろこれはGStreamerのためにしかメンテされないので)、Prefab・ndkportsは前述の通り未熟すぎ、vcpkgはLinuxサポートですら建前でしかなく、パッケージのビルドスクリプトWindows対応のことしか考えていないというのがザラだったので(vcpkgがLinuxで使われるようになる日は一生来ないだろうと思いました)、引き続きCerberoを使っています。

ビルドできたGuitarixは、Androidプロジェクトに取り込むにあたってディレクトリ構成を差し替えないといけないのですが(何しろlib/lv2/GxHogehoge.lv2みたいなディレクトリからターゲットアーキテクチャ向けでもない.soファイルをロードすることはできないので)、それらを自動的に再配置するMakefileスクリプトもaap-lv2で追加されています。誰でも(特に「将来の自分」)同じ手順を追えば任意のプラグインを移植できるようにする、というのが重要です。

ともあれ、Guitarixも無事移植できました。数十種類のエフェクトが利用可能なプラグインのリストに追加されるのを見るとアガりますね。

f:id:atsushieno:20200629230048p:plain
guitarix on Android

Mac環境用ビルド

この3ヶ月くらいメイン開発機のHP Spectre x360のキーボードの故障がひどく、キーが入力できなくなってHPに修理依頼しても、帰ってきてしばらくするとまたキーが入力できなくなる…というのを繰り返していて(実のところ今も修理中)、完全に生産性が下がっていて困っています。

さすがにこのままではまずいと思って、打ち込みマスタリング用のMac環境でも何とかこの辺のリポジトリの開発が継続できるようにビルドを整備しました。GitHub ActionsでMacビルドが通るくらいまではきちんとやってあります…あったのですが、GitHub ActionsはAndroid開発環境のアップデートがまともに行われずAndroid API Level 30がいつまでも入ってこなかったので、CIは放置状態でした。モバイル開発で最前線を走るならGitHub Actionsはやめておいたほうがいいのかも…

ちなみにWindowsでもビルドできました。ただしmakeをWSL環境で走らせてからWindowsAndroid Studioで開いて開発を進める必要があります(ASはWSL2でも動くかもしれない)。GitHub Actions上でWSLのbashを呼び出す方法がわからないので、CIは通さないでしょう。

Next Steps:UI統合

Guitarixの個別のプラグインにはまだ謎のクラッシュを起こすものがあるのですが(要個別調査)、多くが何やら動作はできているっぽいので、「DAWあるいはそれに類するシーケンサーで音楽を演奏できる」状態にするために必要な作業は、インストゥルメント(sfizz)まわりの整備とシーケンサーの整備という感じになりました。

プラグインフレームワーク自体にもLV2バックエンドにもまだまだやることはいっぱいあるので、音楽が演奏できるようになっただけでは完結しないのですが、当面の目標はその辺りです。

aria2webはsfizzをKontaktみたいな商用製品っぽく見せるように構成するのとWeb UIを実現するのが目的でしたが、そのUI統合モデルはそのままこのプラグインフレームワークにも敷衍できます。というドキュメントを先日まとめていたので、この辺に着手しつつ、プレゼンテーションの準備をすることになるでしょう。

シーケンサーはtracktion_engineを使い回せれば十分だと思っています。tracktion_engineがAndroidで期待通りに完全動作するかは不明ですが、juce_emscriptenでもStepSequencerDemoが動いているのでまあ大丈夫ではなかろうか…

tracktion_engineはエディタを伴わず、デスクトップ環境で作成した楽曲データはそのままでは再生できないので、プラグイン情報などを適宜マッピングして再生することになるでしょう。楽曲はMIDIファイルからインポートできるので(デスクトップ向けには実績があります)、Android上でも再生できるような楽曲は作成可能であると踏んでいます。sfizzベースのインストゥルメントであれば、複雑な命令を伴わないので十分に可能でしょう。