こんにちは、トイロジックでプログラマーをしている、うしと申します。『グリッチバスターズ:スタックオンユー』 では、サウンドシステムに加え、エネミー・ボス・ギミックなども担当しました。
今回はサウンドシステムのなかの、イントロ付きループBGMの実装についてご紹介したいと思います。
イントロ付きループBGMって?
イントロ付きループBGMとは、イントロ部分がついたループするBGMの事(そのまんま)なのですが、ちょっと図示してみました。
上のほうが、いわゆる普通のループで、最後まで再生したら先頭に戻るものになります。下のほうがイントロ付きループで、冒頭数秒がイントロ部分となり、再生の初回でしか流れない部分となります。最後まで再生したら先頭に戻るのではなく、イントロの終了部分(LoopStart)に戻ることになります。
実際にBGMのどの区間をイントロとし、どの区間でループを行うのかというのはサウンドのデータ自体に埋め込んだり、サウンドのミドルウェア(CRI ADXやWwiseなど)内で設定するのが一般的です。
しかし、『グリッチバスターズ:スタックオンユー』ではUE4標準のオーディオシステムで実装することになっていましたので、ループの設定をサウンドデータから読み取ることも、標準の機能でサウンドのアセット(SoundWaveやSoundCue)にループ区間を設定することもできませんでした。したがってイントロ付きループをするには自前で実装する必要があるのですが、その流れをご紹介いたします。
試行錯誤
まず、イントロ・ループの区間を1個のサウンドデータから読み取ることができませんので、イントロ部分とループ部分を分割して、それぞれ別々のデータ(SoundWave)として用意します。最初にUE4のサウンドキューのConcatnatorノード
を試してみました。
これは文字通りSoundWaveを”連結する”ノードなので、上のSoundWave(イントロ)の再生終了後、下のSoundWave(Loop)が続けて再生されるのですが…実際は、イントロの終了後明らかな間ができてしまいBGMとして成立しないものになってしまいました。
次にDelayノード
を使って、Loop部分の再生をイントロの秒数分遅らせて、Mixerノード
で再生するようにしてみました。
ただ、これも先ほどと同じように、イントロとループ部分の間に間ができてしまう結果となりました。これは適当なアクターを作って、Tickで指定秒数分Loopの再生を遅らせるようなことをしても同じようにうまくいきませんでした。
なぜこれらの方法でうまくいかなかったかというと、ゲームスレッドの更新レートとサウンドのサンプリングレートで大きな開きがあるからです。ゲームの更新レートとはいわゆるfpsのことで、せいぜい秒間30~60回程度。対してサウンドのサンプリングレートは一般的に秒間44100~48000程度ですので、ゲームスレッドの更新タイミングでLoop部分の再生命令を呼んでいては、サウンド的には大きくタイミングがずれこんでしまうことになります。
Quartz
これを解決するため、UE4のQuartzというシステムを使いました。Quartzを簡単に説明すると、オーディオのサンプルのタイミングでサウンドの再生を行うことができるシステムです。また事前にBPMや拍子記号を指定することで、それらの拍(Beat)や小節(Bar)のサウンドのタイミング(Quantizeされたタイミング)でイベントを取得できます。
今回の場合であれば、小節ごとにイベントを取得し、そのBGMのイントロ部分の小節数分の回数そのイベントが呼ばれたら、次の小節タイミングからループ部分の再生を開始する。ということを実装すれば、きれいにイントロ付きループBGMが実装できることになります。
UE4上の実装イメージは以下のようになります。
- QuartzサブシステムからQuartzClock(オーディオスレッドに指定サンプルタイミングでの再生リクエストやイベント実行をするためのオブジェクト)を取得
- ClockにBPMと拍子記号を設定
- イントロBGMの再生(準備)
- 再生開始タイミングDelegateの準備
- Quantizeタイミング(BarやBeat)で発行されるイベントDelegateの準備
- イントロの再生準備ができたらClockの開始(イントロ自体は準備ができ次第再生される)
- Barタイミングで現在のBar数をチェック
- 指定のBar数に到達したら、
- 次のBarからLoopの再生をリクエスト
各BGMのBPMやBar数、対応するSoundアセットの指定は以下のようなDataTable
を用意しました。
実際にBGMを再生する際は、このDataTable
に登録した”名前”を指定してもらい、BGMシステム側でこのDataTable
から検索するようなフローが入る感じです。
最後に
いかがでしたでしょうか?今回はUE4のオーディオシステムでQuartzを利用したイントロ付きループBGMの実装例を紹介させていただきました。Quartz
を使えばイントロ付きループ以外にも、インタラクティブミュージックの実装や、サウンドに合わせたギミックやアクションの演出などもできます。
『グリッチバスターズ:スタックオンユー』でも少ないですが、インタラクティブミュージック的にBGMを遷移している箇所があります。よければ探してみてくださいね。トイログでは珍しいサウンド関連の内容になりましたが、少しでも参考になれば幸いです。