UnityAudioからCRI ADX2に乗り換えて簡単にリッチな音響体験を作ろう！Part3

# はじめに
この記事では3回に分けて実際にFPSのサンプルを改良しつつ、Unityのデフォルト機能を使って制作されたサウンドシステムをCRI ADX2で実装したものに差し替える方法を紹介しようと思います。今回は前回紹介した内容に加え、ゲーム制作には不可欠な環境による**音響効果**と**立体音響**の実装に関して紹介していこうと思います。


- [1.コンセプト紹介・CRI ADX2チュートリアル編](https://qiita.com/Hirai0827/items/8396c67983ba75b5dbe1)
- [2.サンプルプロジェクトのシステムをADX2で置き換えてみよう！編 1](https://qiita.com/Hirai0827/items/04e46014a3bd5803df68)
- 3.**サンプルプロジェクトのシステムをADX2で置き換えてみよう！編 2←ココ**

# サンプルプロジェクトの紹介
今回制作したのはサンプル用の簡単なFPSです。　WASDキーでキャラクターを操作してターゲットを撃ちましょう。制作に用いたモデル、シェーダーなどは全て今回のために制作したものなので、もし必要ならばそれらに関しては再配布しても問題ありません。

![eeda6a60648ebdd99ddd86814e408b7a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/743f10a0-94ab-c488-f68e-1131af7f82bf.gif)

https://github.com/Hirai0827/ADX2FPSSample/tree/implement-with-unity-audio

それでは第2回の続き、今回は音源にエフェクトを掛ける方法と、立体的な音響表現についてみてみようと思います。

## エコーの実装
インタラクションによって発生する音が環境から受ける影響を再現することを考えてみましょう。例えば、洞窟などといった閉所では、発生した音は直接耳に届いたり、壁に何度か反響してから耳に届いたりします。たどる経路によって音が耳に届くまでの時間が異なるので、音を聞く人にとっては同じ音声が少しずつ時間をずらして再生されているように感じます。これが**反響**と呼ばれる現象です。
![Reverb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/a5883634-ed3e-65dc-6bed-492cc426e5cc.png)

今回のサンプルゲームの例では、第一のステージが比較的開けた場所で第二のステージが下水道という狭い場所なので、第一ステージに比べて第二ステージの方が反響が強く出そうです。反響を効率的に再現するには信号処理の言葉で「**畳み込み**」と呼ばれる処理が必要となるのですが、これを実装するには信号処理やフーリエ変換の知識が必要になります。ADX2ではそのような技術をわざわざ学ばなくても、音源に簡単にエフェクトを掛けることができます。

### ミキサーを使う
Atom Craftは「**ミキサー**」と呼ばれる機能があり、簡単に音源にエフェクトを掛けることができます。早速「ミキサー」ウィンドウを開いてみましょう。下のバーから「ミキサー」ボタンをクリックし、青色にすれば、ミキサーウィンドウが開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/7601b795-e236-560b-d459-babd850703fb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/12eb7aa0-e1ee-ba1c-f8fe-e30690e84f2a.png)
ミキサーでは、音源に様々なエフェクトを掛けたものを合成することができます。複数のバス使ってエフェクトを掛けたのち、最終的にMasterOutに流れてきた音源が最終出力になります。

#### バスの設定
早速バスを作ってみます。ミキサーウィンドウの何もない場所をクリックして「DSPバスの追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/64717425-8393-2635-4768-1ba126203930.png)
新しいバスが生成されました。「センド」と書かれた部分に注目してください。新しく作成したBUS1の方はセンドがMasterOutになっています。これは、「バスを通った音源が次にどこに行くのか」を示したもので、今回の場合はBUS1を通った音源は次にMasterOutを通るよ、ということを示しています。これでBUS1でエフェクトを掛ければ、その音源をMasterOutに出力することができます。
![Bus.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/1db097f3-815c-85a5-3e54-dec505c8cc74.png)

試しにBUS1のエフェクト部分右上の「+」ボタンをクリックして「エコー」を追加してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/2c9d04d2-5638-82b5-7770-93b7b8ae160c.png)
「エコー」のエフェクトが追加されました。エコーについてのより詳しい設定は、エコーをクリックしたときのインスペクタウィンドウから行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/bf0c35a9-8356-8087-82c9-b714ced2ee95.png)

#### バスマップの作成

