ADX2 for UE4でインタラクティブミュージック（ブロック再生編）

# はじめに
UE4.23+「ADX2 LE v2.10.05」を使用します。
アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を連携させ、
ゲーム中の展開に応じてBGMがシームレスに変化していく「インタラクティブミュージック」を実装します。
以前インタラクティブミュージックの実装について記事を書きましたが、

**ADX2 for UE4でインタラクティブミュージック（AtomCraft編)**
https://qiita.com/SigRem/items/8af9b7d8445477906741
**ADX2 for UE4でインタラクティブミュージック（ブループリント編）**
https://qiita.com/SigRem/items/b53dc03d01c5f8fe1465

これらがトラックのパラメータを調整してBGMを遷移させているのに対し、今回はADX2の「ブロック再生」機能により、**「曲の再生位置をダイナミックに変化させ、BGMの展開を変えてしまう」**方法を取ります。

![C01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3d90a554-f3d0-7fad-3e92-fbe91e9e828c.png)

普通にBGMを再生するとAメロ→Bメロ→サビといった通常の進行をしますが、Aメロ→サビ（何度かループ）→Aメロ→Bメロといったように変則的な進行が可能になります。


# 前提
「ADX2 for UE4 LE」を使用します。導入や簡単な使い方は以下の記事にあります。
ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX2 for UE4の導入で、一歩上のサウンド表現を（実践編）
https://qiita.com/SigRem/items/c089b71c42e898980a46


#やること
- 曲のイントロが終わるとゲームを監視し、BGMを変化させる処理に入る
- キャラクターが一定のエリアに入るとサビに遷移する
- エリアにいる間はサビを再生し続け、退出するとAメロに戻ってクールダウンする
- ゴールまで辿り着くとアウトロを一度だけ流し、再生を終了する


# 実装

## AtomCraftでBGMを構成する

### 素材の用意
まずはAtomCraftでBGMを構成し、UE4で変化させるための準備をします。
今回はBGM素材を用意しましたので、もしすぐに試せる音源がない場合使ってみてください。
https://drive.google.com/file/d/12FlChB751am1Gp-KwbU9Q-Jq6_MH3N--/view?usp=sharing

### 素材のインポート
音源をマテリアルツリーにインポートします。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9e318cfd-c78d-eae2-fc32-043c62616bcf.png)
上記の素材では曲の展開ごとにファイルがばらばらになっていますが、後述する「ブロック再生」機能の設定をすれば、ひとつに繋がったBGMファイルでも問題ありません。

### キューの作成
新規にキューを作成します。今回は「ポリフォニック」タイプにします。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a474f650-c3bf-8e25-5b92-d1869824928d.png)

### トラック、ブロックの設定
タイムラインにマテリアルをドラッグアンドドロップし、トラックを作成します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a401e470-1548-f1db-e59c-87d34b8d48a6.png)
そのままトラックリストの空欄で右クリックし、「新規オブジェクト」→「ブロックの作成」を選びます。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9cebbc32-4fd5-e2f6-16e1-b882085325de.png)
「ブロック」が生成されたので、選択してインスペクターで名前を分かりやすいものに設定しておきます。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/735b3e5d-c3e2-0526-a7de-f982e8d626bc.png)

**「ブロック」**は、「Aメロ」「Bメロ」「サビ」のように楽曲の区切りとして使用できるものです。
ブロックごとに遷移先を動的に指定したり、何度ループしてから次のブロックに移るかなどを設定することができます。
インスペクターで「ブロックループ回数」に「1」と入力して再生（F5)すると、一度だけブロックが繰り返されてから停止します（テスト再生はF6キーで停止できます）。
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6c3cb679-04d5-db30-66f0-b5a217c3d89e.png)
2番目の楽曲ファイルをタイムラインに追加し、ブロックを追加します。
![A07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7e9cce6b-ca23-4cc5-fead-6421d71c7583.png)
こちらも分かりやすい名前にしておきます。
![A08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f5d202b1-faf8-e601-a11c-608853904e78.png)
同様にすべての楽曲ごとにトラック、ブロックを作成します。
今回はブロックを「イントロ」「Aメロ」「Bメロ」「サビA」「サビB」「アウトロ」と分けました。
![A09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d8ab014f-141a-3dc0-d591-72bab7b1c7d6.png)
最初のブロックに試しに設定したループ回数は0に戻しておきます。
![A10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/785e28de-29d7-b3e6-fec4-8f79dc3f2a8a.png)

