オーディオプラグインとプロセス分離に関する覚書

ここ数日ばかり、DAWのオーディオエンジンがあまりプラグインをプロセス分離でロードしていないのは何でだろう?というのが気になっていて、いろいろ調べていたので、覚書としてまとめてみる。

プロセス分離モデル

DAWというものは安定して動作させるのが難しいソフトウェアの類型である。その最大の理由はオーディオプラグインを動作させる方式にかかる制約にある。

DAWは、オーディオプラグインのホストとして、さまざまな開発者によって提供されるオーディオプラグインを、エンドユーザーのさまざまなプラットフォーム上でロードして実行する。オーディオプラグインの開発者の視点で言えば、エンドユーザーはさまざまなDAWを使用して、さまざまなプラットフォーム上でそのプラグインをロードして実行する。

一般的に、このようなプラグイン機構においては、プロセスを分離して、プラグインのプロセスがクラッシュしても、ホスト側はアプリケーションを継続して実行できるようにするほうが安全だ。このようなモデルはアウトオブプロセス実行と呼ばれる(アウトプロセスと呼ぶ分野もあるようだ)。Webブラウザプラグイン機構やIDEプラグイン機構には、このモデルを採用するものが少なくない。実際には、諸条件を考慮して同一プロセスの中でライブラリを動的にロードして実行することもある。このようなモデルはインプロセス実行と呼ばれる。

リアルタイム制約

オーディオプラグインの場合には、問題を複雑化する要因がある。オーディオプラグインのパイプラインはリアルタイム優先度で処理されなければならないので、オーディオプラグイン自体がリアルタイム優先度で処理を完了できなければならないし、パイプライン処理にも時間をかけすぎることはできない。

しかし現実には、DAWはかなりの数のオーディオプラグインを処理しなければならない。オーディオトラックが50、100とあるような本格的な楽曲になると、オーディオプラグインが数百件処理されることにもなる。AppleWWDC 2019では最新のMac ProのデモでLogic Pro上で1000トラック作成してKontaktを割り当てて再生するものがあったらしいが、1000トラックもあればさすがに一般的な音楽制作では十分すぎるほどだ。しかし1000という数字が圧倒的ということは、ひと桁減らして100トラックではデモとして足りないということでもある。いずれにしろ、DTMは業務用チーズシュレッダーを使うことができない一般大衆のためにあるべきだ。実際の制作作業ではトラックのフリーズ等の処理を施しながら作業することでパフォーマンス上の問題を回避するのが一般的だと思われるが、オーディオプラグインのパイプラインにシビアな処理速度が求められることに変わりはない。

インプロセスでオーディオパイプラインを処理する場合は、単にリストを辿りながら単純なループでプラグインの処理を実行するだけで足りる。しかしアウトオブプロセスで処理する場合は、呼び出しと応答をプロセス間通信のようなかたちで連結しなければならないことになる。単純なプロセス間のコンテキストスイッチでもそれなりのコストがかかるし、IPCのフレームワークも厳しく選択しなければならない。

CLAPというオーディオプラグイン機構が考案されたときにhacker newsに寄せられたコメントのひとつで、このプロセス分離とパフォーマンスの両立が難しいという問題が挙げられていて、これがやや詳しく解説していたので、参考までに言及しておきたい。1プラグインプロセスの切り替えにつき6-7μsかかるというのはそれなりのインパクトがありそうだ。

リアルタイム処理で重要なのは、遅延が無いという意味での安定的な処理モデルだが、処理速度の観点を無視できるということはなく、パフォーマンスが良いほどより多くのオーディオプラグインを処理できるという利点はある(前述のとんでもない処理速度をもつMac Proの利点はここにある)。

これがもしネットワーク越しに行われるとなるとさらに大規模な遅延が生じうる。YAMAHAのNetDuettoなどはこれを実現しているということになろうが、一般的には同じマシンで動作していることがほぼ前提であると考える必要がありそうだ。Web経由でこれを処理できるようになる状況は、まだまだ期待できなそうに思えてしまう。

2019/06/08追記: Bitwig Studio 2.5には、オーディオプラグインごとにプロセス分離モデルを選択できるオプションがある。

f:id:atsushieno:20190608001806p:plain

アプリケーションの制限されたリソースアクセス

デスクトップPCの環境においては、まだアプリケーションの動作環境に対する制約は小さい。DAWなどのオーディオプラグインホストとVSTなどのオーディオプラグインは別々のベンダーが開発するものであり、ホストのプロセス内部にオーディオプラグインのライブラリをロードして実行するのはごく一般的だ。

しかしモバイル環境におけるリソースのアクセスは、デスクトップ環境ほど自由ではない。一般的には、アプリケーションのそれぞれには、コンテナのようにアクセス制限が課されていて、他のアプリケーションのリソースには自由にアクセスできない。DAWのアプリケーションが、他のオーディオプラグインのアプリケーションに含まれるライブラリを動的にインプロセスにロードして実行することができないとなると、必然的にオーディオプラグインとのやり取りもアウトオブプロセスで行われることになる。

また、デスクトップOSであっても、macOSにはアプリケーションのサンドボックス実行という概念があり、主にMac App Storeで配信されるアプリケーションに課せられる制約だが、一般的には、サンドボックス下にあるアプリケーションには、PC上のファイルやリソースに無制限にアクセスすることはできない。他所のアプリケーションの共有ライブラリをロードして呼び出すことも無条件にはできないし、ライブラリだけをロードできたとしても、別のアプリケーションのリソースにアクセスすることはできない。

