オーディオプラグインの理想的なGUIフレームワークを模索する

音楽ツール・ライブラリ・技術 Advent Calendar 20197日目のエントリーです。今日はポエムに近いです。

オーディオプラグインGUIの要求事項

オーディオプラグインフレームワークというソフトウェアはやや特殊な世界で、歴史的な経緯を脇に置いて2019年現在に求められている要件を列挙するなら、

  • WindowsおよびMac、可能なら*1それ以外(Linux, Web, iOS, Androidなど)をサポートすること
  • オーディオ処理とGUI機構を提供すること
  • DAW上から起動できてGUIイベントを部分的に共有すること(キーボードイベントなど)

などが挙げられます。今回はGUIフレームワークについて少し掘り下げて検討します。先日M3で頒布した同人誌では言及しなかった部分ですね。

VST SDKのように独自ブランドのGUIフレームワークを提供するものや、JUCEのように複数オーディオプラグイン機構・複数プラットフォーム向けに独自のGUIフレームワークを提供するものは、いくつか存在します。オーディオプラグインフレームワークにおいては、GUIフレームワークの提供は必須ではありません。しかし、どのようなGUI機構であってもオーディオプラグインフレームワーク側と接続可能になるような、オーディオ/MIDIストリームの出入り口を用意しておく必要はあります。

オーディオプラグインに求められるGUIアプリケーションとしての要件は、一般的なデスクトップGUIアプリケーションのものと比べると、だいぶクロスプラットフォームで開発しやすいものであるといえます。その理由のひとつは、起動および操作がほぼ必ずDAWを経由したものになるためです。メインメニューは無く、キーボードイベントを「DAWから奪い去る」ことがあまり歓迎されず、DAWからダイアログのようにポップアップされているときだけ操作することになります。

さまざまな制約を受けながら作成できるGUIの利便性は当然ながら一般的なGUIアプリケーションよりだいぶ低く、そのようなGUIであれば「ネイティブアプリケーションのポテンシャルを全然引き出せない」クロスプラットフォームGUIフレームワークの欠点が目立たなくなります。

VSTGUIやJUCE (juce_gui_basics) は、そのような特殊な環境で発展してきたといえます。もちろん、Carbon/CocoaWindows APIを直接使うGUIをもつオーディオプラグインもあり、これらも一般的なGUIアプリケーションに求められる要求事項とはだいぶ無縁に作られてきたはずです。

また、オーディオ処理がリアルタイムで厳格なフレームの中での完結を求められることもあり、これに対応するかたちでGUIを構築するのであれば、ウィジェット/コントロールを操作するGUIフレームワークを使うよりは、コールバックベースの低レベルの描画APIに基づいて実装するものが多くなるのも、それなりにわかりみがあります。

もちろんGUIの描画そのものはオーディオスレッドで行われるべきものではないので、ユーザーコードでオーディオコールバックから呼び出される描画呼び出しはpostにとどまり、実際の描画処理はUIスレッドで行われることになります。一方で、そもそもGUIはオーディオ処理に100%追従することが前提となっていないので、ある程度の遅延は容認できるし、何ならオーディオ処理とは異なりGCJITで世界が止まっても致命的な問題ではない、ということがいえます。実際これはAndroidにおけるオーディオAPIの開発方針でもあります(UIはART上でKotlin/Javaでも可能、オーディオはNDK + OpenSLES/AAudio)。

どのようなx-plat GUI Fxが向いているのか

さて、こうなってくると、オーディオプラグインGUIフレームワークは、クロスプラットフォームGUIフレームワークが利用できる分野であるといえそうです。

もし「低レベルの描画APIだけ提供していれば良い」というのであれば、CairoなりSkiaなりを使えば解決ということになりますが、実際にはマウスやキーボード入力のサポートも必要になるので、きちんとアプリケーションループをもったGUIツールキットであることは必要でしょう。

ここで「クロスプラットフォームフレームワークでは実現できない、プラットフォームの入力デバイスを完全にサポートする必要がある」という立場であれば、ネイティブのGUIツールキットで個別に開発するのが妥当でしょう(Surface DialがLinuxでも使えてLeap Motionのようなデバイスがどのプラットフォームでも動作する現在、筆者としてはそのような状況はあまり一般的には想定できないところですが)。

クロスプラットフォームGUIフレームワークを使う路線でいくとしても、このカテゴリにまとめられるGUIフレームワークにはいくつかの種類があります。

(1) JavaScriptとブラウザ環境が前提であるもの。CordovaやIonicなどが挙げられます。JUCEコミュニティの一部ではReactを使ってGUIを構築するアプローチが話題となっているようです。このやり方であればWeb開発の手法でオーディオプラグインGUIを開発できることになるので、開発は楽になりますがブラウザを組み込むことになるのはアプリケーションとしてはだいぶ重量感が増します。(オーディオプラグインにはGB単位でサンプリングを含むものが多く存在するので、それに比べたら誤差のようなものではあります。) またWebViewの組み込みはどんな環境でも問題を引き起こすことが多く、プラットフォームやブラウザコントロールのバージョンなど、環境による挙動の違いをもたらす変数が大きいこともマイナス点でしょう。