この時点ではまだ音源にエフェクトはかかりません。これは現状音源の出力先がすべて直接MasterOutにつながるように設定されているためです。BUS1にかけられたエコーを反映するには「音源を最初にどのバスに流すか」という設定で、BUS1を選ぶ必要があります。この設定をするために必要なのがバスの一覧、「**バスマップ**」です。プロジェクトツリーを開いて、「バスマップ→キュー設定用バスマップ」を右クリックして、「新規オブジェクト→バスマップの作成」を選択します。するとバスマップが作成されるので、それをクリックしてインスペクタを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/e4d28fbc-d76a-dbf5-d90f-44da2fc71f8c.png)
インスペクタには「バスセンド」という音声をどのバスに送るかの候補を登録するUIがあるので、そこに先ほど作成したBUS1を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/43cc2924-4756-7f46-346a-e6acfc9f90cd.png)

#### キューから再生される音声の送り先を選択する
この「バスマップ」に登録されたバスの中から、キューから再生される音声の送り先を選択することができます。再びエフェクトを掛けたい音源のキューを選択してインスペクタの「バスセンド」ボタンを選択します。右上にバスマップを選択するドロップダウンがあるので先ほど作成したバスマップを選択します。これでMasterOutとBUS1のどちらにも音声を送ることができるようになりました。デフォルトだとMasterOutのスライダが最大で、BUS1のスライダが最小なので、音声は全てMasterOutに直接流れることになります。試しにMasterOutのスライダを最小に、BUS1のスライダを最大にして再生してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/0391e5d0-7562-4642-5d62-2ece5974354f.png)
どうでしょうか？音源に若干エコーがかかったように聞こえましたか？もしよくわからなかったら、ミキサーの「エコー」エフェクトをクリックして、インスペクタからゲインを「0.6」ぐらいにしてみましょう。音が何度もなっている感じがより強く表現されるはずです。
↓エコーの設定項目。「最大ディレイ時間」までの間「ディレイ時間」ごとに「フィードバックゲイン」倍した音源を再生する。これが離散化された畳み込みに相当します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/d3bd6a2a-9837-a9bd-d3a2-1c6ec8d18e1e.png)
![Echo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/de58c0eb-a87c-5036-09ae-9c971b20f635.png)

バスセンドによる音声の送り先は複数選択することも出来て、その場合は複数のエフェクトを合成したような形になります。
このように「ミキサー」を用いて音声にエフェクトを掛けることが出来ました。

#### Unityからバスセンド先を変更する
実際ゲーム中にどのバスにどれだけの音量を通すか、というのはデータ（Atom Craftで設定したもの）と、Unity側で設定する「バスセンドレベル」の積によって設定されます。そのため、Unity側でゲームの進行に応じてバスセンドレベルを調整することで、「特定の環境下で音声にエフェクトがかかる」、といった演出をリアルタイムに行うことができます。

まず、キュー側のバスを全て1.0（最大値）に設定します。すべての設定はUnity側で行うため、こちらは全開にしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/55ee88c8-b516-152d-701e-49cf13349721.png)

ここまで設定したらUnity向けのビルドを実行します。詳しい方法に関しては[第一回](https://qiita.com/Hirai0827/items/8396c67983ba75b5dbe1)をご覧ください。

バスセンドレベルをUnity側で変更するためのコードを書いていきます。ある音源(AtomSource)のバスセンドレベルを変更するには`CriAtomSource.SetBusLevel`で行うことができます。

```C#
//CriAtomSource.SetBusLevel(string busName,float busLevel)
//開けた場所なら通常の音、開けた場所ならエコー
        switch (environment)
        {
            case EnvironmentKind.Open:
                source.SetBusSendLevel("MasterOut",1.0f);
                source.SetBusSendLevel("BUS1",0.0f);
                break;
            case EnvironmentKind.Closed:
                source.SetBusSendLevel("MasterOut",0.0f);
                source.SetBusSendLevel("BUS1",1.0f);
                break;
        }
```

このようにCriAtomSourceにバスレベルの設定を施したのち`CriAtomSource.Play`で再生すると、環境に合わせたエフェクトを掛けた音源を再生することができます。

#### AISACを用いてバスセンド先を変更する
上の例で用いたバスマップはキュー設定用バスマップと呼ばれるものでしたが、バスマップにはそれ以外にもAISAC用のバスマップも存在し、それを利用することでピッチ操作で紹介したのと同様にAISACを用いてバスレベルを調整することもできます。

## 環境音を設定する
ゲーム内のシーンの説得力を増すために環境音を設定することを考えます。特定のオブジェクトから音源を鳴らす
### 音響を2Dにする・3Dにする
人間は音が左右の耳に届くまでのタイムラグや、左右の耳に届く音の音量差で音源がどちらにあるのかを推定する能力を持っています。逆に意図的に左右から出力する音量を制御することで、あたかも特定の方角や距離から音源が再生されているように見せかけることが出来ます。例えば、右側に比べて左側の音量を大きくすれば、音源が左側があるかのように表現することが出来ますし、音量を意図的に小さくすることで音源が遠くにあることを暗に示すこともできます。このように音響によって空間を表現する仕組みのことを**立体音響**と呼びます。
ゲーム制作の文脈においては、立体音響を使うべき場面と使わなくても良い場面が存在し、例えば前面に開くようなメニュー画面におけるUI操作の効果音などは立体音響である必要はありませんし、その一方で3Dゲームにおける銃声や爆発音などは立体音響であった方が説得力が増すでしょう。また地面に埋まった爆弾や隠された宝箱など、視覚的には認識しづらいもののゲーム上重要なオブジェクトに対して、立体音響を用いた（例えば「ピコン、ピコン」といった）アラームを鳴らすことによって、ユーザにその存在や主な位置などを気づかせるといった演出を行うことも出来るでしょう。

![3D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/22942ec9-2fa0-f30a-612c-417fe9d17fff.png)

今回のサンプルの例だと、常に自身を中心として鳴る銃声などには立体音響を使う必要はないでしょう。一方で、例えば噴水からなる水の音や、下水の水が落ちる音などは立体音響を用いないと、プレイヤーの向きに対応した不整合が発生してしまうため、立体音響が有効でしょう。

それではUnityAudioとADXのそれぞれでどのように立体音響を実現するかをみていきましょう。

UnityのAudio Systemでは、インスペクタから簡単に音源を2次元・3次元に切り替えたうえで、グラフを用いて音量などが距離から受ける影響を設定できるようになっていました。
↓UnityのAudioSource
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/646faebf-1cc7-9357-8ed3-4fa59fa5b24e.png)
一方でADXのAtom Sourceのインスペクタにはそのような設定が可能なグラフは存在しません。
↓ADXのAtomSource
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/2512130c-0230-1915-4062-22477104bdb6.png)
Unity側のインスペクタに存在するこれらのグラフは、音響が距離から受ける効果を意図的に強調し、ゲームにおける体験をより向上させるのに重要な役割を持っています。ADXではこのような音響と距離の効果をどう設定するのか見てみましょう。

