ADX + UE5で、BGMのテンポに合わせた演出を実装する（ver2改訂版）

# はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事ではアンリアルエンジン5とサウンドミドルウェア「ADX for UE」を連携させ、BGMのビートに合わせてエフェクトやメッシュを操作する演出について実装します。

https://twitter.com/sleepyslowsheep/status/1388401352544374785?s=20

「ADX for UE」の**BeatSync**イベントを使用すれば、簡単に楽曲のビート情報を取得することができます。


当記事ではUE5.2を使用します。基本的にブループリントのみでの実装を想定しています。
ADX for UEはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/

# 前提
ADX for UEの導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
**ADX for UEの導入で、一歩上のサウンド表現を（導入編）**

https://qiita.com/SigRem/items/4250925f6d66a4fd287a

**ADX for UEの導入で、一歩上のサウンド表現を（実践編）**

https://qiita.com/SigRem/items/c089b71c42e898980a46

# 実装

## AtomCraftでマテリアルを準備
まずはAtomCraftでBGMとなるマテリアルを用意します。
マテリアルツリーに音源をドラッグアンドドロップして追加します。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d87667f5-70fe-92a3-bbf9-4230b776760b.png)

キューを新規に作成します。
ワークユニットツリーのキューシート上で右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択します。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/eff91c48-9855-0043-6227-a18cb122c1d8.png)
キューに名前をつけ、音源をトラック上にドラッグアンドドロップして配置します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8438ef7c-a0e9-bd41-e08a-25b694773ed2.png)


## ビート同期情報の設定
まずは必要な情報として、曲のBPMを確認します。
マテリアルツリーの目的の音源を選択して右クリックし、「BPM解析」を選択します。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0ca80f02-9978-9258-595f-84b52459cabe.png)
ログにBPM情報が出力されます。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f6ae6d01-c8cf-89b2-6bcf-c71fdac3151c.png)
もしログウィンドウが見当たらない場合、ツールバーの「表示」→「メインビュー」→「ログ」を選択することで再表示が可能です。
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e540b11d-04d3-828c-1320-a9f047824c6a.png)

トラックリストの空欄で右クリックし、「新規オブジェクト」→「ビート同期情報の作成」をクリックします。
![A07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/23eb162e-a521-4d08-3a0a-7a86d41f34b5.png)
「BeatSync」と書かれたマーカーが追加されます。
![A08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d4f876ee-e1ca-fca7-6eba-270b5cfffd60.png)
**「BeatSync」マーカーが選択された状態で**、インスペクターの「BPM」に先ほど解析したBPMを入力します。
![A09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/eb083c65-3905-6cf5-bd84-dac2c71942a5.png)



## キューシートのビルド
ここまで完了したらキューシートを書き出します。
![A10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1ec6ce29-7503-45ea-3477-682a8e1b0044.png)
![A11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/41c5d4d1-a26e-3918-931b-2ebeef701010.png)


## UE4でセットアップ
UE4にキューシートをインポートします。acf、acbファイルをコンテンツブラウザ（コンテンツドロワー）の任意の場所にドラッグアンドドロップしてください。
acfファイルをインポートした際のダイアログでは、どちらもYesを選びます。
これにより、Atom Configファイルがプロジェクトに自動的に設定されます。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/246a111a-a0df-b2da-b094-c2c26152bbdd.png)
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a0af0ff4-d66c-7236-dbf4-4334a823cdfc.png)
ふたつのアセットがインポートされました。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8e8fcfcb-dd6a-00ca-344f-6e1b65a2c94a.png)
念のため、キューシート内のキューが正常に再生できるか確認しておきましょう。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/20abda76-ea48-c382-8a80-a3254460e1b9.png)

レベル上にキューを配置すると、ゲーム開始時にBGMが再生されます。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1aa13e79-c53e-bda2-de73-61719f782fae.png)


## ブループリントからビートのタイミングを取得

レベルブループリントから、BGMのビート情報を取得してみましょう。
レベルに配置したキューを選択しておきます。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/508b581f-a4e6-e238-ce62-7e580eaab87a.png)

「Open Level Blueprint」からレベルブループリントを開きます。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/15b24061-1d96-0518-d005-5a84496c4387.png)

レベルブループリントグラフ上の空いている場所で右クリックし、「Create a Reference to （キュー名）」を選択します。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/85c4eb70-2337-79d0-b2e0-6c0720c4d4a2.png)

キューのリファレンスノードが作られます。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/06cbb10d-6387-8c49-8889-6071d0be5d06.png)

リファレンスノードから線を引き出し、**Get Atom Component**ノードを作ります。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/013403ef-d8ed-afd3-6119-836cdd365918.png)
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/435ee993-b04c-86b4-8766-c117f56aac08.png)

さらに**Get Atom Component**ノードから線を引き出し、
「Assign On Atom Sound Cue Beat Sync」を検索して配置します。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/409c9fa7-5dab-aad2-d5c8-d77ab74516a9.png)
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/522fa8db-e827-9f3e-6e60-1c0b0595b434.png)

