🦀

vst-rsでeguiを使う

2022/12/13に公開

この記事はRust Advent Calendar 2022 - Qiitaの14日目の記事です。

はじめに

この記事ではeguiを改造してvst-rsで使っていきます。
他のライブラリでもwinitのバックエンドあるGUIライブラリなら似たようなやり方でvst-rsで使うように改造することはさほど難しくないと思います。

demo

参考

RustでGUI付きのVSTプラグイン作る(Conrod, iced)

vst-rsでGUIを使うための制約

RustでGUI付きのVSTプラグイン作る(Conrod, iced)に書いたようにvst-rsにGUIをつけるには、GUIライブラリが以下を満たしている必要があります

  1. openメソッドが呼ばれたときに、引数のウインドウハンドルを親にした小ウインドウとして自分のウインドウを作らなくてはいけない。WinAPIでいうと、CreateWindowExWのhWndParentに入れてやる。これを他のプラットフォームでどうやるかわからないのが本記事がWindowsのみである主な理由。
  2. イベントループはidleメソッドで細切れにやる。つまり、一回走らせるとウインドウを閉じるまで帰ってこないようなGUIライブラリはだめ。

winitバックエンドを持つライブラリであれば1.はwindowsを作るときにwinit::platform::windows::WindowBuilderExtWindows::with_parent_windowを呼ぶだけです(Windowsの場合)。
また、2.winitのイベントループをwinit::platform::run_return::EventLoopExtRunReturn::run_returnを使って処理する必要があります。
しかし、eguiを含む大抵のGUIライブラリのバックエンドはwinit::event_loop::EventLoop::runを使ってイベントループを処理しているので(これだと処理が一生帰ってこないのでだめ)、run_returnを使ったイベントループに書き換える必要があります。

eguiの改造

そのままのeframe(eguiのネイティブバクエンド)では上で書いた制約を満たすことができないので改造していきます。
eframeではバックエンドとしてglowwgpuを選べますが、glowはバージョンが古くパニックが出てしまったので今回はwgpuバックエンドのみ改造します。

コードはこちら https://github.com/hatoo/egui/tree/vst

1. 親ウインドウを指定して子ウインドウにする

これは簡単です。
eguiのバックエンドであるeframeeframe::NativeOptionsでウインドウの設定を管理しているのでそれに親ウインドウ用の項目を足します。
https://github.com/emilk/egui/compare/master...hatoo:egui:vst#diff-ff3581c7997aa722047969018c3fe1418992ea044a798557ce7b606b3a45cd14R374
あとはeframe::NativeOptionswinitのビルダーに渡す箇所で親ウインドウのハンドルを設定するだけです。

2. run_returnを使ったイベントループ

run_returnを使ったイベントループをするためにGUIの情報全体をstructでまとめます
ウインドウを閉じる操作は下手なタイミングでやるとクラッシュしてしまうのでクローズ用のフラグを追加しています。

    pub struct WgpuIdle {
        wgpu_eframe: WgpuWinitApp,
        native_options: NativeOptions,
        close: bool, // 次のイベントでクローズしてほしい
        closed: bool, // 実際にクローズした
    }

    impl WgpuIdle {
        pub fn idle(&mut self) -> bool /* is exited */ {
            todo!()
        }

        pub fn close(&mut self) {
            todo!()
        }

        pub fn size(&self) -> (i32, i32) {
            todo!()
        }
    }

    pub fn idle_wgpu(
        app_name: &str,
        native_options: epi::NativeOptions,
        app_creator: epi::AppCreator,
    ) -> WgpuIdle {
        todo!()
    }

vst用にrun_returnを使ったイベントループを処理するときは常に*control_flow = ControlFlow::Exit;で大丈夫です。
あとはeguiを含む大抵のいGUIライブラリには、ウインドウを描画する関数、イベントを処理する関数が用意されているのでそれを適当に呼ぶだけです。
詳細はコード参照

利用例

適当なvstプラグインを上記のeguiを使って作ってみました。
コードはこちら https://github.com/hatoo/vst-rs-example-egui

demo

  • GUI上の変更がBitWigのGUIに反映されない
    • おそらくパラメーターの変更をホストに通知するAPIは存在するがvst-rsでどうやるかわからない
  • VstHostではうまく表示されない
    • demo

などの問題点はありますがだいたい動いてます。

GitHubで編集を提案

Discussion