VST3 VSTGUIのUI定義ファイルTips

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

注．2021/03/30にリリースされたVST3SDK3.7.2に含まれるVSTGUI 4.10から、uidescはJSON形式になりXML形式は非推奨になりました。この記事も近いうちにJSONに書き直す予定です。


音楽制作用DAWのプラグイン仕様VST3についてインターネットのヤホーで調べました。今回はVSTGUIのUI定義ファイル.uidescについての説明です。
この記事はVST3プラグインを書く人向けの内容です。

# はじめに

VST3に付属のGUIライブラリVSTGUIでは、UIのレイアウト定義が.uidescというXMLファイルでできるようになっています。これは比較的あたらしい機能のためノウハウが十分共有されていないように思うので、知っておくべき情報やTipsをまとめてみました。

# XMLって今どきちょっとダサくね？

言わんとすることはわかります。中の人もそう思ったようで、現在配布されているバージョン4.9の次の4.10ではXMLからJSONに変更になるとソースコードに書かれています。
https://github.com/steinbergmedia/vstgui/blob/develop/vstgui/uidescription/doc.h

# ドキュメントってどこ？

公式ドキュメント
https://steinbergmedia.github.io/vst3_doc/vstgui/html/uidescription.html

属性のページは必見
https://steinbergmedia.github.io/vst3_doc/vstgui/html/uidescription_attributes.html

詳細ドキュメント
https://www.steinberg.net/en/company/developers.html
で配布されている、VST Module Architecture SDKをダウンロードして展開すると、VSTModuleArchitectureSDK\uixml\index.htmlに、さらに詳しいドキュメントがあります。ただ、なぜか一番知りたいCAnimKnobに関して記述がないなど、これだけを見ていてもわからなかったりします。各タグの説明やtemplateを使って定義する仕様などはこのドキュメントにしかないかも。


# 手で書くべきかツールを使うべきか

UI定義ファイルは手書きせずにVSTGUI付属のWYSIWYGエディタを使うことが推奨されています。
https://github.com/steinbergmedia/vstgui/blob/develop/vstgui/uidescription/doc.h
ただ、個人的には現状のWYSIWYGエディタはまだ十分こなれているとは言えず、当面は手で書くことも多いかと思います。

WYSIWYGエディタのいけてない点：

- スタンドアロン起動できない。ホストからプラグインを表示して右クリックで起動する
- セーブはできるがロードができない。ロードはホストからプラグイン画面を一度閉じて再度開く
- 出力されるXMLが洗練されていない。どう見ても不要な属性が大量についている
- 画面が狭い、わかりにくい、整列などの便利機能がない

# 属性として使えるキーワードが知りたい

公式ドキュメント参照。継承されているクラスは継承元の属性も使えます。
https://steinbergmedia.github.io/vst3_doc/vstgui/html/uidescription_attributes.html


# コメント文って使える？

普通のXMLなので`<!-- -->`が使えます。
そういえばJSONって考案者のポリシーでコメント文が使えないけど4.10ではどうなるんだろう。

# 色指定の方法

colorやbackground-color属性はカラーコード指定と色名指定ができます。

### カラーコード指定

| 形式 | 記述例 |
|---|---|
| #RRGGBB | color="#FF0000" |
| #RRGGBBAA | 赤 color="#FF0000FF"　50%半透明赤 color="#FF00007F" |

注．小文字指定も可、#F00や#F00Fのような各色成分を8bitで指定する形式は不可


### 色名指定

| 色名 | 
|---|
|"~ BlackCColor"|
|"~ WhiteCColor"|
|"~ GreyCColor"|
|"~ RedCColor"|
|"~ GreenCColor"|
|"~ BlueCColor"|
|"~ YellowCColor"|
|"~ CyanCColor"|
|"~ MagentaCColor"|
|"~ TransparentCColor"|

`color="~ BlackCColor"`のように使います。ユーザー定義の名前とかぶらないように事前定義の名前は"~ "を先頭につけるルールにしているようです。
https://github.com/steinbergmedia/vstgui/blob/master/vstgui/uidescription/uidescription.cpp

### 色名のユーザー定義

colorsタグで独自の色名を定義することもできます。

```gui.xml
<colors>
  <color name="labelcolor" rgba="#005566FF"/>
  <color name="labelcolor2" red="0" green="85" blue="102" alpha="255"/>
</colors>
```

# グラデーション指定の方法

CTextButtonなどは色名／カラーコード指定ができず、gradient、gradient-highlighted属性にグラデーション名を指定します。gradient、gradient-highlighted属性を省略するとデフォルトのグラデーション色になります。

```gui.xml
　　<view class="CTextButton" （省略） gradient="ButtonOff" gradient-highlighted="ButtonOn" />
```

グラデーションはgradientsタグで定義します。
グラデーションでボタンを立体的にするのも今どきダサい感じなので、開始色と終了色を同じにしてフラットカラーにするのも良いと思います。

```gui.xml
    <gradients>
      <gradient name="ButtonOff">
        <color-stop rgba="#666666" start="0"/>
        <color-stop rgba="#666666" start="1"/>
      </gradient>
      <gradient name="ButtonOn">
        <color-stop rgba="#AAAAAA" start="0"/>
        <color-stop rgba="#AAAAAA" start="1"/>
      </gradient>
    </gradients>
```

# フォント指定の方法

