ADX for UEで、プレイヤーの聴覚の変化を演出する

# はじめに
アンリアルエンジンとサウンドミドルウェア「ADX for UE」を連携させ、プレイヤーキャラクターの聴覚の変化を演出する実装例です。
ミリタリー系のFPSによくある、「近くで起きた大きな爆発により一時的に耳鳴りが聞こえ、他の音が聞こえづらくなる」といった表現や、「キャラクターの聴覚が研ぎ澄まされ、小さな音が聞こえやすくなる」といったゲームメカニクスに影響するギミックにも使えそうです。

この記事では「カテゴリ」機能と「Aisacコントロール」機能を使い、効果音に高音をカットするフィルタをかける（耳鳴りなどのシステム音にはフィルタをかけない）手法で実装していきます。


# 前提

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

なお、ADX2は「ADX」へ名称が変更になりましたが、ツール構成は変更ありません（2がないから古いほう、というわけではありません）。

記事執筆時点のADX for UEのSDKバージョンはADX LE UE SDK(1.31.00.01)です。

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

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

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

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


# 実装

## AtomCraftでサウンドを構成する

まずはサウンドオーサリングツール「AtomCraft」にて必要なサウンドを構成します。

### マテリアルのインポート

必要となる効果音素材（マテリアル）をインポートします。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c9454dd3-48b8-f070-88a3-7271511655bf.png)
今回はサンプルとして、銃撃音となる「SE_BulletLoop.wav」と耳鳴りの音である「SE_Tinnitus.wav」をインポートしました。
「SE_BulletLoop.wav」を選択し、ループ再生されるようインスペクターにて設定します。
ループ情報の上書きを「True」、ループタイプを「ループ」とします。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/aa5727f3-2fd6-0d7f-7598-29ae4be954cb.png)


### キューの作成

キューを作成します。
キューシートを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5a945fd6-6ff1-c2b4-72c0-1e1f45a82c7e.png)
ふたつのキューを作っておきます。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1a5330a4-9a9b-7dfc-af94-279a3e7ce4fb.png)
それぞれのキューにマテリアルをドラッグアンドドロップして配置します。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5110aab9-c97a-424a-ff42-6a9d29647daf.png)
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/15b13312-9919-adb6-98cb-1c121c40f2de.png)


### カテゴリの設定

効果音のみにフィルタがかかり、BGMやシステム音にはフィルタがかからないよう「カテゴリ」を設定します。
プロジェクトツリーの「カテゴリ」内、「CategoryGroup_0」（任意のカテゴリグループでもかまいません）を右クリックし「新規オブジェクト」→「カテゴリの作成」を選択します。
![A07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5f475257-8975-31c7-11c0-861220c8f62e.png)
それぞれに「SE」「System」と名前をつけます。
![A08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5dc85fbf-1507-d15d-b0ca-afc30e5ede26.png)
キューを選択し、インスペクターの「カテゴリー」にある「編集」ボタンをクリックします。
![A09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/31adff27-c9c1-f3ed-b518-ea6843d08b03.png)
「カテゴリの編集」ウィンドウが開くので、該当するカテゴリのみにチェックをつけます。
「Cue_BulletLoop」なら「SE」、
![A10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/543b95cb-775e-7f7f-01b4-d8c60844bbc4.png)
「Cue_Tinnitus」なら「System」です。
![A11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d8157443-6c3e-74f9-a0e1-68210aa42e06.png)



### グローバルAisacの設定

フィルタをかけるためのAisacコントロールを作成します。
今回は対象となる効果音すべてに対してフィルタを適用したいので、「グローバルAisac」機能を使用します。

プロジェクトツリーの「グローバルAISAC」を右クリックし、「新規オブジェクト」→「AISACの作成」を選択。
![A12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3addf4c9-558a-3940-5096-32c77f0563fe.png)
AISACコントロール名を控えておきましょう。
AISACグラフタイプは「バンドパスフィルター」→「バンドパス - Cof高域」を選択します。
![A13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/85867bdc-27a4-e479-f9c4-23cb542fa46d.png)
作成したAisacコントロールをダブルクリックし、次の画像のような簡単なグラフを作ります。
カーブや遷移具合などはUE側で調整するので、単純なグラフで大丈夫です。
![A14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6fe81495-6131-e848-88a7-cbb08c4e8272.png)
フィルタのかかり方をテストしてみましょう。
作成したAisacコントロールを、任意のキューにドラッグアンドドロップします。
![A15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ebd7a023-7a20-7b6d-e3f0-0fc04defe5d0.png)
「LinkAisac」が作られ、このキューにグローバルAisacが適用された際の挙動を確認できるようになりました。
![A15b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4c760d37-90f9-3644-0fde-7d74704971b0.png)
再生して、スライダーを動かし挙動を確認します。
![A16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/079ba36a-eb53-9853-dc24-c13c737eecd0.png)

Aisacを選択し、「デフォルトコントロール値」にチェックを入れておきます。
デフォルト値を使用しない状態でUE側でタイムラインノード等を使用しサウンドを変化させた際、実際のAisacコントロール値との間にギャップが生じる可能性があるためです。
![E01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/feb3ef57-0e5c-d159-307d-1500687b0234.png)



