CLAP 1.0公開を機にオーディオプラグイン規格の何たるかを知る (4) 拡張機能・各論 ほか

一般的な拡張機能

状態(state)の保存・復元

DAWで音楽を打ち込んだ内容をセーブすると、各トラックに設定されたプラグインのパラメーター等をひと通り操作した状態(state)を保存することになります。逆に楽曲データをロードすると、プラグインのパラメーター等を保存データから復元することになります。

DAWはひとつのプロセスの中にさまざまなプラグインをロードするので、他のアプリケーションに比べると頻繁にクラッシュします。そのため、楽曲をセーブする前に予防的に状態を保存することがあります。

状態の保存先は大抵のプラグインフォーマットではただのバイトストリームですが、LV2では保存する項目と値を構造的に格納するスタイルの仕様になっています。LV2は全体的にSemantic Webの流儀に従っており、LV2 Stateの仕様もその影響を受けていると考えられます。

プリセットの利用

プラグインの中にはMIDIでいうところの「プログラムチェンジ」に相当する機能を実装しているものがあります。シンセの場合は、これは単純にパラメーターの設定値の集合だけで実現していることも多く、その場合はプリセットと呼ぶほうが適切ともいえます。この機能をどう呼ぶかはプラグインフォーマット次第です。ここでは便宜上プリセットと呼びます。JUCE AudioProcessorならProgramと呼ばれます。

パラメーター設定の集合であると考えるとピンとくるかもしれませんが、プリセットが実装すべき機能は実のところ状態の機能とほぼ重複します。プリセットのロードとは、プログラムナンバー、プリセットの番号といったものを状態の代名として指定して状態を復元するのとほぼ同じです。

プラグインフォーマットによっては、ユーザープリセットの保存のような機能を可能にすることも考えられます(JUCEにはそのような機能が存在します。AudioProcessor::ChangeProgramName()など)。

GUI

GUIはオーディオプラグインの重要な機能のひとつですが、「無くても良い」機能でもあります。GUIが無い場合でも、外部のエディターからパラメーターを操作できる「エディットコントローラー」(これはVST3の用語です)の機能があれば、DAWプラグインのパラメーター方法をもとに自前でパラメーター操作のUIを用意できるためです。とはいえ、それでもプラグインはユーザーが操作しやすいUIを提供するのが一般的です。

プラグインフォーマットで専用のGUIフレームワークを提供することは多くありません。汎用プラグインフォーマットでは皆無に近いでしょう。プラグインフォーマットで専用のGUIフレームワークを提供するということは、GUIはその仕組みの上に則って構築するということになります。しかし、一般的にはDAWが利用する言語・開発環境は決め打ちにできないので、プラグインGUIはそのGUIと密結合できません。GUIフレームワークを提供しないプラグインフォーマットにできることは、せいぜいGUI操作においてホストとなるDAWとその小窓で出現するプラグインの間で生じる(その必要がある)インタラクションを、呼び出しや通知コールバックのかたちで定義するくらいです。

GUIフレームワークを開発するというのは大規模な作業になりうるもので、実際大規模な作業を経ずに基本機能だけで済ませたGUIフレームワークではさまざまな問題が噴出します。日本人向けにわかりやすい例を挙げれば、日本語入力にまともに対応できないことが多いです。アクセシビリティ対応、HiDPI対応、マルチプラットフォーム対応など、さまざまな難題があるのです。SteinbergはVSTGUIというオーディオプラグイン向けの汎用フレームワーク(そう、VST専用ではないのです)を作りましたが、やはりデスクトップ向けの一般的なGUIフレームワークと比べたらさまざまな点で妥協の産物です(たとえば2022年現在でもCairoが使われていたり)。

プラグインUI開発に最適な銀の弾丸は存在せず、プラグイン開発者は、自分のプラグインの最適解に近い任意のGUIフレームワークを利用する、という以上の一般化はできないといえます。

オーディオプラグインのオーディオ処理はリアルタイムで完了する必要があります。このリアルタイムとは「必ず一定の時間以内に完了する」というものであり、よくhard realtimeともいわれるものです。一方でGUI処理には一般的に「UIスレッドで動作しなければならない」という制約があります。必然的に、オーディオ処理とGUI処理は別々のスレッドで動作することになります。

さて、一般的にプラグインのオーディオ処理とGUIは別々のスレッドで別々の処理ループによって動作することになりますが、プラグインフォーマットによってはGUIの分離がスレッドの分離より一層強く設計されていることがあります。LV2はこの意味では分離アプローチの最右翼で、UIのためのライブラリを別ファイル上で実装して、オーディオ処理部分とはコードを共有できないようにしています。オーディオ処理のコードを参照しなくても、TTLメタデータの情報をもとにUIを実装することが可能であるためです。もちろんそうはいっても、UIのライブラリを参照してそのAPIを利用するコードを書くのを妨げることはできません。

GUIサポートをクロスプラットフォームで一般化するのは、可能ではありますが、技術的にいくつかのアプローチがあり、これがまた一つ難しい要因です。プラグインフォーマットとして何か1つを規定しないわけにはいきません。

  • VST3ではプラグインIEditController::createView()からIPlugViewというインターフェースの実体としてプラットフォーム別のViewを生成して、それをホストに返します。ホストはGUIのViewを(一般的には)自前のウィンドウにreparentして使うことになります。
  • CLAPではホストがclap_plugin_gui_t.create()を呼び出すとプラグインが内部的にGUIを生成しますが、結果はboolでしか帰ってきません。それをホスト側のGUIに統合するには、reparentするウィンドウのハンドルをclap_plugin_gui_t.set_parent()で渡す必要があります。あるいはfloating windowとして扱うという選択肢もありますが、プラグインがサポートしていなければこれは利用できません。clap-juce-extensionsで(つまりJUCEで)構築したプラグインだとfloatingには対応していません。

CLAPでは、LV2のようなUIとDSPのコード分離ポリシーをAPIとして強制してはいません。これは意図的な設計であるとコミュニティでは説明されています。コードをどのように分離するかは各アプリケーションのアーキテクチャ次第ともいえます。

ホストから提供される「楽曲の」情報

オーディオプラグインは基本的にオーディオ処理関数(CLAPのprocess()関数など)に渡されるオーディオ入力やイベント入力をもとにオーディオ・イベント出力を出力するリアルタイムな処理であり、渡される時間情報は基本的にSMPTEに基づく時間(マイクロ秒など)の即値あるいはそれを変換したサンプル数となります。そこにテンポや拍子(time signature)に関する情報は一般的には不要ですが、プラグインによっては、テンポ等の値をもとに生成する音声やMIDIイベントを調整したいことがありえます。これを実現するためには、DAWからの情報提供機能が不可欠です。この情報はトランスポートとかプレイバックと呼ばれることがあります。各プラグインフォーマットでは、それぞれ次に示す型で実現しています。

  • VST3: ProcessContext
  • LV2: Time拡張機能
  • CLAP: clap_event_transport (events.h)

clap_event_transportは拡張ではなくオーディオ処理で渡されるイベントの種類で、トランスポート情報にアップデートがあったときにホストから渡されます。現在の小節位置なども含まれる = 更新の必要が頻繁に生じるので、このイベントをサポートするDAWからはprocess()で送られるclap_process_tin_eventsに含まれることが多いと考えて良いでしょう。

CLAPにはtrack-infoというトラック情報を取得できるAPIもありますが、これはDAW上の表示色など、だいぶ性質の異なる情報を取得するためのものです。

CLAPのユニークな拡張機能

複雑なノートイベント

CLAPのイベント機構は、イベントの種類をCLAPイベント、MIDIイベント、MIDI2イベントから選択できます(他のイベント体系も規定できますが、ホストとプラグインの両方が合意するものを規定する必要があります)。CLAPイベントには、ノート関連イベント、パラメーター関連イベント、トランスポート情報更新イベントなどがあります。パラメーターについては次の節で説明するとして、ノート関連イベントもCLAPに固有のものがあるので説明します。

CLAPのノート関連イベントは次の4つです:

  • CLAP_EVENT_NOTE_ON: ホストからのノートオン指示
  • CLAP_EVENT_NOTE_OFF: ホストからのノートオフ指示
  • CLAP_EVENT_NOTE_CHOKE: ホストからのノート即時停止指示
  • CLAP_EVENT_NOTE_END: プラグインからのノート完了通知

ノートオンとノートオフはMIDIのものと同様の機能です。MIDI 2.0のノートメッセージとは異なり、アーティキュレーションの指定はできません。

。CHOKEとENDは説明が必要でしょう。まず「チョーク」ですが、これはノートを即座に停止する用途で追加されたイベントです。通常、ノートオフとは「リリース」の開始を意味するものであり、すなわちまだ無音になるまではしばらく時間がかかることを意味します。これに対してチョークが指示されると、そのノートの発音は即座に終了します。これが具体的に用いられる例として、CLAP仕様では(1)ドラムマシンのハイハットなど排他的に発音するノートや(2)MIDIにおけるall notes offのような命令として利用することを想定しています。MIDI 2.0であればノートオフのアーティキュレーションに「これはチョークである」という情報を追加することができたでしょうが、CLAPにはそのようなフィールドが存在しないので、こういう命令を追加するしかなくなります。

「エンド」のほうは、ホストから指示する命令ではなく、プラグイン側からホストへの通知で、リリース処理なども終わって完全にノートが無音になったときに送られます。ホストは、もしこれを受け取ってプラグインが何の音も生成していないことが分かったら、プラグインの処理をスキップするなどの最適化が可能になります。これはtail-length拡張によって実現できていた機能と、目的が類似しています。

パラメーター設定関連イベント

CLAPのパラメーター設定イベントもある程度バリエーションがあります:

  • CLAP_EVENT_PARAM_VALUE: 単純なパラメーターの設定
  • CLAP_EVENT_PARAM_MOD: パラメーターのモジュレーション操作(変化率を指定): 開発チームが "non-destructive automation" と呼んでいるもので、モジュレーションが完了したらパラメーターの値を元に戻せる(オートメーションをかけ終わった後に当初のパラメーター設定がなくならない)ことになります
  • CLAP_EVENT_PARAM_GESTURE_BEGIN, CLAP_EVENT_PARAM_GESTURE_END: ユーザーがDAW上のツマミなどでパラメーター操作を開始したことをプラグインに通知するイベント: この間に呼び出されたパラメーター変更イベントは履歴の記録などで厳密にトラッキングする必要がない、と考えられます

モジュレーションとジェスチャーは、表現力を高めるためのものではなく、DAWを利用するときのUXを改善するためのものといえます。(他の規格にも同様の機能を実現するものがあるかもしれません。)

また、パラメーターではありませんが、ノートエクスプレッションもCLAP_EVENT_NOTE_EXPRESSIONで設定できます。対象パラメーターの代わりに以下のいずれかを「エクスプレッションID」として指定します:

