u-he Hive UHM - DTMプログラミング言語探訪

[DTMプログラミング言語探訪](https://qiita.com/aike@github/items/77b3eccc6861de09513a)

# u-he Hive UHM

## 概要

u-heのウェーブテーブルシンセサイザー[Hive](https://u-he.com/products/hive/)はウェーブテーブルデータを生成するための言語UHMが用意されています。

## 用途

- ウェーブテーブルデータ（波形とその時間的変化）の生成
- ウェーブテーブルデータのwavファイル出力

## 言語仕様

- 独自言語
- 数式処理
- システム変数
- 波形バッファ
- wavファイル出力

読み取り専用のシステム変数があり、その状態によって処理を分岐することができますが、チューリング完全を満たすプログラミング言語ではありません。ユーザー定義関数も作れません。

計算途中の波形を保持しておくためにmain、aux1、aux2の3つのバッファがあり、通常のプログラミング言語の配列のように使用できます。

1周期2048サンプル分の波形を計算式で生成します。
ひとつのプログラム内で最大256個の波形を定義することができます。これらはフレームと呼ばれ、フレームの順番で波形をモーフィングして発音します。つまり、1周期分の波形×フレーム数がウェーブテーブルデータとなります。
ウェーブテーブルデータはwavファイルにエクスポートすることができます。エクスポートしたwavファイルは、Hive以外のウェーブテーブルシンセソフトでも利用することができます。

公式リファレンス　[Hive Wavetables](https://u-he.com/downloads/manuals/plugins/hive/Hive-Wavetables.pdf)


## GUI仕様

UHMでは独自のGUIは作成できません。
Positionノブがフレームに対応しており、モーフィングOffのときは指定したフレーム位置の波形を鳴らします。モーフィングが有効なときは指定位置から後ろのフレームを使用してモーフィングします。
![hive6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/ca9f5402-1f95-1802-223f-c8b6160407ba.png)



余談ですが、Hiveをはじめu-heのシンセサイザーソフトは独自画像を使ったGUIスキンを作ることができてユーザー同士で自作スキンの配布もさかんにおこなわれています。スキンはテキスト形式の.h2pファイルで記述することができますが、その仕様はオープンになっていません。
u-he/Hive.data/Presets/Hive/default.h2pファイルに以下のように記述すると、画面を右クリックすることで各種のGUIパーツのパラメータを設定できるようになり、そのように調整した結果をh2pファイルに出力することで独自のスキンを作成します。

```default.h2p
!EDITOR=YES
```
![hive_skin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/3d4b1107-3023-20e9-dfa4-8b69b467776b.png)



## プログラム例

### 各種波形合成

サイン波生成
phaseは1周期分の変化を0～1.0で表すシステム変数です。

```c++:Sine.uhm
// Sine wave
Wave "sin(2 * pi * phase)"
```

減算合成
2 * phase - 1でノコギリ波を生成したものにローパスフィルターをかけています。

```c++:SubtractiveSynthesis.uhm
// Subtractive synthesis
Wave "lowpass(2 * phase - 1, 0.3, 0.5)"
```

加算合成
blend=addとすることで直前に生成した波形との加算を指定できます。

```c++:AdditiveSynthesis.uhm
// Additive synthesis
Wave "sin(2 * pi * phase * 1) * 0.5"
Wave "sin(2 * pi * phase * 2) * 0.3" blend=add
Wave "sin(2 * pi * phase * 4) * 0.2" blend=add
Wave "sin(2 * pi * phase * 8) * 0.1" blend=add
```

FM合成
sin(θ + sin(2θ))の例です。

```c++:FMSynthesis.uhm
// FM synthesis
Wave "sin(2 * pi * phase + sin(2 * pi * phase))"
```

### フレーム番号を指定したモーフィング

波形1から波形2になめらかに変化させる指定です。この例では普通のサイン波からオクターブ上のサイン波へ変化します。

```c++:Morphing.uhm
NumFrames = 2

Wave start=0 end=0 "sin(2 * pi * phase)"
Wave start=1 end=1 "sin(4 * pi * phase)"
```
モーフィング指定でOne ShotまたはLoopを指定することでモーフィングが有効になります。
![hive5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/54802328-e3ae-6b27-58ad-6c20c3f4de37.png)

### tableシステム変数を使ったモーフィング

tableは0～1.0まで256フレーム分変化するシステム変数です。
以下のように記述することでローパスフィルターが徐々に開いていく波形をモーフィングで表現することができます。

```c++:FilterMorphing.uhm
// Filter morphing
Wave "lowpass(2 * phase - 1, 0.1 + table * 0.5, 0.5)"
```

### Wavファイルへのエクスポート

Export文でwavファイルへ出力します。
出力はNumFramesで指定した周期だけ生成されます。省略時は256周期分になります。

```c++:ExportWav.uhm
NumFrames = 1
Wave "sin(2 * pi * phase)"

Export "sine.wav"
```


## 実行方法

あらかじめu-he/Hive.data/Wavetables/user/に.uhmファイルを置いておく。

タイトル部を右クリックしてInitを選択。設定を初期化します。
![hive1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/b2925150-278e-32f5-66e0-434214759bd6.png)

OSC1の波形欄タイトル部をクリックしてWavetableを選択
![hive2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/53c1d67b-7d22-4657-3673-188cdbdc3765.png)

中央の六角形上部のWAVETABLE1ボタンをクリック
![hive3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/146131b7-8d03-78e8-8e49-dfacbd199d36.png)

click here to browse wavetablesと書いてある箇所をクリックするとuhmファイルが選択できます
![hive4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/b199c4fa-3d9c-73ac-1c64-12e1e48150ce.png)

uhmファイルを編集して保存したときは、自動的に更新を検知して読み直してくれます。


## 感想

1周期分の波形を生成することに特化した大変ユニークな言語です。ある種、信号処理の一番面白いところに専念できる感覚があり、書いていてとても楽しいです。
汎用言語にくらべると表現力の自由度が低いのは否めませんが、目的のために小さな仕様の専用言語を設計するというDSLとして理想的なかたちだと思います。

本エントリー執筆にあたり、SoundQuestさんの[Wavetable言語「UHM」の基礎知識](https://soundquest.jp/article/plugin/uhm-introduction/)を参考にしました。

[DTMプログラミング言語探訪](https://qiita.com/aike@github/items/77b3eccc6861de09513a)