【Unity(C#)】AudioMixerでアプリ内の音量をBGM、SEなどにグループ分けして操作する

# はじめに

下記ツイートの動画のようなBGM、SEなどを簡単に変更できる実装方法を教えてもらったのでメモします。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今更ながら、こういうAudio関連の実装のメモを記事化してます🙆‍♂️ <a href="https://t.co/1tnNx09IUJ">pic.twitter.com/1tnNx09IUJ</a></p>&mdash; KENTO⚽️XRエンジニア😎Shader100記事マラソン挑戦中39/100 (@okprogramming) <a href="https://twitter.com/okprogramming/status/1441947305402200066?ref_src=twsrc%5Etfw">September 26, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# バージョン情報

| 諸々名前 | バージョン |
|:-:|:-:|
|  Unity | 2020.3.4f1  |
|  UniRx | 7.1.0  |


# 実装
大まかな流れとしては下記です。

**①Mixerを作成する。
②Mixer内で”SE”、”BGM”などのGroupを定義する。
③AudioSourceにMixerのGroupを割り当てる。
④Sliderの値をMixerのGroupに渡す。**

## ①Mixerを作成する

まずはAudioMixerを開きます。`Window` -> `Audio` -> `AudioMixer`の順です。
![Chu1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/99b125e0-dfed-1e12-2ebc-1cdb581c7193.png)

未設定の場合、下記のような状態です。
`＋`を押下してMixerを作成します。
![Chu2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/b47905ad-6a09-56bd-ff1d-96232ccb4e4d.png)

作成すると下記画面となります。Mixerに適当な名前を付けることができます
![Chu3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/947040b4-0795-de18-9831-7514fc301891.png)

## ②Mixer内で”SE”、”BGM”などのGroupを定義する

GroupsのMasterを選択した状態で`＋`を押下することで新しいGroupを定義できます。

![Chu4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/a7c9b760-90be-8b33-f4f9-4f5da81de0fd.png)

次にGroupのVolumeをパラメータとしてScript側に公開する設定をします。
任意のGruopを選択した状態でVolumeのパラメータ上で右クリックをします。
`Exposed Volume to script`を選ぶことでVolumeの横に矢印マークが出ます。
![Chu11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/5cf5a05a-f4c7-1bc0-31b1-6171bb15b605.gif)

これでScript側から操作が可能になりました。
あとは、呼び出す際のパラメータ名を任意の文字列に変更します。
AudioMixerタブの右上にあるExposedParametersから変更可能です。

![Chu5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/e1f4ce44-a943-a07f-f124-65a6dd363d84.png)

SEに変更するとScript側で任意の関数の引数に"SE"を渡すことで値を参照できます。
![Chu6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/4a0e476a-a6a4-6dce-e3f4-e94bd7b30ae9.png)

## ③AudioSourceにMixerのGroupを割り当てる
AudioSourceにある`output`の設定項目に先ほど作成したGruopを設定します。
![Chu12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/e39e8eb2-3e9d-b9e8-bc15-70f33f72feb3.gif)


## ④Sliderの値をMixerのGroupに渡す

ここまででScript側からMixerの値を変更する準備が完了しました。
あとはコードでSliderの値をMixerに渡せばOKです。

```cs
using UniRx;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

/// <summary>
/// ボリュームの設定
/// </summary>
public class VolumeSettings : MonoBehaviour
{
    /// <summary>
    /// Mixer
    /// </summary>
    [SerializeField] private AudioMixer _mixer;
    
    /// <summary>
    /// MasterVolumeのスライダー
    /// </summary>
    [SerializeField] private Slider _masterVolumeSlider;
    
    /// <summary>
    /// BGMのスライダー
    /// </summary>
    [SerializeField] private Slider _bgmSlider;
    
    /// <summary>
    /// SEのスライダー
    /// </summary>
    [SerializeField] private Slider _seSlider;

    /// <summary>
    /// インスタンス
    /// </summary>
    private static VolumeSettings _instance;
    
    void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad (gameObject);
        }
        else 
        {
            Destroy (gameObject);
        }
    }
    
    private void Start()
    {
        //================================
        // Sliderの値をMiserへ
        //================================

        SetSliderValueToMixer("Master", _masterVolumeSlider);
        SetSliderValueToMixer("BGM", _bgmSlider);
        SetSliderValueToMixer("SE", _seSlider);
    }
        
    /// <summary>
    /// 0 ~ 1の値をdB( デシベル )に変換
    /// </summary>
    /// <param name="volume">ボリューム</param>
    /// <returns>変換後のデシベル</returns>
    private float ConvertVolume2dB(float volume) =>
        Mathf.Clamp(20f * Mathf.Log10(Mathf.Clamp(volume, 0f, 1f)), -80f, 0f);

    /// <summary>
    /// Sliderの値をMixerに設定
    /// </summary>
    /// <param name="groupName">グループ名</param>
    /// <param name="slider">値を通知するスライダー</param>
    private void SetSliderValueToMixer(string groupName,Slider slider)
    {
        slider.OnValueChangedAsObservable()
            .Subscribe(value => _mixer.SetFloat(groupName, ConvertVolume2dB(value)))
            .AddTo(this);
    }
}

```

Mixerの値はデシベルなので、0～1に変換する関数を用意しています。
(下記リンクから拝借しました。圧倒的感謝！)
【参考リンク】：[Unity AudioMixerで音量等のパラメータをスクリプトから操作する際のつまりポイントメモ](https://qiita.com/matsumotokaka11/items/2eb0e7ac34c6dec3f80b)

# おわりに
先駆者のおかけでスムーズに実装できました。教えてくださった方ありがとうございます。

今回の実装を施したゲームを公開しているので良かったら遊んでみてください。
→[逃走中 In AMERICA](https://unityroom.com/games/kento_chu)