5月の開発記録 (2023)

5月はGoogle I/Oがあったり(リモートでひと晩見てただけ)、ADC-xがあったり(リモートでひと晩見てただけ)、技術書典14があったり(サークル出展して当日スタッフやってただけ)、割とタイムゾーンを越える必要があって、完全に疲労困憊していました。そんなわけでアウトプットも少なめです…いやそうでもねえかなこれ…

オープンなアプリケーションストアを改善する? PackageInstallerとそのアップデート

5月の上旬にTechBoosterで技術書典14向けの新刊を出すという話が出ていたので、Android 14向けにアップデートが含まれていて、サードパーティアプリケーションストアの文脈でそれなりに時流に乗ったトピックであろうPackageInstallerの話を書きました。が、その新刊自体がポシャったのでzennで供養しました(他の著者もやってたのでまねっこ)。

zenn.dev

この記事では完全に余談扱いのandroid-ci-package-installerですが、zennの別記事にも書いた通り、PackageInstallerベースの実装は(書いてはあったものの)パッケージインストールまでまともに進むことがなく、ずっとIntentベースのインストーラーになっていました。今回この記事の調べ物に合わせて、これを何とかして動くようにしました。

ついでにこの記事でも書いた事前承認のAPIもサポートしたので、Android 14以降のtargetであれば、事前承認さえあればインストール処理が完全にサービスベースになって、GitHubからのダウンロードが完了したときにAndroidシステムから承認UIが「飛び出てくる」こともなく「ちゃんと使える」ようになります。

ADLplug-AEとaap-juce-adlplug-ae

OPL3/OPN2エミュレーターのオーディオプラグイン版であるところのADLplugにはCMakeのビルドスクリプトが存在しているのですが、JUCE6で新しく導入されたCMakeモジュールではなく開発者の独自ビルドスクリプトで何もかもが構築されている(!)ので、すごいんだけどJUCE CMakeモジュールとしての応用は何ひとつ効かないという問題がありました。aap-juceを使ったビルドもProjucerで行っていました。

Projucerサポートもだんだん無理が出てきて、0.7.6ではついにビルドが通らなくなってしまったので(もはや原因を覚えていない)、独自にJUCE公式スタイルのCMakeサポートに置き換えたものをADLplug-AEという名前で新しく作ることにしました。ADLplugは実質もうメンテされていないので(そもそも最近jpcimaが何をしているのか、霊圧を感じない…)、独自版として自分の名義で開発してもいいだろう、みたいな判断です。

github.com

従来のADLplugと異なり、JUCE7に移行して、モーダルダイアログの類も全部禁止して再構築してあるので、Android版のビルドもシームレスに行えます(ADLplugにも自分のパッチを当てていたので、自分としては何の変化も無いに等しいのですが)。ついでにclap-juce-extensionsも組み込んだので、CLAP版もビルドできます。LV2サポートは従来のADLplugにもありましたが、JUCE公式のAtom portとLV2 Patchを使ったアプローチが2023年のLV2の王道スタイルなので、ADLplug-AE版を使ったほうがおすすめです。

これに基づいてaap-juce-adlplugは引退してaap-juce-adlplug-aeに置き換えられました。

相変わらずADLplugとOPNplugのどちらかしかビルドできないのはまだイマイチなのですが、手が空いてやる気が出たら複数プラグインをビルド出来るような仕組みを考えます…

aap-juce-ddsp

今月はNeuralNoteが話題になって、そういえば最近NNを活用する類のプラグインは何も移植してないな…となって、雑にmagenta/DDSP-VSTをAAP化しました。

github.com

シンプルなJUCEプラグインなら小一時間あれば移植できるようになってきたのですが、DDSPにはLinuxでちゃんとビルドできない問題があったり、tensorflowliteのビルドでちょっとハマったりして、1日くらいかかっていました。ただまあさすがにAndroidでは重いですね(とはいってもパフォーマンス分析までやっていないので、いつもみたいにJUCEの問題かもしれません)。実用性は疑問符がつくところだと思います。

NeuralNoteも気が向いたら移植しようと思いますが、すでにBYODで移植が実証できているRTNeuralだけでなく、onnxruntimeも使われているので、それ自体はAndroidで動作済としてもC++プロジェクトで使えるかわからないので、それなりに気合いが必要そうな印象です。

rtmidi-javacpp