### キューシートのビルド

ここまでできたらキューシートをビルドし、UEに持っていきます。
![A17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/81f4f8e0-0655-9219-6427-80247145e1a7.png)
![A18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7461709b-1a0e-85bf-3131-3c532dd138a3.png)



## UEで演出を実装する

ここからはUE5で実装をしていきます。

### キューシートのインポート、サウンドの配置

ビルドしたacb、acfファイルをコンテンツブラウザの任意の場所にドラッグアンドドロップしてインポートします。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b2eda7d2-dce7-f04a-fd2b-3583fb4162db.png)
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/99a606ee-d955-0d66-cac3-8ab8804a95d8.png)
プロジェクト設定を開き、
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/741779c2-775b-fb79-4bd2-040aefa10a1e.png)
「CriWare」タブにて「Atom Config」にビルドしたacfファイルを指定します。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f9f400b9-8965-68dc-d958-16928820038c.png)
レベルにループ音を配置し、正常に再生されるか確認しておきましょう。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/86f3031e-1584-02df-b04e-f3963a9296ca.png)


### Aisacコントロールでエフェクトをかける

レベルブループリントを開きます。
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5ec1ce4f-0b3b-7e01-8ec4-4e8902b3f747.png)
1,2キーで起動するイベント **Input Key 1**、**Input Key 2**を作成します。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d54d0e92-8762-1c2a-3dd5-2123ac15568c.png)
カテゴリに対してAisacコントロールをかけるには、**Set Aisac Control by Name**ノードを使用します。
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3f387a2b-6384-a483-70f3-811d03f822ff.png)
1,2キーを押すとそれぞれ、「SE」カテゴリに対して「バンドパス - Cof高域」の効果が「0.2」「0.9」かかるよう入力してみます。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e8a27033-5cba-d068-e746-18d5a34e4ac5.png)

ゲームを再生し、1,2キーを押して聞こえ方を確認してみましょう！
2キーを押してAisacコントロールの値が「0.9」の状態では、よりこもって音が聞こえるはずです。


### タイムラインを使用して遷移を作る

現状では突然音がこもって聞こえる状態なので、聞こえ具合がなめらかに変化するようタイムラインを使って遷移を管理します。
イベントグラフの空いている場所で右クリックし、「Add Timeline」を検索して配置します。
![C01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4fb611d4-ddcd-2385-686d-7e40018549a3.png)
タイムラインには任意で名前をつけられます。
ダブルクリックしてタイムラインを編集しましょう。
![C02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c85f820d-5035-72bf-edeb-fdff3566886d.png)
「+Track」のボタンを押し、「Add Float Track」を選択します。
![C03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/08ca0fb5-933f-1d43-a737-61635b4f6399.png)
Floatが扱えるグラフが作成されました。
![C04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e7a80a5b-1667-efb5-ba7d-e048a95e48cd.png)
グラフの線を右クリックし、「Add key to CurveFloat」でコントロールポイントを追加します。
![C05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7a24ac63-a448-0af5-b884-db6a7904a747.png)
0.5秒かけて値が「0.0」から「0.8」まで遷移するグラフを作りました。
![C06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5ef64c66-bd04-5fe0-04cf-a093246ea593.png)
「Length」を「0.05」にし、**グラフの長さを遷移時間と一致させましょう**。
これらが一致しない場合、タイムラインの逆再生をする際うまく処理されない場合があります。
![C07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3081bc4d-206a-71b4-37f3-a07c344a947f.png)
コントロールポイントを右クリックすればカーブタイプも設定できます。
![C08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/dff1c45f-6b0d-1089-dbb2-297fa3ceebea.png)
イベントグラフに戻り、次の画像のようにつなげます。
1キーを押すとグラフが再生され音が徐々にくぐもり、2キーを押すとグラフが逆再生され音が徐々にクリアに聞こえるようになります。
タイムライン内で数値が変動した際、**Set Aisac Control by Name**ノードによりAiscコントロールが行われます。
![C09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0914df70-e768-4ee7-1c6e-2a8c39bc06e0.png)



### 演出に影響されないサウンドの再生

さて、仕上げとして耳鳴りの音を「バンドパス - Cof高域」の効果を受けずに再生したいところです。
既にAtomCraftでカテゴリの設定をしており、**Set Aisac Control by Name**ノードでは対象となるカテゴリを「SE」に指定しているので、「System」カテゴリに属する耳鳴り音はこのまま再生しても影響を受けなくなっています。

つまり、単純に耳鳴り音のキューを再生するだけで処理は完成です。
![D01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b68f3825-e48c-725e-9014-646dcdbf5e4b.png)


## 補足

タイムラインの再生処理を連続で行ってしまうと、「Play from Start」「Reverse from End」のインプットピンを使っているため遷移が最初から行われてしまいます。
現在の値を保ったままにしたい場合、「Play」「Reverse」ピンを使えばOKです。
![D02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ff71635b-8df7-d6b8-c989-b86dd7c66198.png)