COSCUPのために台北に来ています(気が早い)。毎月のように出国していて、全然落ち着いて日本で活動できないですね…
uapmd MIDI-CI integration
先月書いたuapmdのMIDI-CI対応のためのktmidi-ciのC++化モジュールであるところのmidicciですが、今月も隙間時間を縫って手を加え続けていった結果、ようやくMIDI-CI receiverとして機能するようになってきました。Property Exchangeのやり取りが可能になれば、read-onlyでしか機能しないレベルであっても、AllCtrlListやProgramListは公開できることになります。そういうわけで、満を持してMIDI-CIデバイス化に着手することにしました。
ただ、ktmidi-ciとその応用としてのktmidi-ci-toolは、現状ほとんど混然としていて、ktmidi-ciの機能だけでMIDI-CIデバイスの機能をクリーンに追加できるほどうまく設計されているわけではありませんでした。動作確認用ツールの他にはアプリケーションが何も無く(これはどのMIDI-CI実装もそう)、uapmdのMIDI-CI統合は初の試みということになります。midicciはktmidiの移植コードとして成り立っているので、midicciに直接手を加えるのはあまり筋が良くありません。ということで、変更はktmidiのレベルで加えつつ、midicciの変更は「ktmidiの変更点をこっちでも反映しる」という感じの命令をClaude Codeに与えて進めています。
また、AllCtrlListやProgramListといった「標準プロパティ」については、そもそも明確に実装があったわけではありませんでした。これらについてはJSON Schemaの定義が存在しているので、これをマスターデータとしてコードを自動生成できればいいと思っていたのですが、JSON Schemaを解するKotlin Multiplatformのライブラリが無く、JSON Schemaライブラリを自作するのは面倒だなあ…MIDI-CIプロパティのJSON Schemaから手作業でコードを作るのも面倒だなあ…と、とにかく面倒がっていました。それが実際に使うコードを作るという段になると、さすがに多少やる気がでてきて、結局、手作業でコードを作成しました。この辺はいったん雛形を作ってからClaudeにやらせているところもあります。MIDI-CIプロパティのJSON Schemaはそんなに件数が多いわけではないので、コードジェネレーターを作る時間はもったいないところです。
この辺の作業を進めるためには、ktmidi-ciモジュールをktmidiモジュールに依存するように変更する必要があって(ktmidi-ciはktmidiに依存していなかったわけです(!) )、これはやや破壊的変更っぽい側面があるので億劫になっていたのですが、9月にPanamaがJava 25 LTSで使えるようになれば、最新のktmidiも抵抗なく破壊的変更を加えられるという見込みもあって(すでにv0.10.0のktmidi-jvm-desktopはPanama依存なのですが)、やや先走りですが変更に踏み切っています。
C++のほうはそもそもktmidiではなくlibremidiを使っているので、実装が一致しない側面があってやや座りが悪いところがあるのですが、とりあえず現状有姿で進めています。uapmdでも満を持してmidicciを依存モジュールとして追加して、とりあえずAllCtrlListはuapmdのパラメーターリストから生成できるようになりました:
bsky.app仮想MIDI 2.0で演奏できるOPNplugのプラグインパラメーターをAssignable Controllerに割り当てて、その情報をMIDI-CIクライアントで取れるところまできた(内容はまだまだいろいろおかしいけど) ProgramListをpresetsに割り当てて、StateListをStateバイナリに割り当てたら、とりあえず当面の目的は達成だ
— Atsushi Eno (@atsushieno.bsky.social) 2025-07-27T12:17:56.100Z
ktmidi-ci-toolだけでなく、JUCEのMIDI-CIモジュールのdogfoodであるCapabilityInquiryDemoでも取得できています:
bsky.appVST3のOPNplugだとパラメーターが2100件くらいあって、それをAssignable Controllerで制御可能にすると、AllCtrlListの内容がそれだけのパラメーターが全部で500KB近いJSONメタデータになる。 gist.github.com/atsushieno/2... JUCEのCapabilityInquiryDemo取得させたら何分もかかってこれはちょっと使い物にならない。デモアプリにすぎないから真面目に最適化されていないっていう話はあるけど、現状これ以上に作り込まれたツールはあとは自作のktmidi-ci-toolくらいしかなさそう(これはちゃんと読める)。
— Atsushi Eno (@atsushieno.bsky.social) 2025-07-27T15:23:28.755Z
ただ、blueskyの投稿でも書いている通り、MIDI入力を受け付けるVST3には悪名高い「(CC128件 + Program Change + Channel Aftertouch) x チャンネル数」の隠しパラメーターという問題があって、2100件近いパラメーター…から自動生成されたMIDI-CIプロパティを扱うことになります。JUCEのこのアプリは全然最適化されているわけではないので、およそ実用的な操作はできません。まあこのJUCEアプリのようなコードでMIDI-CIデバイスを使う場面は無いと思いますが、ktmidi-ci-toolにはこのような問題がなく、Compose Multoplatformを使うことでこの辺の問題が自然に解決できているありがたみが表出した感じです。
ちなみにAllCtrlListを実装するために仕様書の細かい部分をいろいろ読んでいたら、仕様書として不鮮明な箇所がパラパラと出てきて、これはまともに実装しないうちに規格化しちゃったんじゃないの…?と思いながらいくつかmidi.orgにレポートしています。正直あんまし良い仕様だとは思ってないです。
本当は続いてProgramListにも対応したかったのですが、そもそもuapmdがまだProgram Changeに対応できるようなPresetsアクセスの共通化を実現しておらず、そっちが解決してから対応することになりそうです。Presetsおよびその前提となるStateのAPIは、プラグインフォーマットごとの差異が強いので(これについては理想のオーディオプラグインフォーマット本で詳しく書いてあります)、十分な時間があるときに腰を据えて取り掛かりたい課題のひとつですが、例によって1箇所で落ち着いて作業できる状況はまだまだ先になりそうです。