5月はktmidiをいじる機運だと思っていたのですが、ktmidiの応用(ktmidi, mugene-ng, kmmk, augene-ng)をLinux以外の環境でいじるにはktmidiのRtMidiAccessを使えるようにしなければならず、先月書いた「rtmidi-jnaがApple Siliconでビルドできない問題」に向き合わざるを得なくなりました。

実際にはずっと向き合ってはいたのですが、(a) JNAeratorを何とかしてM1で動かすアプローチ (b) PanamaをAndroidでも使えるような代替を作るアプローチ (c) JavaCPPをrtmidiに適用するアプローチ、のどれも中途半端に試して成果が出ていなかった、というのが実態です。どれもそれなりに問題があります:

  • JNAeratorは仮にdawrin-arm64でビルドできるようになったとしても、そもそも延命して使い続けるのが妥当なのか? JNAeratorはBridJのためにあった側面が強く、Panamaとjextract(機能的にはこっちがJNAeratorに相当)の正式版が出たら完全にリタイアするのではないか? といった疑問が拭えない
  • Panama自体は当然ながらまだ正式版が出ておらずAPIも変更されうるし、あと根本的な問題として現行のjextractには単独でネイティブライブラリのロードが可能な仕組みがなさそう
  • JavaCPPはJNAやPanamaのようなJNI glue不要の仕組みではないので、ビルドしたバインディングライブラリにはネイティブコードが含まれ、各プラットフォーム/ABI用にビルドされなければならない。

いろいろ問題があるとはいえ、やってみればなんとかなるかもしれないと思って、とりあえず一番無難そうなJavaCPP版を真面目に取り組んで見ることにしました。さまざまな部分でハマりましたが、一応MIDIポートの列挙くらいはできています。

github.com

ただ、現状これをMaven Centralでパッケージ配布するところまでは進めていません。「無理そう」という印象があります。これは「darwin-arm64版をGitHub Actionsでビルドできない」のと「darwin-arm64ビルドを用意しなければならない」の2つが組み合わさって生じる問題なのですが、長くなりそうなので(先にコレを書き終わりたい)気が向いたら別の機会にまとめます。

Logic Pro for iPadの登場でオーディオプラグイン/DAW開発は変わるのか?

という記事をAppleの発表直後(実物が出る2週間くらい前)に書きました。

zenn.dev

2022年にはCLAPがオーディオプラグイン開発の世界を席巻しましたが、今年はAUv3化が最大の波になりそうな気がします。AUv3の発表は2015年で、すでに8年が経過しており、VST3並みに「無視されてきた」フォーマットといっていいと思いますが、Logic Pro for iPadが大々的にフィーチャーしてきたことで、AUプラグインのv3対応が始まる可能性は高いと思います。すでにBeatScholarなど、23日のLogic Pro for iPadのリリースに合わせて出してきたところもあります。

Compact ViewがプラグインUIとして求められるようになったら、プラグイン開発にだいぶインパクトがあるなと思っています。iOS AUv3のadoptionが進めば、macOS上でのデフォルトプラグインフォーマットもAUv3にシフトしてくる可能性が高いです。そして各社DAWがAUv3をサポートしようとすると必然的に「Androidではオーディオプラグインをサポートしないの?」っていう話が上がってくるはずなので(たとえば今月ではないけどこんな感じ)、AAPの開発をそれなりの段階まで進めないとなあ、と思っています。

exploring SurfaceControlViewHost for AAP GUI vNext

AAP GUI統合のアプローチとして、主にWeb UIを使ったプロセス境界越えとSystem Alert Windowがあるという話を、4月まではずっとしていて、ここはAndroidフレームワーク側も改善の余地があるんじゃないの?みたいな話を書いていましたが、ここにきてSurfaceControlViewHostという新しいAPIを発見したので、最近はそのアプローチでAUv3相当のプラグインUIを実現できるのではないかと考えています。

SurfaceControlViewHostはAndroid Rで新しく追加されたAPIで、「(主に他の)アプリケーション上のSurfaceViewをBinder経由で操作する」仕組みです。現状このAPIOSSの世界ではWear OSでしか使われていません。使い方は以下の記事が詳しくまとめてくれています。というかこの記事しか情報源がないし、自分もたまたま目にしなければこのクラスの存在自体知ることがなかったし、この記事でも「Googleが何も詳細をアナウンスしていない」と書いていたり…

commonsware.com

CommonsWareは最近わたしが新しいAndroid APIについて調べているとだいたい引っかかるサイトで、その手の情報はここから見始めるといいんじゃないかと思います。

