10月の開発記録 (2023)

例年であればスケジュール的に追い込まれている10月ですが、今年はM3にサークル申し込みし忘れ、11月の技術書典15にはオンラインのみ参加の予定で、新刊の準備もMIDI 2.0 UMPガイドブックの新版(June 2023 Updates対応)のみの予定(これは別途告知エントリーを書くつもりです)…というわけで、主に開発作業にかかっていました。

alsakt 0.2.0

今月ようやくLinuxデスクトップ環境をKernel 6.5にアップデートして、MIDI 2.0対応のALSAが組み込まれた環境にして、alsaktをMIDI 2.0対応の追加されたalsa-lib 1.2.10のAPIに追従させました。alsa-lib 1.2.10がインストールされた環境であればMIDI 2.0接続が可能になっていると思います。「思います」というのは、実はまだ動作確認できていないためです。

alsa-libについて調べた結果、どうやらlibasound.soをJavaCPPパッケージにバンドルしなければならないということが判明し、それがユニバーサルなビルドとして可能かどうか(Linux x86/x64のほかLinux arm64等も対応できるのか)も要調査…というステータスのまま今に至ります(他の作業のほうが優先度が高い…)。

ktmidiもこれに合わせて「MIDI 2.0の仮想デバイスを作成できる」つもりのところまではアップデートしたのですが、alsaktが動作未確認なので、こちらはバージョンすら上げていない状態です。ktmidiのレベルでMIDI 2.0サポートが確認できたら、次はkmmkのMIDI 2.0サポートの動作確認ということになるでしょうが(MIDI2サポート自体はAndroid + AAP用にすでにkmmkで実装済み)、この辺は気が向いたらやると思います。

AAP extensibility service enhancements

AAPの開発は、先月に引き続き拡張機能とAAPXS (AAP extensibility service) の再設計が中心になっています。先月はrealtime safeな拡張機構を実現するためにBinderの専用関数の代わりにMIDI 2.0のSysEx8メッセージをオーディオ処理と一緒に渡す仕組みを実装していました。今月はこの基本部分が動くようになったので、mainブランチに大量の変更を取り込んであります。

これは拡張機能サポートの大幅な変更になりましたが、まだ最初の一歩に過ぎなかったという状況が見えてきました。他にやるべきこととしては、以下のような変更が必要そうだというのが見えています:

(1) 既存の拡張機能サポートランタイムは、拡張機能の基本部分が同期メソッドを前提とした(非同期メソッドを前提としていない)設計に基づいているので、望まないブロッキングが発生します。根本的なAPIの再設計が必要になります。

(2) LV2 URID類似のindexed URIサポート: UMPのSysEx8に含まれるURIなどはパケット解析した結果得られる文字列バッファとなるため、non-interned stringを同値比較しなければならなくなってしまいました(interned string同士の比較であればポインタのアドレス比較だけで済んでいたわけです)。文字列の同値比較を回避する手段はあって、LV2のURIDという拡張機能が一例としてあります。URIに対応する整数をホストとプラグインの間で合意しておくことで、URIの代わりにint32_t等で識別できるようになります。

(3) AAPXS untyped runtime: 拡張機能のやり取りが、CのAPIではなくバイナリデータのプロトコルというレベルで規定されることになった結果、ホストやプラグインがそれぞれ認識しない拡張機能であっても、特に操作しないまま受け渡すことが可能になりました。ユーザーがある拡張機能を使用してプラグインにメッセージを送りたい場合、その拡張機能をサポートしないホストDAWを使っていても、任意のSysEx8メッセージを送信できるものであれば、それをプラグインに送ることがなお可能です。一方で認識できている拡張機能の操作については、バイナリメッセージを解析して然るべき処理に渡すことが求められます。

拡張機能の呼び出しをプロトコル指向で実現するというのは、拡張可能性を考慮したプラグインのフォーマットとしては割と画期的なのではないかと思います。プロトコル指向という意味ではLV2 Atomも同様のアプローチであると言えますが、LV2 Atomのシーケンスを編集できるDAWは普通はありえないでしょう(LV2に特化したものであればありえますが)。MIDI 2.0メッセージであれば将来的には可能性があります(1.0から変換してもいいですし)。

プロトコルは実装を伴う必要があるので、この仕組みをサポートするC/C++のuntyped runtimeが必要になります。

(4) KotlinからのAAPXS untyped runtimeの操作: 0.7.8時点でのAPIでは、拡張機能をサポートするメソッドは、全て個別具体的に定義・実装されたaap::PluginInstanceの関数を呼び出すことになります。これでは既知の拡張機能しかサポートできませんし、拡張機能が増えるたびにaap::PluginInstanceの対応コストが増大することになります。そして一番の問題はKotlinでクライアントを開発している場合です。C++ホスティングAPIにAAPXS untyped runtimeを用意した上で、そのAPIを直接呼び出せるKotlinのAPIが必要になります。

(5) 動的にロード可能なAAPXS: AAPXSの仕組みは、C++コンパイルして統合すれば十分機能するともいえますが、複数バージョンのホスト(のリファレンス実装)で問題なくロードできる拡張機能ライブラリをサポートしようと思ったら、CレベルのABIが必要になります。(拡張機能を動的にロードする場面は実用上は無いはずなのであまり重要な問題ではありませんが、できるならやっておいてもよい事項です。)

(6) ホスト拡張機能のサポート: AAPに拡張機能サポートが追加されたとき、それはプラグイン拡張機能を意味していました。ホストがプラグイン拡張機能APIを呼び出す、プラグイン拡張機能APIを実装する、という構図です。コレに対して、現在のAAPにはホスト拡張機能のコンセプトが実装されています。CLAPがプラグイン拡張機能とホスト拡張機能の両方を定義しているのと同様です。

このホスト拡張機能のサポートは、AAPXSの仕組みとしてはきちんと規定されておらず、ホストのリファレンス実装で独自に直接実装していました。Binderにコールバックオブジェクトを用意しておいて、そのhostExtension()というメソッドを呼び出すだけになっていました。AAPXSがリアルタイムモードでオーディオのprocess()のみ利用可能になるという状況には対応できていないので、新たにもう1系列のAAPXSサポートを追加する必要があります。

(7) 独立性の高いAAPXS実装手段の提供: AAPの現在のAAPXSサポートには、リファレンスモデルといえるような規範的なモデルがありません。既知の拡張機能についてはStandardExtensionsというクラスが用意されていて、C++の複雑なマクロとクラス階層構造の上に実装されていて、整理が追いついていません。

10月は、これらの問題を割りと試行錯誤を繰り返しつつ洗い出しながら、包括的に解決できる仕組みを再構築しており、だんだん形になりつつはありますが、新しいブランチにのみ変更が溜まっていくような状況が続いています。

11月の予定

10月で開発に区切りが出た様子はまったくないので、11月も引き続きこの拡張機能まわりのサポートを設計しつつ実装していくことになるでしょう。あとは上記のalsa-libまわりの問題を解決してktmidiのMidiAccessにMIDI 2.0サポートを追加したものが出てくる可能性もなくはないです。あと、4年ぶりにADC23にオフライン参加する予定なので、その間は何も進展しないだろうし、内容次第でまた開発の方向性も多少影響を受ける可能性があるな、と思っています。ADC23があるので技術書典15はオンラインサークル参加のみの予定です。