3月の開発記録

4月ももう1/3くらい過ぎているのに3月かよ?ってなりますが、PCを修理に出したり、そこに至るまでそもそもPCの不調にやられたりでいろいろ止められていた感じです。

3月からいよいよ世間がコロナ一色になって落ち着かないですね。わたしは世間一般でようやく自分の在職時代の日常だった在宅勤務が普及するようになったのを横目で眺めながら、家でゲームしたりしていました(半分くらいは↑のせい)。3月はどちらかといえば生産少なめです。

目次

aap-juce

先月も書いていたAndroid用オーディオプラグインのプロジェクトにJUCEを統合するやつ、あまりにも手作り作業が多かったので、これを誰でも手順通りにやれば作れるように作業フローをまとめてCIできるところまでもっていこう、というhigh意識でちょいちょい作業しました。

github.com

Android用に組み込むと言いながら、実際にはAndroid用とemscripten用の2つをビルドしていて、これはだいぶ面倒なことではあります。ひとつには、先月書いたjuce_emscripten app gallaryのページもCIでリリースしたいという希望があったのと、もうひとつは後で詳しく書くUI統合で利用する目論見があったためです。juce_emscriptenのデモは、2月にやりたいと書いていたtracktion_engine統合の実験も兼ねて移植したStepSequencerDemoも追加してあります(統合サンプル自体は未着手)。tracktion_engineの開発者もTLで見つけたらしく、質問されたりしていました。

juce-demos.atsushieno.dev

それはさておき、ビルド自動化にあたって一番問題だったのはやっぱりProjucerが生成するMakefileemscripten用)を手作業で加工していた部分なので、ここは諦めてProjucerに手を加えました。

その過程で気づいたのですが、juce_emscripten自体はソースツリーがJUCEからのforkになっていなかったものの、実際には本家からのforkとして公開するのも全然難しくはありませんでした。なので現在はそういう構成でJUCEの独自forkとして発展させています。(juce_emscriptenの本家Dreamtonicsは現在進行中の製品開発で忙しいようなので、この辺はあっちが落ち着いたら連携して統合する予定です。)

結果的に以下の5つを移植してビルド自動化して、半分くらいはまだ謎クラッシュしたり音が出なかったりといったところまではやってある感じです。

  • AudioPluginHost
  • andes
  • SARAH
  • dexed
  • Magical8bitPlug2

それぞれどんなものなのかは、(Androidではありませんが)juce_emscripten app gallaryで見ることができます。

ちなみにビルドはGitHub Actionsで行っています。これは3月になってようやくactionsのAndroid SDKコンポーネント不足が解消されることによって実現しました。Android Studio 4.0の想定するAndroid Gradle Plugin 4.0.x系列が使用するCMakeが3.6から3.10.2にバージョンアップしたのですが、去年12月に試したときは、GitHub ActionsのVM (ubuntu-18.04) ではAndroid SDKに含まれるcmake 3.10.2がインストールされていなかったので、actionsに直接プルリクを送りつけて対応を求めたのですが全然反応が無く、2月になって他のユーザーも問題に気づき始めてコメントされるようになってから、ようやく3月にマージされました。

また、GitHub Actionsで1つのサンプルをビルドするのにかかる時間は20〜30分、それが5本あるので、1ビルド150分くらいかかっています(!) 1つのアプリをビルドすると500MBくらい消費してしまうので、intermediatesを削除して回ることでようやく可能になっています… 500MBのfree tierでもビルドできるようにしたいのですが(今はProの1GBを使えている状態)、500MB削るのは困難そうです。

UI統合の再検討

aap-juceでjuce_emscriptenを使っている主な理由は、UI統合のスキームとして使えるんじゃないかという目論見があったためでした。ロジックとなるオーディオ処理はプラグイン側のアプリケーションで処理するが、UIはjuce_emscriptenで生成したHTMLをホスト側のアプリケーションでWebViewとしてロードする、という設計が最も合理的なのではないかと思ったためです。

ただ、実際にjuce_emscriptenのアプリをAndroid WebViewで実行してみると、途中でエラーが出て止まってしまいます。ChromiumのDevToolsにあるremote devicesの機能を使ってデバッグしてみると、emscriptenが内部的に使用しているAtomicsAndroidでサポートされていないことがわかりました。GUI部分にatomicを使う必要はないはずなのですが2020/6/1追記: GUIコードもオーディオプラグインパラメーターを直接いじる時にはatomicsを使う必要がある場面があります、これがJUCEの膨大なコードベースから呼び出されるlibc等のどこで使われているかは、emscriptenの標準ライブラリに踏み込まないとわからなそうなので(juce_emscripten自体はJSのAtomicsを参照していない)、ちょっとこれは無理ゲーの香りがして中断しています。

UIをHTMLで実現するというアイディアはjuce_emscriptenでなくても可能なので、このアプローチ自体は引き続き考慮しています。たとえば、JUCE方面ではUIをReactで記述するblueprintというプロジェクトがあります。

sfizzからARIAまわりを探る

2月にはtracktion_engineを移植して音楽を鳴らせるようにしたい、という話を書いていましたが、音楽を鳴らすためには再生エンジンの他に楽器として使えるプラグインが必要です。JUCE方面ではjuicysfpluginというFluidsynthを使ってサウンドフォントベースのinstrumentプラグインがあって、最新のFluidsynthがAndroidでも動くことはよく知っているのですが(何しろ自分が移植したコードが公式なので)、これ自体はgtkを使ったりしていて、移植するより自前で作ったほうが早いかな…でもfluidsynth相当ならMIDIプレイヤーでもいいんだよな…みたいなことを考えていました。