enum {  
  // with 0 < x <= 4, plain = 20 * log(x)  
  CLAP_NOTE_EXPRESSION_VOLUME,  
  // pan, 0 left, 0.5 center, 1 right  
  CLAP_NOTE_EXPRESSION_PAN,  
  // relative tuning in semitone, from -120 to +120  
  CLAP_NOTE_EXPRESSION_TUNING,    
  // 0..1  
  CLAP_NOTE_EXPRESSION_VIBRATO,  
  CLAP_NOTE_EXPRESSION_EXPRESSION,  
  CLAP_NOTE_EXPRESSION_BRIGHTNESS,  
  CLAP_NOTE_EXPRESSION_PRESSURE,  
};

ボイス(発音)数の管理

まだ1.0正式仕様には含まれていませんが、CLAPにはプラグインの発音数を管理できるvoice-infoという拡張機能があります。これが使えると、ホストでプラグインの現在の発音総数や最大発音数を取得できます。といっても。出来ることで音声処理に影響があるとは考えられません(雰囲気でパフォーマンスのある種の指標を得られるといったところでしょうか)。

enum {  
CLAP_VOICE_INFO_SUPPORTS_OVERLAPPING_NOTES = 1 << 0,  
};    
typedef struct clap_voice_info {  
  uint32_t voice_count;  
  uint32_t voice_capacity;    
  uint64_t flags;
} clap_voice_info_t;
typedef struct clap_plugin_voice_info {  
  bool (*get)(const clap_plugin_t *plugin, clap_voice_info_t *info);  
} clap_plugin_voice_info_t;

リアルタイム並列処理の制御 (thread_pool拡張)

u-heで頻繁に主張しているCLAPのアドバンテージのひとつが「ホストによって制御されるスレッドプール」です。これについて筆者は「スレッドプールはLV2 Workerなどでも実装されているし、さすがにそれはおかしいんじゃないか」と思ってだいぶコミュニティで掘り下げて議論して分かったのですが、結論からいえば一般的な意味でのスレッドプールでは全くありませんプラグインが非同期実行を実現するための仕組みではありません。

では何なのかというと、CLAPのthread_pool拡張のAPIは、リアルタイム処理を並列で実行するためのAPIです。プラグインがオーディオスレッドで動作しているprocess()の中からホストの機能を呼び出すかたちで利用します。次のような流れになります:

  • プラグインclap_host_thread_pool_t型のホスト拡張をclap_host_t.get_extension()で取得し、これがnullptrなら並列処理ではなく逐次処理を行う
  • clap_host_thread_pool_tを取得できたら、プラグインは続けてrequest_exec(host, numTasks)メンバーを呼び出す
  • ホストのrequest_exec(host, numTasks)の実装では、もし現在そのホストが指定されたnumTasks本のタスクをOpenMPなどの並列実行機構を用いた並列化を試みる
    • できないようなら、それ以上は何も実行せずにfalseを返す
    • 並列化できるようなら、そのプラグインclap_plugin_thread_pool_t型の拡張機能clap_plugin_t.get_extension()で取得する。これがnullptrならfalseを返す
    • clap_plugin_thread_pool_tを取得できたら、ホストは続けてそのexec(plugin, task_index)numTasks回呼び出し、request_exec()の戻り値としてtrueを返す

exec()で呼び出されるプラグインのタスクは、process()のサイクルで完了しなければならないものなので、並列であれ逐次であれ、処理全体をリアルタイムで実行完了しなければなりません。

CLAPのthread_pool拡張とは、こういった機能を実現するためのものです。一般的な意味でのスレッドプールのAPIはありません。一般的なスレッドプールのAPIであれば、タスク/ジョブのオブジェクトを生成してハンドルを渡すようなAPIになっていないと意味を為さないところですが、CLAPの場合はnumTasksという並列実行スロットの本数を渡すのみで、プラグイン側のタスクの呼び出しも同期的です。「thread poolという名前がおかしい」というのは概ねコミュニティにおける共通理解だと思ってよさそうです。

tuning

tuningはmicrotonal(微分音)を実現するための拡張機能です。この機能がオーディオプラグインフォーマットの一部として規定されるのは珍しいといえるでしょう。一般的に、これが拡張機能として規定されないのは、MIDI 1.0に基づくMMAの仕様としてMTS (MIDI Tuning Standards)というものがあって、DAWはこれに沿ってMIDIメッセージを送信し、プラグインはこれを受け取ったらその内容に応じた周波数変換テーブルを適用すれば良いので、独自にイベントを規定する必要がなかったためです。

CLAPの場合、MIDIイベントではなくCLAPイベントで全てを処理するユースケースに対応することを考えると、MTSに相当するメッセージを規定する必要があるといえるでしょう。tuning.hにはclap_event_tuningというMTS相当のイベントが規定されています。

関連情報

あんまし宣伝エントリにしたくないのですが、多分CLAPの位置付け等を理解するうえでそれなりに参考になると思うので並べておきます。

DAWシーケンサーエンジンを支える技術(第2版)」では、DAWがどうやってプラグインを利用するのか、オーディオプラグインはざっくりどういう仕組みとして作られているのか、楽曲のシーケンスはどう作られて保存されているのか、といった話をふわっと書いています(「ふわっと」というのは主観的な表現ですが、コードが出てこない程度の抽象論に終始する内容です)。

https://xamaritans.booth.pm/items/2397203

「LV2オーディオプラグイン開発者ガイド」は日本語でまとまった情報が多くないLV2オーディオプラグインについて解説し、プラグインの開発方法を説明しています。プラグイン開発に携わっていないと難しく、プラグイン開発をやっていると物足りないレベルかもしれません。

https://xamaritans.booth.pm/items/2394242

最後になりましたが、7/6に開催した勉強会のスライドを公開しておきます。内容はこの連載と合わせて作成していたため、かぶる項目が多いと思います。

speakerdeck.com

CLAP 1.0公開を機にオーディオプラグイン規格の何たるかを知る (3)オーディオ処理のパイプライン

オーディオ処理部分の基本形

オーディオプラグイン規格は、それぞれ互換性が無いものですが、楽器やエフェクターとしての基本的なオーディオ処理の部分には共通の部分が多いです。以下に擬似コードで列挙します。

MIDI入力」と書いている部分は、実際にはMIDIではなくプラグイン規格ごとに異なりますが、これについては次の節でじっくり説明します。ここではオーディオ入力について掘り下げます。

オーディオデータとバス、ポート、チャンネル

「オーディオデータ」に渡ってくるのは、「全オーディオチャンネル」分のfloatあるいはdoubleの配列です。最近はdoubleを使う状況もありますが、一般的にはfloatが使われるでしょう。「全オーディオチャンネル」とは、1つ以上の「オーディオバス」ごとに割り当てられた「チャンネル数」です。オーディオバスは少しややこしい概念で、難しければ飛ばしても何とかなる概念です(飛ばした場合は「ステレオ」になると考えれば良いです)。もう少しちゃんと説明すると、オーディオバスとはチャンネルの構成に名前と特性がいくつか付いた構造です。具体的なものを挙げたほうがわかりやすいでしょう:

  • mono
  • stereo
  • 5.1ch
  • 7.1ch
  • ambisonic

これらの名前は暗黙的に「メイン入出力」を含意していることが多いです。これらはそれぞれ固有のチャンネルを有しており、一般的にはチャンネルにも名前が付いています("L", "R", "front left", "rear back right", ...)

「メイン」があるということは補助的なものもある…というわけで、オーディオプラグインには「サイドチェイン」として直接再生するわけではなく波形の計算に補助的に利用するオーディオデータを渡すこともできます。LV2ではCVPortがサイドチェインを実現するためのものです(CVにはLV2のどんなポートを使っても特に問題はなく、あくまで指針としてCVPortを使うのが適切ということです)。

ホストDAWは、各トラックについて、オーディオプラグインに「利用できるオーディオバスの情報」を提示してもらい、トラックで利用できるバスを調整し、バスのオーディオバッファを準備します。メインのバスは一般的には1つになりますが、補助的にサイドチェインのバスが複数有効化される可能性があります。そして実際にオーディオ処理process()を呼び出すとき、有効なオーディオバス全てに関連付けられたオーディオチャンネル分のバッファが、引数として渡されることになります。

VSTの場合はバスと呼ばれますが、CLAPではポートと呼ばれています。LV2でもポートと呼ばれるのですが、これはバスに相当する概念ではなくチャンネルに相当する概念なので(つまり「ステレオ」ポートにはならず「左」ポートと「右」ポートになる)、混乱しないように区別して捉えておかなければなりません。

オーディオプラグインにおけるMIDIサポートの基本

CLAP開発チームがさかんに宣伝している機能のひとつが高度なノート命令ですが、これを理解するためには、そもそもオーディオプラグインはどうやってMIDI命令を処理しているのか、理解しておく必要があるでしょう。

実のところ、オーディオプラグインでなまのMIDIメッセージをそのまま処理することはあまりありません。オーディオプラグインフォーマットごとにMIDIより高度な(データ幅や追加情報が多い)ノートイベントやコントロールチェンジイベントなどが規定されていて、MIDI入力はDAWによって変換されてプラグインに渡されるのが一般的です。プラグインを開発できるSDKによっては、受け取ったイベントメッセージをMIDIメッセージに(DAWとは逆の方向に)変換して、VSTAUやLV2の共通コードとして実装できるようにすることも多いです(JUCEなど)。

オーディオプラグインMIDIのようなイベントを受け取る入口は主に2つあります:

  • イベントとして受信する: DAWでPCに接続されたMIDIキーボードの鍵盤を押すと今のトラックのオーディオプラグイン設定で非リアルタイムに演奏されます(発音します)
  • 演奏命令として受け取る: DAWに打ち込んだ内容を再生するとき、DAWは対象の全トラックでリアルタイムオーディオスレッドを用いて「オーディオループ処理」を回します。1回の処理はリアルタイムと言える間隔(10ミリ秒程度)の間に全て完了しなければなりません。そうしないと不自然な「空き」が生じてしまい、遅延やノイズの原因になります。このループの中に、演奏命令としてイベント列も含まれることになります。

ここで一つ気をつけないといけないのは、オーディオループはリアルタイムスレッドで回っていて、一方でMIDIキーボード等の入力はI/Oを伴う非リアルタイムスレッドから受け取るということです。リアルタイムでオーディオ処理を回しているときに、ちょっとだけ時間を借りてMIDI入力に対応する音声を生成して戻ってくる…ということはできません。

実際にDAWを使っているときは、トラックを再生しながら同時にMIDIキーボードを叩いていることがあり、この意味では受信した入力イベントは演奏命令にマージされると考えて良いでしょう。ただしそのタイミングは1回のオーディオループで処理される実際の演奏時間の長さによって変わります。もし仮に1回のオーディオループで1000ミリ秒分のオーディオデータが処理されるとしたら、オーディオループは1秒に1回しか回りません。その間のどのタイミングでMIDIキーボードの鍵盤が押されたとしても、ノートイベントが発生するのはその1秒単位のスライスの始点でのみということになります。