新規にノードとイベントノードが作成されました。適当に名前をつけます。
このイベントがBPMに合わせて呼ばれるものになります。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/76ea8efd-1df6-e6cc-0ea8-a3d6e04317e9.png)

**Bind Event to On Atom Beat Sync Callback**ノードに**Event BeginPlay**から線をつなげます。これで、下にあるイベントがゲーム開始時に紐付けられることになります。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ebe3044b-1110-f6af-22d9-21f2df764afa.png)


この「イベントの紐づけ」に関して詳しく知りたい場合は「イベントディスパッチャー」を調べてみましょう。
（深く理解しなくても、このまま進めていけば当記事の内容は実装可能です）

https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/Blueprints/UserGuide/EventDispatcher/


テストとして、イベントから**Print String**ノードにつなげて実行してみましょう。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1b119fa2-3259-0233-91a1-2e6e84e6a7cd.png)

実行してみると、BGMのテンポに合わせて画面左上に文字が表示されていくはずです。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8e1bc71d-f9a4-f779-48a3-147cf31f48e2.png)



## ビートに合わせて拡縮するリング

この処理を利用して、テンポに合わせて大きさが変わるオブジェクトを作ってみます。

コンテンツブラウザの任意の場所で右クリックし、「Blueprint Class」を選択して新規にアクターを作成します。
![C01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e3f47819-71d8-3d44-8009-3f8df1a0a9eb.png)

親クラスは「Actor」を選択します。
![C02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1de97f17-1b94-c20e-e5e9-7cbcadd47a02.png)

作成されたアクターに適当な名前をつけます。
![C03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/41c90bf1-5195-0fd0-ee76-2120e6e5a0a2.png)

アクターをダブルクリックして開き、見た目となるコンポーネントを追加します。
画像では平面のStaticMeshにリングが描かれたマテリアルを適用しているだけです。
![C04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fa076af6-4b7c-5c4b-6556-00d7b87e3f47.png)

AtomComponentも追加します。
![C05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7217d631-c1e8-6f49-63a8-f61c03e3418a.png)
![C06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/907cf22a-b67e-b9bc-6dc3-a90a338c006a.png)


AtomComponentを選択し、Detailsパネルで再生したいサウンド（キューシートを選択してからキューを選択）を指定しておきます。
![C07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/178be973-8aaf-7cea-d5a2-dc9e7b01aa53.png)


AtomComponentを右クリックし、「Add Event」→「Add OnAtomBeatSyncCallback」を選択してイベントを追加します。
![C08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/27969340-2522-ab90-113c-171b4b0d49eb.png)

イベントグラフに自動的に移動し、BeatSync用のイベントが追加されたのが確認できます。
![C09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fada357e-cd24-acae-be88-57671a8ecf86.png)



リングの大きさを変化させる処理を書きます。
まずはコールバックイベントからつなげる処理です。
メッシュのコンポーネントをイベントグラフ上にドラッグ&ドロップして、**Get （見た目のコンポーネント名）**を配置します。
![C10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/80ed4d2f-f2cc-cc6c-3c84-d4dfffa31202.png)

そこから線を引き出し**Set Relative Scale 3D**を置きます。これはアクター内で相対的なスケールを変えるものです。「New Scale 3D」にはとりあえず「3」を入力しておきます。
この処理により、ビートごとにリングの大きさが「3」倍に設定されます。
![C11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/30565209-ce6c-e5cd-5892-516244b7012d.png)


次にTickイベントからの処理です。
コールバックイベント側とほぼ同じですが、少しだけ複雑になります。スケールの指定には**VInterp To**ノードを使い、大きさが滑らかに変化するようにします。「Current」には**Get Relative Scale 3D**をつなげて現在の相対スケールを、「Target」には「1」を指定します。
「Delta Time」には**Event Tick**の「Delta Seconds」をつなげます。
「Interp Speed」にはひとまず仮で「5」を入れておきます。
これにより、Tick毎にリングの大きさは常に「1」倍に近づきます。
![C12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/2d70730c-24fa-eabf-77ed-3a7c0ea8001d.png)

ふたつのイベントからの処理により、**常に1倍のスケールに近づくリングが、ビートのタイミングで3倍のスケールに再設定される**という仕組みができあがります。どう動くかは実際に見てみるのが早いと思います。

レベル上にアクターを配置します。
（最初にテスト用に置いていたキューは削除し、またエラーが出るのでレベルブループリントの内容も消しておきます）
![C13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/57853d63-3477-82e3-c3cb-70b82a11c1b3.png)

実行すると、ビートごとにリングの大きさが変わります。ライブシーンのエフェクトなどにも使える演出かもしれませんね。
![C14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8058bb9b-48ec-20c5-19b6-b8ecbe30f5c0.png)




## ビートに合わせて発光するマテリアル

ビートに合わせて発光するオブジェクトも作ってみます。
同様にアクターを作成し、
![D01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b5c2b78d-1950-e466-8f5a-34c88ba4cad8.png)

