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()関数によって取得することになるので、必然的にライブラリをロードすることになります。