AudioMixerを活用して、サウンド調整の処理

# サウンド周りの調整、管理

---

## はじめに:

Unityでサウンドの処理（サウンドの音量を調整や再開、ストップ、一時停止など）はAudioSourceというComponentでやるのは一般的かもしれません。ですがこれは一番良い方法ではないと思います。Unity提供したAudioMixerを活用してゲームサウンドの調整処理をしてみました。

---

## UnityのAudioMixerの紹介：
Unity Docのページに「Unity のオーディオミキサーでは、いろいろな音源をミックスしたり、それにエフェクトをかけたり、マスタリングを行ったりすることができます」が書いてあります。AudioMixerを使用すると、音量レベルを変更したり、信号をグループにルーティングしたり、オーディオエフェクトでサウンドを処理したりできます。

+ [マニュアル][Audio Mixer Doc]
+ [スクリプトリファレンス][Audio Mixer Scripting Doc]

---

## AudioMixerを使うの設定ステップ：
ゲームによる、ゲームのサウンドタイプが違います。今回は下記のサウンドタイプを分けています。
+ BGM
+ SFX (インゲームのサウンドエフェクト)
+ UI　(UIのサウンドエフェクト：ボタンクリック、ポップアップなど)

1. Audio Mixerの作成：
![CreateAudioMixer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/c444d2ab-7c7a-2bbe-e9ca-429b77d85715.png)


2. Audio Mixer Windowを開く：
![AudioMixerWindow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/08221b94-2b4b-43c6-c73b-a2a6b5488447.png)


3. Master Group下に、サウンドグループを追加します：
![AddSoundGroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/d222b54c-86d6-2685-662d-6a3b6a559252.png)
MasterグループはAudioMixerのDefaultグループです。  
画像を見るとbgm, sfx, uiグループはMasterグループの下に配置されています。

4. シーンにAudioSourceのGameObjectを作成する：
![SampleSceneHierachy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/d167de91-cc80-8eca-8c7d-3704ef5c909e.png)


下記は一般的な設定ですね。
　
![NormalSoundSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/983d2e76-4c03-074c-82e2-35f050418d5e.png)


AudioMixerをつかうなんで、こんな形に設定する。

!(AudioMixerSoundSetting.png)![AudioMixerSoundSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/580a0724-62d1-8d99-e2a6-a65baeb3b795.png)


**簡単解説**
+ AudioSourceのOutputを何も設定しない場合、音声の挙動はこんな流れです：

    ![NormalSoundPlayFlow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/dceab00d-c1cf-161d-6c45-db674ae4dc91.png)


    > **メモ**：  
Audio Listener は、マイクのようなデバイスとして機能します。これは、シーン内で所定の Audio Source からの入力を受信し、コンピューターのスピーカーを通じて音声を再生します。ほとんどのアプリケーションで、メインの カメラ にリスナーを追加するのが一般的です。オーディオリスナーが リバーブゾーン の境界内にある場合、それはシーン内のすべての可聴音が適用されます。さらに、Audio Filters をリスナーに適用でき、シーン内のすべての可聴音に適用されます。

+ AudioSourceのOutputをMixerグループに設定する場合、音声の挙動はこんな流れです:
  
    ![AudioMixerSoundFlow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/23d295d1-31a5-d051-f341-af95b9ceebd0.png)


5. MixerのパラメーターをExportする：

MixerグループのVolumeパラメーターをExposeする。ParameterをExposeのははRuntimeコードでMixerのパラメーターを調整できるためです。
![ParameterExpose.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/50ae671f-9703-002e-34a2-3f1371c542f2.png)


Exposeされたパラメーターリストです
![ParameterList.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/05aecc63-61f4-5fe2-3b0e-5ea7d53c8559.png)


ここまでの設定は完了しました！！！

---

## 今までのやり方：
![CommonDesign.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156015/846a81bc-41ef-d9a5-3b1a-55eea2fd9dac.png)


### **シナリオ：**
ユーザーがオプションで音量調整する場合、サウンドマネジャーに、一般的下記の処理を行うと思います

```csharp
[SerializedField] private AudioSource[] _seAudioSourceArray;
[SerializedField] private AudioSource[] _uiSfxAudioArray;
//...

// SEのVolumeを設定したい時に呼ぶメソッド
public void ChangeSEVolume(float vol){
    foreach(var audio in _seAudioSourceArray){
        audio.Volume = vol;
    }
}

// Master（ゲーム全体の音声）のVolumeを設定したいときに呼ぶメソッド
public void ChangeMasterVolume(float vol){
    foreach(var audio in _seAudioArray){
        audio.Volume = vol;
    }
    foreach(var audio in _uiSfxAudioArray){
        audio.Volume = vol;
    })
    foreach(var audio in _xxxxxxxxAudioArray){
        audio.Volume = vol;
    })
    ...

    // もしくはこんな感じ
    var audios = GameObject.FindObjectsOfType<AudioSource>();
    foreach(var audio in audios){
        audio.Volume = vol;
    }

    //....設定方法はいっぱいありますがだいたい上記感じかな。。
}
```

