6月の開発記録 (2021)

2021年も半年が過ぎてしまいました。去年の今頃は「来年には正常化しているだろう…いるんじゃないかな…たぶん…」くらいに思っていたものですが、まあ段階的に正常化しつつありますよね。日本以外はな。台湾なんかもう50人/日くらいに収まっているので、渡航できるようになれば概ね安心して行けることでしょう(まあ渡航を受け付けていないわけですが)。

海外のカンファレンスもぼちぼちハイブリッド開催に移行しつつあるようです。ADC21とか。もうちょっとちゃんと動くものがあればCfP出したいところですが…まだその時ではなさそう… 最近は無職の副業…といえるのかわからんですが*1…でロンドンの音楽アプリ開発のヘルプに入ったりしているので、リアルで参加しておこうかな〜くらいに思っています。まあその時までやってるか分からんですが…*2

まあそんなわけで、6月も5月に引き続きクローズドソース案件があって更新は少なめです。

Fluidsynth tests on Android

OSSではFluidsynthのAndroidビルドで動作するテストを追加したりしていました。これが地味に面倒で、まずテストそのものがctestで書かれていて(たぶんCMakeでサポートされているからなんじゃないかと思います)、これがテストごとにexecutableをビルドして実行するスタイルなので、Android NDKを使ったビルド・実行のあり方と完全に相性が悪い。仕方ないのでexecutableになるテストコードをスクリプトで書き換えてshared libraryをビルドできるようにして、それをABI別にビルドして実行できるようにしました。

Fluidsynthはなぜか(?)Azure DevOpsをCIで使っているのですが、ADではAndroidの4ABI分のビルドを並列に走らせられないレベルのスペックしかなく、ビルドスクリプトがABI別に動作するようになっているので、ビルドスクリプトの構成がやや特殊です(完全に無駄なエンジニアリングをさせられていそう…)。AD側は管理権限が無いのでメンテナーに丸投げして、自分はローカルスクリプトでビルドできるところまで面倒を見る…というつもりでいたのですが、CIもいじれそうな開発チームに加えられてしまったので、またそっちに時間リソースが消えるかもしれません。GitHub Actionsを常用している身としては、Azure DevOpsをいじりたい気持ちはゼロというかマイナスなのですが、メンテナ氏にはAndroidビルドを助けてもらった恩もあるしな…

tracking Android Studio

6月はAndroid Studio Canary (Bumblebee) もbeta (Arctic Fox) もちょいちょい更新されていたのですが、ついにBumblebeeのネイティブデバッガーにMemory Viewが搭載されたので、現実的なデバッグ作業が可能になりつつあります。CLionユーザーなら分かると思うのですが、IDEAではポインタの表示が配列みたいにはならないんですよね。なので内容を見ようと思ったらMemory Viewを見るしか無いわけです。構造化表示してくれるわけではないので、不親切なことに変わりはないのですが、無いよりはずっとマシなのです。

Memory View ただ、Bumblebee alpha02のプロダクションはかなりイマイチで、clangのパス設定が間違っていてコード補完などのC++編集機能がまともに動作しないとか、デバッガーが出鱈目な位置でブレークする(ので1行stepoverするごとに出鱈目な行にジャンプする…)など、使い物にならない状態です。仕方ないので、プロジェクトによって再現したりしなかったりするところから、問題ををそれぞれ調べて言語化してissuetrackerに登録する作業などをやっていたりしました。native toolchainまわりは特にユーザーが少ないのでわれわれ(ホントに複数形か…?)が藪を切り開くしか無いのじゃ…

BumblebeeがダメならArctic Foxでやればいいんじゃないか、と思うわけですが、Arctic FoxにするとC++ソースがAndroidプロジェクトビューに全然表示されない問題などにぶち当たったりして、そっちはそっちでうまく行かなかったりします。最近気づいた問題としては、.ideaディレクトリの内容がAFとBBで互換性が無さそう(なので切り替えるたびに全消しするしか無い)、みたいなものもありました。

まだ条件が判明しない類のバグがいくつかあって、たとえばデプロイメントに関して、インストールしたアプリのStorage & Dataをクリアすればコードがまともに動作するようになる、みたいな挙動を見るのですが、再現条件がわからずレポートにならないところです。Apply ChangesがおかしいのかAndroid Gradle Pluginがおかしいのか…

cmidi2とktmidiのUMP Byte Orderの調整

