BGM とアナウンスを同時再生してみる

ゲームや映像を作っていると、「それっぽさ」を出したくなります。

今回は、レース前の演出として

  • BGM を流す
  • 少し待ってからアナウンスを流す
  • アナウンス中は BGM を少し下げる

という仕組みを実装してみました。

シンプルですが、これだけで一気に雰囲気が出ます。

作品

最終的な作品はこちらです。

音量変化のイメージ

今回の処理では、BGM を流したままアナウンスを再生しています。

ただし、そのままだとアナウンスが聞き取りにくくなるため、
アナウンス再生中だけ BGM の音量を下げています。

流れとしては次の通りです。

  1. BGM を通常音量で再生
  2. アナウンス直前に BGM を少し下げる
  3. アナウンス再生中はそのまま維持
  4. アナウンス終了後に BGM を元の音量へ戻す

図にすると、BGM と Voice の音量変化は次のようになります。

音量変化 通常 アナウンス直前 アナウンス中 終了後 Voice BGM

音量変化を滑らかにする

音量の変更は、単純に値を切り替えることもできますが、
Lerp(線形補間)を使って徐々に変化させることで、より自然な演出になります。

・Lerp なし
・Lerp あり

の 2 つを比較してみます。

聞き比べ

Lerp なし
Lerp あり

Lerp を使うことで、音量の変化が滑らかになり、
アナウンスがより自然に聞こえるようになります。

わずかな違いですが、体験としては大きく変わります。

図での比較

Lerp なし
音量変化(Lerp なし) 通常 アナウンス直前 アナウンス中 終了後 Voice BGM
Lerp あり
音量変化(Lerp あり) 通常 アナウンス直前 アナウンス中 終了後 Voice BGM

Unity での実装

ポイントは 3 つです。

  1. AudioSource を 2 つ使う(BGM 用 / Voice 用)
  2. コルーチンで順番に制御する
  3. BGM の音量をフェードさせる(ダッキング)

コード

using System.Collections;
using UnityEngine;

public sealed class SampleAudioPlayer : MonoBehaviour
{
    [SerializeField] AudioSource bgmSource;
    [SerializeField] AudioSource voiceSource;

    [SerializeField] AudioClip bgmClip;
    [SerializeField] AudioClip voiceClip;

    [SerializeField, Min(0f)] float voiceDelaySeconds = 0.8f;

    [SerializeField, Min(0f)] float BgmNormalVolume = 0.4f;
    [SerializeField, Min(0f)] float BgmDuckVolume = 0.2f;
    [SerializeField, Min(0f)] float DuckDurationSeconds = 0.3f;
    [SerializeField, Min(0f)] float RestoreDurationSeconds = 0.5f;

    void Start()
    {
        StartCoroutine(PlaySequence(voiceClip));
    }

    private IEnumerator PlaySequence(AudioClip clip)
    {
        PlayBgm();
        yield return new WaitForSeconds(voiceDelaySeconds);
        yield return PlayVoiceWithDuck(clip);
    }

    private void PlayBgm()
    {
        bgmSource.clip = bgmClip;
        bgmSource.loop = true;
        bgmSource.volume = BgmNormalVolume;
        bgmSource.Play();
    }

    private IEnumerator PlayVoiceWithDuck(AudioClip clip)
    {
        yield return bgmSource.FadeTo(BgmDuckVolume, DuckDurationSeconds);

        voiceSource.clip = clip;
        voiceSource.loop = false;
        voiceSource.Play();

        yield return new WaitWhile(() => voiceSource.isPlaying);

        yield return bgmSource.FadeTo(BgmNormalVolume, RestoreDurationSeconds);
    }
}

public static class AudioSourceExtensions
{
    public static IEnumerator FadeTo(this AudioSource source, float target, float duration)
    {
        float start = source.volume;
        float time = 0f;

        while (time < duration)
        {
            time += Time.deltaTime;
            source.volume = Mathf.Lerp(start, target, time / duration);
            yield return null;
        }

        source.volume = target;
    }
}

素材

BGM

Aesthetics Of Stoppage
by Lui_Epicmusic (Pixabay)

Voice

VOICEVOX: No.7