12月の開発記録 (2024)

2024年がもう終わろうとしています。今年は個人開発は惨憺たる状況でしたが、半分以上は予想外にしごと(いろんなレベル)が舞い込んできて、常に何かしらに気を取られていた(いる)状況だったということがあります。まあ1年分を振り返るのは時間がもったいないので、今月分だけ書きます(1年分については、こっちではなくgithub.ioのほうにまとまっています)。

experiments

今月も引き続きプラグインホストみたいなやつを作っていたのですが、半分以上はWebViewを使ったWeb UIをどう構築したもんかな…とこねくり回していたように思います。この辺の知見はある程度たまったら公開したいところです(書きかけが放置されている状態)。webview.h、choc webview、saucerを触ってみて、現状saucerが一番よさそうと思っていますが(chocはコードを書く上で致命的なバグが放置されているレベルなので使い物にならない)、どのWebViewにも依存しないWebView実装中立なAPIを作ってコーディングしています。

実装中立にするのは割と重要で、MVCのようなアプリケーションのモデルを特定のWebView実装の上に構築できるほどには信頼できるものが現状ありません。仕組みまで構築したくはないのですが、下回りが駄目になると上に積み上げたものが全滅するので、なるべく層を切り分けて作り上げたいところです。

UIでは現状ReactやVueではなくShoelaceやwebaudio-controlsなどのWebComponentsの技術を使っていて、WebViewからのinterop部分は現状JSONにシリアライズしています。ここにWITなどが使えると可能性が広がると思うのですが、これは各プラットフォームのWebView実装のレベルで追加されないといけないので敷居が高いですね。開発体験は良くないので他の人におすすめはしませんが、WebViewを使うなら他にない感じです(今回はQt等が動かないような特殊環境も想定していて、多分WebViewで無理やり作ると思います)。

あと先月分がスカスカだった理由のいくぶんかは今月のJUCE Advent CalendarのネタだったDAWの挙動に依存するコード、の反対側つまりプラグインの挙動に依存する部分にいろいろ振り回されていた、ということもあります。まあこれは10月からそうなのですが(それが先月の同人誌のネタに繋がる)。現状VST3, AU, LV2に対応していて、CLAPにも対応したいのですがそこまでやると手が回らなくなる感じです。

ちなみに、まだpublicにする予定はなかったのですが、ちょっと他所のリポジトリで再現報告したり他所のプライベートリポジトリで一部を使いまわしたい等の理由があってpublicになっているだけなので、宣伝する予定はありません。まだPoCとしてすらまともに動きません。

externals

今月はrtlog-cppを複数ログクライアントで使えるようにするパッチをいろいろ書いていました。これはzennにまあまあ詳しく書いたのでこれで終わりです。rtlog-cppは懇切丁寧に対応してもらえて非常に体験がよかったし、API設計もユーザーフレンドリーなかたちで再構築してもらえたので全面的にお勧めできます。

あとsfizz, sfizz-uiのdarwin-arm64版をビルドできるようにしたりちゃんと使えるようにしたりといったバグフィックスもやっていたのですが、sfizzは完全に開発チームが止まってしまっていて(開発者が就職してからずっとそうではある)、これはのんびり待たないとなあという気持ちと、来年SforzandoがLinux対応したらもう開発しなくなっちゃうかもなあという悲観的な読みがあります。まあOSS実装はそれでもsfizzが最先端なので、Sforzandoにお任せというわけにはいかないし、最悪の場合自分で何かしらのアプリケーションのレベルで独自に巻き取るしかないかも…とはちょっと思っています。

extended

そういうわけで、今年はいろいろ仕掛のものをかかえこんだまま2025年に持ち越す感じになりそうです。どうも春先まではタスクがいっぱいいっぱいになりそうなので、こっちに書くネタも少な目になりそうですが、地味に進めていければと思っています。

JUCEのソースからDAWのプラグインホストの挙動の違いを探し出す

JUCE Advent Calendar 2024、4日目のエントリーですが、最近すっかりAndroidではなくデスクトップでJUCEを使わないプラグインホストを作る遊びにふけっているatsushienoです。

オーディオプラグイン開発者は、どのフォーマットであれ、さまざまなDAWでプラグインをロードできなかったり正常に動作しなかったりといった問題に悩まされてきたことでしょう。これはJUCEのようなプラグイン開発フレームワークを使っていると、JUCEにさまざまな部分で面倒を見てもらえている側面があります。特定のDAWでのみ動作しない問題が、何年にもわたってJUCEチームに分析され、回避策が実装されているということです。