DSPコードの共通化

VSTAUもCLAPもそれぞれバラバラなパラメーターとイベントの機構をもっていますが、VSTでもAUでもLV2など他のフォーマットでもプラグインをリリースしたいと思ったら、それぞれのフォーマットに固有のDSP処理を書くよりも、MIDIのような共通の音楽演奏命令のデータを使って記述するようにしたほうが、再利用性が高いです。

DSPでコードを共通化できるということになったら、JUCEのようなクロスプラットフォーム・マルチプラグインフォーマット用フレームワークのほか、FAUSTやSOUL(SOULの権利はROLI社に残ってしまったので創始者のjulesは今は新しくc-majorという言語を作っているようですが)といったオーディオ処理に特化した言語、あるいはMATLABのような言語環境も適用できる可能性が高くなります。

例として、オーディオプラグインフォーマットのようなものが登場すると、MDAという定番DSPモジュールの集合体がmda-vst, mda-vst3, mda-lv2といった感じで移植されますが、このオリジナルのMDAのコードは汎用的なDSPコードとして書かれています。各プラグインフォーマットのプロジェクトは、それぞれのプラグインAPIを使った「ラッパー」となっているわけです。

この領域で新しく開発されているのが、MIDI 2.0サポートの追加です。共通コードでMIDI 1.0の表現力しか得られないのは残念な状態だったわけですが、MIDI 2.0が利用できるようになれば、note expressionや32ビットパラメーター(CCやNRPN = Assignable Controller)、アーティキュレーションなどを処理できるようになります。Appleがいち早くAudioUnitで実装しており、JUCEが追従しています2022.7.19追記: これは正しくない理解でした。AUでは任意の可変長バッファではなくMusicDeviceMIDIEvent()MIDIイベントをサポートしており、32ビットintの3値ではUMPをサポートする余地がありません。JUCEのソースでも現状対応する実装がありません。。CLAPも規格のレベルでMIDI 2.0メッセージをそのまま(VST3とは異なり、そのまま)処理できるようになっています。

プラグインフォーマットにおけるイベント定義

VST2の時代は、MIDI入力はそのままのかたちでプラグインが受け取って処理できるようになっていました。一方でプログラムチェンジとパラメーターも利用できるようになっていたので、ある意味役割がかぶっていた状態でした。

Steinbergはこれを問題だと考えて、VST3ではMIDI入力をパラメーターとしてプラグイン側でマッピングして処理させることにしました。その結果、VST3ではなまのMIDIメッセージを受け取ることができなくなりました。これはそれなりに大きな副作用があり、まずVST3プラグインでどんなDAWでも一意に復元できるようなMIDI出力が出せなくなりました(全てVSTイベントとして出力されるため)。そしてJUCEのようにVST3イベントをMIDIメッセージに変換したうえでオーディオ処理に渡す仕組みがあって、かつプログラム番号もMIDIのプログラムチェンジとならずにそのまま渡される仕組みになっていると、DAWにはMIDIのプログラムチェンジを入力したはずなのに、プラグイン側にはプログラムチェンジとして渡されない…といった問題もありました。JUCEのように「プラグイン側ではホストからのイベントは全てMIDIメッセージに変換してその範囲で処理する」仕組みになっていると、この影響をストレートに受けることになります。

CLAPは、VST3とは異なり、MIDI 1.0イベント、MIDI 2.0イベント、CLAPイベントの3種類がサポートされており、DAWはどの入力もそのままプラグインに渡せば良いということになります。

VST3は「役割が重複したら困るだろうからホストが全部われわれのVSTイベントに変換するのでそれを使え」という姿勢ですが、CLAPの場合は「複数の入力イベントで役割が重複するかもしれないが、その解決は自分でやれ」ということになります。

ノートエクスプレッション

ノートエクスプレッション (Note Expression) またはノート別エクスプレッション (Per-Note Expression) とは、プラグインに送信された全てのノートではなく、特定のノートだけに適用されるプラグインのパラメーターを実現する仕組みです。MIDI 2.0 UMPには含まれている命令ですが、MIDI 1.0の原規格には含まれておらず、MPE (MIDI Polyphonic Expression) という派生規格で別途実現しています。もしMPEが無ければ、一般的にMIDI 2.0がサポートされていないOSではMIDI入力デバイスから受け取ることができないでしょう。

(ノートエクスプレッションについては過去に一度踏み込んだ話を書いたことがあるので、ここで改めて踏み込むのは避けます。)

CLAP 1.0公開を機にオーディオプラグイン規格の何たるかを知る (2)オーディオプラグインの拡張機能の種類

連載2回目の本エントリーでは、オーディオプラグインの「拡張機能」としてどのようなものが存在するのか、CLAPとLV2を例としていくつか見ていきましょう。各拡張機能の詳しい内容には今回は踏み込みません(以降の回に期待して下さい)。

まずはCLAPにどのような拡張機能が定義されているのか、一覧を画像で示します。

CLAP extensions

画像にしたのは、他のプラグインフォーマットの拡張機能リストと簡単に比較してみるためです。次の画像はLV2の拡張機能の一覧です。

LV2 features 似たような名前の機能がいくつか並んでいるのが見て取れます。

CLAP拡張機能へのアクセス

CLAPでは、拡張機能がクリーンに整備されています。CLAPの拡張機能にはプラグイン拡張とホスト拡張がありますが、全てのプラグイン拡張機能clap_plugin_*_tとして定義されており、同様に全てのホスト拡張機能clap_host_*_tとして定義されています。プラグイン拡張のAPIは「プラグインが実装し、ホストが呼び出す」ものであり、ホスト拡張の機能は「ホストが実装し、プラグインが呼び出すもの」と理解しておけばOKです。

拡張の種類 実装者 利用者
プラグイン拡張 プラグイン ホスト
ホスト拡張 ホスト プラグイン

プラグインが実装する拡張は、clap_plugin_factory_tcreate_plugin()で返されるclap_plugin_tget_extension()メンバー(関数ポインター)の実装となる関数で、IDに対応するものを返すかたちで実装します。たとえばプラグインでstateを保存する機能(パラメーターが存在するプラグインではほぼ実装することになるでしょう)を実装する場合はこうです。

clap_plugin_state_t state_ext{my_plugin_state_save, my_plugin_state_load}; // それぞれ関数
void* my_plugin_get_extension(const clap_plugin_t* plugin, const char* id) {
    if (!strcmp(id, CLAP_EXT_STATE))
        return &state_ext;
    ...
    return nullptr;
}

プラグインがホスト拡張を呼び出す方法については少し追加説明が必要でしょう。これに関連してはまず、拡張ではありませんが、CLAPのplugin factoryとなるclap_plugin_factory_tcreate()の定義について説明します。

const clap_plugin_t *(*create_plugin)(const struct clap_plugin_factory *factory,
  const clap_host_t *host,  
  const char *plugin_id);

この2番目の引数はclap_host_t*という型になるのですが、これはホスト実装のポインターである必要はなく、プラグインが必要とするホスト機能を提供する実装でさえあれば十分です。clap_host_tには次のようなメンバーがあります(コメントを削っています):

typedef struct clap_host {
   clap_version_t clap_version;
   void *host_data;
   const char *name;
   const char *vendor;
   const char *url;
   const char *version;
   const void *(*get_extension)(const struct clap_host *host, const char *extension_id);
   void (*request_restart)(const struct clap_host *host);
   void (*request_process)(const struct clap_host *host);
   void (*request_callback)(const struct clap_host *host);
} clap_host_t;

ホストのメタ情報のほか、ホスト拡張機能を取得するためのget_extension()、ホストのmain (UI)スレッドで処理を呼び出すためのrequest_callback()、オーディオ処理を開始させるためのrequest_process()request_restart()などが定義されています。ホスト拡張機能はこのget_extension()で取得して使います。

一方で、筆者はCLAPが必須拡張と任意拡張を区別しないのは問題だと考えています。特定の拡張機能プラグインでサポートされていない時に、それでも正常にオーディオ処理を続行できるのか、それとも無効化すべきなのかは、区別できるべき情報です。

参考: LV2の拡張機能アクセス

LV2の拡張機能は他のプラグイン機構と比べると特殊です。RDFメタデータによる定義だけでほぼ全てが完結していてCヘッダーでは定数のURL定義しか含まれていないような拡張機能が少なからずあります。それらの拡張機能は、RDFのクエリだけでプロパティを取得したり設定できたりするように作られているため、追加のAPI定義を必要としないのです。

一方でRDFの操作によって機能を実現する仕組みは弱い型付けに基づいているため、すぐ間違ったコードを書いてしまいがちという問題があります。メタデータコンパイル時に検証できないため、メタデータを変更してコードを書き換えないことで問題がすぐ生じます。

前回のエントリでも書きましたが、LV2のRDFメタデータ中心の拡張機能設計は、動的に変わりうるメタデータ項目の扱いをややこしくするという副作用がありました。先にスクリーンショットで列挙したLV2拡張機能のうち、Dynamic Manifest、Morph、Resize Portの一部仕様は、LV2のメタデータが静的であることから生じる問題を解決する(すなわち、動的なメタデータ定義を可能にする)ために定義された拡張機能です。

CLAP 1.0公開を機にオーディオプラグイン規格の何たるかを知る (1)

5月に「CLAPオーディオプラグイン is 何?」という雑なLT(LTなので!)を行いました。このときは短時間だったので技術的な詳細には踏み込ませんでしたが、より多くの人が踏み込んで技術的に評価できるように、もう少し技術的な詳細に踏み込んだ解説があるべきでしょう。そういうわけで、新たにこの文章を起こすことにしました。わたし個人にはCLAPを普及させる理由はなく、CLAPの話をする理由はないので、オーディオプラグインフォーマット全般に関する話としてまとめています。まだ書きかけの残りが3/5くらいあるので、(1)としています。たぶん3回くらいになります。2022.7.7追記: 全4回になります

この内容の一部は7/6に開催予定のオーディオプラグイン勉強会#1でも言及する予定です。短めの発表 + カジュアルな検討会にしようと思っているので、この分野に興味のある方はお気軽にどうぞ。

music-tech.connpass.com

概論

オーディオプラグインフォーマットの基本

CLAPは汎用オーディオプラグインフォーマットです。汎用オーディオプラグインフォーマットは、任意のDAWで任意のプラグインを利用できるようにするために作られる規格です。。オーディオプラグインは、プラグインフォーマットが規定するAPIを実装し、DAWは、プラグインフォーマットが規定するAPIの実装コードをバイナリプログラム(DLLなど)からロードします。

