Week 52026年1月30日

Love.js用のカスタムオーディオバックエンドの開発

Love.jsのオーディオ再生の課題

少しバタバタしておりあまり開発できていませんでしたが、以前に引き続きLove.jsのフォークの改善に取り組んでいました。以前はWebGL2の対応しましたが、もう一つ解決したかった問題がオーディオの再生でした。

Web Audioはなかなか厄介で、Wasm側からデータをストリームするような設計だとどうしてもモバイル端末などのデバイスやブラウザによって再生が安定しづらい性質があります。Audio Workletなど最新のAPIを使用してもWASM側から生の音声バッファをストリームする場合、メインスレッドへの依存が避けられないため、オーディオを完全に途切れなく再生させる保証が難しいです。

Love.jsのデフォルトのオーディオバックエンドは、依存するSDLのオーディオバックエンドであるOpenALを介したものです。SDLはEmscriptenがデォルトでブラウザ用の実装を提供しているのでこれで利用できますが、上記で言及したように根本的にWASM側から生の音声バッファを渡す処理自体に限界があります。

解決策:2つのWeb Audio APIの活用

自分が確認した限りで最も安定してWeb Audio APIを利用してオーディオを再生できるのは、createBufferSource と createMediaElementSourceの2つのアプローチでした。

createBufferSource は、WASM側から生の音声バッファをストリームするのではなく、全体をメモリに読み込むためレイテンシもストリームの問題ありません。しかし全体を読み込む性質上、長時間の音楽などには適さず効果音などの短い音声での使用が想定されます。

createMediaElementSource は、通常のHTML5 Audio要素を作成し、createMediaElementSource 経由で音声をWeb Audio APIに接続して制御するものです。HTML5 Audio要素はブラウザが最適化を行っているため、様々な環境で滑らかに再生が動作します。音声のデータについてはHTTP経由で利用可能にする必要があるため、ビルド時に工夫が必要です。

実装例とテスト

今回その2つのAPIを利用したバックエンドを作成し、簡単な音声APIのテストを行うexampleを作成しました。

性能の低いAndroid端末などで試すと、既存のLove.jsビルドを利用するexample (/projects/comprehensive-audio-example-reference) ではオーディオが途切れる事が確認できます。

また、右下のHeavy Processボタンを押下すると重い処理を数秒間実行し、フレームレートの低下がオーディオ再生にどう影響するかを確認できます。