ADX2 for UE4で、BGMのテンポに合わせた演出を実装する（改訂版）

# はじめに
アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を連携させ、BGMのビートに合わせてエフェクトやメッシュを操作し、演出を実装してみます。

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

「ADX2 for UE4 LE」の新バージョンにて追加された**OnAtomBeatSyncCallback**イベントを使用すれば、簡単に楽曲のビート情報を取得することができます。


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

# 前提
ADX2 for UE4の導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX2 for UE4の導入で、一歩上のサウンド表現を（実践編）
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ファイルをコンテンツブラウザの任意の場所にドラッグアンドドロップしてください。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4e2df483-5672-66ad-d188-a940e3787b62.png)

ツールバーの「Edit」→「Project Settings」を開き、
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/960ae861-74b3-b7fb-f792-234b7e941d84.png)
「CriWare」タブの「Atom Config」にビルドしたacfファイルを入力します。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/831d9398-4de8-9371-a170-db1922c28bb2.png)

レベル上にキューを配置すると、ゲーム開始時にBGMが再生されます。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d42e77b0-90bf-f291-dd67-fcb408da8aa8.png)


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

レベルブループリントから、BGMのビート情報を取得してみましょう。
レベルに配置したキューを選択しておきます。
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/cf00a20a-420a-9413-12fa-2461ceb895e0.png)
「Blueprint」→「Open Level Blueprint」でレベルブループリントを開きます。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a90f91b4-e6b1-763e-c129-7b34913f387d.png)
レベルブループリントグラフ上の空いている場所で右クリックし、「Create a Reference to （キュー名）」を選択します。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4da7e209-f706-726e-10e4-9fe05c9c1cb8.png)
キューのリファレンスノードが作られます。
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/53fd20af-7cb5-e2a7-33b1-541f379e7662.png)
リファレンスノードから線を引き出し、**Get Atom Component**ノードを作ります。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c34ad22d-3d74-dd57-5809-450282202d04.png)
さらに**Get Atom Component**ノードから線を引き出し、「beat」と検索します。
「Assign On Atom Beat Sync Callback」が候補に出てくるので選択します。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fc736d1d-8f6f-4da6-c307-dbd2c913f28b.png)
新規にノードとイベントノードが作成されました。適当に名前をつけます。
このイベントがBPMに合わせて呼ばれるものになります。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c4f1faab-477c-b729-77d3-063fe105ec89.png)
**Bind Event to On Atom Beat Sync Callback**ノードに**Event BeginPlay**から線をつなげます。これで、下にあるイベントがゲーム開始時に紐付けられることになります。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a1ca0f27-cf36-829b-5157-eb1d9d989b8d.png)
テストとして、イベントから**Print String**ノードにつなげて実行してみましょう。
![B13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e1aa5666-7a41-c3af-7493-cddbe36446dc.png)
実行してみると、BGMのテンポに合わせて画面左上に文字が表示されるはずです。
![B14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/2f30388d-45f6-ae3a-52c6-6eabaf17a19a.png)


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

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

コンテンツブラウザの任意の場所で右クリックし、「Blueprint Class」を選択して新規にアクターを作成します。
![B15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/257c947a-5606-696d-d493-9d34f8a2e2e1.png)
親クラスは「Actor」を選択します。
![B16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/567099fd-d76d-ad34-de8d-c584a8faa76c.png)
作成されたアクターに適当な名前をつけます。
![B17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/26f5a3f8-b5df-9bd9-7b06-b6921d73ff11.png)
アクターをダブルクリックして開き、見た目となるコンポーネントを追加します。
画像では平面のStaticMeshにリングが描かれたマテリアルを適用しているだけです。
![B18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a1b39909-f92f-30e2-f79b-71cc599731cb.png)
AtomComponentも追加します。
![B19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d27cb6e3-a7a9-4b85-6d49-d706f424c877.png)
AtomComponentを選択し、Detailsパネルで再生したいサウンドを指定しておきます。
![B20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/cdd754b4-908d-2372-c55e-1f8b0fbc4241.png)
AtomComponentを右クリックし、「Add Event」→「Add OnAtomBeatSyncCallback」を選択してイベントを追加します。
![B21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/65fbfa1d-1bcf-70df-a71a-b24fb171656a.png)
イベントグラフに自動的に移動し、BeatSync用のイベントが追加されたのが確認できます。
![B22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f78bb3c8-c9a7-9c64-38df-36de50abd705.png)


リングの大きさを変化させる処理を書きます。
まずはコールバックイベントからつなげる処理です。
**Get （見た目のコンポーネント名）**を配置し、そこから線を引き出し**Set Relative Scale 3D**を置きます。これはアクター内で相対的なスケールを変えるものです。「New Scale 3D」にはとりあえず「3」を入力しておきます。
この処理により、ビートごとにリングの大きさが「3」倍に設定されます。
![B23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8c761403-5ef1-cecd-a00e-0ae98128ae3d.png)