2022年現在、オーディオプラグインフォーマットは複数の規格が並立しています(次節で列挙します)が、基本的な機能は大きく違うものではありません。

  • 動的ライブラリに類するかたちでロードでき、複数のインスタンスを生成できる
  • ステレオ等のオーディオ入力とMIDI等のコントロール入力を「オーディオ処理」のサイクルで受け取って、オーディオ出力およびコントロール出力に変換する
  • 外部から操作でき、変更をGUIに通知できるfloatのパラメーターがある(その他の型をサポートすることもある)
  • MIDIなどの「イベント」を受け取ったり通知したりできる(オーディオ処理と連動するかしないかは規格による)
  • プラグインのパラメーター等を状態として保存・復元できる
  • メタデータとしてプラグイン名やベンダー名をもち、システム上に有るプラグインをリストアップできる
  • ホストDAWからサブウィンドウに表示できるGUIをもつ

これらだけであれば、素朴に設計するのも実装するのもそんなに難しくはありません。特にプラグインフォーマットとはAPIであって実装コードである必要はないので、宣言してしまえば大部分の仕事は終わりです。

もちろん、適当にAPIを作っただけではプラグインでもDAWでも対応してもらえないので、実際にプラグインフォーマットを定着させるためには、それ以上の仕事をすることになります。魅力的な追加機能を用意したり、それらが多数になっても一貫性を保てたり、簡単に実装できたり…といった設計の調整力が必要になります。

各種オーディオプラグインフォーマットの状況

オーディオプラグインフォーマットとしてはVST、AudioUnit、LV2といったものが存在します。どのフォーマットにもさまざまな長所・短所があります。

AppleのAudioUnit以外はデスクトップのクロスプラットフォーム(Win/Mac/Linux)用と考えて良いです(VSTLinuxをサポートするようになったのはだいぶ最近になってからではあります)。

この他、ProTools用のAAXなど、汎用ではなく特定のDAW専用のプラグインフォーマットで著名なものもいくつかあります。

VSTはVST2とVST3で大きく異なり、SteinbergはもうVST2のSDKを公開していないので、新規企業がVST2製品を公開することは無いと想定されていますが、古くからある製品のバージョンアップでは残り続けるでしょうし、VeSTigeやvst-rsのようなVST2SDK非依存の実装も存在しており、VST2ロゴ以外でSteinbergがライセンスクレームをつけることも出来ないので、急速にフェードアウトしていくことは無さそうです(現在でもVST2版のプラグインは各所でリリースされています)。

AppleのAUv2とAUv3は、VST2/VST3とは全く異なる位置付けです。AUv2は従来型のデスクトップ用プラグインで、DAWのプロセスでロードできるプラグインです。AUv3はiOSMac App Store用のプラグインで、セキュリティ上の要件からプロセス分離が要求され、これが最適なリアルタイム処理を妨げる制約となっています。

(LV2についてはこのエントリの最後にまとめる同人誌で詳しく書いており、この一連のエントリではあまりLV2に寄せすぎた話をしたくないので最低限の言及にとどめようと思います。)

新しいオーディオプラグインフォーマットのインパクト、サポート状況

一般的には、DAWがサポートするオーディオプラグインには、そのDAW固有のものと汎用的なものがあります。VSTも元々はSteinbergCubase用に作ったものでした。

DAWが新たに汎用的なフォーマットをサポートするには、その機能を(一部ではあっても意義がある程度には)サポートできる状態になっていなければなりません。プラグインフォーマットに含まれる機能に、あまり本質的ではない過剰な機能が搭載されていてもいけないわけです。

CLAPを現時点でサポートしているのは商用DAWではBitwig Studioのみで、これは主要な開発メンバーがBitwig社のメンバーだからという非常にストレートな理由です。OSSでCLAPをサポートしているものは存在しませんでしたが、6月末の時点でQTractorのmasterに実験的なCLAPサポートが追加されています。

オーディオプラグインフォーマットの設計ポイント

拡張性

オーディオプラグインの拡張性 (extensibility) とは、シンプルにいえば機能追加のための仕組みです。プラグイン規格に追加機能を持ち込むには、APIを拡張しなければなりません。これを無計画に行うと、後から「やっぱりこの機能はいらなかった」とか「やっぱりこのAPIだとイマイチだから仕切り直そう」と思っても、後方互換を全面的に破壊することになってしまいます。つまり、古いプラグインのコードが新しいプラグイン規格SDKのバージョンでビルドできなくなったりするわけです。

VST2がこの無計画なスタイルで開発されてきましたが(20世紀に作られた仕様であり、誰もがAPI後方互換性を強く意識するような時代ではありませんでした)、VST3ではこれが大きく変わりました。VST3ではコア機能と拡張機能を切り分けて、拡張機能WindowsのCOM技術におけるクエリインターフェースの仕組みで動的に取得するようになりました。もし拡張機能の一部でAPIの進化が行き詰まったとしても、それ以外の部分は後方互換のままで利用できることになります。これはVST-MA (module architecture) と呼ばれる仕組みです。詳しくはこちらの記事などを見て下さい。

qiita.com

よくVST3はVST2と比べて複雑だと言われますが、この拡張性に関する設計方針は、フレームワーク開発者の間では広く受け入れられていて、LV2でもCLAPでも同様の機構をCで実現しています。オーディオプラグイン規格以外でも、OpenSLなどにも見られます。

何をもってコア機能とし、何をもって拡張機能とするかは、これらモダンなプラグインフォーマットの間でも違いがあります。CLAPはだいぶアグレッシブに「拡張機能化」を実現していて、オーディオポートやコントロールポートの定義すらも全て拡張機能で実現しています。

プラグインの列挙に対応するメタデータ取得API

われわれDAWユーザーがオーディオプラグインを使うとき、最初にローカル環境にインストールされているプラグインのリストを取得する必要があるのが一般的です。リストには次のスクリーンショットのような内容が含まれます。

プラグインリスト (JUCE AudioPluginHost) VSTAUには、このリスト取得処理に時間がかかりすぎるという問題があります。

VSTの問題の原因は、プラグインのリストに含まれるべき情報が、プラグイン実際にプログラムとしてロードしてプラグインインスタンスを生成しないと取得できないことにあります。これがメタデータの含まれたファイルをロードするだけで済めば、プラグインのリストアップは単に対象のファイルを開いて内容を解析するだけで終わるので、迅速に完了します。LV2ではこれをメタデータのテキストファイル(*.ttl)に格納するというかたちで実現しています。

2022/7/7追記: 勉強会開催後に、VST3 3.7.5からメタデータ記述ファイルのサポートが実装されたことを教えていただきました:

CLAPは公式発表ではfast scanningをサポートしていると公言しているのですが、CLAPのメタデータは実のところライブラリに格納されていてDLL等をロードしないと取得できず、この点ではLV2に劣ります。プラグインのfactoryのインスタンスさえ取得すればメタデータを取得できるので、プラグイン本体のインスタンスを生成しなくても済む、という点においてのみVSTより高速だといえることになります。DLLをロードすると全てのstaticデータの初期化が発生するため、JUCEのBinaryData初期化などでDLLのmmapロード以上のコストがかかるということもありますし、プラグインによってはこのDLLロードとメタデータ取得の時点でライセンスアクティベーションダイアログを出してくるものがあり、これらが迅速なプラグインリストの生成を邪魔してくるわけです。DLLをロードする方式だとそういった問題があるため、JSON等でメタデータを生成して解析できるようにしたほうが良い、というコミュニティ(筆者も含む)からはフィードバックが出ているのですが、開発チームは「JSONを解析しないといけなくなるから嫌だ」というレベルで否定的な見解を示しており、改善が施されるかは不透明なところです。

ちなみに、プラグインの列挙が仕組み上高速に完了するとしても、プラグインリストをキャッシュするDAWの仕組みがなくなるというとは限りません。プラグインリストキャッシュには「ロードに失敗した」プラグインをリストから除外する、いわゆるallowlist/denylistを管理することも期待されるためです。

プラグインメタデータに何を記述するか

プラグインメタデータに「何を」記述するかも設計における考慮事項のひとつです。ここでひとつ意識しておくべきは、プラグインのプロパティというべき情報には、プラグインの状態(たとえば選択されているプログラム・プリセット)によって動的に変わり得るものがある、ということです。ファイルに書き込まれるメタデータは静的なので、プラグイン名など不変のものか、初期値くらいの意味しかありません。

LV2では、プラグインのオーディオポートやMIDIメッセージの送受信に使われるコントロールポートの情報を、メタデータに記述することになりますが、VST3やAUの場合は、ポートのレイアウトはホスト(DAW)から提示された構成(ステレオ、モノラル、7.1chなど)をプラグイン受け付けるかどうかを判断する、という流れになります。LV2では、メタデータテキスト(*.ttl)に静的に記述されているポートのグループをホストが見てから「このレイアウトは受け入れられる」と判断できますが、VSTAUのように提示された構成の受け入れを動的に決定するには、dynamic manifestという拡張機能を使うことになり、その場合はやや複雑で面倒です。

CLAPはオーディオポートやコントロールポートの定義も拡張機能で定義し取得する仕組みになっており、メタデータをあらわすclap_plugin_descriptor_t型にはポートの情報は含まれません。コア部分に含まれない情報は拡張機能で取得できるかもしれませんが、拡張機能get_extension()関数によって取得することになるので、必然的にライブラリをロードすることになります。

6月の活動記録 (2022)

6月は雨が多くて好きじゃないという人も少なくありませんが、わたしは好きじゃないですね(時候の挨拶)。

AAPのPrefabパッケージ化とlibcxx-provider

AAPの開発がAndroid Studioデバッグ実行まわりの不安定さに引っ張られてスムーズに進まないので、今月は少し周辺的なタスクを片付けていました。その過程で、本来やるつもりではなかったAARのPrefab化が完了しました。Prefabパッケージ、当初は問題だらけで、こんなの採用しようがないと思っていたわけです。2020年に一度詳しく書いています。

atsushieno.hatenablog.com

ここで列挙した問題のうち、いくつかは未解決のままですが、2022年現在、少なくともAAPについては「Prefabとnon-Prefabは共存できるようになった」「project(...)を使ったモジュールの参照がまともに解決されるようになった」「ビルドタスクの依存関係はbuild.gradleの依存関係を手作業で書き加えて何とか解決できる」「ヘッダファイルのディレクトリは1つになったし、その後AGPも対応したっぽい」「STLの競合は解決するアプローチを見つけた」というレベルでざっくり解決しつつあります。そして、 デバッグ時も含めたライブラリの正しい参照解決がNDKを使った開発の課題になるのに、Prefabを使わないビルドの場合はCMakeビルドの調整でクリーンにならない、という事態は好ましくなかったので、それならPrefab荷移行したほうがマシだろう、と考えたのでした。

上記の解決課題のうち「STLの競合は解決するアプローチを見つけた」については、今月新しく公開したlibcxx-providerというAARのパッケージのREADMEで具体的に解説しています。