### ADXによる3Dポジショニングの設定
#### Atom Craft側の設定
それでは、ADXを用いて噴水の音を立体的に表現してみましょう。まずはAtomCraftを開きます。新規作成したキューに水音のループ素材を登録します。特にキューで複雑なことをする予定はないので、キューの種類はポリフォニックでOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/17680338-7b4e-d322-5c4e-499ffc41decf.png)
次に、ADX側で立体音響を利用可能にするための設定をします。キューに登録した音源をクリックした状態で、インスペクタを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/7bd37084-9022-7714-d5c4-07b522d53d2a.png)
設定可能な項目のなかに「パン設定」と呼ばれる項目があるので、これを「3Dポジショニング」か「オート」に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/ec61f8d7-b9a8-7200-3bd1-c5b859d0a86e.png)
これによって、キューが再生されたときにUnityシーン上の耳(Atom Audio Listener)と音源(Atom Source)の位置関係をパン（ヘッドホンの左右から出力される音の大きさの違い）に反映することが出来ます。

キューの設定が終わったら、前回同様Unity向けにビルドを実行します。
#### Unity側でAtom Sourceコンポネントを生成する
Unityプロジェクト側でAtom Browserウィンドウを開いて、先ほど作成したキューがちゃんとビルドに含まれていることを確認して、シーン上にAtomSourceを生成します。今回は任意のオブジェクトと同じ座標から音声を鳴らしたいので、Atom BrowserのAdd Componentを利用しましょう。音源として登録したいオブジェクトを選択した状態でAtom Browser下部のAdd Componentを選択すると、そのオブジェクトにAtom Sourceコンポネントが追加され、音源として機能するようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/93a26ee8-2a99-ffe5-f61b-f67dba0ce0ee.png)
今回は水音が初めから最後まで永続的に鳴っていてほしいので、インスペクタの`PlayOnAwake`と`Loop`にチェックを入れておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/aa553c24-3f70-4a44-f5f8-4fb87c12c6ad.png)
Atom Sourceコンポネントにはデフォルトで3DPositioningのチェックが入っているので、一見するとこれだけで立体音響として機能するように思えますが、もう少しだけ設定が必要です。
#### Audio Listenerを差し替える
ADXの立体音響システムを利用するには、UnityデフォルトのAudio ListenerをADX仕様のものに差し替える必要があります。Playerが持つカメラについたAudioListenerコンポネントを削除して、Atom Audio Listenerコンポネントを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/67a061a2-45c9-4adb-5226-3e2a6f7a650a.png)
プロジェクトを再生してみます。マウスをグリグリしてプレイヤーの向きを回転させると、噴水のある方向から音が聞こえてくることがわかると思います。
### 音源が距離から受ける影響を調整する
現実では、例えば音源からの距離が離れるにつれてその音量は小さく感じられる、といったように音源と耳の距離によって感じられる音が変化します。UnityAudioにはそれらの減少を再現するためのグラフがありました。Audio Clipのデフォルト設定では、プレイヤーと音源の距離に応じ
てその音量が対数的に減少していくように設定されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/646faebf-1cc7-9357-8ed3-4fa59fa5b24e.png)