それでふとsfzならkey switchとかもサポートしているし、もう少し高機能なんじゃないかと思って、OSSの合成エンジンを探して(何しろLinux方面では一番ポピュラーなLinuxSamplerが非OSSなので)、まずはJUCE統合もあるSFZero-Xを見つけました(実際にはSFZeroを見つけてその中で最も新し目のforkを見つけたわけですが、細かいことはおいといて)。それで、sfzformat.comからリンクされているsfzを試してみたのですがサッパリ期待通りに鳴らない。どういうことだろうと調べてみて、どうやらSFZeroはkey switchサポートも含めていろいろ機能が足りないということがわかりました。それで他にもいろいろ試した結果、OSSではsfizzが良さそうだということになりました。

sfizzはLV2をサポートしていて、QTractorで試しに使っている範囲ではちゃんと音が出るようなので、Androidに移植するのも現実的であるように思えます。ただ、sfzによってはSforzandoの独自拡張として定義されているARIAというUIマークアップW3Cとは無関係、仕様も未公開)もサポートしているものがあって、これをまずsfizzでサポートしたい気持ちがちょっとあります(ほぼ未着手)。ARIAは単なるXMLマークアップで内容もシンプルそうなので、SVGあたりに変換すればWebViewで表示できそうです…というあたりでさっきのUI統合の話と繋がります(!)

ちなみに、sfzで移植したら面白いことになりそうだと思っているのは、sfzformat.comからもリンクされているこの辺のギター音源とかです。keyswitchやvelocityいかんで各種奏法を切り替えられるし音色も使い勝手が良さそうです。

unreal-instruments.wixsite.com

あと、関連してLV2をVSTとして使うlv2vstというプロジェクトがあって、コレがあるとTracktion WaveformのようなLV2をサポートしていないLinuxDAWでもLV2音源が使えるのですが、LV2 featureまわりの解決に問題があってsfizzがロードできなかったので、その辺を修正するパッチを書いて取り込んでもらいました。最新版ではsfizzもロード出来ますが、lv2vstはnon-X11 UIをサポートしておらず、sfizzがファイル名を受け取るためのAtomポートにファイル名をバイト列として渡せるルートが無いので、sfizz側に手を入れないと実質使えない状態です。わたしは諦めてsifzzを組み込んだJUCEプラグインをちょっとだけ作ってその後放置しています…

guitarixとそのUIを眺める

これはどちらかといえばデスクトップ側でsfizzとギター音源を組み合わせてからの話なのですが、ギター音源があってもそれ単体だとありがたみがありません。本格的なオーバードライブやアンプを組み込んで音を作りたくなるはずです。Collectiveとかで適当にプリセット音色をいじっているときは組み込みエフェクトだけでもそれなりの音が作れますが、Androidには移植できないのでどこかから持ってくる必要があります。

Native InstrumentsのKompleteで遊んでいた時はGuitar Rigっていう製品があったけどああいうものはLinuxには無いのか…と思って探したら、ありました。知ってました。Guitarix。今でもsourceforgeで(!)開発されていて、LV2もサポートしています。これなら移植しがいがありそうです。

しかもソースを覗いてみるとなにげにwebuiなんてディレクトリまであります。コレもHTML UIの仕組みに乗っけやすそうなやつなので、もう少し深入りしてみようと思っています。ただ、enyo.jsとかいうやや古そうなフレームワークなのと、今guitarix自体がUIをgtkなどからx11に移植しつつあって、これはもしかしたらemscriptenで直接サポートできるUIになるのではないかという期待もあり、とりあえず移植が終わるまで待っています。

Androidネイティブバイナリビルドの動向

sfizzにしろguitarixにしろ、LV2プラグインなので、LV2がプラグインフレームワーク開発の出発点であるわたしとしては着手しやすいものです…となるはずなのですが、実際にはLV2サポートの根幹となるネイティブライブラリのビルドを整備して、aap-juceのリポジトリと同じくらい手順フローを整備してプラグインを簡単に移植できるようにしたいところです。

そんな中、AndroidオーディオチームがOboeのパッケージを新しく"prefab"フォーマットのaarで配布するよ、という話が流れてきました。prefabというのはAndroid Studio 4.0(用のGradle Plugin)で新しくサポートされる形式です。

google.github.io

詳しくは今回は省きますが、これまでのaarとは、拡張子こそ同じだけど根本的に違う内容になっています。そしてこのprefabをビルドするための仕組みとして、Googleはndkportsという仕組みを併せて公開しました。

android.googlesource.com

1つ以上のネイティブライブラリのソースtarballとビルド記述ファイルとなるport.ktsがあれば、後はndkportsのビルドスクリプトがNDK各種ツールチェインを駆使してaarまでビルドしてくれるという代物です。という目標はいいのですが、現実にはまだまだ機能が全然足りない感じです。さいわいprefabはndkportsが無くてもビルドできるので(自前でzipアーカイブすれば!)、ある程度の省力化・ビルド自動化はできそうです。

もっともこれでは開発がスムーズになる気がしないので(フレームワークやLV2ビルドに手を入れたらアプリケーションをAndroid StudioからF9一発でデバッグできるようにはならない)、パッケージング以外の場面ではまだ取り込めないかもしれません。いずれにしろ、4月はこの辺に手を出すタイミングなのかなと思っています。