github.com

本当はブログエントリにしようと思っていた(思っている…)のですが、READMEでほぼ説明しきってしまったので、それで終わりかもしれません。7月もカンファレンストークの準備(調べ物)などをしないといけないので、落ち着くのは8月になってから…?

AAPクライアントAPI再構築(未了)

4月にAAPで汎用的な拡張機構を実現するAAP extensions APIを構築した話を書きましたが、今月はこれをstate APIにも適用して拡張機能化する破壊的変更を実装しました。ただ、これに伴って、Kotlin APIを抜本的に書き換える必要があることが分かって、思いのほか大掛かりな作業になりつつあって完了していません。

AAPはホストアプリケーション(DAWなど)をKotlinでも構築できることになっているのですが、現状ではAIDLで定義したAPIを叩くクライアントのレベルでKotlinとC++の両面で実装している状態です。4月に具体的に書いたのですが、AAP拡張機能は一般的なオーディオプラグイン拡張機能APIとは異なり、拡張機能の提供者が(まあこれは現状標準拡張を規定している自分だけなのですが)AIDLで定義された拡張機能操作メソッドextension()を呼び出すネイティブ実装も提供する必要があります。その実態は「渡された命令コードがn番だったら、共有メモリバッファの0..mは引数xとして扱う」といったプリミティブな処理になります。

これらはC/C++レベルで実装されますが、Kotlin側には対応する機能が現状ありません。Kotlinのプラグインクライアント(DAW)が使うAPIは、あくまでAIDLで生成されたKotlin APIでしかないので、Kotlinでこれらの拡張機能を使おうと思っても、再実装するか拡張機能そのもののラッパーを作るしかありません。前者はそもそもKotlinで拡張機能の作者がC/C++でやっていることを再実装するということなので筋が悪く、特にC/C++拡張機能の作者と別人でありうるKotlin API実装者が同じURI拡張機能を実装している状態は治安が悪いので、誰でもKotlinでC/C++ APIバインディングを作る必要がある(けど治安が悪いとまではいえない)後者のほうがまだマシということになります。

Kotlinで拡張機能のラッパーを作るとしても、そもそも何に対して「ラッパー」を作らなければならないかというと、実のところlibandroidaudioplugin.soに含まれる非公式のC++ hosting実装に対するラッパーとならざるを得ない状態でした。これは、拡張機能のサービスAPIがlibandroidaudioplugin.soのC++ hosting APIの実装に深く依存していたためです。そういうわけで、今月は少なからず時間を割いて、4月に実装していたこのAPIを再構築して、拡張機能APIホスティング実装のAPIを切り離しました。

本当はこの切り離しが完了(変更したAPIに合わせてaap-lv2もaap-juceもそれらを使ったアプリを全部変更)したら、その続きとしてKotlin APIで純粋に拡張機能を呼び出せるような仕組みを構築するつもりだったのですが、前述の通りその方式では拡張機能の再実装ということになってしまって筋が悪いことに気がついたので、やはりKotlin APIもlibandroidaudiopluginのhosting APIのラッパーにせざるを得ないかな…となっているところです。

オーディオプラグイン勉強会#1(準備)

そろそろまたオーディオ開発の勉強会をやりたいと思っていた頃に、6月にCLAP 1.0がリリースされたので、それならCLAP 1.0を肴に勉強会をやると良いだろうと思って開催することにしました。オンラインで7/6 20:00スタートです。今回もこの分野に関心がある人には大いに刺激になる勉強会になると思うので、ぜひ参加してもらえればと思います。

music-tech.connpass.com

勉強会のスタイルを設計するというのは(少なくとも自分としては)割と考慮事項がたくさんあっていつも悩むところで、今回は特に以下のような設計方針にしました。いずれ書こうと思っていたので、今回ここでまとめることにします。

  1. 勉強会は「参加者のため」にやる
  2. みんながしゃべれるようにする
  3. 発表者がしゃべるだけの会にしない
  4. ただし雑談に依存しない
  5. カジュアルからどっぷりまで各人の好きな度合いで参加できる

1.〜3.はざっくりセットです。聞いているだけ、質問・コメントでしかやり取りできない勉強会になってしまうと、どうしても「数字」(人数)・養分にしかなっていない感じになってしまいます。自分の場合、コメントが半分拾われなくなったら「他人事」になってストリームを閉じることが多いですが、ホスト側になったら全部拾っていられないですよね。自分の場合、資料を読み上げて発表したいのであれば1人でしゃべって動画をうpすればいいし、文章やスライドとして公開したほうが読む側も助かるだろうし、「参加人数」にKPIが無くて、どちらかといえば「せっかく関連技術に詳しい人が集まってくれるので、そこから最大限いいシナジーが生み出されてほしい」わけです。

これは普遍的な話ではなく、たとえば「多人数向けに話すためならたっぷり時間をかけて最高の資料とセッショントークを準備して最高のマテリアルを遺すことができる/業務時間なども使える」という環境にいる人にとっては、多人数向けのオンライン勉強会などが最適解になるわけです。わたしは「みんなを引っ張り上げる」立場にもないので、共同体的な勉強会が向いています。

このやり方は多分名目30人くらいが限度だと思うので、ストリーミングの制限にかかわらず最大30人としています(10〜15人くらいは完全に聞き専と想定)。トピック的にはもっと集められてもおかしくないですが、それは全くKPIに基づく別のスタイルになるでしょう(複数人に事前にセッションをお願いして人づての窓口も増やす)。まあイベント感ある勉強会もそれはそれで楽しいですよね。

資料発表の時間は全体の1/2〜1/3くらいにして、ざっくりにして、いつでもしゃべりを中断して質問・コメントできるようにしています。何なら「ちなみに…」と直接関係ない話をされても、経験上、これで治安が悪くなる(話題が逸れすぎる)ことはほぼありません。話題が逸れ過ぎたらいつでも「スライド(本題)に戻りましょう」といって元に戻れるのです。何なら話題が逸れ過ぎても、それがみんなの話したいことならそれが話題の本質なのかもしれません。予定時間をタイトにするとみんなしゃべらなくなるし、盛り上がっても話の腰を折ることになるので、避けたいところです。

一方で、勉強会の場が「100%ただの雑談場」になってしまうと、それはそれで「何しに来ているのかよくわからない」状態になってやっぱり満足度が上がりません。われわれには多かれ少なかれ「自分のためになる時間」である勉強会に参加するという建前が必要です。雑談だけの時間は予定時間の後に十分にあるので、「勉強会では何もしゃべらなかったけど終わった後にみんなで晩飯に行ったら急に喋りだす人」ムーブも全然OKですし歓迎です(オンラインなのであくまで晩飯云々は完全に比喩です)。

勉強会は録画しようと思っていますが、公開は前提ではないです。まず、役に立つ情報を公開したければ1人で録画できます。公開するとなると私的な話などを出しづらくなって、参加者が非参加者を意識して発言を遠慮するという本末転倒の事態になります。参加者が楽しめることが最優先です。その上で、「録画して可能なら公開する」ことにしています。これは、経験上この種の読書会スタイルで共有される情報はやっぱりめちゃくちゃ参考になる話が多く出てくるためです。

CLAP JUCE hostingの試験実装

CLAPはオーディオプラグイン勉強会ではあくまで「肴」という位置付けなのですが、発表資料をふわっとしたレベルで終わらせるのは躊躇われるので、ちょっと自分でもコードを書いてみることにしました。JUCEでプラグインを作るモジュールはclap-juce-extensionsという公式リポジトリで公開されているのですが、ホスト側で利用できる実装がないようなので、先週くらいから自分で作ってみようと思ってチマチマと作っています。現状、リポジトリにするほどメンテする意思も無いのでgistです。

https://gist.github.com/atsushieno/d47a82739c64595da2f15cd8bc87673a

CLAPホストは実際にOSSではまともに存在しないのが現状です(公式リポジトリのclap-hostは機能しません)…というのが作り始めた頃の状況だったのですが、作っている間にQTractorで実装されました。いずれにしろJUCEモジュールにすれば、AudioPluginHostで使えたりtracktion_engineやhelio-workstationに組み込んだりできるのであってほしいところです。LV2には(JUCE7で正式にサポートされる以前から)jlv2というホスト側実装のプロジェクトがあって、これでtracktion_engineに組み込んでLV2プラグインをロードしていたので、CLAPでも同じことが出来るとたぶん便利でしょう。

もっとも、LV2と違ってCLAPでやりたいことは特に無いので、これを進めたいという動機もメンテしたいという動機もほぼありません。勉強会資料作成の肥やしのひとつです。

CLAPに関してはもうひとつ技術調査の動機があって、AAPのネイティブAPIの実装を、Binderでやり取りするのとは別のレイヤーでCLAPに置き換えて実用できるかどうか評価する、という目的がありました。CLAPにはAPI設計で参考になる部分もあるのですが、現状ではホストとクライアントの相互運用(API呼び出し)が頻繁にあって、プロセス境界をまたぐ必要があるAAPには馴染まなそうだというのが現時点での評価です。

その他

6月の最初は内閣官房デジタル市場競争本部事務局の力作に応えるべくパブリックコメントを書いたり本文を読んだりしていました。これは前回書いたので詳細はまあ今回書くまでもないでしょう。

atsushieno.hatenablog.com

あと、7月末に台北COSCUP 2022MIDI 2.0に関するセッションをひとつ担当します(英語)。観光ビザでは相変わらず入国できない状態ですが、今回は渡航できる予定なので、問題が発生しなければ現地でしゃべることになると思います。来月はその発表準備や渡航準備で多少ごたごたする予定です。

モバイル・エコシステムに関する競争評価(中間報告)に対するパブリックコメント 最終版

話題の*1「モバイル・エコシステムに関する競争評価(中間報告)に対するパブリックコメント」を自分でも書いたので公開しておきます。

public-comment.e-gov.go.jp

以下本文:


この報告書の位置づけに対する理解

(この項目は、提出用フォーマットの「2.記載された内容の他に、考慮すべき視点とそれに対する意見」として記載します。)

パブリックコメントは公開されて読まれる前提である、という考えに基づいて、このコメントは担当者の方以外にも読まれる体裁でまとめられている。

本コメントはmarkdown形式で書かれたものをメールで送信しているので、デジタルデータがあれば読みやすく復元できる。

この報告書は内閣官房デジタル市場競争本部事務局の名義で出されている。競争政策だが公正取引委員会デジタル市場競争会議ワーキンググループの中で報告者として参加していたに過ぎない(ただGoogleの法務担当者から、ワーキンググループの議事録での参加は少なく見えるが実際には何度もミーティングしてきた旨、ジュリストNo.1564(2021年11月号)に書かれているとされている)。