上記の処理で感じる事：
+ コード書くのが多い。
+ LoopでAudioSourceづつの音量を設定しないといけない。
+ Master音量だけ調整するとエフェクトの音量やUIの音量なども影響されます。（音量のバランスがなくしました）。  
  例えば：  
  Master音量が10ときに、effect音量を8にセットしました。  ＝＞effect音量とMaster音量は10分の8
  Masterを6にセットする。この場合、effect音量とMaster音量は10分の8を変わらない事をほしかったですがEffectもMasterと同じく6なってしました。。

### **上記のシナリオでAudioMixerを使います：**

ユーザーがオプションで音量調整する場合、サウンドマネジャーに、下記処理をおこまいます。

```csharp
[SerializedField] private AudioMixer _audioMixer;

// SEのVolumeを設定したい時に呼ぶメソッド
public void ChangeSEVolume(float vol){
    _audioMixer.SetFloat("sfxVolume", ConvertVolumeToDecibel(vol));
}

public void ChangeMasterVolume(){
    _audioMixer.SetFloat("MasterVolume", ConvertVolumeToDecibel(vol));
}

// 要注意な点はここで設定する値は 0 ~ 1 の値ではなくdB単位( -80 ~ 0 )なので直感的な0 ~ 1での制御をし
// たい場合は別途 0 ~ 1 をデシベルに変換する関数を作成する必要がある
// 0 ~ 1の値をdB( デシベル )に変換.
private float ConvertVolumeToDecibel(float vol){
    var result = 0f;
    var vol = Mathf.Clamp(vol, SoundConfig.VOL_MIN_VAL, SoundConfig.VOL_MAX_VAL);    
    // normalize = (zi - min(x)) /  (max(x) - min(x))
    var normalize = (vol - SoundConfig.VOL_MIN_VAL) / (SoundConfig.VOL_MAX_VAL - SoundConfig.VOL_MIN_VAL);
    // AudioMix min: -80db, max: 0db
    var masterVolume = normalize * 80 + (-80));
    return result;
}

```

上記の処理で感じる事：
+ コード書く大体簡単くなりました。
+ Master音量だけ調整するとエフェクトの音量やUIの音量なども影響されない。（、音量調整はAudioSource毎に行うではないですから音量のバランスはそのままで保留できます）。

---

## 結論:
+ AudioMixerはAssetなので、サウンド周りのバランス（Master、ui, effect,...）の調整はEditorで調整できます。
+ サウンドの調整コードも軽くなります。
+ 簡単にオーディオレベルを制御したい、AudioMixerはベストチョイスです。

---

## 更にTipです：
### **PlayOneShotを効果的に使用する**:
非常に基本的なアドバイスのように思えますが、Unityフォーラムで繰り返し質問される質問です。

「最初のサウンドを停止せずに、2番目のサウンドを再生するにはどうすればよいですか？」

シンプルで、PlayではなくPlay One Shotを使用します。

>PlayOneShotは標準のPlay機能と同じように機能しますが、いくつかの重要な違いがあります:
>+ **PlayOneShotは、オーディオソースで既に再生中のクリップを中断しません**  
これにより、マシンガンの発射、足音、スイング、ヒットなどの繰り返し音に最適です。
>+ **PlayOneShotでは、関数を呼び出すときに再生するオーディオクリップを指定する必要があります**  
これにより、オーディオソースのクリップフィールドを交換する代わりに、バリエーションにさまざまなクリップを簡単に使用できます。
>+ **PlayOneShotを呼び出すときに、クリップの音量スケールを設定できます。**  
これにより、クリップのボリュームが（0-1のフロートスケールで）変更され、オーディオソースの全体的なボリュームに影響を与えずにサウンドをランダム化するのに最適です。

スクリプティングでは、PlayOneShotは次のようになります。
```csharp
audioSource.PlayOneShot（audioSource.clip、0.75f）;
```

> PlayOneShotでトリガーされた複数のオーバーラップサウンドはすべて、総音声カウント（デフォルトでは32）にカウントされることに注意することが重要です。そのため、クリップがCulledされないように、繰り返し音の尾を短くするように注意してください。

[Audio Mixer Doc]: https://docs.unity3d.com/ja/current/ScriptReference/Audio.AudioMixer.html
[Audio Mixer Scripting Doc]: https://docs.unity3d.com/ja/current/ScriptReference/Audio.AudioMixer.html