前提として オーディオ入門 の Audio Mixer(BGM/SEグループとExpose)まで済んでいると話が早いです。そこまで作ると、次に気になるのが 「BGMがずっと同じで単調」 ではないでしょうか。探索中も戦闘中も会話中も同じ曲がループするだけだと、どんなに良い曲でも場面 の緊張感が出せません。
名作ゲームの音楽は、状況に反応して動いています。敵と戦い始めた瞬間に曲が切り替わり、会話が始まるとBGMがすっと下がって声が聞き取りやすくなる。この記事では、その動的な音楽制御を Audio Mixer の3つの武器——スナップショット・ダッキング・クロスフェード——で実装します。
この記事でわかること
- スナップショット——ミキサーの状態を保存し、状況に応じて滑らかに切り替える
- ダッキング——会話・SEの間だけBGMを自動で下げる(コード不要)
- クロスフェード——2つの曲を途切れさせずに入れ替える
- ExposeパラメータとdB変換で音量を滑らかに操作する
- 実践:通常↔戦闘の切り替え+会話ダッキングを1シーンで組む
動作確認環境: Unity 6 (6000.x)
3つの武器と前提
動的BGMと一口に言っても、やりたいことによって使う道具が変わります。まず全体像を押さえましょう。

| 武器 | 何をする | 主な使いどころ |
|---|---|---|
| スナップショット | ミキサーの音量・エフェクト状態をまるごと切り替える | 探索↔戦闘で音場の雰囲気を変える |
| ダッキング | 声やSEが鳴る間だけBGMを自動で下げる | 会話・カットインで声を聞き取りやすくする |
| クロスフェード | 2つの曲を途切れずすり替える | ボス戦入場など、別の曲へ切り替える |
いずれも土台は オーディオ入門 の Audio Mixer です。BGM・SE・Voice の3グループを作り、それぞれの音量パラメータをExposeしてある状態から始めます。
スナップショット:状況でミキサー状態を切り替える
スナップショット(Snapshot) は、その瞬間のミキサー設定(各グループの音量やエフェクトの値)をまるごと保存したものです。「探索」「戦闘」「ボス」といった状態を保存しておき、ゲームの状況に応じて切り替えます。

スナップショットの作り方
- Audio Mixerウィンドウ左の Snapshots の「+」で「Combat」などを追加します
- そのスナップショットを選択した状態で、各グループの音量やエフェクトを戦闘向けに調整します(例:戦闘BGMグループを上げ、環境音を下げる)
- 別のスナップショットを選び直せば、いつでもその状態を編集できます。起動時の状態は、星のアイコンが付いたスナップショット(最初は「Snapshot」)です。右クリ ックの Set as Start Snapshot で変えられます
Play中に聞きながら調整したいときは、ミキサーの Edit in Play Mode をオンにします。オンのまま動かした値は、Playを止めても残ります。
コードから切り替える
スナップショットへの遷移は 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も鳴らしっぱなしにしておき、スナップショットで音量バランスだけを切り替えることです。曲の再生位置がずれないので、切り替わりが自然になります。
1つ注意があります。設定画面の音量スライダーなどでSetFloatした音量パラメータは、スナップショットを切り替えても動かなくなります(ClearFloatを呼ぶまで、スクリプトの値が優先されます)。ユーザーの音量はMasterや親のグループで、場面ごとの音量は子のグループで、と分けておくと両立します。
ダッキング:会話・SEの間だけBGMを下げる
会話ボイスやカットインのSEが鳴っているのにBGMが大きいままだと、肝心の声が埋もれます。かといって手動で下げると戻し忘れが起きます。そこで使うのが ダッキング(Ducking) ——「声が鳴っている間だけBGMを自動で凹ませる」仕組みです。

嬉しいのは、これが コ ードなしでミキサーの配線だけで動くことです。
- BGMグループに 「Add Effect > Duck Volume」 を追加します
- Voice(またはSE)グループに 「Add Effect > Send」 を追加し、送り先(Receive)を BGMグループのDuck Volume に設定します
- Sendの Send level を0dB付近まで上げます(既定は -80dB で、何も送られません)
- BGMグループのDuck Volumeで Threshold(発動する音量)・Ratio(下げる強さ)・Attack Time / Release Time(下がる/戻る速さ) を調整します
これで、Voiceグループから音が出るたびにDuck VolumeがBGMを自動で下げ、声が止むとReleaseの時間でふわっと戻ります。「声が鳴る→BGMが下がる」を毎回コードで書く必要はありません。
Attack/Releaseの目安: Attackを短く(数ms〜数十ms)すると即座に下がり、Releaseを長め(300〜800ms程度)にすると戻りが自然になります。Releaseが短すぎると、会話の「間」のたびにBGMがバタつくので注意します。
クロスフェード:曲を途切れず入れ替える
スナップショットは「同じ曲たちの音量バランス」を切り替える道具でした。一方、まったく別の曲へ入れ替えたい(フィールド曲→ボス曲など)ときは、クロスフェードが出番 です。1曲をフェードアウトしながら、もう1曲をフェードインさせて、無音の瞬間を作らずにすり替えます。

必要なのは 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 = Mathf.Clamp01(t / fadeTime);
// 線形に交差させると真ん中で音が薄く聞こえるので、cos と sin のカーブで交差させる
active.volume = startActive * Mathf.Cos(k * Mathf.PI * 0.5f); // 今の曲:下げる
standby.volume = Mathf.Sin(k * Mathf.PI * 0.5f); // 次の曲:上げる
yield return null;
}
active.Stop();
// active と standby を入れ替えて、次回に備える
(active, standby) = (standby, active);
fadeRoutine = null;
}
}
active と standby を入れ替えながら使うのがコツです。こうすれば何回切り替えても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シーンに組み上げます。

ミキサー側の準備(コードの前に配線を済ませておきます):
- BGM・Voice・SE の3グループを作り、各音量をExpose
- Exploration / Combat の2スナップショットを作り、戦闘側はBGMバランスを戦闘向けに調整
- 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();
}
}
戦闘エリアを重ねて置く場合は、片方から出ただけで探索に戻ってしまいます。入っているエリアの数を数えて、0になったときだ け 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、いまも最初から最後まで同じ音量で鳴りっぱなしになっていませんか?
さらに学ぶために
- Unityオーディオ入門:BGM、SE、3Dサウンド ——Audio Source/MixerとExposeの土台
- ポーズ実装ガイド ——ポーズ中もフェードを進める
unscaledDeltaTime - ScriptableObjectイベントチャネル設計入門 ——状態変化をマネージャーへ疎結合に伝える
- Unity公式ドキュメント:Audio Mixer Snapshots ——スナップショットの一次情報