本報告書に対しては、こんなかたちでAppleGoogleを規制しても日本の企業がAppleGoogleに勝てる市場を作れるわけではない、国粋主義者が非国産プラットフォームの足を引っ張る目的で作った非現実的な報告書である、といった批判が上がっているのが観測できる。前者については、本報告書の議題となる競争市場はプラットフォーム市場そのものだけでなく個別のアプリ市場(たとえば音楽ストリーミングアプリ市場)に対しても影響するものであり、本報告書の意図するかたちで対策を検討することは適切であることを確認しておきたい。

後者は国家による企業に対する正当な法規制ではないという主張であり、傾聴すべき意見ではある。これについて、米国でもモバイル独占市場にかかる規制法案が審議されるにあたって、議員の意見の割れ方に興味深い結果が出ている。現与党である民主党は全員規制側、共和党は半々に割れており、企業は国家に服従すべきと考える議員が民主党と同じ規制側に、企業の経済活動を最大限自由にすべきと考えるような議員が規制否定側に回っている状況であると理解できる。筆者は、競争法の観点から、合目的的な、最小限の、しかし積極的な介入は必要であると理解している。

デジタル庁には、かつてWindows PhoneというApp Storeのように独占的なモバイルプラットフォームを打ち出そうとして失敗し撤退した日本マイクロソフトの出身者が政府CIO補佐官の時代から何名も在籍しており、今回の報告書にも影響を及ぼしている可能性はある。一般にプラットフォーム企業の出身者は出身企業の従業員と密に連携して法に明確に反しない範囲で利益誘導を得ることがあり(たとえば招待講演を請けて現業を宣伝する場を設けてもらえる)、AppleGoogleから営業秘密を引き出す意図をもって関連制度の枠組みに参加する危険性もあることは意識しておきたい。関連プラットフォーム業者には忌避の申立を可能にする等の対策が考えられる。


(以降は提出用フォーマットの「1. 記載された内容に対する意見」として記載します。)

I. 総論

第1.市場の構造と実態

<中間報告の該当箇所:16ページ>

モバイル OS を維持するためには年間数百億円かかると言われているが、一方で、OS の事業に関しては、根源的に先行者メリットがある。

コストばかりが強調されていて、収益について言及が無いことから、これはプラットフォーム側(AppleおよびGoogle)が主張したい数字だけをそのまま書いているのではないかという疑念が生じる。この引用部分は、間接的な先行者利益がこれらのプラットフォーム運用の動機に直結しているかのように読めるが、AppleApp Store登録開発者は50万人おり、99ドル = 10000円という大雑把な換算でも1年で50億円の売上がある(アプリ内課金による収益のほうが大きいことは言うまでもない)。最終的な報告書では、開発者からのプラットフォーム利用料などが主要な収益源であることが読者にも理解できるようなまとめ方が望ましい。

<中間報告の該当箇所:17ページ>

ユーザーにとっては、ブランド・ロイヤリティだけでなく、使い慣れた UIやコンセプト、使い慣れたアプリなどをインストールする手間、既に端末内やクラウドに保存している多種大量のデータを移動する時間や労力などがあることから、スマートフォンの OS をスイッチすることについては、ハードルがある。

これに関連して、アプリ市場の消費者には、プラットフォームを切り替えるだけで同一のアプリケーションに再度対価を支払って購入させられているという状況があり、これが放置されていることが問題である。PCソフト市場においては、同一のソフトの市場において、同一ユーザーに対する複数のプラットフォーム分、数台のマシンへのインストールが可能になっているのが一般的であり、モバイルアプリマーケットが独占的であることは、対価の二重取りを肯定することになっている。

複数プラットフォームにおいて「同一の」アプリケーションが配布される場合に、対価の二重取りが生じないことを保証するような、同一ユーザーによる購入情報を確認できるようなアプリ市場間の相互運用の仕組みが、一定規模のアプリケーション市場において実装されるような施策が求められる。(同一性はアプリ名、アプリ内コンテンツの同一キャンペーン・イベント等、あるいは広告等で実質的に判断できる。)

第2. 目指すべき姿と対応に向けた基本的な考え方

<中間報告の該当箇所:35ページ>

「1. モバイル・エコシステム全体に関する認識」「2. モバイル・エコシステム全体のあるべき姿」ともに適切な内容でまとめられていると考える。

モバイル・エコシステムは、これらのサービスを利用する消費者の日常生活、そして、当該サービスを提供するビジネスユーザーの経済活動の基盤(インフラストラクチャー)としての機能を果たしているととらえることができる。

この他に、行政においてモバイルアプリケーションが開発・利用されているという観点が重要であると考える。そもそも論として可能な限りプラットフォーム依存性を排したWebでできる以上のことを行政で利用するアプリケーションにおいて利用すべきでないという問題もあるが、必要最小限の範囲でモバイルアプリケーションを利用せざるを得ない場合もあろう。そのプラットフォームは公正競争に則り独占に資することがあってはならないし、当該プラットフォームをサポートしないことで国民生活に多大な健康上の被害や金銭的利益の多寡といった影響が出るのであれば、それは国家がプラットフォームの機構に積極的に介入する必要がある。

この点で近年独占性が問題になったのはコロナウィルス濃厚接触を検出するExposure Notification APIとそのサービス実装で、日本でもCOCOAというアプリケーションがこれを組み込んでいる。COCOAは「公共事業案件を受注前のアピールだけは大々的に行い、受注後は何もしない」という方針に等しい開発企業のネグレクトによりユーザーフィードバックを放置して問題になったが、ここに競争原理が機能していれば、このような問題で国民の健康・生存権を幅広く損なうことはなかった。この独占構造に資することになったのがAppleGoogleの1国1アプリという私的な制限だった。独占禁止政策はこのような観点でも他の官公庁から独立して影響力を及ぼす、具体的には国民および公正取引委員会などから問題の指摘を吸収し改善を促していく機関が存在すべきである、と考える。

<中間報告の該当箇所:36ページ>

アルゴリズムを利用しているためにビジネス上の決定の過程がブラックボックス化していること等により、情報の非対称が存在しており、

「企業秘密である非公開アルゴリズムに基づいており公開できない」といったエクスキューズのことを指していると思われるが、アルゴリズムに計算機にかかる判断処理がブラックボックス化されることは無い。 特許技術であればそれは公開されていなければならないし、営業秘密の保護は独占禁止法違反を正当化するものではなく、企業には官公庁において事実関係を確認するための監査を受け入れる義務がある、と立法で対策することが考えうる(もちろんこれは独占禁止法に基づく行政手続であって犯罪の捜査等に目的外利用できてはならない)。

<中間報告の該当箇所:37ページ>

複数のレイヤーで影響力を行使し得るプラットフォーム事業者による一定の行為に対し、現行の法的枠組みの制約にとらわれず
に、実効的に対応することができる方策を検討することとしている。

根拠法なしで実効的に対応する方策を検討するのは法律による行政の原理に反するので、少なくとも対応根拠に関しては明確に法に基づく対応が求められる。弊害の類型化と明示があれば、対応手段まで詳細に規定することは必須ではないと考えるが、基本的に政令等に基づいて対応する必要があろう。

<中間報告の該当箇所:38ページ>

今回競争評価の対象としているモバイル・エコシステムにおける競争上の諸課題については、その特性から、これまでの競争法によるアプローチとは異なるアプローチを考えていく必要があるのではないか。

本項に関連して、「独占的状態に対する措置」(独禁法第2条第7項、第8条の4)が注釈として言及されているが、本条はいわゆる伝家の宝刀であり、その適用を視野に入れるのは不当とまでは言えないものの、現状で野放図である市場の独占的状態に対して、最初から用いていく筋書きよりは、着実な競争促進策を推し進めるほうが適切であると考える。

<中間報告の該当箇所:39ページ>

セキュリティやプライバシー保護など例外的に何らかの理由を持つ場合もあり得ることから、プラットフォーム事業者がそれを示した場合、十分に精査したうえで正当な理由と認められる場合には、禁止から取り除くといった対応が可能ではないか。

「正当な理由のない禁止の禁止」は、法の原則として適切なものであり、プラットフォームが公共的存在である認定される以上は、これはユーザーおよびプラットフォーム内開発者に対するプラットフォームからの「禁止」についても妥当する原則といえる。

とはいえ、それがあまねく事前規制として存在すべきかどうかは別の問題である。行政にたとえるなら、地方自治体が独自の規制を定める際に、国政に対して事前に届け出をすることはないはずである。プラットフォームによる競争阻害行為についても、それが類型的に予測可能で事前承認を必要とする場合もあり得るが、それ以外は事前規制には馴染まないと考える。

セキュリティの関連では、プラットフォームに対する根源的に解決困難な攻撃が比較的短期間で可能になる状況がしばしば存在する。Intel系CPUに対するSpectre攻撃は、WebブラウザにおけるShared Array Buffer機能の利用を封印させるに至った。またセキュリティ対策がある時期に一気に普及することもある。HTTPSでないHTTPトラフィックの一般的な乗っ取りは、20世紀には理論上の存在でしかなかったが、現在では現実的な脅威となってきたため、ある時期にWebブラウザのベンダーやプラットフォーム側でHTTPの接続要求がHTTPSの接続要求に置き換えられるようになった。これらは安全策の強制が良い意味で世界を改善した例といえるが、いつから「対応必須」と言えたかは判断が難しく、「禁止の禁止」が強制されていたら実現は困難だったと考えられる。

この点では、プラットフォーム事業者がTerms of Serviceなどにおいて反競争的な禁止項目を追加したときに、そのプラットフォーム上のアプリ開発者やユーザーが幅広く反競争行為について申告できる対応窓口を行政側で提供し、それに基づいてプラットフォーム側に対応を要求する仕組みが構築されることが望ましいと考える。

一方で、類型的に反競争的なTerms of Serviceの追加などを事前に禁止類型として提示しておくことは、問題にならないと考える。プラットフォーム側に十分な対応リソースがあると考えるのが合理的である範囲においては、それを為さなければ独占禁止法違反となるという法的根拠がある限りにおいて、作為義務を認めることも妥当であると考える。なお、これに対して、たとえば「著作権法違反を防ぐため…」のような理由付けは独占禁止法違反の認定に内在する曖昧さとは無関係であり、本項に基づく作為義務の対象にはなりえないと考える。

<中間報告の該当箇所:39ページ>

デジタルプラットフォーム事業者が行っている行為については、データやアルゴリズムなどに関して、プラットフォーム事業者との間で情報の非対称性がある。このため、規制当局に対して、広範な情報提供や説明を求める権限を付与するなどの仕組みも考えられるか。

本項で注記された欧州委員会のほか、米国でもAmerican Innovation and Choice Online ActやOpen App Markets Actの制定といった動きがあり(これらは本報告書で後々に言及されている)、日本の行政においてもこれらの担当部署・機関と連携しての情報交換および国民に対する成果公開を期待したい。

第3. モバイル・エコシステムにおける各レイヤーに関する評価及び対応の方向性

