VST3でGUIサイズ変更可能なプラグインの作り方

[VST3制作の過去記事一覧はこちら](https://qiita.com/aike@github/items/05a14911bb89db8b6c2c)

音楽制作用DAWのプラグイン仕様VST3についてインターネットのヤホーで調べました。今回はVSTGUIライブラリを使ったプラグインのGUIサイズを変更できるようにする方法の説明です。
この記事はVST3プラグインを書く人向けの内容です。

# はじめに

4Kのような高解像度ディスプレイを使っているとVSTプラグインの小さな画面が見づらいと感じることがあります。ましてや1990年代にCubase 1.0を使っていた20歳の若者もいまや50歳です、小さい文字など読めるはずもありません。そんなわけでVST3ではプラグインのサイズを可変にすることができるようになっています。例によって公式ドキュメントにはやりかたや制限など詳しく書いていないので調べてみました。

# TL;DR

* .uidescファイルにminSize、maxSizeを記述するとリサイズ可能になる
* 文字やビットマップのリサイズは（簡単には）できない
* リサイズ時の子要素比率の案分は指定できない

![resizable.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/881d1781-bc73-6072-9b74-19cccd866fb9.gif)

# GUIのデフォルトサイズ

ちなみにWindowsの場合、VSTプラグインのGUIサイズはWindowsのディスプレイ設定の影響をうけます。
たとえば、以下のようにアプリサイズを150%にしていると、ピクセル数の1.5倍のサイズで表示されます。

![disp_reso.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/8cacdb7e-3cfc-8463-bffe-b927fc856342.png)


# 実装方法

では、実装していきます。
今回は.uidescファイルのXMLで実現できる範囲で説明します。はじめに言っておくと、XMLだけだとかなり制限が厳しいです。VSTGUIのCViewを継承した独自のビューをC++で書けばもっとやれることは広がるように思います。

一番外側のビューです。size属性の他にminSize, maxSizeを設定するとその範囲でリサイズ可能になります。ビットマップはリサイズされないので、背景画像はmaxSizeに合わせた大きさで、拡大縮小時にも破綻しないように作っておく必要があります。
autosizeはアンカーを意味します、親のビューは上下左右すべての端に設定します。

```gui.uidesc
  <template name="view"
    bitmap="panel"
    origin="0, 0" size="640, 480"
    minSize="640, 480" maxSize="1280, 960"
    autosize="left right top bottom"
  >
```

中央のタイトル部はこのように記述しています。
テキストラベルの場合autosizeをleft right両方に設定するとセンタリングになります。
また、拡大時に下に移動しないようにbottomは設定していません。
GUIをリサイズしても文字が拡大されないのは残念です。
中央のタイトルは、back-color="#ffffff00"で背景のアルファチャンネルを透明にして、style-no-frame="true"で枠を非表示にしています。

```gui.uidesc
  <view 
    class="CTextLabel" 

    title="Resizable VST3" 

    origin="20, 20" 
    size="600, 60" 
    autosize="left right top"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="true"

    font="MainTitleFont" 
    font-antialias="true" 
    font-color="#000000ff" 
  />
```

フォントは別のところで次のように定義しています。自分で定義せずに"~ NormalFont"、"~ NormalFontVeryBig"といったあらかじめ定義済みのフォント名を使うこともできます。[^1]

```gui.uidesc
  <fonts>
    <font font-name="Arial" name="MainTitleFont" size="48"/>
  </fonts>
```

続いて上段の枠の定義です。枠専用のビューは用意されていないので、空文字のテキストラベルを作ってその枠を表示させています。back-colorは背景色です。末尾の22でアルファチャンネルの値を指定して半透明にしています。

```gui.uidesc
  <view 
    class="CTextLabel" 

    title="" 

    origin="20, 100" 
    size="600, 150" 
    autosize="left right top bottom"
    text-alignment="center" 

    back-color="#00000022" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />
```

上段の枠の中のノブはこんな感じ。
GUIをリサイズしてもノブのサイズが変わらないのが残念です。zoom-factorというそれっぽいアトリビュートがあって期待したのですが、これはマウス移動距離に応じたパラメータの増減値の設定のようです。
また、アンカーをtop bottomにしたら拡大時にも中央に配置してくれるかと思ったらそんなことはありませんでした。これも残念。
そんなわけでノブの位置は上下のいずれか、左右のいずれかからの距離が固定になるよう配置するしかなさそうです。

```gui.uidesc
  <view
    class="CAnimKnob"
    control-tag="Param1"
    origin="100, 150" size="49, 49"
    bitmap="knob" sub-pixmaps="127"
    autosize="left top"
  />
```

下段左側の枠の定義です。これも左右に良い感じで案分してくれる機能はないので、左側の枠はGUI全体と連動してリサイズしますが、右側の枠は固定幅となってしまいます。

```gui.uidesc
  <view 
    class="CTextLabel" 

    title="" 

    origin="20, 270" 
    size="320, 180" 
    autosize="left right bottom"
    text-alignment="center" 

    back-color="#00008822" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />
```

下段右の枠です。高さも幅もすでに可変の枠を定義してしまったので右下の枠のサイズは必然的に固定になります。

```gui.uidesc
  <view 
    class="CTextLabel" 

    title="" 

    origin="360, 270" 
    size="260, 180" 
    autosize="right bottom"
    text-alignment="center" 

    back-color="#ffffff00" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />
```

そんなわけで、WebのCSSのような柔軟性を期待したのですが、ちょっと残念な結果になってしまいました。
サンプルプラグインを見ても、マウスドラッグではCDataBrowser（Excelのような表形式のデータビュー）みたいなスクロールビューを可変サイズにするような用途でしか使われていないようです。
サンプルプラグインのhostchecker[^2]では、拡大率固定のボタンを用意して、それが押されたらCFrame::setZoom()を呼ぶ処理を書いてノブのビットマップを含めた画面全体のリサイズを実現しているようです。[^3] [^4]
この場合UIのバランスが崩れないのでデザイン的には良さそうです。いつかまたその手法によるリサイズの実験をしてみたいと思います。


最後にXMLの全文を掲載しておきます。

```gui.uidesc
<?xml version="1.0" encoding="UTF-8"?>
<vstgui-ui-description version="1">

  <template name="view"
    bitmap="panel"
    origin="0, 0" size="640, 480"
    minSize="640, 480" maxSize="1280, 960"
    autosize="left right top bottom"
  >

  <!-- メインタイトル -->
  <view 
    class="CTextLabel" 

    title="Resizable VST3" 

    origin="20, 20" 
    size="600, 60" 
    autosize="left right top"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="true"

    font="MainTitleFont" 
    font-antialias="true" 
    font-color="#000000ff" 
  />

  <!-- 枠 上段 -->
  <view 
    class="CTextLabel" 

    title="" 

    origin="20, 100" 
    size="600, 150" 
    autosize="left right top bottom"
    text-alignment="center" 

    back-color="#00000022" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />

  <!-- 枠 上段　タイトル -->
  <view 
    class="CTextLabel" 

    title="Parameter Area 1" 

    origin="20, 100" 
    size="600, 40" 
    autosize="left right"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="true"

    font="~ NormalFontVeryBig" 
    font-antialias="true" 
    font-color="#000000ff" 
  />

  <!-- 枠 下段左 -->
  <view 
    class="CTextLabel" 

    title="" 

    origin="20, 270" 
    size="320, 180" 
    autosize="left right bottom"
    text-alignment="center" 

    back-color="#00008822" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />

  <!-- 枠 下段左 タイトル -->
  <view 
    class="CTextLabel" 

    title="Parameter Area 2" 

    origin="20, 275" 
    size="200, 40" 
    autosize="left bottom"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="true"

    font="~ NormalFontVeryBig" 
    font-antialias="true" 
    font-color="#000000ff" 
  />

  <!-- 枠 下段右 -->
  <view 
    class="CTextLabel" 

    title="" 

    origin="360, 270" 
    size="260, 180" 
    autosize="right bottom"
    text-alignment="center" 

    back-color="#ffffff00" 

    frame-color="#000000ff" 
    frame-width="4" 
    round-rect-radius="10"
    style-round-rect="true"
  />

  <!-- 枠 下段右 タイトル -->
  <view 
    class="CTextLabel" 

    title="Parameter Area 3" 

    origin="360, 275" 
    size="200, 40" 
    autosize="right bottom"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="true"

    font="~ NormalFontVeryBig" 
    font-antialias="true" 
    font-color="#000000ff" 
  />

  <view class="CAnimKnob" control-tag="Param1" origin="100, 150" size="49, 49" bitmap="knob" sub-pixmaps="127" autosize="left top" />
  <view class="CAnimKnob" control-tag="Param2" origin="400, 150" size="49, 49" bitmap="knob" sub-pixmaps="127" autosize="left top" />
  <view class="CAnimKnob" control-tag="Param1" origin="100, 350" size="49, 49" bitmap="knob" sub-pixmaps="127" autosize="left bottom" />

  <view 
    class="CTextLabel" 
    bitmap="logo"
    title="" 

    origin="420, 330" 
    size="140, 89" 
    autosize="right bottom"
    text-alignment="center" 

    back-color="#ffffff00" 

    style-no-frame="false"
  />
  </template>

  <control-tags>
    <control-tag name="Param1"  tag="100"/>
    <control-tag name="Param2"  tag="101"/>
    <control-tag name="Param3"  tag="102"/>
    <control-tag name="Param4"  tag="103"/>
  </control-tags>

  <bitmaps>
    <bitmap name="panel" path="panel.png"/>
    <bitmap name="knob" path="knob.png"/>
    <bitmap name="logo" path="logo.png"/>
  </bitmaps>

  <fonts>
    <font font-name="Arial" name="MainTitleFont" size="48"/>
  </fonts>
  <colors>
  </colors>
</vstgui-ui-description>
```


[VST3制作の過去記事一覧はこちら](https://qiita.com/aike@github/items/05a14911bb89db8b6c2c)


[^1]: https://github.com/steinbergmedia/vstgui/blob/ae8d195b2907909fc27a204570f6d0cab4b120d9/vstgui/uidescription/uidescription.cpp#L169-L178
[^2]: https://steinbergmedia.github.io/vst3_doc/vstexamples/index.html#HostChecker
[^3]: 関連情報：https://ryukau.github.io/VSTPlugins/dev_note/vst3_dev.html#:~:text=%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%AB%E3%82%BA%E3%83%BC%E3%83%A0%E6%A9%9F%E8%83%BD%E3%82%92%E8%BF%BD%E5%8A%A0 FL Studio 20.5ではバグが出たとのことですが、20.7.2だとhostcheckerが上手く動いているのでバグフィックスされたのかも
[^4]: 関連情報： https://steinbergmedia.github.io/vst3_doc/vstinterfaces/iplugviewcontentscalesupport.html