はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事ではUE5とADX for UEを連携させ、オーディオの視覚化を行う実装を紹介します。
ADX for UEに用意されている「エンベロープ解析」機能を使用します。これは音の変化をリアルタイムに追跡できるもので、Float型の数値として出力されます。
この数値を使用することで、音に合わせて変化する外観や演出を実現することが可能です。
シチュエーションとしては音楽に合わせたビジュアライズやホラーゲームにおける心拍の表現など、音と見た目をシンクロさせたい場合に役立つ機能です。
やること
- ADX for UEを使ってサウンドを再生する
- オーディオのエンベロープ解析機能を使い数値化する
- 数値をビジュアルに変換する
また、記事中に「blueprintue」を使用したBPグラフ共有を載せています。コピペするだけで大体の実装ができますので、よろしければご活用ください。
当記事ではUE5.6 及び 「ADX LE UE SDK(2.04.02)」を使用します。
また、基本的にブループリントのみでの実装を行います。
ADX for UEはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/
前提
「ADX for UE LE」を使用します。導入や簡単な使い方は以下の記事にあります。
ADX for UEの導入で、一歩上のサウンド表現を(導入編)
ADX for UEの導入で、一歩上のサウンド表現を(実践編)
実装
AtomCraftでサウンドを用意する
まずはサウンドオーサリングツールAtomCraftで、今回使用するサウンドを用意していきます。
といっても専用のサウンドは必要ありません。既に解析したいキューがあればこの工程をスキップし、それらを使用してOKです。
今回は解析結果を分かりやすくするため、心音やドラムループ、BGMなどのサウンドを用意しました。
ループ対応のサウンドはインスペクターにてループ情報の上書き、ループタイプを設定しループ再生されるようにしておきましょう。

今回はすべてのキューが通常再生される「ポリフォニック」タイプであれば良いので、まとめてワークユニットツリーのキューシートにドラッグ&ドロップします。

すべてのマテリアルについて対応したキューが作られます。

テスト再生し、ループ再生などが問題ないことを確認します。

キューシートをビルドします。


UEでサウンドを視覚化する
UE5のエディタを起動します。
キューシートのインポート
AtomCraftでビルドしたacbファイル、acfファイルをコンテンツドロワー(コンテンツブラウザ)にドラッグ&ドロップしてインポートします。
acfファイルインポートの際に表示されるダイアログでは「Yes」を選択します。これにより、AtomConfigがプロジェクトに自動的に設定されます。

アセットがインポートされました。キューシートアセットをダブルクリックして開き、正常に再生されることを確かめます。

サウンド解析用のアクターの準備
エンベロープ解析はAtomComponentがあればどこでも可能です。
今回は中身を分かりやすくするため、新規にアクターを作成します。
コンテンツドロワー(コンテンツブラウザ)の適当な場所で右クリックし、「Blueprint Class」を選択します。

親クラスは「Actor」を選択。

新しいブループリントアクターが作られました。

Atom Componentを追加します。これはサウンド再生と解析、どちらにも使用します。

追加したAtom Componentを選択し、Detailsパネルで再生するキューシート及びキューを選択します。
今回は心拍の音を選択しました。

ブループリントアクターをレベル上にドラッグ&ドロップして配置します。

ゲームを再生し、アクターからサウンドが再生されていることを確認します。
画像ではコンソールコマンド「atom.3dVisualize.Enabled」を使い再生中のキューを視覚化しています。

エンベロープ解析
AtomComponentを使用してエンベロープ解析を行います。
AtomComponentを選択し、イベントグラフの空いている場所で右クリックして「Add Event for Atom」→「Event Dispatchers」→「Add On Atom Sound Single Envelope Value」を選択します。

イベントノードが配置されます。

「Envelope Value」というアウトプットピンから解析結果の数値が出力されますので、Print Stringを使って簡単に表示してみましょう。
毎Tick表示するのでログが流れないよう、Print Stringノードの「Duration」は「0.0」にしておきます。

画面左上に数値が表示されました。音に合わせて絶えず変化しているはずです。

音の変化を追いかける形で数値が変動しています。
変化に合わせて即座に数値を変動させたい場合やスムージングをかけたい場合(変動を遅くしたい場合)はDetailsパネルで「Anyalysis」のセクションを編集します。

「Envelope Follower Attack Time」は数値が高い場合への追従速度、
「Envelope Follower Release Time」は数値が低い場合への追従速度を指します。
これらを小さくすれば変動が速くなり、大きくすればその時間だけかけて追従していくことになります。
これらのオプションは、この後の「解析の視覚化」を実装した際に試すと効果が分かりやすいでしょう。

解析の視覚化
解析結果を一目で分かりやすいよう視覚化してみます。
Draw DebugLineノードで、現在時間を横軸、エンベロープ解析の数値を縦軸としてラインを描画し、グラフを形成します。
横軸はGet Real Time Seconds、縦軸はOn Atom Sound Single Envelope Valueイベントの「Envelope Value」です。

グラフはこちらからコピペできます。
ゲームをSimulateモードで再生します。解析結果を3次元の座標上に描画していくと……

グラフが現れました。時間経過と共に横の方へ描画されていきます。
心音がループしており、「Envelope Follower Attack Time」が低く(大きい数値への追従が速く)、「Envelope Follower Release Time」が高い(小さい数値への追従が遅く)ように設定されているためこのような形になりました。

ドラムループではこんな感じになります。
キックとパーカッションがそれぞれスパイクとして表示されていますね。

通常のBGMを再生すると、もう少し複雑なグラフになりました。

ここからのメッシュへの反映に備えて、Analysisセクションの数値を元に戻しておきます。

メッシュへの反映
メッシュのスケールにエンベロープ解析結果の数値を反映させ、簡単な演出を作ってみましょう。
StaticMeshコンポーネントやSphereコンポーネントなど、メッシュを表示できるコンポーネントを追加します。


やることは単純です。Set Relative Scale 3Dノードを使い、「Envelope Value」の数値をスケールとして代入しメッシュのスケールを変化させます。
もしアクターのスケールに関わらずメッシュのスケールを絶対的な数値として指定したい場合、アクターのスケールを反映しないSet World Scale 3Dノードを使用します。

再生すると、Sphereメッシュが音に合わせて大きくなったり小さくなったりしています。

音が無音の場合にメッシュのスケールも0になってしまうので、それを避けたい場合はメッシュのスケール二制限をかけましょう。
**Clamp(Float)**ノードを使い「Envelope Value」の数値に下限・上限をつけます。

また、「Envelope Value」を生の数値でなく任意の数値間の変動量として使いたい場合、Map Range Clampedを使い「0.0~1.0」の数値を好きな数値に変えてしまいましょう。

グラフはこちらからコピペできます。
ここで先ほどの「Envelope Follower Attack Time」や「Envelope Follower Release Time」を大きめに設定すると、メッシュの変化も緩やかになります。

エンベロープ解析によるオーディオの視覚化は実装が単純なわりに、ダイレクトに音を伝える手段として有用です。ぜひ演出のひとつとして使ってみてください。