総論としての事実認識、問題の提起については適切にまとめられていると考える。対応策に関しては、その妥当性および実効性について、II.各論で検討したい。

第4. モバイル・エコシステムにおける諸課題への対応における対象の考え方

<中間報告の該当箇所:52ページ>

モバイル・エコシステムにおける諸課題への対応策を検討するに当たっての対象の考え方について、どのように考えるか。

本報告書から想定される法規制の対象を競争市場とすることは妥当と考えるが、モバイルアプリケーションのプラットフォームに限らず、パーソナル・コンピューター市場も規制対象として考えるのが妥当であると考える。現状ではWindowsMacのシェアが大きいが、Chromebookも普及しつつあり、Googleが対象となる日が来る可能性もあろう。ただし、本報告書で指摘されている通り、モバイルプラットフォームではデバイスの性質上プラットフォームベンダーがユーザーのアテンションを集中的に得られる等の側面があることが法の積極的な介入の理由のひとつであり、この問題が当てはまらない場面ではPCプラットフォーム市場は対象外とするのが適切であると考える。いずれにしても、独禁政策における市場策定や法の適用は公正に行われなければならない。

この他にゲームプラットフォームも独占的なアプリケーションの配布モデルとなっており、競争促進の観点では対象になりうるように思われるが、モバイルプラットフォームやPCプラットフォームとは異なり、行政の場面で利用するようなプラットフォームとはなっていないため、積極的な法システムが介入すべき市場としての側面が小さいことは否めない。

第5. モバイル・エコシステムにおける諸課題のとらえ方と対応の方向性

総論としての反競争状態に対する取り組みの方向性は、本節に付された諸外国動向資料を踏まえるに、正当なアプローチであると考える。

II. 各論: 第1. エコシステム内のルール設定・変更、解釈、運用

第1-1. 【OS・一部ブラウザ】

1. OS 等のアップデート・仕様変更への対応

<中間報告の該当箇所:72ページ>

オプション A は、問題の解決に有効か。また、どのようなメリットがあるか。
オプション A 以外に、問題の解決のために有効に機能すると見込まれる方策はあるか。
オプション A の実施に伴い、セキュリティ、プライバシー等どのようなコスト、リスクが生じるか。
その問題を軽減させる方策として、どのようなことが考えられるか

本項で論じられる本質的な問題は2点、(1)アップデートに(主に)Appleの規定する期限内に十分に対応できない (2)プラットフォームの新バージョン公開時に告知される新たな要求事項に対応する期間がAppleGoogleにとって先行者利益をもたらす結果になっていること、と解釈できる。

このうち、後者を事前規制するのは困難で、独占的状態に対する規制すなわち事業分割を伴わなければ実効性が無いと考えられる。先行者利益は毎年とはいえ「たかだか数ヶ月」であり、これが長いか短いかは対象事業次第だが、独占的状態の規制を持ち出すにはさすがに問題が小さすぎると考えられる。プラットフォーム規制には、より直近に解決すべき問題が山積みである。

アップデートの内容および対応期間の問題について、特に日本語での「最新バージョンに関する適切な情報開示」「デベロッパからの問い合わせに関する手続・体制の整備」はほぼ実現できないと考えられる。プラットフォーム企業の日本法人はそもそも営業拠点でしかなく、プラットフォーム開発部隊のメンバーはおらず、短期間で新発表の技術等について伝達できる開発スキルを有する人材が十分にいない可能性が高く、簡単に増員できるものでもない。また、新バージョンの公開に伴って公表される資料は通常は膨大なもので、通常は一生日本語化されない。開発者が自己責任で機械翻訳にかけて読めれば十分である。

「運営状況の政府への報告」は、特に前者をプラットフォーム企業主導で行うことを要求しても、開発者が実際に直面する問題が適切に反映されない可能性がある。「政府によるモニタリング・レビューの実施」は、そのフォーマット次第ともいえるが、政府はアプリ開発者ではないので、プラットフォーム事業者から提供されるリソースをレビューできる技術力も時間リソースも無いであろう。それよりは、アプリ開発者および一般ユーザーが政府に対してプラットフォームの新たな制限等にかかる問題を報告できる窓口を設け、それに沿って政府側から新バージョン公表後は3ヶ月程度は毎月、各種変更追従対応にかかる要請(〜命令)を連絡する制度で対応するのが現実的かと思われる。

また、反競争的契約条項に関する報告窓口は常時設置して、新たな問題をタイムリーに審議し対応できる体制があることが望ましい。

2. OS のアップデート等に伴うアプリ開発の時間的優位性

<中間報告の該当箇所:77ページ>

事実関係や懸念事項について、さらなる情報(具体例の追加や補足等)はあるか。

Appleはこれまでに何度も反競争的な制限を開発者に課している。最初期に話題になったのは2010年にAdobe Flashを排斥するためにiPhone Developer Agreementに追加されたsection 3.3.1すなわちアプリケーションはObjective-C, C, C++コンパイルしたものかWebKit上で動作するJavaScriptのみが許される(当時)とした条項である。

ゲーム開発フレームワークを開発しているUnity社は、それまで何の問題もなくC#でアプリケーションを開発し公開できていたものを、いったんC++コードに変換する仕組みに着手せざるを得なくなり、その後本条件が実質的にAdobeのみを狙い撃ちにするかたちで実施されているとわかるまで開発コストを割くことになった。(この仕組みはその後JITにかかるコーディング制限の緩和の目的でIL2CPPという名前で公開されている。)

本報告書で全く触れられていないと思われるのは、Google以外のAndroidバイスベンダーが必要とするコードは、正式版のリリースまで全く公開されないことである。GoogleAndroid 12が正式公開される前に3回のプレビュー版をリリースしたことが言及されているが、これはアプリケーション開発用のバイナリコードのみの公開であり、これは自社デバイスに向けてAOSPをカスタマイズしなければならないデバイスベンダーにとっては意味をなさない。ここで、アプリケーションではあまり問題にならない「2年間のサポートライフサイクル」の問題が、デバイスベンダーにとっては大きな問題になりうる。特に終期のないアプリケーションにとっての3ヶ月の先行利益とは異なり、最先端デバイスがリリースされてからの2年間のうち3ヶ月をキャッチアップに費やされる問題に対しては、何らかの制度的な救済が必要と思われる。

オプション A は、問題の解決に有効か。また、どのようなメリットがあるか。
オプション A 以外に、問題の解決のために有効に機能すると見込まれる方策はあるか。

いずれの分離政策も、日本単独で規定しても実効性が担保できない懸念があるものの、サンクションとしての制裁金を回収するレベルにまで至れば法的に完全に無意味というわけではないので、その方向で規定することに反対するものではない。とはいえ、規定の実効性が確保できる方が望ましく、EU・米国等関心のある各国で提携して、あるいはWTOのような組織レベルで、条約レベルで独占禁止政策を共同施行できる仕組みを模索されたい。

もっとも、コロナ禍も経て世界的にリモートワークが普及した2022年以降の世界で、データ分離は開発業務においてオフラインワークの強制に繋がることにもなりかねず、また分離業務が行われているという虚偽の申告に対しても検証可能性が低く(AppleGoogleEU圏では法令遵守より法規違反に伴う制裁金のほうが安いと判断すればその道を選んでいるという実績がある)、実効性が疑わしいように思える。

私見としては、独占的プラットフォームにかかるこれ以外の問題が解決されれば、この問題自体は「プラットフォーム開発者は先行者利益だけは引き続き得ることになるが、それも競争政策上否定すべきか?」という問題になり、これに対しては答えは割れるのではないかと思う。その意味では「他の問題が解決するまでの条件付き規制」という位置付けにする選択肢もあると考えられる。