4月からAAPの開発の主なフォーカスがMidiDeviceServiceの応用にずっと集まっているところですが、MIDI 1.0アプリとMIDI 2.0アプリの相互運用がまだまだきちんと実現できておらず、その原因はさまざまな箇所に問題があった(ある)ためのようでした。そのひとつとして、まずcmidi2とktmidiの間でバイトオーダーの調整がきちんとなされていなかったことがあります。バイトオーダーが問題にならなかったMIDI 1.0とは異なり、MIDI 2.0では32ビット整数がデータの中心になっていることもあり、バイトオーダーがきちんと交通整理されている必要があります。

そういうわけで、今月はこの問題に対処する作業がいくつかのリポジトリ上で行われました。具体的な問題の内容については別途zennでまとめたものがあります。

zenn.dev

MIDI-CI generators in cmidi2/ktmidi

当初、AAPの内部プロトコルMIDI 2.0オンリーにするつもりでした。これはMIDI 1.0のメッセージをMIDI 2.0化するのは簡単で、それをMIDI 1.0に戻すのも現実的に可能だから、という目算があってのことだったのですが、aap-lv2やaap-juceも含めて少しusage scenariosを整備した結果、やはりMIDI 1.0アプリから接続したときはMIDI 1.0のままで、MIDI 2.0アプリから接続したときはMIDI 2.0で、といった切り替えをAndroid MIDI APIの枠内で実現するためには、外部から情報を与えるのには限界があるため、MIDI-CIで規定されているProtocol Negotiationを使ってMIDI 2.0モードへの切り替えを指示できるようにしよう、と考えるようになりました。

ひとつには、MIDI 1.0をサポートするAPIに自分がUMPを流し込もうとしていて、そのためにI/Oポートのデータ転送処理側で余計なバイトストリーム加工処理を走らせないでほしいと期待しているにもかかわらず、自分がむしろそういう期待を積極的に裏切りに行くという構図になっていて、少々忸怩たるものがある、という話があります。(まあそうはいってもタイムスタンプを加工する処理が必要になる以上、そのままのデータを送受信できる日は来ないわけですが。)

MIDI-CIは基本的にユニバーサルシステムエクスクルーシブなので、MIDI 1.0をサポートする出力ポート(Android MIDI APIではMidiReceiver)があれば、そこにsysexを送りつければ良いことになります。MIDI-CIメッセージの多くはinquiry/replyの双方向を前提としたものなので、MIDI 1.0の1ポート接続のみを前提としたら無理そうにも見えますが、Set New Protocolは一方的にプロトコルを設定するものとして送りつけることができ、その確認用には別途Test New Protocolメッセージが規定されています。MIDI 2.0に切り替えるSet New Protocolだけ一方的に送りつけて、後はUMPを送りつけるような仕組みにすれば、接続オプションを無理やりハックすることなくMIDI 2.0と1.0を切り替えることが可能そうです。

これを実現するため、cmidi2とktmidiにMIDI-CIのuniversal sysex generatorsを追加しました。ktmidiのほうはcmidi2に追加したAPIをそのまま持ってきただけなので、まだAPIの変更あるいは上モノの追加が想定されるところです。cmidi2のAPI追加がそれなりの作業量だったので、Kotlinコードは自動変換で対応しました。これもzennのスクラップで別途まとめてあります。

zenn.dev

ちなみに、これをAAPのMidiDeviceServiceに実際に組み込んで応用する部分は進んでいません。というのは、前述したAndroid Studioのデバッガがまともに使えない問題のせいでまともに先に進めないためです…そういうわけでこっちはBumblebeeの修正待ちです。

AAP Web UIの実装

MidiDeviceServiceの実装作業が先に進められないので、その間にできることを先に進めておこうと思い、最近は何度か段階的に着手していたGUI統合の作業を進めています。何度か書いていますが、プラグインとホストはアプリケーション プロセスが別々になるので、ホスト側にはプラグイン側が提供する…かもしれない…Web UIをインプロセスのWebViewでロードさせて、そこからアウトプロセスのプラグインを制御する、あるいは変更通知を受け取る、というやり方が必要になってきます。

Web UIをプラグイン側が実装する期待値は高くないので、デフォルトでポート全部を対象とするknobを出すUIを出そうと思っています。作りかけですが、MidiDeviceServiceのデモに上乗せしたらこんな感じです。

AAP Web UI

いや…まあさすがにknobの画像は差し替えるかもしれんな…? (あとキーボードもInstrument以外では不要だし) まあ機能的にはこのツマミをいじったらプラグイン側にパラメータ(ポート)変更命令が飛び、キーボードを押したらノート命令が飛ぶ、みたいな感じです。まだその受け口を実装というか調整していないので、この辺は来月の調整事項でしょうか。

*1:双方が雑で契約関係もろくに決めていなかったりとか…

*2:前回は夏の入りくらいに仕事を始めてM3直前に辞だった気がする