### キューシートのビルド
ひとまず、ここまででキューシートをビルドしておきます。
![A11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/75eb0754-6fad-fdab-64de-a0f467ad03bc.png)
![A12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f764692a-1968-edb8-9c42-f066d26d532f.png)


##UE4でインタラクティブミュージックを実装する

###キューシートのインポート
ビルドしたキューシート（acf,acbファイル)をコンテンツブラウザにドラッグアンドドロップし、インポートします。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a22d53dd-c003-6957-616a-d286294dbc32.png)
ツールバーの「Edit」→「Project Settings」を開き、「CriWare」のタブから「Atom Config」をインポートしたacfファイルにします。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4faa6cab-fe6e-c3cb-87a9-b3774ed40c3b.png)
必要に応じてエディタを再起動します。

### レベルを作成する
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f95a9217-79b2-a78c-44cf-e3e52a55a37d.png)
新規にレベルを作成し、コンテンツブラウザからキューをドラッグアンドドロップして配置しました。ひとまずこれで再生はされるはずです。

今回、デフォルトのアセットを使用してこんな感じのレベルを作りました。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/035c9a5d-ca3d-038a-1c5d-2d0cce2115e0.png)
楽曲と連動する要素として、以下のように想定します。
![C02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b9fbee41-b757-c891-587f-a4c7617ceaf5.png)


各エリアに進入したことを感知するため、部屋の入り口にトリガーを置きます。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/68201a3f-df7a-a4b6-e7f2-f7bb7ff8c1a5.png)
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7d2ec5e3-4b26-8224-5a38-43b0e1bfb7a7.png)
「Trigger_RoomA」を置いたのは、サビ再生エリアから戻ってきた際に曲の進行をAメロに戻すためです。

### キューの再生位置を取得する
最初の部屋ではイントロ→Aメロ→Bメロ→再びAメロという流れにしたいので、再生位置に応じて遷移先のキューを指定してあげる必要があります。
レベルブループリントを開き、以下のようなブループリントを組むことで画面上に再生位置が出力されます。
**Get Sequence Position**が再生位置の取得をするノードです。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7f090720-8f3d-f391-7261-989d63f67e1d.png)
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fa2fe1ee-620a-0d44-484d-25d6b8e16164.png)
サンプル音源の場合、Aメロ→Bメロのループの場合は20秒付近で、サビA→サビBのループは35秒付近でループ命令を渡してあげれば大丈夫そうです。

### 現在のエリアを取得し、変数に代入する
プレイヤーがいるエリアを記憶しておくための変数を作成します。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c3c72685-7094-8192-de1a-f79dcbc55c7d.png)
Int型で、値はエリアAでは「0」、エリアBでは「1」、ゴール地点では「2」とします。

トリガーを選択し、OnActorBeginOverlapイベントを作成します。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7938a075-02fa-57dc-52dc-a08b3d512304.png)
すべてのトリガーに対して同様にイベントを追加します。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f2075595-370b-c7c4-b1f7-203de09f03ec.png)

それぞれがプレイヤーキャラクターを感知した際、エリアの値を「CurrentArea」変数に代入します。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3c933f09-041d-f984-9498-a7c328643ce7.png)


### エリアに対応したブロックに遷移させる
遷移先のブロックを指定するには、**Set Next Block Index**ノードを使用します。今回の処理の肝です。
これにより指定されたインデックス番号のブロックが、現在のブロックの再生を完了した後に再生されます。
![B13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a23b158f-8dee-b5c1-7b0d-424c3ee83db1.png)


### 異なるブロックをループさせる
仕上げに、「Aメロ→Bメロ→Aメロ」といったように異なるブロックをループさせる処理です。
Tickイベントで再生位置を取得した後、**Switch on Int**で変数「Current Area」の値ごとに処理を分岐させます。
![B14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1f25c76e-36c3-bb0c-893f-be0f606be6ee.png)
エリアAでは再生位置が20秒を越えたあたりで遷移先ブロックをAメロである「1」に、エリアBでは35秒を越えたあたりで遷移先ブロックをサビAのブロックである「3」に指定します。
![B15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/10cfd958-a0a7-8f11-8b09-eb9bcc564aac.png)

ここまででとりあえず処理は完成です！ループ処理は雑にTickイベントで処理してしまいましたが、他に適切なタイミングがある場合、処理速度の問題が気になる場合は明確なトリガーを作ったほうがベターです。
テストプレイしてみると、設計した通りにエリアに応じたBGMがループするはずです。
![B16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ba213592-5ef3-004f-8c8d-cedcea52c9e5.png)