(2) プラットフォームごとにネイティブのUIコントロールを呼び出すように実装されたもの。XamarinやReact Native、WxWidgetsはここに分類されます。開発が楽になるかどうかはそれぞれの開発者のバックグラウンド次第、アプリケーションとしての配布が楽かどうかもフレームワーク次第と、十把ひとからげに評価するには変数の多いところです。プラットフォームのネイティブコントロールがUX満足度を高める要因になりますが、オーディオプラグインGUIでは、伝統的に標準コントロールがあまり使われていないので、伝統的なGUIではメリットが小さそうです。一方でプラットフォームごとに挙動がバラバラになるデメリットはそのままです。React NativeはWindows用のバックエンドはあるものの、Gtkなどはサポートされていないでしょう。XamarinのGtkサポートも実は貧弱です。Gtk2なので(!) もともとはGNOMEの開発を主導していた会社なのに(!)

(3) UIコントロールを独自にレンダリングするもの。Gtk, Qt, Flutter, JUCE, Unity UiWidgetsはこのカテゴリに属するといえます。これらは、フレームワークの完成度が重要なファクターになってきます。特にどのプラットフォームでも満足に動作するものは皆無といってもよいでしょう。QtやGtkLinux以外ではあまり歓迎されず、オーディオプラグインGUIとしても実績値は高くありません。またQtもGtkもデスクトップが「どちらであるか」によってエイリアンになる可能性が高く、まだX11が直接使われている可能性が高いといえるでしょう。しかしX11もまたWaylandなどで置き換えられつつある存在です。また、オーディオプラグインの主戦場はデスクトップ環境であり、Androidで快適、iOSでもまあまあ許容されているFlutterは、デスクトップではまだまだ発展途上(そもそも開発中)なので、現状で適切な選択肢であるとは言いがたいところです。不十分な多言語入力もこの種のフレームワークにありがちな問題です。

opinion

JUCEは古典的なオーディオプラグイン用のGUIフレームワークとしては必要最低限の機能を提供していて、しかもC++なので、現在ではよく採用されています。ウィジェット・ツールキットとしては他のフレームワークと比べると描画APIに毛が生えた程度であり、少しでも高度な機能を使おうとすると自前で実装することになります。基本中の基本のようなHBox/VBoxのようなレイアウトが"Advanced GUI layout techniques"と言われるのがJUCEのレベル感です。レイアウトエンジンがウィジェットとして組み込まれておらず、単独で存在するFlexBoxやGridのレイアウトの実装などを自前でコントロールの描画に適用することになります。JUCEはユーザー数の割には開発者層が薄く、特にjuce_gui_basicsは絶望的なので、筆者としては全然将来に期待していません。

(レイアウトエンジンは必ずしもGUIフレームワークと密接に結びついているわけではありません。具体的な例を挙げると、Facebookが開発したCSS Flexbox相当のレイアウトエンジンであるYogaはWeb以外でも使うことができましたし、AppleのAutoLayoutやAndroidのConstraintLayoutはCassowaryと呼ばれる制約付きレイアウトを実装したもので、Cassowary自体はGUIフレームワークから独立して存在しうるものです。なのでたとえばAbletonがQt用にCassowaryを実装することもできたりします。独自のGridレイアウトも同様といえます。)

筆者がこの分野で一番将来に期待しているのはFlutterです。FlutterはMaterial Design Componentをフル実装しており、十分にモダンなGUIを構築できる一方で、描画の低レベルレイヤーはSkiaが使われており、すなわちVulkanやANGLE、Metalのポテンシャルを引き出せる可能性が十分にあります(SkiaのMetalバックエンドはiOS 11以降のみですが)。Flutterでなくても、モバイル環境で育ったGUIフレームワークであれば、たとえばマルチタッチに対応した豊富な機能を持つGUIを構築することが可能でしょう。juce_gui_basicsで満足していたら逆立ちしても実現できません。

ただし、Flutterがオーディオプラグインの世界に適用されるためには、C/C++と相互運用できるだけの十分なFFIサポートが不可欠です。この部分はDartでまだまだ発展途上であり、残念ながら筆者がlibclangで相互運用を試してみた範囲では、とても実用段階にあるとは言いがたいところです。プラットフォーム独立の動的ライブラリのロードや、Stringの変換くらいは、ファーストクラスで実装されている必要があるでしょう。

あと、JUCEで最近さかんに試されているReact NativeというかJavaScriptにもいえることですが、float型が無いのはホントに大丈夫なのか?っていう問題はあるかもしれません。まあWebAudioで実証済みの世界とはいえるかもしれません。

*1:わたしはLinuxをサポートしないフレームワークには価値も未来も無いと考えています