5. ブラウザにおけるトラッキングのルール変更(Google

<中間報告の該当箇所:89ページ>

本件にかかる最終的な意見は「2. OS のアップデート等に伴うアプリ開発の時間的優位性」におけるものと変わらない。

Google Privacy Sandboxについては、Google Play Servicesの機能のアプリケーションバンドル(aab/apk)からの分離によって「悪意のある改ざんが加えられていない」広告SDKの仕組みが期待でき、セキュリティと透明性に資するものと考える(Google Play Adsの仕組みが透明化されるという意味ではなく、Google Play Servicesの機能の一部がPrivacy SandboxによってGoogleの制御下でダウンロードされるようになれば、GPSを利用するアプリケーションにGPSのコードをバンドルする必要も、それに伴ってapkがGoogleのライセンスに拘束されることもなくなる、という意味において)。とはいえ、現時点ではAndroid 13以降でのみ利用可能な機能であり、まだ未来形の話であると理解している。

6. クローズド・ミドルウェアGoogle

<中間報告の該当箇所:94ページ>

一定規模以上の OS を提供する事業者が、当該 OS をオープンソースで提供している場合には、アプリの開発環境を提供するときは、その開発環境に、当該オープンソースの OS を利用して自らの OS を提供する事業者がアクセスできるようにすることを義務付ける規律を導入することが考えられるのではないか。

オプション A は、問題の解決に有効か。また、どのようなメリットがあるか。
オプション A 以外に、問題の解決のために有効に機能すると見込まれる方策はあるか。

これは公平性に欠け、プラットフォーム事業者に要求できることではない。「当該 OS をオープンソースで提供している場合には」という条件の設定が失当である。プラットフォームAPI非独占的であることがプロプラエタリ部分のオープンソース化を要求できる正当な理由にはならない。クローズドミドルウェアによる囲い込みの解消策は、Windowsを公開しているMicrosoftにも、iOSmacOSを公開しているAppleにも、等しく公正に要求すべきである。モバイル・プラットフォームであるか否かは、囲い込みの成否に影響する問題ではない。本項目の記述からは、そのような公正な発想が欠落している。実務上も「(理由は全くわからないが)プロプラエタリOSにすれば解決だ」と考えてプラットフォームコードの一部を非公開にして回避されるだけであり、透明性確保に完全に逆行することになる。

サードパーティのOS開発者には許可制で見えるようにするのは一つの手」などと意見しているのは、おそらく日本マイクロソフトの関係者かアマゾン・ジャパンの関係者からの差し込みであろうと考えられる。日本の競争政策はGoogle/Apple以外の独占的プラットフォームが横槍を入れるために存在するものではない、ということを確認したい。

Google Play Services (GPS)の囲い込み問題を解決するための、より適切な方法は、GPSに相当するプラットフォームサービスプロバイダーAPIの策定とその適用をプラットフォーム提供者に義務付けることである。これならばGoogle等プラットフォーム事業者に「反競争状態を解消するための現実的かつ妥当なコスト」として認められると考えられる。Google Android以外のAOSP互換プラットフォームで当該サービスプロバイダーAPIの実装が存在しない状態がある場合に、それによってアプリケーションが利用できない不利益を受けるべきはプラットフォーム事業者であるべきである。

第1-2. 【アプリストア】

7. アプリストアの拘束(Apple

<中間報告の該当箇所:98ページ>

報告書に示されているようなAppleの主張は、米国でOpen App Markets Actが審議されていたときに、日本も含め世界的に名前が広く知られている米国のセキュリティ研究者Bruce Schneierによって幅広く否定されており、日本語でもその詳細が「競争法案に反対するアップルの主張に反論するブルース・シュナイアーの意見書」という翻訳文書で読めるようになっている。

実際、Appleは開発者向けオンラインカンファレンスWWDC 2022において、iOS 16で開発者モードを導入し、開発者署名が付いたものはApp Storeで公開されていないアプリケーションであっても実行できるようにしている。Appleの開発者用ベータテスター向けアプリ配布サービスTestFlightを使用するとアプリケーションが配布できたため従前と変わらないという主張も見かけるが、開発者署名が付加されていれば配布チャンネルを問わないというのはsideloadingに近いと考えられる。何より、これはEUのDMAに対応するための機構と考えられている。開発者署名はAppleの有償サービスに開発者登録しないと付加できないため、これが実際にDMA適合的であるとは言えないとも考えられるが、まずは具体法をもつEUの判断が待たれる。日本でも同等の立法に着手し、反競争行為を積極的に規制していく必要があろうと考える。

なお、iOS16によって実現している開発者モードには、「8.サイドローディングの制限(Google)」で指摘される問題が同様に当てはまると考えられる。

サイドローディングが認容されている Macバイスとの違い

この節にまとめられているAppleの主張にも理由がない。macOSからもiCloudに保存されている情報をはじめとする重要な個人情報にアクセスできることにも、ユーザーからの承認を得ない限りこれらの情報にアクセスできないことにも、iOSmacOSで違いはない。

12. OS 等の機能のブラウザに対するアクセス制限(Apple

<中間報告の該当箇所:166ページ>

事実関係、懸念事項に関するさらなる情報について
・事実関係や懸念事項について、さらなる情報(具体例の追加や補足等)はあるか。

本節によればAppleは「JIT は、攻撃者が iPhoneバイスにアクセスするために悪用できる攻撃対象領域を提供するため、JIT コンパイラを使用する代替エンジンは、セキュリティ上の大きな脅威となる」と説明しているが、このAppleの主張は、GoogleがかつてWeb Assembly技術の前身ともいえるNaCL (Native Client)と呼ばれる技術において、コードの書き換えに繋がる命令を書き換えることで危険なコードの実行を抑止しつつJITを有効にする手段が有効であったことから、端的に事実に反している。

*1:と書くと他人事っぽいですが多少は自分も波風を立てたはず…

5月の開発記録 (2022)

5月、割と大したことをしていないうちにあっという間に過ぎましたが、ちょいちょい活動していました。

MIDI Innovation Awards応募記録

これは正確にはほとんど4月なのですが、4月にオーディオ開発者界隈でちまちまと話題になっていたMMA (MIDI Manufacturers Association) のMIDI Innocation Awards (MIA)のSoftware Prototype/Non-Commercial部門にひっそり応募していました。

www.midi.org

募集の存在自体は4月初頭には気づいていて、ちょっとAAP MIDIDeviceServiceにプリセットを切り替えられる機能くらい実装すれば音源だけでもそれなりにいけるかな、と思っていたのですが、先月はそれでそのままずるずると拡張機構そのものを全面的に作り込むことになってしまい、プリセット切り替えまでは至らなかったわけです。それまで"Prototype"の部分に気づいていなかったので、下旬にはこりゃ間に合わんから諦めよう…と思っていたのですが、月末になって他の応募作品を眺めながら「あ、完成していなくてもいいんだ…」と気づいて、さらにWebMIDI.jsやらags (advanced GTK sequencer)やら、昔からずっとあったソフトが新作みたいな顔をして並んでいるのをみて、「今年出来たものじゃないといけないはずなんだけど、MIDIの新機能があるだけでOKなら(MIDIDeviceServiceの実装は2021年4月だし)出すだけ出そう…」という感じで1日で適当にエントリーを作文して出しました。MIA、去年からやっていて今年で2回目らしいですが、Webサイト自体が割と雑で(!)、エントリーに複数段落書いていたのが全部1段落にまとめられて何かしら脳に病があるような体裁の文にされています…(他のエントリーもちょいちょいそんな感じのやつがある)

応募するコストは低い割に、見返りとしてMMAから応募者向けに、6月上旬に開催されるNAMM招待券(数量限定)みたいなやつがもらえることになっていて、これが割とおいしそうなやつでした。オフラインとオンラインがあって、オフラインは確か$900くらい、オンラインも$50くらいはして、オフラインに申し込んだほうが圧倒的にお得感はあるしNAMMは一度くらい見てみたいと思っていた(いる)のですが、今このご時世に観光旅行も十分に楽しめないだろうし(普段ドミトリーとかで過ごしてたことも多いし)、ちょっと足を伸ばしてトモダチを訪ねるのもだいぶ気が引けるので、心理的コストが大きかった(めんどくさかった)のでやめました。オンラインは誰でも参加できると思います(参加って言えるほどの体験があるのかはわかりませんが)。特に秘密だと書かれていないので数字も書いちゃいますが、オフラインチケットもオフラインチケットも65枚あって(ただこれは特別招待枠などを含む数字)、応募が全部で100件ちょいだったので、1応募あたり2名くらい、半分は参加しない(たぶんフツーの人は仕事があるし…)と考えると多分オフラインを申し込めばもらえたと思います。

Software Prototype/Non-Commercial部門で受賞したのはMusiKrakenというモバイルアプリなのですが、これはデバイスで取得できるモーションセンサー類を入力としてオーディオグラフノード化して出力まで(これもオーディオとMIDIがあり、ただしMIDIは有料版)いろいろ繋ぎ込める面白いやつでした。デモ動画がよく出来ていたので動画も出しときます(47:40くらいから)

youtu.be

MIAは、Commercial Software部門にも今年ちょっと話題になったFluid Chordsが出てきたり(この記事が詳しい)、この業界の技術開発の最先端が垣間見えるので、これは面白い企画を回すようになったな〜と思っています。まあNAMM Ticketsがもらえたのは今年限りかもしれませんが(2019年までは1月頃にやっていたので)。

CLAPオーディオプラグイン is 何? @ MusicLT vol.2

昨年12月に開催されたMusic LTが今月に早くも2回目を開催していて、完全に視聴者モードで眺めていたのですが、登壇側が少なそうだったのでじゃあ何かしゃべろうと思い、とりあえず年末頃に出てオーディオプラグイン開発者界隈(?)で注目を集めたCLAPについてざっくり発表しました。資料はspeakerdeckに置いてあります。カスタムURL作成が有料アカウント限定機能になちゃったのでもしかしたら引っ越すかも…

speakerdeck.com

CLAPは特徴も用途も概ねLV2とかぶるので、将来性があるかというと個人的には半信半疑なところがありますが(特にLV2はこれからJUCE7で公式サポートされるようになるので商用ソフトでの利用可能性が広がるはず)、仕様としては面白いところが少なからずあるので、選択肢として期待したいところです。ノートメッセージひとつとっても、MIDI 2.0にあるノートエクスプレッションやノート別コントローラーはもちろん、ノートオフの後tail完了後にホスト側に通知するコールバックを呼び出すような仕組みまで整備されています。

個人的にはCLAPの開発者は "Proprietary Audio Plugin for Linux, but the right way" という文章をまとめた人として注目しています。

https://gist.github.com/abique/4c1b9b40f3413f0df1591d2a7c760db4

はてなブログのgistの埋め込み、無駄に長文埋め込もうとしてでかくなるのでURLだけにします)

Linuxで商用オーディオプラグイン(特にGUI)をどう構築して配布するかはここでもちょくちょく書いていますが悩みの種で、このメモだとオーディオプラグインのプロセスを分離することでGtk/Qt混在問題を解決しようと提案していて、Ardourの開発者が全面的に反論して議論が紛糾しているのが面白いやつです。(わたしはオーディオだけRTで回せばプロセスコンテキストスイッチいらんだろ派なので他人事気分で読みました。)

この方面では今月ロンドンでオフライン(ハイブリッド)で開催されたTAP meetupに登場したJUCE始祖のJulesがぶち上げたSoundStacksの新しいアーキテクチャ(構想)のセッションが完全に面白いやつだったので、興味ある人は見てみるといいと思います。

www.youtube.com

UIにはWeb関連技術を見込んでいるというので、先のLinux GUIの話とこのSound Stacksの話を組み合わせると2年前に自分がやっていたaria2webの実験とだいたい同じアプローチになるので、みんな早くこっちに来てくれ〜ってなっています…といえるほど自分は作ってないわけですが…! (最近Androidしかやっていない)

今月CLAPを調べていたのは、「AAPの拡張機能サービス実装があればコールバック呼び出しにも対応できそうな気がするし、AAPのネイティブ処理部分は案外CLAPみたいなやつに置き換えても何とかなるんじゃないか?」みたいなことを考えていて、そのために調べていたということもあります。現状リアルタイムイベントにおけるコールバックはやっぱり無理そうなので、CLAPで置き換えるのはナシかな、というところに落ち着いています(Realtime Binderがアプリ側に開放されていたらまだ可能性があるところですが)。CLAPのGUI統合は、作者が↑のようなプロセス分離の構想にも親和的にできているのではないかと期待していることもあります(LV2でも出来なくはないと思いますが)。

AAP

実は作業に費やした時間の多くがバグフィックス…以前にASANを有効にしてビルドするまともな方法を模索するのに費やして、ほとんど生産的なことが出来ていない感じです。まあ今月はGoogle I/Oもあったしな…!(正直ほぼ関係ないです。コミュニティ・バインディング・コンテンツがほぼなかったこともあってあんまし見ていない。)

ただ先月ついにbreaking changeを導入したので、ついでに今のうちにいろいろ破壊的変更を目論んで手を加えたりとかはしています。が、ここに書くような話もほとんどないです。てか「開発記録」とか言いつつ開発に関する話ここだけだしその内容がうっすらしてる…(!?)

その他

今月はモバイルプラットフォームと独禁法に関する調べものや文書作成にも時間を使っていることがあり、コードを書く時間が相対的に減っている感じです。ネタ自体はこの記事で話題になっています。

www.itmedia.co.jp

この記事以前にわたしもTwitterでまあまあ拡散しようという意図を持った書き方で紹介していますが、このパブコメ募集自体はそもそも小寺さんから教えてもらったから読んだ、という流れです。300ページ近くある大作で明らかに複数人の作業の集大成なので、とても全部は見ていられないのですが、6/10までなのでまだちょっと時間があるので、書けそうなところを増やしていきます。

他にもやっていたことはあるのですが(異世界の仕事とか)、そういうのはまた追々…