【Unity】UnityのAudio Mixerで作る動的BGM:スナップショット・ダッキング・クロスフェード

作成: 2026-07-12最終更新: 2026-07-13

同じBGMをループさせるだけでは場面の緊張感は出せません。Audio Mixerのスナップショットで状況に応じてBGMを切り替え、ダッキングで会話中だけBGMを下げ、クロスフェードで曲を途切れず入れ替える——ゲームの「らしさ」を上げる動的な音楽制御を実装コードとともに解説します。

前提として オーディオ入門 の Audio Mixer(BGM/SEグループとExpose)まで済んでいると話が早いです。そこまで作ると、次に気になるのが 「BGMがずっと同じで単調」 ではないでしょうか。探索中も戦闘中も会話中も同じ曲がループするだけだと、どんなに良い曲でも場面の緊張感が出せません。

名作ゲームの音楽は、状況に反応して動いています。敵と戦い始めた瞬間に曲が切り替わり、会話が始まるとBGMがすっと下がって声が聞き取りやすくなる。この記事では、その動的な音楽制御を Audio Mixer の3つの武器——スナップショット・ダッキング・クロスフェード——で実装します。

動的BGMのイメージ。フラットなミキサー卓の上で「探索」と「戦闘」の状態カードが切り替わり、BGMの波形が場面に応じて変化している

この記事でわかること

  • スナップショット——ミキサーの状態を保存し、状況に応じて滑らかに切り替える
  • ダッキング——会話・SEの間だけBGMを自動で下げる(コード不要)
  • クロスフェード——2つの曲を途切れさせずに入れ替える
  • ExposeパラメータとdB変換で音量を滑らかに操作する
  • 実践:通常↔戦闘の切り替え+会話ダッキングを1シーンで組む

動作確認環境: Unity 2022.3 LTS / Unity 6

Sponsored

3つの武器と前提

動的BGMと一口に言っても、やりたいことによって使う道具が変わります。まず全体像を押さえましょう。

3つの武器の対比図。スナップショット=ミキサー状態をまるごと切り替え、ダッキング=声の間だけBGMを凹ませる、クロスフェード=2曲の音量を交差させて入れ替える
武器何をする主な使いどころ
スナップショットミキサーの音量・エフェクト状態をまるごと切り替える探索↔戦闘で音場の雰囲気を変える
ダッキング声やSEが鳴る間だけBGMを自動で下げる会話・カットインで声を聞き取りやすくする
クロスフェード2つの曲を途切れずすり替えるボス戦入場など、別の曲へ切り替える

いずれも土台は オーディオ入門 の Audio Mixer です。BGM・SE・Voice の3グループを作り、それぞれの音量パラメータをExposeしてある状態から始めます。

スナップショット:状況でミキサー状態を切り替える

スナップショット(Snapshot) は、その瞬間のミキサー設定(各グループの音量やエフェクトの値)をまるごと保存したものです。「探索」「戦闘」「ボス」といった状態を保存しておき、ゲームの状況に応じて切り替えます。

探索/戦闘/ボスの3スナップショットを滑らかに遷移する図。敵と遭遇で戦闘へ、ボ��ス出現でボスへ、それぞれミキサーの音量バランスが変わる

スナップショットの作り方

  1. Audio Mixerウィンドウ左の Snapshots の「+」で「Combat」などを追加します
  2. そのスナップショットを選択した状態で、各グループの音量やエフェクトを戦闘向けに調整します(例:戦闘BGMグループを上げ、環境音を下げる)
  3. 別のスナップショットを選び直せば、いつでもその状態を編集できます。最初の1つ(既定は「Snapshot」)が起動時の状態です

コードから切り替える

スナップショットへの遷移は AudioMixerSnapshot.TransitionTo() の一行です。第1引数の遷移時間が、切り替わりの滑らかさになります。

using UnityEngine;
using UnityEngine.Audio;

public class MusicStateController : MonoBehaviour
{
    // Inspectorでスナップショットアセットを割り当てる
    [SerializeField] private AudioMixerSnapshot explorationSnapshot;
    [SerializeField] private AudioMixerSnapshot combatSnapshot;

    private AudioMixerSnapshot current;

    void Start()
    {
        current = explorationSnapshot;
    }

    public void EnterCombat()
    {
        if (current == combatSnapshot) return; // 同じ状態への無駄な切り替えを防ぐ
        combatSnapshot.TransitionTo(1.5f);     // 1.5秒かけて戦闘の音場へ
        current = combatSnapshot;
    }

    public void ExitCombat()
    {
        if (current == explorationSnapshot) return;
        explorationSnapshot.TransitionTo(2.0f); // 戻りは少しゆっくり
        current = explorationSnapshot;
    }
}

複数を混ぜたいとき: mixer.TransitionToSnapshots(snapshots, weights, time) を使うと、複数のスナップショットを重み付きでブレンドできます。「戦闘度合い」に応じて探索と戦闘を70:30で混ぜる、といった連続的な変化に向いています。