この対数は「人間が認識する音量は物理的な波形から算出される音量に対して対数的になる」、という、「ウェーバー・フェヒナー (Weber-Fechner) の法則」に基づいたもので現実に即しています。しかし、ゲームデザイン上しばしば重要とされるのは「現実的に正しい」ことではなく、「プレイヤーに伝えるべき情報をしっかり伝えられる」ことであったりします。この距離による影響をよりこだわって設計することが出来れば、よりリッチでわかりやすい表現ができます。
Atom Sourceにはインスペクタでこれらのグラフを編集するのではなく、Atom Craft上で事前に効果を設定したものを利用します。
#### お手軽に設定する
ADXでは、3Dポジショニングがオンになっていればデフォルトで距離と音量が比例するような形の距離減衰が適用されます。Atom Craftでは音響が最大となる距離と、最小となる距離をパラメータから設定できます。キューに登録した音源ファイルを選択した状態でインスペクタを開き、3Dポジショニングのタブを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/9421b4ea-98ea-3e28-3777-b45bf35cd51d.png)
中に距離減衰を設定する項目があるので、この「最小」「最大」のパラメータを編集することで、「通常より遠くまで届く音声」、「近くでしか聞こえない音声」を設定することが出来ます。このパラメータはUnity上の距離(m)を示していて、物体とプレイヤーの距離が最小未満なら100%の音量で、最大以上なら0%の音量で、その間なら線形補間された音量で音源が再生されます。試しに噴水の音の距離減衰の最小を「3.0」、最大を「10.0」にしてみます。再びビルドすると、かなり噴水に近づかないと水音が聞こえないことがわかると思います。デフォルトの状態だと最小が「1.0」、最大が「500.0」だったので、距離によっては音量の減衰がわかりづらかったかもしれませんが、このように最大と最小距離が比較的近いようなパラメータだと、その減衰がはっきりわかると思います。また、「最小」の値を十分大きなものにすると、「向きによって左右の音量は変わるけど、常に聞こえる音声」を作ることが出来ます。

#### AISACを用いてより複雑な表現をする
[第二回](https://qiita.com/Hirai0827/items/04e46014a3bd5803df68)でパラメータにランダム性を持たせるために利用したAISACですが、距離と音源のパラメータをグラフとして表現することにも使えます。
AISACについての詳しい解説は先述の第二回を参照してもらうとして、今回はAISACを利用した距離減衰の設計の方法を紹介します。
前回同様AISACウィンドウからAISACを作成します。ボリューム用のグラフを作成して、コントロール値が0.0の時AISAC値が1.0、コントロール値が1.0の時AISAC値が0.0となるようにポイントを作成します。先ほどの3Dポジショニングの最小・最大の間をこのAISACの0.0~1.0の部分で補間することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/5ab4fb99-7729-8d42-3f95-64b89f75bfd4.png)
このカーブの形状を編集することによって、任意の距離減衰を表現することが出来ます。今回はUnityAudioSystemデフォルトの対数関数っぽい距離減衰を表現してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/66b0a229-3bc5-292d-0837-0cd7d83935c8.png)
このままだと直線的なグラフになってしまうのでカーブを持たせます。コントロール値1.0のポイントを選択した状態でインスペクタを開き、フェードカテゴリのカーブタイプを高速変化にします。AISACウィンドウを確認するとカーブが生成されているのを確認できると思います。インスペクタのカーブの強さを編集すれば、カーブの急具合を調整することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/f98ae00c-e86b-aed4-c140-55b8d58fe87c.png)

制作したカーブを距離減衰に適用します。再度インスペクタ上で3Dポジショニングカテゴリを選択して、AISACコントロールの部分から距離減衰の欄を「なし」から制作したAISACに変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256231/7cc8750f-54bf-33a1-f11c-1dbfbebdb0f5.png)

プロジェクトの変更を保存して再度Unity向けにビルドすれば、AISACで作成したカーブが適用されます。直線と対数関数的な距離減衰だと少し変化がわかりづらいかもしれませんが、設定が反映されているのが確認できると思います。

### まとめ

今回はCRI ADX2を用いてUnityAudioにおける基礎的な音響システムを置き換えてみる、という試みについて、特にバスを用いたエフェクトの追加や、3D音響について、ということについて解説しました。今回紹介したように、ADX2ではAtom Craftを利用してUnityに依存せず様々な音響効果を付与することができます。ぜひ他のADXの機能も利用して、より良い体験創造を目指してみてください。