Unreal Engineでイントロ付きループ曲を扱うあれこれーサウンドデザイナー向けー

今ではありとあらゆる場面で聞くことが出来るイントロ付きループ曲をUnreal Engineで実装するために様々な試行錯誤をした、してるので、ここに自分用の為も含めた上まとめる。

初めに

サウンドデザイナーとしての一つの理想はwavが読み込まれ、LoopEndのsample数まで来たらLoopStartのサンプル数まで戻ってループしてくれると大変うれしいのだけれどUE上ではそれはただの幻想郷にすぎない。

f:id:OtObOx:20210601163401p:plain
こんな感じ

この理想が出来るのか否か自分が試したのは以下の三つのブループリント(モジュール?ノード?)

  1. Cue
  2. Time Synth
  3. Quartz

Cue

まずCueでイントロ付きループ曲を作成した場合簡単にこうなる。

f:id:OtObOx:20210601164147p:plain
Cueの場合

これはIntroファイルが終わるとConcatenatorが自動でLoopファイルを読みこんでくれる。

f:id:OtObOx:20210601170530p:plain
簡単図

大変シンプルでUE初心者の私でも簡単に構築できるが、問題点もある。
単純にIntroからLoopに移る際、空白が出来てしまうのだ。
原因は以下のブログが示す通りゲームスレッド依存によって人間が感知可能なレベルで空白期間が出来てしまうのが問題点。
note.com

上記ブログにもあるようこれを何とかしようと先達の方々があれやこれやしていた痕跡がフォーラム等で見られるが、素晴らしくも恐ろしくもあるのでここでの紹介は割愛する。

Time Synth

さて次に試したのはTime Synth。
何とこれを用いるとゲームとは別に独自のクロックを持つスレッドによってオーディオを任意の再生タイミングで鳴らせるすごいプラグインだ。

有効化並び簡単な使い方は以下のブログにて教えてくださっている。
historia.co.jp

こちらの方も動画を添えた上解説してくださっている。感謝。
pafuhana1213.hatenablog.com


確かにBPMが定まっている曲の場合これでかなり本格的なイントロループができる。
しかしBPMが定まっている曲というのはそれはそれで珍しい存在で、人間味あふれる曲だといとも簡単に拍のズレが生じてしまう。
一応幾つかの可能性は試した。

  • BPMをサンプリングレートと同じクロックになるよう値をぶち込み、サンプル数換算で制御できるようにする。

BPMを256万6000に設定しプレイボタンを押した瞬間UEが落ちた。彼には速すぎたようだ

  • On Playback Timeを用いてintro曲終了直後に流すようにしてみる。

→Cueで生じたような空白は無いもののノイズが生じてしまう

f:id:OtObOx:20210601175927p:plain
下に流れてるノードはデバッグ表示

Synth Playback TIme SecondsはFloatなのでサンプル数より細かく受け取れるはずなのだが、Nearly Equalを用いて動作を見るに1/100秒しか判断できないらしい。
ちなみに整数で等しくなった際のみにしても同じようなノイズが生じるので意味がない。

ではなぜUnrealEngine公式のLiveDemoでは奇麗なループになっているのか。
youtu.be

これはオーディオファイルレベルでインタラクティブミュージックをデザインする事を前提とした状態になっているからである。

f:id:OtObOx:20210601192326p:plain
同じ曲が重なった状態で再生されている

このようにこの記事最初の理想郷とはかけ離れた方式で作られており、
BPMさえそろっていれば重なっていても問題ように作られている為だ。
その為、曲頭と終わりの波形がノイズを生み出さない形に納まっているので上記Live Demoではシームレスなループが完成している。


そして次に試したQuartzを触ってみた限りUnreal Engineは理想郷は理想郷のままサンプル数ではループさせない強い意志が垣間見える。

Quartz

4.26で追加されたこの機能はTime Synthと似たアプローチだが、より使いやすくなっておりインタラクティブミュージックもTime Synthと同じく可能だ。
公式ドキュメントはこちら。
docs.unrealengine.com


こちらを使用した日本語記事はなく、UE初心者であるにもかかわらず手探りの状態で始めたので間違っている箇所があれば指摘してほしい。


最初に書いたようにTime Synthと似たようなアプローチをしておりQuartzという独自のクロックを用意しその中でオーディオの再生位置が決められる
Time Synthと同じようにBPMを指定し小節または拍毎にカスタムイベントを発行しそれらを用いてインタラクティブサウンドを持つゲームが作れるようになっている。
TimeSynthと大きな違いはサウンドに既存のノードを使用することができ、TimeSynthのようにPlayClipで鳴らす必要はない。
その代わり、既存のサウンドノードの後にPlay Quantizedノードに繋げ、来たサウンドQuartzが持つクロックのタイミングで再生する形だ。
この為Time Synth Clipでわざわざクリップ自体のデータを作る必要が無くなっており、解りやすくなっている。
そして何よりも時間の指定方法が豊富であることがQuartzの強みではないだろうか。
公式ドキュメントにもあるように以下の指定方法が存在する

  • Beats per Minute
  • Milliseconds per Tick
  • Ticks per Second
  • Seconds Per Tick
  • Thirty-second Notes per Minute

しかし何れの指定方法を用いてもサンプル単位で指定させる事は不可能だった

f:id:OtObOx:20210601200252p:plain
Quartzを用いたBP

上のBPはこちらを参考に作成した。感謝感謝
chriszuko.com

まとめ

sample単位でのループ指定が不可能という事はTime Synthと同じようなアプローチで曲を作る必要があり、理想郷とは程遠い位置になる。
この為Loop EndからLoop Startに行く従来の方法が使いたい場合はCRIwareWwise、FMODを用いるのがベストなのかもしれない。
あとはこの方のプラグインを使うとか…
github.com

以上のことからBPMが変動する曲をUnreal Engineで使おうとしているならば注意してほしい。
sample単位での指定は現状できない。



もし良い方法があればご教授いただければ幸いです。