ポイントは、探索用のBGMも戦闘用のBGMも鳴らしっぱなしにしておき、スナップショットで音量バランスだけを切り替えることです。曲の再生位置がずれないので、切り替わりが自然になります。

ダッキング:会話・SEの間だけBGMを下げる

会話ボイスやカットインのSEが鳴っているのにBGMが大きいままだと、肝心の声が埋もれます。かといって手動で下げると戻し忘れが起きます。そこで使うのが ダッキング(Ducking) ——「声が鳴っている間だけBGMを自動で凹ませる」仕組みです。

ダッキングの図。BGMの波形が、SE/ボイスが鳴る瞬間だけ自動的に凹み、鳴り終わると元に戻る

嬉しいのは、これが コードなしでミキサーの配線だけで動くことです。

  1. BGMグループに 「Add Effect > Duck Volume」 を追加します
  2. Voice(またはSE)グループに 「Add Effect > Send」 を追加し、送り先(Receive)を BGMグループのDuck Volume に設定します
  3. Sendの Send level を0dB付近まで上げます
  4. BGMグループのDuck Volumeで Threshold(発動する音量)Ratio(下げる強さ)Attack / Release(下がる/戻る速さ) を調整します

これで、Voiceグループから音が出るたびにDuck VolumeがBGMを自動で下げ、声が止むとReleaseの時間でふわっと戻ります。「声が鳴る→BGMが下がる」を毎回コードで書く必要はありません

Attack/Releaseの目安: Attackを短く(数ms〜数十ms)すると即座に下がり、Releaseを長め(300〜800ms程度)にすると戻りが自然になります。Releaseが短すぎると、会話の「間」のたびにBGMがバタつくので注意します。

Sponsored

クロスフェード:曲を途切れず入れ替える

スナップショットは「同じ曲たちの音量バランス」を切り替える道具でした。一方、まったく別の曲へ入れ替えたい(フィールド曲→ボス曲など)ときは、クロスフェードが出番です。1曲をフェードアウトしながら、もう1曲をフェードインさせて、無音の瞬間を作らずにすり替えます。

クロスフェードの図。曲Aの音量が下がりながら曲Bの音量が上がり、2つの音量カーブが交差して曲が入れ�替わる

必要なのは AudioSourceを2つ(両方ともBGMグループに出力)。片方を「今鳴っている方」、もう片方を「次に使う方」として交互に使います。

using System.Collections;
using UnityEngine;

public class MusicCrossfader : MonoBehaviour
{
    [SerializeField] private AudioSource sourceA;
    [SerializeField] private AudioSource sourceB;
    [SerializeField] private float fadeTime = 2f;

    private AudioSource active;   // 今鳴っている方
    private AudioSource standby;  // 次に使う方
    private Coroutine fadeRoutine; // 進行中のフェードを覚えておく

    void Awake()
    {
        active = sourceA;
        standby = sourceB;
    }

    // 次の曲へクロスフェードで切り替える
    public void CrossfadeTo(AudioClip nextClip)
    {
        // 進行中のフェードがあれば止め、フェードイン中だった曲を主役に昇格させてから始める
        if (fadeRoutine != null)
        {
            StopCoroutine(fadeRoutine);
            active.Stop();
            (active, standby) = (standby, active);
        }

        standby.clip = nextClip;
        standby.volume = 0f;
        standby.Play();
        fadeRoutine = StartCoroutine(CrossfadeRoutine());
    }

    private IEnumerator CrossfadeRoutine()
    {
        // 途中で切り替えられても自然につながるよう、「現在の音量」から補間する
        float startActive = active.volume;
        float t = 0f;
        while (t < fadeTime)
        {
            // ポーズ中でも進むようにunscaledを使う
            t += Time.unscaledDeltaTime;
            float k = t / fadeTime;
            active.volume = Mathf.Lerp(startActive, 0f, k); // 今の曲:下げる
            standby.volume = Mathf.Lerp(0f, 1f, k);         // 次の曲:上げる
            yield return null;
        }

        active.Stop();
        // active と standby を入れ替えて、次回に備える
        (active, standby) = (standby, active);
        fadeRoutine = null;
    }
}

activestandby入れ替えながら使うのがコツです。こうすれば何回切り替えてもAudioSourceは2つのままで、二重再生や消し忘れが起きません。ポーズ画面でもフェードを進めたいので、Time.deltaTimeではなく Time.unscaledDeltaTime を使っています(ポーズ実装の記事 参照)。

もう1つの守りが 連打対策 です。フェード中にCrossfadeToをもう一度呼ばれたとき、素朴な実装ではコルーチンが2本同時に走り、active/standbyの入れ替えが二重に起きて管理が崩れます。上のコードでは、 進行中のフェードをStopCoroutineで止めてから次を始める ことで、「ボス曲へ切り替え中にすぐ通常曲へ戻された」ようなケースでも破綻しません。