次にTickイベントからの処理です。
コールバックイベント側とほぼ同じですが、少しだけ複雑になります。スケールの指定には**VInterp To**ノードを使い、大きさが滑らかに変化するようにします。「Current」には**Get Relative Scale 3D**をつなげて現在の相対スケールを、「Target」には「1」を指定します。
「Delta Time」には**Event Tick**の「Delta Seconds」をつなげます。
「Interp Speed」にはひとまず仮で「5」を入れておきます。
これにより、Tick毎にリングの大きさは常に「1」倍に近づきます。
![B24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3cc41822-3c08-99b8-539f-77059f4216d5.png)
ふたつのイベントからの処理により、**常に1倍のスケールに近づくリングが、ビートのタイミングで3倍のスケールに再設定される**という仕組みができあがります。どう動くかは実際に見てみるのが早いと思います。

レベル上にアクターを配置します。最初にテスト用に置いていたキューは削除し、またエラーが出るのでレベルブループリントの内容も消しておきます。
![B25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ced2c487-55bd-cad2-6c9d-0e48c96c6e67.png)
実行すると、ビートごとにリングの大きさが変わります。ライブシーンのエフェクトなどにも使える演出かもしれません。
![B26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/35926db3-13f9-e480-28cf-bbbbddae38f0.png)



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

ビートに合わせて発光するオブジェクトも作ってみます。
同様にアクターを作成し、合わせて新規にマテリアルを作成します。
コンテンツブラウザで右クリックし→「Material」を選択です。
![B27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/94a51fea-2d32-85a5-270e-455b1c39c9fb.png)
作成したマテリアルをダブルクリックしてマテリアルエディタを開き、キーボードの「3」キーを押しながらクリックすると3つのパラメータを持つノードが作られます。
「Emissive Color」につなげます。これでこのマテリアルが、パラメータに応じた色で発光するようになります。
![B28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5505a306-63d4-4497-737d-478b7358d024.png)
作成したノードを右クリックして「Conver to Parameter」をクリックします。
![B29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e32c4ed2-fd37-455a-d9e2-9e1b9203a946.png)
ノードがパラメータ（変数）化されるので、「EmissiveColor」と名前をつけます。
![B30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b631def7-564e-ac1e-18f9-d6ca8a831c06.png)

アクターを開きます。
リングのときと同じように、見た目となるコンポーネントとAtomコンポーネントを追加します。今回は外観をSphereにしています。
Atomコンポーネントには、忘れずに再生する音源を指定しておきます。
![B31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8935adbc-d78b-dbe9-2a7e-fe157d65521c.png)
イベントグラフに移動し、**Event BeginPlay**から**Create Dynamic Material Instance**ノードを配置します。これはブループリントにより動的に操作可能なマテリアルを作成するものです。「Parent」には先ほど作成したマテリアルを指定します。
![B32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/05fe0582-b70e-b6b3-ec16-ab2182e0fcf3.png)
青いピン「Return Value」を右クリックし、「Promote to Variable」を選択します。
![B33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/424f2beb-23d1-7cbc-45b1-8ebdfd23bfcd.png)
これで作成した動的なマテリアルが変数化され、このブループリントからいつでも操作可能になります。今回は「DM_Color」と名前をつけました。
![B34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/57531781-8087-bfd3-1968-a7112f7ca1c3.png)
外観となるSpehreコンポーネントの**Get**ノードを作り、**Set Material**ノードで先ほど変数化したマテリアルを指定します。これでSphereに操作可能なマテリアルが適用されることになります。
![B35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/62c64e7b-bcd7-1a39-d022-996ddc19adfd.png)

あとはリングの大きさを変えたように、コールバックイベントとTickイベント間で色を変えるだけです。
マテリアルの色を変えるには**Set Vector Parameter Value**ノードを使います。まず**Get DM_Color**を配置し、そこからノードを作成します。「Parameter Name」にはマテリアルのパラメータ名である「EmissiveColor」を入力します。
処理は**On Atom Beat Sync Callback**イベントノードからつなげましょう。
![B36a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6844d444-0d3a-de94-cbe5-4407521b79d5.png)
色を数値で指定するには「Value」ピンから線を引き出し、**Make Color**ノードを置きます。
今回は青に「50」を指定しました。かなり眩しく発光するはずです。
![B36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3db03733-3a4a-da46-87ab-f26ba6cb32ff.png)
**Event Tick**側にはまず**Get DM_Color**からの**GetVectorParameterValue**をつなげます。これで現在の色のパラメータ値を取得します。
![B37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/2fb57aa3-0041-25d4-ccf0-3dad3ca6ce26.png)
あとは**Set Vector Parameter Value**と**Interpolate(LinearColor)**ノードを使用し、黒色が指定されるようにします。
「Interp Speed」はとりあえず「10」とします。「Delta Seconds」（黄緑色の線）も忘れずにつないでください。
![B38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b1665a4c-2919-5014-1a60-40ffa441047b.png)

レベルに配置してテストしてみましょう。音楽が被って聞こえてしまうので、リングのアクターは取り除いておきます。
![B39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3eb2934b-6ff3-0448-5a25-2ec77bf65de2.png)
実行すると、音楽に合わせて明滅します。
![B40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/551a3d6f-6329-99e0-9b3c-94e5127f23b0.png)



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