CTextLabel、CTextButton、CParamDisplayなどのフォントは以下のように指定します。

```gui.xml
  <view class="CTextLabel" title="Hello World!" font="MyFont" />
```

```gui.xml
  <fonts>
    <font name="MyFont" font-name="Arial" size="48" style="bold" />
  </fonts>
```

フォントも事前定義されたキーワードが使えます。

| フォント名 | 
|---|
|"~ SystemFont"|
|"~ NormalFontVeryBig"|
|"~ NormalFontBig"|
|"~ NormalFont"|
|"~ NormalFontSmall"|
|"~ NormalFontSmaller"|
|"~ NormalFontVerySmall"|
|"~ SymbolFont"|


# 手で書くときに元となるテンプレートがほしい

自分の場合、こんな感じのファイルをテンプレートとして使っています。
これはGUIパーツ画像を必要としないバージョン。オーディオ処理を実装していて、とりあえずのUIがほしいときに便利です。テキストラベル(CTextLabel)やパラメータの数値表示(CTextEdit)は必須ではありませんが、デバッグ時にあるとわかりやすいので表示しておきます。ちなみにCTextEditをCParamDisplayに変えると編集不可の表示のみになります。
最低限の属性しか記述していないのでわかりやすく、改変もしやすいかと思います。

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

	<template name="view" origin="0,0" size="800, 180" background-color="#333333">

		<view class="CTextButton" control-tag="Bypass"  origin="20,   20" size="50, 20" title="Bypass" kick-style="false" gradient="ButtonOff" gradient-highlighted="ButtonOn" />

		<view class="CTextLabel"      title="Drive" origin="100,  20" size="50, 20" back-color="#00000000" style-no-frame="true" />
		<view class="CKnob"     control-tag="Drive" origin="100,  40" size="90, 90" />
		<view class="CTextEdit" control-tag="Drive" origin="100, 130" size="50, 20" />

		<view class="CTextLabel"      title="Level" origin="200,  20" size="50, 20" back-color="#00000000" style-no-frame="true" />
		<view class="CKnob"     control-tag="Level" origin="200,  40" size="90, 90" />
		<view class="CTextEdit" control-tag="Level" origin="200, 130" size="50, 20" />

	</template>

	<bitmaps>
	</bitmaps>

	<control-tags>
		<control-tag name="Bypass" tag="100"/>
		<control-tag name="Drive"  tag="101"/>
		<control-tag name="Level"  tag="102"/>
	</control-tags>

    <gradients>
      <gradient name="ButtonOff">
        <color-stop rgba="#666666" start="0"/>
        <color-stop rgba="#666666" start="1"/>
      </gradient>
      <gradient name="ButtonOn">
        <color-stop rgba="#AAAAAA" start="0"/>
        <color-stop rgba="#AAAAAA" start="1"/>
      </gradient>
    </gradients>

	<fonts>
	</fonts>

	<colors>
	</colors>

</vstgui-ui-description>

```
以下のような表示になります。
![draft_gui.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/27c95a45-d6ae-7a69-2efc-301657d2ddb2.png)




# GUIパーツ画像を使うテンプレート

前項のXMLをベースに開発し、GUIデザインが進んだらノブやスイッチを画像に置き換えます。
その場合、XMLの内容は以下のようになっていきます。
CTextButtonをCOnOffButtonに、CKnobをCAnimKnobに置き換えてbitmap属性で画像ファイルを指定しています。画像ファイルは縦につながった連続画像なので、1枚分の高さをheight-of-one-image属性で指定します。


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

	<template name="view" origin="0,0" size="800, 180" bitmap="panel">

		<view class="COnOffButton" bitmap="button" control-tag="Bypass" title="Bypass" height-of-one-image="20" origin="20, 20" size="50, 20" />

		<view class="CTextLabel"          title="Drive" origin="100,  20" size="50, 20" back-color="#00000000" style-no-frame="true" />
		<view class="CAnimKnob"     control-tag="Drive" origin="100,  40" size="90, 90" bitmap="knob" height-of-one-image="90" />
		<!-- view class="CTextEdit" control-tag="Drive" origin="100, 130" size="50, 20" / -->

		<view class="CTextLabel"          title="Level" origin="200,  20" size="50, 20" back-color="#00000000" style-no-frame="true" />
		<view class="CAnimKnob"     control-tag="Level" origin="200,  40" size="90, 90" bitmap="knob" height-of-one-image="90" />
		<!-- view class="CTextEdit" control-tag="Level" origin="200, 130" size="50, 20" / -->

	</template>

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

	<control-tags>
		<control-tag name="Bypass" tag="100"/>
		<control-tag name="Drive"  tag="101"/>
		<control-tag name="Level"  tag="102"/>
	</control-tags>

	<fonts>
	</fonts>

	<colors>
	</colors>

</vstgui-ui-description>
```
以下のような表示になります。
![image_gui.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/d650da39-ade8-74d1-5080-9c7226450670.png)




# 本記事のGUIパーツ画像

本記事で使用した画像を以下に示します。右クリックで保存して参考にしてください。

![panel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/ffa8e817-6a07-3936-c544-702e00a9187c.png)

![button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/5dc188b2-389c-c6fa-6eb4-10cdc56824a9.png)

![knob.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/badb734e-de9a-7cdb-f9dd-a19666719d78.png)

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