合わせて新規にマテリアルを作成します。
コンテンツブラウザで右クリックし→「Material」を選択です。
![D02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a0d645ba-9852-e883-3d33-c18e246849e7.png)
![D03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/52a012f7-d62b-c0ad-d6a5-f064ccc93aae.png)


作成したマテリアルをダブルクリックしてマテリアルエディタを開きます。
![D04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6c645f5e-18b3-dca8-debe-2cf4d708980e.png)

キーボードの「3」キーを押しながらクリックすると3つのパラメータを持つノードが作られます。
「Emissive Color」につなげます。これでこのマテリアルが、**外部から操作可能なパラメータに応じた色**で発光するようになります。
![D05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6ce9ca24-2bec-8915-7b16-221284ac19f4.png)

作成したノードを右クリックして「Conver to Parameter」をクリックします。
![D06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ef84c595-c2b4-cc9d-51f3-21f1527e5657.png)

ノードがパラメータ（変数）化されるので、「EmissiveColor」と名前をつけます。
![D07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6d05d5ed-d75a-618e-1815-9bef21d95a32.png)

「Apply」を押して変更を確定します。
![D08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b80d78a6-9265-9a3a-2371-cee716cde6bc.png)



アクターを開きます。
リングのときと同じように、見た目となるコンポーネントとAtomコンポーネントを追加します。今回は外観をSphereにしています。
![D09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/22f8c706-3e35-4e2f-9c09-99d09490c2c1.png)

Atomコンポーネントには、忘れずに再生する音源を指定しておきます。
![D10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a4ae965a-0bff-4693-9c2d-3ae19424fffe.png)

イベントグラフに移動し、**Event BeginPlay**から**Create Dynamic Material Instance**ノードを配置します。これはブループリントにより動的に操作可能なマテリアルを作成するものです。「Parent」には先ほど作成したマテリアルを指定します。
![D11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/830f5cf1-f13a-201c-5ab7-063bd107bd50.png)

青いアウトプットピン「Return Value」を右クリックし、「Promote to Variable」を選択します。
![D12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fe04c06b-ddf8-426a-8509-9814a0394115.png)

これで作成した動的なマテリアルが変数化され、このブループリントからいつでも操作可能になります。今回は「DMI_SphereColor」と名前をつけました。
![D13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fb4eeec2-9a07-0aa2-28d3-3bd7cbd84d5c.png)

外観となるSpehreコンポーネントの**Get**ノードを作り、**Set Material**ノードで先ほど変数化したマテリアルを指定します。これでSphereにゲーム中に操作可能なマテリアルが適用されることになります。
![D14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3c770a6b-2314-8ec8-c3c7-93c37175e835.png)


あとはリングの大きさを変えたように、コールバックイベントとTickイベント間で色を変えるだけです。
マテリアルの色を変えるには**Set Vector Parameter Value**ノードを使います。まず**Get DM_Color**を配置し、そこからノードを作成します。「Parameter Name」にはマテリアルのパラメータ名である「EmissiveColor」を入力します。
処理は**On Atom Sound Cue Beat Sync**イベントノードからつなげましょう。
![D15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1de161c4-5889-09cc-e7ed-a21fdfe0d2de.png)

色を数値で指定するには「Value」ピンから線を引き出し、**Make Color**ノードを置きます。
今回は青に「50」を指定しました。マテリアルの「EmissiveColor」は数値が大きいほどHDRにより発光して見えるので、かなり眩しく輝くはずです。
![D16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/04f6752e-babb-8c15-b2f6-03bcc2d0811d.png)

**Event Tick**側にはまず**Get DMI_SphereColor**からの**GetVectorParameterValue**をつなげます。これで現在の色のパラメータ値を取得します。
![D17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/07800141-d17a-5dda-ac2e-55811deebe57.png)

あとは**Set Vector Parameter Value**と**Interpolate(LinearColor)**ノードを使用し、黒色が指定されるようにします。
「Interp Speed」はとりあえず「7」とします。「Delta Seconds」（黄緑色の線）も忘れずにつないでください。
![D18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/63c141d6-b49c-1d8e-b170-3aed358a4ce5.png)

ノードの全体図はこんな感じです。うまく動かない場合、見比べてみてください。
![D21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/aecf3e65-6d1d-52c7-97b4-e8669b6c7c09.png)


レベルに配置してテストしてみましょう。音楽が被って聞こえてしまうので、リングのアクターは取り除いておきます。
![D19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/61a4b411-d13a-5aa0-84a5-bd48ad578564.png)

実行すると、音楽に合わせて明滅します。
![D20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/df17a4f9-61c5-70d7-d92e-4bd92469e6c6.png)




## 参考リンク
今回の記事は、「ADX2 for UE4 LE」アップデートに伴い、過去記事の処理内容に当たるノードが追加されている旨の指摘をいただき作成しました。
## 
https://twitter.com/ArusoN_AFS/status/1366746984481136644?s=20