この関係で面白いのはmacOSiOSを同様にサポートしているAppleのAudioUnit v3(以下単にAU、v3が前提)なのだけど、長くなるので節を改めて続ける。

AudioUnit v3のアプローチ

AUAppleプラットフォームで(プラットフォームのレベルで)サポートされているオーディオプラグインのための仕様だ。OSの一部なのかよ!というのが多分正しいリアクションだが、OSの機能が拡張される理由の一因になっている側面はありそうだ。というのは、macOSのセキュリティ機構の一部であるアプリケーション サンドボックスと、オーディオプラグインのようなプログラムは、先に軽く言及したとおり相性が悪いので、何かしらの対応策が必要になったからだ。

AUホストとなるアプリケーションをMac App Storeで配布する場合にはサンドボックス環境をサポートする必要がある。サンドボックス環境では、外部のアプリケーションとなる従来のAUではロードできない。このため、AUはv3で任意のアプリケーションでロードできるApp Extensionとして実装することになった。

App Extensionの動作原理については、ある程度のレベルまではUnderstand How an App Extension Worksというドキュメントに詳しくまとめられている。また、AU v3については、WWDC 2015におけるセッション資料が詳しい。

AUホストは、AUをアウトオブプロセスで動作させることもインプロセスで動作させることもでき、アウトオブプロセスで動作する場合は、XPCと呼ばれるプロセス間通信の仕組みに基づいてメッセージングが行われるようだ。ホスト側はkAudioComponentInstantiation_LoadInProcessを、AU側はAudioComponentBundleの内容を調整するかたちで設定する。アウトオブプロセスで動作する場合は、レンダリング処理1つあたり40μsくらいまでのレイテンシーが加わるようだ(macOSでの話と思われる)。

インプロセスで動作させることが可能になっているというのは、App Extensionという特殊な機構に基づいているがゆえの特権である、といえそうだ。Appleは自らGarage BandやLogic Proもリリースしているので、低レイテンシーオーディオにOSのレベルで積極的にコミットしていて、AU v3の仕様はこの現れであるといえる。

AUホストやAUプラグインの開発については、特にサンドボックスとの関連も含めて、以下のドキュメント群が詳しい。

もっともプロセス分離モデルに関する詳細な解説は見当たらなかった。インプロセスのAUがどのようにサンドボックスを実現しているのか、あるいはリソースにアクセスできてしまうのか、といった疑問は解決されなかった(試せばわかることだとは思うが、普段Mac上で活動していない筆者にはあまり本気で調べる意思が無い)。

AUサポートに関しては、macOSiOSで大きな違いは無さそうだ。OSによるセキュリティ機構としてもおそらく大きな違いは無いのだろう。

VST3とsandboxing

ちなみに、こういったmacOSの状況を鑑みると、「ということはVST3もAUみたいな機構を実装しているのか…?」という疑問も浮かんでくる。AUサンドボックスの都合でApp Extensionとなることを強いられたのだとしたら、VST3も同様にインプロセスにアクセスできるApp Extensionとして設計される必要があるはずだ(これがユーザーランドで可能なのかどうかはわからないが)。

どうなっているのか…と思って"App" "Extension" でvst3sdkのソースツリーを検索してみたが、出てきたのがAddVST3AuV3.cmakeというcmakeモジュールくらいであり、これはiOSビルドにのみ適用されるようだ。

sandboxingせずにsandboxed hostでプラグインとして使用することは出来ないだろうし、sandboxed hostで使えるようにすることは諦めているのだろうか…と思ったところでふと気付いてApp StoreDAWを検索してみると、Logic Pro以外はほぼ無いという状況だった。音楽アプリケーションがApp Storeで公開されていないのであれば、いくらApp Storeでsandboxingを強制しても無駄なことだ。Logic ProではもともとAUしか使えないわけだし、MacをサポートしているオーディオプラグインはほとんどVSTにもAUにも対応しているし、VSTホスト(DAW)のベンダーにとってはVSTをサポートしているだけでLogic Proに対して優位にあるといえるし、App Storeに置けないことにはほぼデメリットがない。

Androidのアウトオブプロセスによる処理の可能性

iOSと同様にアプリケーションごとに異なるLinuxユーザーアカウントを作成しているAndroid環境で、サンドボックスAUのようなことは実現できるのか。筆者が現時点で思いつく範囲では、以下のような課題がある。

(1) オーディオプラグイン同士のインタラクション: オーディオパイプラインとプラグインホストの間で渡されるオーディオバッファへの読み書きが問題なく行えなければならない。これは共有メモリへの読み書き(shm, ashmemなど)でおこなれそうだ。ashmemはandroid-15以降でサポートされている(Java APIのSharedMemoryは27以降のみ)。

(2) リアルタイム処理可能なIPCのサポート - Androidは8.0でBinder IPCのリアルタイム優先度を実現しているようだ(ただしユーザーに開放されているかは未確認)。リアルタイム優先度のbinderメッセージングは、native MIDI APIの実現のためには必須だったと考えられるが、AAudioにおけるlow latencyモードのオーディオ処理でも必要だったと考えるのが妥当そうだ。

いずれにしろ、この辺りの課題をクリアできれば、AndroidでもAUのようなアウトオブプロセスのプラグイン機構が実現できるかもしれない。

6/12追記: ELK(Linuxベースのオーディオ用リアルタイムOS)の開発者が今年になって書き始めた一連のブログ投稿(現時点で未完成)で、今回のネタに関連するLinux方面での取り組みなどがよくまとめられている。