補足: ここで書き換えているのはAudioSource.volume(0〜1)です。ユーザーが設定画面で調整する音量は Mixerグループ側(Exposeした音量パラメータ)にあるため、フェードがユーザー設定を上書きすることはありません。この「演出はSource、設定はMixer」という分担も、Mixerを使う利点の1つです。

実践:通常↔戦闘+会話ダッキングを組む

アクションRPGの探索⇄戦闘、ローグライクのフロア⇄ボス、ステルスの通常⇄発見——「2つの状態を行き来しつつ、会話中は声を立てる」構造は、ジャンルを問わず同じ形で作れます。ここまでの武器を1シーンに組み上げます。

実践フロー図。戦闘エリア進入でEnterCombat()が戦闘スナップショットへ遷移、会話開始でVoiceが鳴りダッキングが自動でBGMを下げ、会話終了とエリア退出で元に戻る

ミキサー側の準備(コードの前に配線を済ませておきます):

  1. BGM・Voice・SE の3グループを作り、各音量をExpose
  2. Exploration / Combat の2スナップショットを作り、戦闘側はBGMバランスを戦闘向けに調整
  3. BGMグループに Duck Volume、Voiceグループに Send(→BGMのDuck Volume) を追加(=会話ダッキング)

コード側は「いつ・どのスナップショットへ」だけに集中します。戦闘の出入りは前掲の MusicStateController をそのまま使い、戦闘エリアのトリガーから呼びます。

using UnityEngine;

[RequireComponent(typeof(Collider))]
public class CombatZone : MonoBehaviour
{
    [SerializeField] private MusicStateController music;

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player")) music.EnterCombat();
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Player")) music.ExitCombat();
    }
}

会話については、コードは一切足しません。会話システムがVoiceグループのAudioSourceで声を再生すれば、ミキサーのダッキングが勝手にBGMを下げ、声が止めば戻ります。これで「戦闘で音場が変わり、会話で声が立つ」体験が完成します。

ポイントは2つです。 「ダッキングはコードで書かない」(声のたびにBGM音量を手で下げると、必ずどこかで戻し忘れます。ミキサーのSend+Duck Volumeに任せれば、配線した瞬間から全ての声に自動で効きます)と、 「同じ状態への切り替えをスキップする」current で今の状態を覚え、戦闘中に敵と遭遇するたびに戦闘スナップショットへ再遷移しないようにします。これを怠ると、遷移が何度も走って音場がざわつきます)。切り替えのきっかけを各所からマネージャーへ伝える設計は、イベントチャネル にすると疎結合に保てます。

おまけ:先に知っておくと良いこと

  • 音量は対数(dB)で扱う: Exposeパラメータを直接いじるなら、mixer.SetFloat("MusicVolume", Mathf.Log10(Mathf.Clamp(value, 0.0001f, 1f)) * 20f) のように0〜1をdBへ変換します。人間の音量感覚は対数なので、線形に下げると急に無音になったように聞こえます。設定の保存は PlayerPrefs入門 へ。
  • スナップショットは音量以外も保存する: Duck Volumeのかかり具合やLowpassのカットオフなど、エフェクトのパラメータも状態に含まれます。「ボス戦だけ少しこもった音にする」といった演出もスナップショットの切り替えだけで作れます。
  • Reverb Zoneで空間ごとの響きを: 洞窟に入ると響く、といった場所ごとの残響は Audio Reverb Zone が手軽です。BGMではなく環境音・SEにかけると自然です。
  • 曲の尺・ループ点は素材側で: 途切れないループやイントロ→ループの構造は、オーディオ素材の作り込み(ループポイント設定)が土台です。コードは「いつ切り替えるか」に集中させます。

まとめ

同じBGMをループさせるだけの段階から、状況に反応する音楽へ。Audio Mixerの3つの武器で、そのほとんどが実装できます。

  • スナップショット: ミキサー状態をまるごと保存し、TransitionTo(time) で滑らかに切り替える。曲は鳴らしっぱなしで音量バランスだけ変える。
  • ダッキング: BGMにDuck Volume、声/SEにSendを配線するだけで、声の間だけBGMが自動で下がる。コード不要
  • クロスフェード: AudioSourceを2つ使い、音量を交差させて別の曲へ途切れず入れ替える。
  • 状態の重複切り替えを防ぐ: current で今の状態を覚え、同じ状態への再遷移をスキップする。
  • 音量をコードで動かすなら Mathf.Log10(value) * 20 でdB変換する。

まずは「探索」と「戦闘」の2スナップショットを作り、TransitionTo の遷移時間を変えて耳で確かめてみてください。音楽が場面に反応し始めると、ゲームの手応えが一段深くなります。あなたのゲームのBGM、いまも最初から最後まで同じ音量で鳴りっぱなしになっていませんか?

さらに学ぶために