2019年以来東京と台北にしか出現していなかったのですが、今月は3年半ぶりに昨日まで他県に出かけていました。完全にあぶねーなこりゃ…ってなったので、まだしばらく旅行とかしなくてもいいかな…まあそんなわけで今月は(今度こそ)少な目です。
ktmidiのMIDI 2.0 June 2023 Updatesサポート
6/12にMIDI 2.0 updatesがようやく出たので、とりあえずktmidiのエコシステム(ktmidi/mugene-ng/kmmk)でUMPサポートをアップデートしました。UMP仕様そのもののアップデートについては↓に詳しくまとめてあります。
ktmidiではUMP Stream messageやFlex Dataメッセージを生成できるようになり、mugene-ngではMIDI 2.0対応の音楽ファイルフォーマットを変更して、各トラックはMIDI Clip File specification準拠のデータを生成するようになりました。複数トラックを統合する音楽ファイル自体はSMF Container Fileと呼ばれている秘密の仕様がまだ公開されていないので対応していません。mugene-ngのFlex Data対応作業をやっていて思いましたが、MIDI Clip FileはMarkerイベントが存在しないままではSMF format 0の代替としても使い物にならないですね。MarkerはContainer Fileのほうでカバーされるべき機能なので、SMFの代替は「実質的にまだ出ていない」とわたしは捉えています。
今回のMIDI 2.0アップデートはUMPだけのアップデートではないのですが、とりあえずMIDI-CIは現状ほぼ自分のプロジェクトと無関係なので(特にSet New Protocolが廃止された結果ますます関係なくなった)、その辺のアップデートはまだです。Android用のMIDI-CI Discovery Serviceくらい自作してもよいのですが、Android audio teamから出てくるだろうし、特に自分がやりたいことではないので様子見です。
あとは新しいフォーマットに対応したMidi2Playerのdogfoodingに使えるアプリケーションをビルドしたいところで、managed-midiの応用として存在していたxmdspの置き換えになるやつを作りたいところなのですが、Jetpack Compose 1.4のMultiplatformがJDKサポートまわりでリグレッションを起こしていて、SwingのAPI にしか無いファイルダイアログを出せなくなっているので、Compose Multiplatformが正常化するまでは様子見です。
compose-audio-controls
先月Knobを作った話を書きましたが、続いてKeyboardも作ったので、とりあえずこれでまとめておくかと思ってリポジトリを作って公開しました。
Material Design準拠のキーボードウィジェットはとにかく「表示できるキーを多くしたい」と「48dpの範囲でタッチが混乱しない」のせめぎ合いになるわけですが、この実装では「タッチUIの場合はポイント位置と中心座標に最も近い鍵を選ぶ」「それ以外のポインティングデバイスでは正確にポイント位置の下にある鍵を選ぶ」というアプローチで実用性を担保しています。
ドラッグ操作に対しては、ピッチベンドを送れるようになっていますが、この種のキーボードコントロールに求められる典型的な動作はシンプルなノート切り替えなので、デフォルトは単なるノート切り替えにして、この2つの動作モードを切替可能にしています。マルチタッチでドラッグ操作が可能なので、ノート別ピッチベンドも送信可能です。そのためにMIDI 2.0モードのスイッチもdemo appでは追加してあります。とはいえノート別ピッチベンドに対応するプラグインがまだ無いわけですが。
ピッチベンドに割り当てているのはdemo appでしかないので、他のコントロールに割り当てることも可能です(アプリ次第)。現時点では、縦方向ドラッグ、横方向ドラッグ、プレッシャーの3つがこのコントロールで受信可能です。demo appでは縦方向がPolyphonic Aftertouchに割り当てられていますが、本来ならプレッシャーに割り当てられていたほうがいいやつでしょう(縦方向はExpressionとかがよさそうだけど初期値とかリセットとかどうするか悩ましい)。
ちなみに、MIDI 2.0切り替えスイッチはUMP仕様に新しく追加されたStream Configuration Requestを(現在のプロトコルを無視してUMPで)一方的に送りつけてそれ以降は勝手にUMPを送りつけるスタイルです。受信するMIDIデバイスがAAPのMidiDeviceServiceならこれで効きます(どちらもmainブランチのみ)。以前はMIDI-CIのSet New Protocolメッセージを一応MIDI 1.0のSysExとして送り付けていたわけで(返信は無視)、MIDI1を受け付けているところにUMPを送りつけるのは以前よりさらに乱暴な挙動なのですが(!)、little endianな環境なら(大抵のAndroidデバイスはそう)12バイトの0が送りつけられることは仕様上無いだろうし、big endianな環境でもF0で始まるのはSysExで、ステータスコード5に相当するSysex Vendor IDは操業停止したPassport Designs社なので、99.999%無害と言って良いでしょう(!)
compose-audio-controlsはKMPで作られていますが、主にAAPのGUIのために存在しているので、AndroidでタッチUIとして使えることを主目的にしていて、デスクトップの仮想MIDIキーボードの実装であることを主目的としているkmmkとはだいぶ設計思想が違います。たとえばこういう用途を想定しています:
JUCEホストアプリの上でJetpack ComposeのプラグインUIが表示できていることがわかるような画面にしましたが、AAPのnative in-plugin-process GUIの今のデフォルト実装はこうなっています(あくまでデフォルトUIでしかないので、Jetpack Composeで自作UIを構築して表示させることも可能です)。先月、SurfaceControlViewHostでネイティブUIを表示できるとアピールするならdogfoodingが必要だという話を書いたのですが、それを実践した感じです。先月のsshotはin-host-processでも可能なWebViewでしたが、今月のはin-plugin-processのComposeViewです。
正直Jetpack Composeはスクロール周りのサポートが煩雑でデメリットのほうが大きそうだなあという印象ですが、その辺はSurfaceControlViewHost上でJetpack Composeを動かす知見が溜まってきたらどうにかなるかもしれません。
UIまわりは、サイズ設定を考えないとな…というところで止まっています(その頃にMIDI 2.0 updatesが来たので頭のチャンネルを切り替えてしまった)。
AAP: 動的パラメーターサポートの改善、列挙値サポート、aap-juceのデスクトップビルド不要化
Composeベースのnative default GUI実装がざっくり出来たので、パラメーターリストで「優先度」の設定を「プロパティとして」取得できるようにparameters拡張のAPIに手を加えたのですが、その過程で、パラメーターリストを動的に生成するプラグインのプロパティを取得できるネイティブAPIを、あくまでKotlinのAPI経由でしかパラメーターを取得しないホストでは呼び出していないことに気が付き、動的なパラメーターリストもIPC経由できちんと取得するように作り替えました。
それから、パラメーターリストをそもそも動的に生成していればaap_metadata.xml
に何も記述されていなくても良くなるはず…というのを思い出して、まずaap-juceでこれを実現しました。先月作ったaap-juce-adlplug-aeでは、現在<parameters>
がコメントアウトされています。
パラメーターリストが無くても良い、ということになると、JUCEプラグインからaap_metadata.xml
を自動生成する必要はほぼなくなります。メタデータの自動生成には「AAPを組み込んだJUCEプラグインのデスクトップビルド」が必要で、これがJUCEプラグイン移植の難易度をかなり上げていたのですが、このステップが不要になったことで、移植の可能性が高まったと思います。たとえばSurge-XTはこの段階で挫折していたのですが、手作業でaap_metadata.xml
を作成して動かせるようになりました。
aap-lv2でのサポートはまだです。aap-import-lv2-metadataはデスクトップ版のプラグインをlilvでロードできてしまえばいいので、移植の妨げになったことは現状一度もなく、実装を移植するモチベーションがあんまし高くないところです…(!) まあ、やったほうがいいですけど。今月はAIDA-XをAAPに移植したのですが、こういうのもパラメーター情報を含めなくても済むようになりますし。
あと関連して列挙値サポートもparameters拡張のAPIに追加してあります(構造が複雑なのでプロパティでは解決できなかったやつです)。パラメーター情報に列挙値リストが含まれている場合は、GUIでも表示を変えるようになりました。オーディオプラグインの場合、列挙値は基本的に「数値に対応する文字列ラベル」になり、数値はfloatのままであることが多いので、native UIのほうはknobのままで(スペース的に厳しい)、値ラベル文字列だけ列挙値のものになります。列挙値はaap_metadata.xml
にも記述可能で、aap-metadata-generatorやaap-import-lv2-metadataによる自動生成もサポート済です。
今回デスクトップビルドを省略できるようにしたことで、aap-juceの難易度はだいぶ下がったと思いますが、もうちょっとがんばってCMakeLists.txtに数行追加するだけで対応完了できるようなところまで持っていきたいところですね。clap-juce-extensionsなんかは実現できているので、あの辺を見習いたいところです。