具体的にJUCEにどんな面倒を見てもらえているのか、興味が出てきませんか?

実はこれを、全部ではないにしても、大部分(多分)を調べる手段があります。juce_audio_processors/utilities/juce_PluginHostType.hというクラスがあります:

class PluginHostType
{
public:
    ....

    enum HostType
    {
        UnknownHost,                /**< Represents an unknown host. */
        AbletonLive6,               /**< Represents Ableton Live 6. */
        AbletonLive7,               /**< Represents Ableton Live 7. */
        AbletonLive8,               /**< Represents Ableton Live 8. */
        AbletonLive9,               /**< Represents Ableton Live 9. */
        ...

そしてisXXX()関数(XXXにはAbletonLiveなどのホスト名)が40件強含まれています:

      /** Returns true if the host is the JUCE AudioPluginHost */  
        bool isJUCEPluginHost() const noexcept { return type == JUCEPluginHost; }  
        /** Returns true if the host is Apple Logic Pro. */  
        bool isLogic() const noexcept { return type == AppleLogic; }  
        /** Returns true if the host is Apple MainStage. */  
        bool isMainStage() const noexcept { return type == AppleMainStage; }  
        /** Returns true if the host is any version of Steinberg Nuendo. */  
        bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; }  

このisXXX()関数の利用箇所を追跡していくと、プラグインをロードしたホストによって、どのような回避策が取られているのか、調べることができます。各DAWにどのような問題があるのか簡単に調べられるわけです。このクラスだけがすべての特別ルールを掌握しているわけではありませんが(たとえばJuceVST3EditControllerにはisBlueCatHost()という関数があり、BlueCat's PatchWorkなどに特化した処理が見られます)、大部分はここから調べられるでしょう。

JUCEを使っていない人も、「JUCEでは対策済みの問題」かどうかを調べられますし、プラグインホストを開発している人も、どんな問題が発生しうるのか知ることができます。

さて。このisXXX()の関数は(本稿執筆時点で)40件以上もあるので、全部を追っかけていると大変そうに見えますが、実は(CLionのclang analyzerで見ている限り)半分以上が定義だけされていて使われていません。実際に使われているのは次の関数だけです。一言で説明が終わるものはついでにこのリストで済ませちゃいましょう:

  • isAbletonLive()
  • isAdobeAudition()
  • isBitwigStudio() : VST3 on LinuxでchildBoundsChanged()が発生した時にrepaint()も呼び出すように動作を変更します
  • isCubaseBridged() // "Steinberg Cubase 5 Bridged"
  • isFruityLoops() // FL Studio
  • isLogic() : AudioUnitでバスの情報を取得するとき、Logicだけは最大でも8チャンネルまでしか無い前提で処理されます
  • isPremiere()
  • isReceptor() : VST2のUIでマウスイベントに対応するaddMouseListener()を呼び出します
  • isReaper()
  • isSonar() // Cakewalk
  • isSteinberg() (isCubase()、isNuendo()、isSteinbergTestHost() を含む)
  • isWavelab() (isWavelabLegacy()を含む)

(上記のほかに)どんな問題が回避策として実装されているのか、具体的に見てみましょう:

  • isWavelab() || isCubaseBridged() || isPremiere() : これらのホストでは、VST2のGUIがUIスレッドから作成されないことがあるようです。
  • isAdobeAudition() || isPremiere() : これらはVST3のGUIã‚’IEditControllerのAPIから正常に取得できないのか、常にGUIを生成できるものとしてコーディングされています
  • isFruityLoop() : FL PatchはsetActive()を呼び出す前(あるいは呼び出し中)にprocess()を呼び出す実装になっていて、それを防ぐ仕組みが必要なのだとか
  • isAbletonLive() || isSonar() : これらのDAWはMIDI-only pluginをロードしてくれないので、オーディオ出力をでっち上げて対応する必要があるようです(これはJUCE本体ではなくMidiLoggerPluginDemoのコードで実装されているので、JUCEプラグインでも個別に対応する必要がありそうです)

VST3ホストウィンドウのリサイズも個別に対処されていますが、条件がややこしいので、コードをそのまま引用します:

#if JUCE_MAC  
 if (host.isWavelab() || host.isReaper() || owner.owner->blueCatPatchwork)  
#else  
 if (host.isWavelab() || host.isAbletonLive() || host.isBitwigStudio() || owner.owner->blueCatPatchwork)  
#endif  
  setBounds (editorBounds.withZeroOrigin());

だいたいこれくらいでしょうか。GUIインスタンスを生成するのにUIスレッドから呼び出されない等は割とビックリする案件ですが、幸いVST2固有の問題のようなので、現代では概ね整理されプラグインの仕組みが開発者に理解されてきたということでしょう。

JUCEが回避策を提供しているDAWの問題としては、これらの他にも例えば「GarageBandやLogic Proがパラメーターのリストを取得する時にパラメーターIDでなくパラメーターリストのインデックスを使用してしまっていて、不要になったパラメーターをプラグインの新バージョンで安心して削除できない」というものがあります。これを解決するのがjuce::AudioProcessorParameterのコンストラクターに渡されるversionHintなのですが、先日の技術書典17で公開した新刊でもう少しだけ詳しく解説しているのでそちらを見て下さい(無料です):

以上ちょっとした小ネタでした。今回紹介してきたのはあくまでプラグイン側(ホストの挙動の違いの影響を受ける側)の実装に関する問題なので、プラグインホストの実装にかかるバッドノウハウの類は、また別途いろいろあります。ただPluginHostTypeクラスのような分かりやすいフラグ集があるわけではないので、収拾して体系的にまとめるのはやや骨が折れそうです。書けそうだったら機会を見てまとめようと思います(期待値低)。

11月の開発記録 (2024)

何か今月は毎週末のようにイベントにふらふらと参加していて、後半は親族の葬儀などが入ってしまい、妙に忙しくなり、開発にあんまし時間が割けなくなっていました。

最近は主にWebViewをどうオーディオアプリケーション(プラグインではなく)のUIとして構築できるかを模索していて、いろいろ模索しているのですが、これはここに書くよりは別途そのうちまとめて書こうと思います(時間切れ)。公開コードでは何も見えませんがwebviewとかsaucerとかに片鱗が見えます。

参加していたやつ

技術書典17

今回は11/3にオフライン参加していました。いろんな方に来ていただいていたのですが、なぜかめちゃくちゃ波があって、暇なときはぼ〜っとしているのに忙しいときはみんな一度にやって来てボトルネックの単一障害点はあっぷあっぷしていました。お話できなかった人も少なからずいて心残りの少なからぬ日でしたが、多くの方とは十分にお話できてそれは良かったです。

先月書いた新刊などを販売していました。当日は500円の印刷版も販売していて、やはりこれが一番売れていました。1冊売れるたびに100円の赤字になったような気がしますが、まあもとが無料本だしな…。新刊は、今のところはまだ無料配布しています:

techbookfest.org

本当は英語版を作って公開しようと思っていたのですが、仕事やら雑事やらが舞い込んできて先送りになっています。原稿も全然書けてないし、これに着手できるのはだいぶ先になりそう…

ADC2024 (オンライン参加)

毎年「行こうかな…どうしようかな…」と迷っては行ったり行かなかったりするADCですが、今年は10月末頃から依頼が入り込んできたりなどして、行かない方に振れました。

正直オンラインも参加しなくてもいいかな…と思っていたのですが(オンラインだけでも100GBP = 20000円近くするので明らかに費用対効果が悪い)、結局ほぼストリーミングを眺めるためだけに参加としました。

ADC24のセッションで期待していたのは先月も書きましたがプラグインフォーマットの比較評価したものでしたが、半分くらいは自分が書いていた話とかぶった問題意識だったと思います。AUの状態を維持しまくるAPIが良くないみたいな話は予想外で良いと思いましたが、よく考えたら自分もLV2のinstantiate()のsampleRateの件で同じ議論をしていたかも…? 一番興味深いと思った(そして一番話題にもなっていた)のは、「プラグイン インスタンスの情報はホストとプラグインのどちらがsingle source of truthになるべきか」という議論で、プラグインフォーマットごとに異なる側面があるというのは面白い分析でした。自分の視点としては、ホストが保存・復元できないtruthは評価の対象外だと思っています。

他のセッションだと、思いのほか良かったのはalt C++ / safe C++関連のセッション、debugger visualizerのセッションあたりでしょうか。まあ今後1年くらい動画は上がってこないので、ADCでしか出てこない話題は無視していいと思います。RealtimeSanitizerは次のclangリリースに入ってくるようですし、期待して待ちましょう。

SESSIONS 2024

ADCのだいたい裏番組くらいのスケジュールで開催されていたので、こっちに行ってきました。demosceneもインタラクティブアートも全然入り込んだことがなかったのですが、内容は面白かったです(1日目は途中でフェードアウトしましたが)。

当日はPC98とかSC-8850とかAmigaとか持ち込んでる人たちがいたのですっかり老人会ムーブに巻き込まれてしまいましたが(Amigaなんて触ったことないけど)、新しいもので何か出したい気持ちは出てきました。

↑のふいんき(なぜか変換できない)はbskyで流してたのでこっちで:

b35.jp

10月の開発記録 (2024)

去年もM3サークル参加を申し込み忘れていて、去年は伸び伸びと開発していたのですが、今年は技術書典17にオフライン参加予定です。技術書典、去年はADC23とかぶってオンラインのみ参加でしたが、今年は逆に(現時点で)ADC24に参加予定ないです。いま興味があるのはどちらかというとLinux Audio Conferenceのほうですが、これはまだだいぶ先ですね。

そういうわけで、10月は主に先月から手を付けていたプラグインホスティングまわりのコードを書きながら新刊を用意していました。githubだとrtlog-cppとかchocとかでバグ修正していた程度しかやってないように見えるかと思います。

先月も書いた気がしますが、プラグインホスティングのコードはもともと雑にMIDI 2.0デバイスがほしいな…と思ったところから作り出して沼に落ちた感じで、今月はAudioUnitのためにAudioToolboxとかLV2のためにlilvとかを使ってマルチフォーマット前提にいろいろ試行錯誤している感じです。特にVST3もAUも直に触ったことは一度もなかったので、みんな(juce_audio_plugin_clientを使わない勢は)苦労しているんだなあと思いながらコードを書いています。

理想のオーディオプラグインフォーマットを求めて(技術書典17新刊)

最近は商業案件で執筆しているものがあるのですが、その辺の下地を積むのも兼ねて、技術書典17ではこの辺の知見とこれまで書いてきたプラグインフォーマットの話を合わせて、VST3, AU, LV2, CLAPの各フォーマットをいくつかの側面で比較し、可能なときは優劣を判定する(!) …という本を出すことにしました。

techbookfest.org

今回は30ページちょっとで、図版を一切入れていないクオリティなので(だからページ数が少ないってことはあります)、デジタル版は無料です。11/3の技術書典17オフラインでは紙で読みたい人向けに薄い本をごくわずかに持っていくので、ほしい方は当日サンシャインシティ文化会館までいらして下さい(印刷所クオリティではありません)。

題材をこれにしようと思ったきっかけは割とシンプルな思いつきで、「民法の争点」「刑法の争点」ならぬ「オーディオプラグインフォーマットの争点 (2024)」という感じです。

昔「刑法と民法の対話」っていう書籍(というかもともとは法学教室の連載)があって、各論の諸問題をつまみ食いで検討するやつだったんだけど、技術書典17の新刊はそのオーディオプラグインフォーマット版みたいなやつにしようかと思っている(伝わらなそう)。 まだ目次案が出来たくらいで実現性は未定

Atsushi Eno (@atsushieno.bsky.social) 2024-10-09T05:47:28.044Z
bsky.app

VST3にもLV2にもCLAPにもあとJUCEにも割と均等にダメ出ししていて、われながらこれは刺激的な本になったな…? と思います。AUだけあんましダメ出しポイントが無かったのですが(皆無ではない)、そもそも「ダメ出し」よりプラグインフォーマットのあるべき姿を炙り出すための技術的特性の比較がメインなので、AUのアプローチが優れているという内容でもないです。

以下本書にまとまらなかった部分について。

本当は分析に続いて「プラグインはこう作れ!」みたいなプロファイルの提案に漕ぎ着ければベターなのですが、その辺はちょっと関心と時間が足りなかった感じです。そういうのはどちらかというとGMPIが追求しているトピックかなと思っています(長くて自分でも全部は読んでいません)。GMPI自体はプラグイン「フォーマット」に関するプロファイルを目指しているつもりだと思いますが、自分にはどちらかといえば半分くらいはプラグインSDKにかかるプロファイルを目指しているように見えますし、プラグインAPIとプラグインSDKは別々の次元で語るべきものだと考えています。GMPIに関してはLV2の開発者もちょいちょいdisagreeを出しているので(ただこのリンク先自体が最新の仕様を前提としていません)、ひとつの考え方としては面白いという感じです。とはいえ草案の公開が2005年と考えると、意義深いものだっただろうと思います。

今回の新刊に近いトピックとしては、Image-Line(FL Studioの開発元)の元CTO ADC'23のセッションのひとつに関連してオーディオプラグインのさまざまな性質を因数分解して列挙しているこのリポジトリがあります。

github.com

そんなに論点整理されていないですが項目数が多いので読み込むと参考になりそうです(全部は見ていない)。個人的にはちゃんと特徴の良し悪しを評価すべきかなと思います。

(セッション動画の内容は正直このトピックとしては3割くらいしか参考にならないのでgithubのREADMEを見るだけでいいと思います。DAWを作るのが難しいみたいな話もあって、それならこっちをじっくり見るといいです)

あと似たようなトピックでADC'24にプラグインフォーマットの違いを総括しそうなセッションがあるので、ADC24に参加する人はこれを見て「答え合わせ」ができるかもしれません。未来を見据えた提言も含んでいそうで期待できます。このセッション概要から見える範囲では、オーディオバス調整以外の論点にはだいたい新刊で触れたはずですが、こんな感じで争点整理もいろいろ出てきそうだなと思っています。この新刊もそのひとつだと思って下さい。

9月の開発記録 (2024)

いつの間にか9月が終わろうとしていますが、裏解決屋の仕事をしていて時間がありません。今月もあまり表立った活動が無いので手短にいきます。

ktmidi 0.10.0

先月試行錯誤していたlibremidiのJVMバインディングが、javacppである程度は使えるようになったので、とりあえずpanamaバインディングはいったん凍結してlibremidi-javacppをベースに、クロスプラットフォームでMIDI 2.0デバイスアクセスをサポートするというかたちにして、これを取り込んでktmidi-jvm-desktopにLibreMidiAccessを追加したktmidiを0.10.0としてリリースしました。LinuxとMacOSはこれで動作しています。libremidiを使う最大のメリットはWindows MIDI Services対応のような気もしますが、気が向いたら or 必要が生じたらやることにします(動作確認さえできたらCIビルドをちょっといじるだけのはず)。

libremidiにはALSAだけでなくPipeWireのドライバもあるので、LibreMidiAccessの初期化オプションでPipeWireを指定すれば、Flatpakアプリケーションでも使えるようになるはずです(未確認)。

MIDI 2.0デバイスアクセスを実装していて気づいたのですが、CoreMIDIやALSAではtransport protocolが異なるデバイスもクライアントAPIでは列挙できて、プロトコルが異なる場合はこれらのAPIが内部的に変換してくれるようなので(ktmidiのAPIでいえばUmpTranslatorの機能を実装しているはず)、単にUMPプロトコルのクライアントをテストしたいだけであれば、UMPトランスポートのクライアントを作ってMIDI 1.0デバイスのポートを開けば済むようです。PipeWireにはまだMIDI 2.0サポートのAPIが存在しないので、いずれ追加されてlibremidiが対応したらktmidiでも使えるようになるだろう、というフェーズです。

書き物

今月は結構な時間を原稿書きに割いていたのですが、公開postとしてはPlugin Buddyが出たときに書いたこれしか出ていないです:

zenn.dev

misc. experiments

最近はマルチフォーマットのプラグインホストの実装がちょっとほしくなって、ただJUCEを組み込んでAGPLにするのは避けたいし、マルチフォーマットでGPLなしで使えるプラグイン/ホスト開発ライブラリは現状存在しないので、仕方なく自作しようとしています。GPLなしだとvst3sdkも使えないのでDPFに含まれるtravestyを使っていますが、まだVST3プラグインの列挙とインスタンス生成くらいしかできていないのに、この時点で割とバッドノウハウがたくさんあるなあ…という感じです。

しばらく「VST3プラグインを列挙してインスタンス生成」するコードを自分の(商用製品がいろいろ入っている)macOS環境で試したら、クラッシュするプラグインだらけだったので、ひとつひとつ確認して問題を潰していく作業をしていましたが、ほとんどがVST3 APIとかMacOS (Apple)の問題です。

VST3 APIでハマった例でいえば、フツーに考えたらIComponent::initialize()の前に他のメンバーのsetterを呼び出すなんて考えられないのにsetIoMode()だけはinitialize()の「前に」呼び出さなければならない、あたりでしょうか。APIリファレンスに何度も目を通しているうちにこの関数の存在に気づいたのですが、他のどのホスト実装でも使われておらず、とにかく呼び出すようにしてみたらDPFなプラグインが死ぬ…みたいなことになりました(詳しくは解決済のissueに書いてあります)。そしてこの関数、一体何のために存在しているAPIなのか、まったく意図がわかりません。VST3のドキュメントも何の役にも立たないです。

MacOSの問題はJUCEなんかでも議論になった(自分が確認している範囲では現存している)案件で、プラグインのCFBundleをアンロードしてもメモリが残り続ける、みたいなものがあります(そもそもCFBundleでApple専用コードを書かされる時点でめんどい)。ライブラリがアンロードできないと、大量のプラグインをもつユーザーはプラグインリストを更新するだけでメモリが死ぬことになるでしょう。CFBundleUnloadExecutableなんかを呼び出してアンロードするとクラッシュするプラグインも多数あり、Apple非推奨APIでもあり…という感じです。まあ元.NET使いとしては「AppDomainにロードしたDLLはアンロードできない問題」と同じだと思えばわからんでもないですが…(?)

あと既存のJUCEプラグインだとなぜかAudioUnitとしてはUniversalでビルドされているのかRossettaの機能なのかでロードできるプラグインがVST3だとx64のみでロードできない、みたいなハマり方もしました(手元ではddsp-vstがこれ)。

…みたいな感じで、まだ`process作れるのかどうかわからないホストを書いていますが、日の目を見ることがあるかはわかりません。まあ、せっかくなのでJUCEではできないような機能をちょいちょい取り込みたいですね。sample accurateなパラメーター設定等のイベント処理なんかは作れるはずです。

8月の開発記録 (2024)

8月、ひさりぶりに開発に時間をとれたような気がします。たくさんってほどでもないけど。最近は割と長期戦の前提で新刊(?)を書くのに勤しんでいて、フルタイムで開発はやっていない感じです(これは出せる目処が立ったら改めて書こうと思います)。

先月ひたすら準備で苦しんでいたセッションですが、何とかやってきました。最終的なスライドはこれです。

speakerdeck.com

今回いつもオーディオの話をしている仲間がカンファレンス自体に参加できなくて、こりゃ誰も来ないかな…とか思っていたのですが、現場には15-20人位の人が来てくれてありがたい限りでした。今回トピックを5つに絞ったわけですが、泣く泣くスライドから落としたPipeWireとアプリケーション コンテナまわりでなぜか質問が出てきて、それな、それな…!みたいな感じで答えているうちにタイムアップしてしまい、終わってからも教室(カンファレンス会場は大学)の外で延々と話し込んで、これはセッションやった甲斐があったな〜ってなりました。

KMDSP

ktmidiはもともと半分はC#を書いていた時代に作っていたmanaged-midiをKotlinに持ってきたプロジェクトなわけですが、.NETでやっていたビジュアルプレイヤーのxmdspだけはKMPでGUIをどうするかという問題があって棚上げになっていました。以前にcompose-audio-controlsを作った頃に実験的に作ってあったのですが、ローカルファイルI/Oなどの部分で解が無くてやはり途中で放置していました。最近ktmidiのMIDI 2.0 I/Oをカジュアルに試せるやつがほしい…そういえばKotlin 2.0が出てCompose Multiplatformも落ち着いてきたし、FileKitなんてのも出てきたしwasm版も出せるな…!となって、最低限の再生機能だけ追加して公開しました。

github.com

Web MIDI API対応版もあります。GitHub Actionsで毎回ビルドするので常に最新版です。デスクトップ版と比べてあまり遜色なく動いています(ただCompose WasmがノートPCのタップに反応しなくなっているリグレッションが出ていて不便):

atsushieno.github.io

公開してから、パンポットやキーオンメーターを追加していったので、元のxmdspの機能は概ね実現しています。FileSystemWatcherで更新を自動検出して自動再生するモードだけありません(Webでは無理だけど、これもKMPライブラリがあればいけそうな気がする)。

ただ当初の目的だったMIDI 2.0対応まわりは宙ぶらりんで、再生くらいしか実装していません。パラメーターディスプレイヤーが完全にMIDI 1.0の値域を前提にしているので、そこから作り直す必要があります。多分floatにしたほうがいいやつです。MIDI 2.0対応音源も手元に無いので、こっちを先にどうにかしないとな…となっています。時間が無限にほしいところ…

libremidiバインディング (-javacpp, -panama) - 試行中

KMDSPでMIDI 2.0に対応するには、MIDI 2.0に対応するMidiAccess実装が必要ですが、現状MIDI 2.0に対応しているのはAndroidMidiAccess2とNativeのCoreMidiAccessのみです。ALSAバインディング実装はちゃんと機能してくれず、原因はまだわからずじまいです。Compose MultiplatformはJVMなのでこのCoreMidiAccessは使えず、デスクトップでPoCを実現するための環境すらないことになります。

そういうわけで、そろそろlibremidiのバインディングでも作って対応しよう…と思ってまずjavacppバインディングを作ってみたのですが、rtmidiとlibremidiは(rtmidiが由来なのに)どうも文字列のマーシャリングまわりがjavacppのやり方と相性が悪く、const castに失敗してコピーが返ってこないみたいな問題と格闘することになります(issueにするためにreproを作ろうとしているんだけどなかなか期待通りにならない…)。javacppのコード生成のやり方を変えてみようとローカルで試そうとしてみたり、いろいろ試行錯誤で時間を溶かしています(進行形?)。

github.com

そんなわけで、メモリ操作まわりで安心して使えないのであれば、より低レベルで操作できるpanamaのほうが良いのではないか…と思ってjextractを使ってpanamaバインディングも作ってみたのですが、こちらはjextract自体がまだ完成度が低くて生成コードもコンパイルできず、手動でコードを書き換えてようやくビルドできる…みたいな感じでした。ただこれはjextractの問題なので大したことはないです。一方でpanamaのほうはjavacppとは異なりそもそもビルドしたライブラリをバンドルできない(そもそもJNAと同じでネイティブライブラリのビルドを要しない)ので、ライブラリを自動的にロードできるようにバンドルする仕組みがない問題にぶち当たり、対応を考えるのがめんどくさい…で止まっています。jextractはどうも問題を報告できる窓口が bugreport.java.com に存在しないらしく、発見した問題も報告できずみたいな状態です。

github.com

そんなわけでどっちのバインディングが先に実現するか、まだ見えないところです。

あとMIDI 2.0対応デバイスが無い問題がここでも関わってきて、まずはMIDI 2.0仮想デバイスになるアプリケーションをでっち上げないと駄目かなあ、となりつつあります。

AAP: AAudioの使い方の調整

最近裏稼業でAOSPのオーディオシステムの調べ物をいろいろやっていた関係で、AAPで適当に使っていたAAudio(API的にはOboe)のオーディオI/Oについて、以前よりだいぶまともに使えるようになってきました。そういうわけで、AAPの特に規範的アプリケーションにもなっているモジュール (androidaudioplugin-manager) やMidiDeviceService実装 (androidaudioplugin-midi-device-service) を見直して、まずはLow LatencyストリームでExclusiveモードを使うのを止めました。Sharedストリームでも十分なパフォーマンスが出るはずだし、Exclusiveを使ったところでBinderが/usr/binderのドメインでmutex lockをかけてしまう現状では意味がないでしょう。

Androidオーディオシステムについてはここ数ヶ月でだいぶ詳しくなった…何なら大抵の中華系の情報源より詳しくなったと思うので(これは分かる人にしか分からない言い方かもしれないけど、要するにだいぶ自負がある)、次の技術書典あたりを目処に何か書いて出したい気持ちがちょっとあります。ただM3秋にサークル参加申し込みし損ねてしまったので(6月が忙しすぎて忘れてた)、やる気ゲージが貯まるかと作業時間が取れるかどうか次第です。

書き物

今月は2つくらい書いてました:

zenn.dev

zenn.dev

後者はたまに「MTS-ESPが多数に使われるようになったらAndroidでも使えるようにする必要があるな…作っておくか…?」みたいに思うことがちょいちょいあって(主にsurgeのコードを読んだりいじったりしているとき)、一度まともに調べておこうと思ってがっつり時間をとって、やっぱりこれは無いか…となった時の備忘録でした。時間が無限にあればこっち方面でも新しいものを作りたいところですが、自分がまず微分音作曲やらないしな…という感じで優先度が高くないです。

7月の開発記録 (2024)

今週末のCOSCUP 2024のスライドの準備でテンパってるので(順調ではない)、手短にいきます。

ktmidi 0.9.0 and AAP 0.9.0

先月の時点でKotlin 2.0対応は済ませてありましたが、さらにmacOS用のCoreMidi2Accessの実装が何とか動くようになって、AlsaMidiAccessもAPIの設計はとりあえず現状でいけるだろう…となったので、とりあえずずっとpendingになっていたktmidi 0.9.0をリリースしました。ただiOSではまだ期待通りに動いていないというissueも届いており、まだ修正が必要そうです。iOSデバイスは手元に無いし今そんなことをしている暇が無いので詳細は未確認…

AAPは先月からほとんど変更はありませんが、Android 15のAPIが固まってPlay StoreにもcompileSdk = 35のアプリを公開できるようになったので、AAP 0.9.0もリリースしました。

これらに合わせてresident-midi-keyboardもMIDI 2.0仮想ポートを追加するかたちで更新しています。

Kotlin 2.0 updates on mugene-ng, missing-dot, compose-audio-controls, ...

ktmidi 0.9.0がリリースできたので、mugene-ngとcompose-audio-controlsもこれを使う形でK2のエコシステムに乗っかってアップデートしました。唯一この流れに乗られなかったのがaugene-ngで、このプロジェクトはKSPでコード生成している部分がうまく更新できず、KSPのK2対応の正式版がリリースされたら移行しよう…となっています。

KSPはXMLシリアライザーの自前実装コードを生成するために使っているのですが、このXMLシリアライゼーションには.NETのXML APIを模倣したmissing-dot(自作)を使っているので、このmissing-dotもK2にアップデートすることになりました。そういえば結局.NET APIで必要になったものって全然無いな…というわけでこのライブラリは(御大層な名前の割には)全然成長していません。

aap-airwindows (WIP)

Airwindowsは以前からオーディオプラグインを大量に抱えているプロジェクトとして「時間が無限にできたらこれをAAPに移植してみよう」と思っていたのですが、何ヶ月か前にairwin2rackというプロジェクトがこれをVCVRackとJUCEでプラグイン化できるようにしていて、これを使い回せばAAP移植も楽にできるな…?と思っていたのでした。今月ちょっと試しに着手して全部プラグインとして列挙できるところまではできたのですが、なぜか期待通りに動かないものが大半で、ちょっと追加調査しないと使えないな…という感じです。このプロジェクトひとつでプラグイン自体が数百件あるので、インストールしたい気持ちにならないのがひとつの問題です…(!)

# 2024年のオーディオアプリケーション開発技術の動向に関する私的見解(1-3)

COSCUPのセッションがある関係で、最近のオーディオ開発のトピックをいろいろおさらいしていたのですが、普段からこの方面に深入りしているわけではない(!?)ので、ほとんどの時間が調査に費やされていてたいへん厳しい…という感じです。そんなわけで、調べていたものをちまちまと(まずは)日本語の文章でまとめていたのを、今月は3本くらい公開しました。

zenn.dev

zenn.dev

zenn.dev

jeq8: Waveform view on WebView

↑のPart 1で言及しているWebViewに関して、「ちゃんとオーディオ入力をプラグインのUIが受け取ってレンダリングするやつ」を、実験だけでもしてみないとなあと思って、Part 1の関連動画で説明されている「HTTPリクエストハンドラ経由でblobを渡せる」というのをJUCE WebViewで実践してみたプロジェクトを作ってみました。Web UIにはweq8というWeb AudioのプロジェクトのUIをそのまま使いまわしています。

github.com

動いている様子も一応ここで見られます(サムネのやつはデモとしてはびみょい)

View post on imgur.com
imgur.com

ただ、動いているときはまあまあ妥当そうなサイクルで描画できているのですが、プラグインとしてロードするとかなり頻繁にクラッシュするので(ロックとかが完全にいい加減なコード)、まだ「これで実用性が証明できた」とは言い難いところがあります。余裕ができたら再訪したいところです。