見出し画像

unity2023 イントロ付きループBGMの罠

久々に技術記事を書きます。
義務的ではなく描くべき事項があったからだ!

きっかけはTUの某チーム。おたじゃむ5のチーム。

それはこのチームの制作工程で発生した。

■前提:イントロ付きループBGMの実装

unity-webGLにおいてイントロ付きループBGMを実装するには、上記の記事で取り上げている特殊な処理が必要……逆に言えばその処理を行えばイントロ付きループBGMが実装可能……というのがこれまでの習わし。簡潔にソースを書くと以下のような感じになる。

[SerializeField] int loop_start; 
[SerializeField] int loop_end; 
[SerializeField] AudioSource src; 

void Update() { 
    if (src.timeSamples >= loop_end) { src.timeSamples -= loop_end - loop_start; } 
}

ループの開始と終わりのサンプル数を指定。再生中のBGMのサンプル数がループ終端を超えた時にループ分のサンプル数を巻き戻すことで実装可能。
……の、はずだった。

■おこった事象

↑のチームで制作したゲームにおいて、BGMが正しくループされない不具合が発生。しかも人によってループのされ方が異なるというカオスっぷり。エンジニア班は事象の究明に勤しむことになる。(現在は解消済み

■結論をいえ

結論から言えば、unityのwebGLビルドの際のオーディオの仕様が、2023以降で変わったことに起因する。

どうやら2022以前では、webGLにおける音声ファイルの出力のaacフォーマットの周波数が44100Hzで統一されていたものが、unity2023以降のビルドでは96000Hzを上限とする環境依存になってしまったようだ。このせいで、現在再生中のBGMのサンプル数の位置が環境によって異なる値を示すようになってしまい、ループ処理が正しく行われない結果になってしまったようだ。

■対処法

幸い、該当のBGMのaudioclipのfreqencyに値が記録されているので、それに応じてサンプル数に計算を入れればよい。以下、対応プログラム例。

[SerializeField] int loop_start;
[SerializeField] int loop_end;
[SerializeField] int frequency=44100; // 元の周波数
[SerializeField] AudioSource src;

void Update() {
    int CorrectFrequency(long n) {
        return (int)(n * src.clip.frequency / frequency );
    }
    if (src.timeSamples >= CorrectFrequency(loop_end)) { src.timeSamples -= CorrectFrequency(loop_end - loop_start); }
}

尚、AACのデコード時にfrequencyが再計算されるという報告もあり(確証無し・検証中)。なので補正計算は初期化時ではなく、リアルタイムで行ったほうがよさそう。

■まとめ

対応してunity2023-webGLでもたのしいイントロ付きBGMライフを!!!!

◆すぺしゃるさんくす

↑のチームの方々。特にエンジニアの赤モンド君。
あと細かい検証に協力してくれたUGDGの方々。さんくす!

◆定型句

当記事がいい!とおもったら
スキ!やシェアとかフォローなど、お願いいたします!!

この記事が気に入ったらサポートをしてみませんか?