🎃

MTS-ESPに関する覚書

2024/08/18に公開

MTS-ESPは複数のオーディオプラグインにまたがるMTSの設定を一括で変更できるようにしようというマスター/クライアント型の有償製品だ。MTSはMIDI仕様の拡張のひとつで、SysExによってチューニング設定を行うもので、これをサポートしているプラグイン(もちろんMIDIデバイスでもいい)に対してはそのSysExを送りつければ、あとはプラグイン側が勝手にチューニングを調整するというものだ。DAWが特別にMTSに対応していなくても、最悪SysExを送りつけることくらいはできるだろう(プラグインフォーマットがSysExを受け付けられないようだと問題になるが)。

この仕組みにはひとつ実用的な問題があって、通常ひとつの楽曲ではたくさんのインストゥルメントプラグインを使うことになるのだけど、一般的な微分音作曲では、楽曲全体で同じチューニング設定を利用するだろう(そうしないトリッキーな楽曲ももちろんあり得るけど、チューニングが揃っていても十分トリッキーなのにそれ以上やるだろうか…?)。そうなると、マスタートラックのようなところで1箇所変更するだけで、その楽曲で使われているMTS設定をまとめて変更できるようになっていてほしくなるわけだ。

これをやってくれるのがMTS-ESPということになる。これを実現するためには、マスタープラグインとそれに対するクライアントのような実装が必要になる。MTS-ESPはこれを、(1)インプロセスで処理する場合はlibMTS(.so/.dylib/.dll)の関数を動的にロードして呼び出す(2)クロスプロセスで処理する場合はlibMTSがIPCでやり取りして設定を取得できるようにする、というアプローチで実現している。マスタープラグインとクライアントプラグインが同一プロセス上に存在しない可能性は、特にBitwig Studioのプロセス分離設定では十分にあるし、あるいはAudioUnit V3で利用しようとしたら基本的に別プロセスになる。

MTS-ESPは有償製品なのだけど、このマスター機能とクライアント機能に対するクライアントはODDSound/MTS-ESPというリポジトリでライブラリとして公開されている。

https://github.com/ODDSound/MTS-ESP

「クライアント機能に対するクライアント」と書いているのは編集ミスではなくて、このライブラリ自体は単にlibMTSdlopen()なりLoadLibrary()なりで動的にロードしてMTS-ESPの機能を呼び出すだけのガワにすぎないからだ。だからMTS-ESPはOSSとは言えないとしてたとえばDPFの開発者なんかはこれをサポートしているsurge-XTの機能に関しては否定的だったし、それに対してsurge-synthesizerの開発者の一人は「別にOSSで実装できないわけじゃないだろ」と反論してリファレンス実装をOSSで作ってしまった(ただ完全な実装とはいっていない)。

ちなみに同様の課題を解決するプラグインとしてはInfinitone DMTというものがあるらしい。ただこれも有償製品である上に公式サイトの情報が完全に登録ユーザー向けに閉じていて、全く詳細がわからない。Infinitoneを紹介したとおぼしきMIDI協会のページも404になっている有様だ。そういうわけでこれは見なかったことにしてもいいだろう。ただRedditにこの2つを詳しく比較した投稿がある。

MTS-ESPの設計上の問題点

これを書いているのは「surgeみたいなプラグインがMTS-ESPをサポートしているなら、Androidに移植するときもこれが使えるようにしたほうがいいのかな」と思って眺めだしたのがきっかけだったのだけど、少し真面目に中身を眺めてみると欠点がいろいろ浮かんできた。

まず、チューニング設定対象を限定すべきコンテキストIDのようなものを指定する方法が何も無い。クライアントAPIとしては、まずMTS_RegisterClient()という関数を呼び出してそのハンドルを取得する:

    extern MTSClient *MTS_RegisterClient();

これは、いま稼働しているマスターに対してクライアントを新規登録する関数なのだけど、マスターは1つしか存在しないことになっている。これはDAWの中で1つの楽曲しかロードされていないことが前提になっている。IPCを経由して呼び出す場合も同じ仕組みになっているのだから、ここでクライアントがマスターを識別する余地は無い。実際MTS_CanRegisterMaster()は「すでにマスターセッションが存在するならfalseを返す」「falseが返されたらインスタンスを生成するな」とlibMTSMaster.hに書かれていて、つまり複数のマスターが存在する状況は想定されていない。複数のDAWの全然関係ないプロジェクトで、それぞれがMTS-ESPクライアントを含むプラグインを使用していると、それらは楽曲として全く別々の設定を必要とするにもかかわらず、別々の設定を使用することはできない、ということだ。複数の楽曲を同時に編集することは現実的なワークフローとしてないとしても、複数のDAWを立ち上げっぱなしにして2つを行ったり来たりしながら作業することすらできないことになる。

これは根本的な欠陥で、現状のAPIでは直しようがないと思う。

もうひとつの問題は、「リアルタイムで設定を一括変更できる」としているが、実際のチューニング設定はクライアントがノートメッセージを受信するたびにマスターに問い合わせるべし、とされていることだ(libMTSClient.h2. REQUIRED: Query retuning when a note-on message is received and adjust tuning accordingly.とある)。ノートメッセージはオーディオ処理のリアルタイム呼び出しの中で受信するものであり、その呼び出しの中で発音するところまでもっていかなければならない。インプロセスでクライアントがマスター設定をローカル変数なり共有メモリなりで取得できるのであれば問題にならないが、クライアントがIPCを経由してマスターに接続している場合、実際のチューニング設定を(一般的には)リアルタイム性の無いIPCで問い合わせないといけないことになる。そしてこれはプラグイン開発者の責務ということになっている。MTS-ESPを開発しているODDSoundは自分の問題ではないと認識しているだろう。

これはプロトコルの設計がまずくて、そもそもマスターで変更があった場合はクライアントに対して一括通知して、クライアントはマスターの設定をきちんと反映できているという前提で問い合わせを不要にすべきだ。そうすれば、ローカルで.sclや.kbmをロードしているのと何も変わらない状態でチューニングを反映できる。

この問題も、現在のプロトコルを破壊せずに修正するのは無理だと思う。

これをAndroidでサポートするためには、Serviceの仕組みを使ってマスターインスタンスとして動作するアプリケーションを作成すれば良いと思っていたのだけど、どうもプロトコルとしてかなりイマイチだと分かってしまったので、このままだと手を出すことはないだろうなあというところに帰着した。

ただ、MTS-ESPみたいな仕組みは、微分音作曲クラスタとしてはありがたいだろうから、何かしら似たような仕組みがあると良さそうだなとは思っている。MTSはMIDI 1.0が前提なのでクライアントを登録するという発想がないが、MIDI-CIの仕組みであれば十分に可能そうな気がしている。それであれば後はMMAがやるべき仕事だろう。

Discussion