描画先としてSurfaceViewが選ばれるだけで描画元は「Display IDだけあれば描画できる」ものであれば何でもよく、UIインタラクションも適宜伝播されるという感じなので、試しにComposeViewを転送するサンプルを何も考えずに書いてみましたが、全然できませんでした。いろいろ試行錯誤して出来るようになったので、サンプルコードを新しく適当に作ったリポジトリに公開してあります。

github.com

Composeが使えるくらいならSystem Alert Windowを置き換える存在として十分に役に立つだろうと考えて、AAPにもサポートを追加してみましたが、現状では(SystemAlertWindowと同様に)単にWebViewを使ってdogfoodingいるだけで、GUIイベントのプラグイン本体とのインタラクションも十分に行えていない状態です。in-process UIになるのでプラグイン実装のコストは格段に下がるはずですし、もうちょっと有用なデフォルトUIをComposeで用意したいところです。

aapinstrumentsample w/ native UI

Compose Knob Control

SurfaceControl UIを正式に推奨アプローチにするなら、まずネイティブUIとしてのちゃんとしたdogfoodingが必要だと思っているのですが、現状AndroidのネイティブUIとして動作する有用なコードが存在せず、WebViewで作ったUIのほうがまともなので、とりあえずComposeで作った雑なUIでいいから動くものがほしいかな…となっています。

しかしこれは待っていても出てこない類のものなので、とりあえずKnobから作るか…と思って自作することにしました。Jetpack Compose Knob などでぐぐるとそれっぽいyoutube動画が出てくるのですが、実装アプローチも操作方法もコレジャナイ感が強いというか、われわれがKnobコントロールに求めるのはKnobGalleryのフリーKnob素材がそのまま使えることです。超縦長(たまに横長?)の画像の、もっとも値に近い矩形を表示するという原始的なアプローチですが、コードなしにビューを実装できるという点でこれ以上移植性の高いknobは無いでしょう。AAPのWeb UIで使っているのもwebaudio-knobでKnobGalleryにある画像ですし(作ったのは自分ですが)。

そういうわけでざっくり作りました。近日中にWaveform Viewなんかも移して独立したリポジトリにまとめようと思います。

ComposeKnob sshots

ちなみに矩形と書きましたが正方形しか(まだ?)サポートしていません(正方形でない画像はvalidなのか、validだとしたらどうやって適切な1要素を切り出せるのか、何もわからない)。

関連して knob or slider? みたいなことも考えたのですが、現状以下のような理由でモバイルにはknobのほうが合っているかな?と思っています:

  • sliderのほうがでかい(横か縦に伸びる): モバイルUIでスペースをとるのは基本的に好ましくない
  • 視認性はsliderのほうがわずかに良いが、knobでもいったん指を左右に「どける」ことでなんとかなる(それで値が「見えれば」十分)
  • sliderは本質的に指の位置と表示位置が一致しないといけないが、knobはドラッグ操作の開始点として存在さえすれば十分で、動きに合わせた値の変更幅も調整できる
    • sliderもknobもホールド操作などをトリガーとして拡大スライダーをオーバーレイ表示するようなアプローチがあり得る(ただ、ホールド位置がスクリーンの左端や右端などだとそこから動かせる範囲が限られるし、縦スクロールバーにしても上端・下端で同じことになる)

現状、Compose Knobは上下ドラッグでのみ値を変更するので(デスクトップでは一般的な挙動だし、モバイルでもいちいち2本指で回転とかしたくないわけです)、スクリーンの上下端に置くと変更範囲が限られるわけですが、2本目の指を使って反転操作や微細操作(webaudio-knobのshift+マウス操作)に対応する必要はあるかもしれません。

操作中だけ表示するツールチップラベル表示もデフォルト実装があって(常時表示も可能、実装カスタマイズもComposableとして可能)、Knobの最小サイズとして50.dpを初期値に割り当てていて(推奨しないけどより小さくできる)、これはDPの160dpi = 1inchという定義から約0.8cmとなり、細い指であれば値ラベルを別途用意しなくても見えるとは思いますが、指で完全にノブが隠れてしまったとしても、指を左右に水平にどければ何も値を変えずに見えるようになります。1本指のときに左右に操作を割り当てると指を「どける」操作ができなくなるので、これは避けたいですね。

来月の予定

6月はひさびさに何も締切やイベントがないので、AAP GUIサポートなど仕掛りの作業をのびのびと進めたいと思っています。5月にはMIDI 2.0のアップデートが出てこなかったので、ktmidiに手を加える必要が生じるとしたら6月になりそうです(さらに順延されていなければの話ですが)。