Web ゲームに音楽を入れる方法
ブラウザゲームに音楽を入れる一般的な方法は 4 つあります。音声ファイルを鳴らす(たいていは Howler 経由)、ZzFXM のような小さなトラッカーで曲をレンダリングする、Tone.js で合成する、そして私たちが作っている plonk で合成する方法です。ファイルなら録音できるものは何でも鳴らせますが、いちばんバイト数がかかります。コードベースの方法は小さく、ゲームに合わせて変化できますが、シンセサイザーで作れる音しか出せません。
結論から
本物の楽器やボーカル、作曲家の仕上げたミックスが必要なら音声ファイルを使いましょう。js13k のようなサイズ制限のあるジャムには ZzFXM を。シーケンサー、ジェネラティブな作品など本格的な合成が必要で、音楽そのものがプロダクトなら Tone.js を。ゲームに反応する小さなゲーム音楽をコードで作りたいなら plonk を使いましょう。チップチューンやシンセ系のスタイルで、テンポ、レイヤー、曲のキーに合った効果音が組み込まれています。
ひと目で比較
| 音声ファイル + Howler | ZzFXM | Tone.js | plonk | |
|---|---|---|---|---|
| 配布するもの | ライブラリと音楽ファイル | 曲の配列と小さなレンダラー | ライブラリ、コードで書いた曲 | ライブラリ、テキストで書いた曲 |
| ライブラリ(brotli)* | 8.8 kB(howler 2.2.4) | npm にないため、ここでは未計測 | 51.0 kB(tone 15.1.22) | 3.8 kB(plonkjs 0.2.0) |
| 1 分のループ | 96 kbps で約 720 kB | 数百バイトの曲データ | あなたのコード | 数百バイトのテキスト |
| 音 | 録音できるものは何でも | ZzFX 系のシンセ楽器 | フル機能の合成、サンプラー、エフェクト | シンセの音色、ノイズドラム、エコー、リバーブ |
| ゲームへの反応 | 別々のファイル(ステム)をクロスフェード | 再レンダリングするか曲を差し替える | プログラムしだいで何でも | 曲のキーに合わせた tempo()、layer()、sfx() |
| タイミング | 1 つのバッファ、音符ごとのタイミングなし | レンダリング済みの 1 つのバッファ | 先行スケジューリング | 先行スケジューリング(計測) |
| 作り方 | DAW、作曲家、ストックライブラリ | 専用のトラッカーツール、または手書き | コード | テキストのパターン、プレイグラウンド |
| 音楽のライセンス | 購入または依頼した条件しだい | 自分のもの | 自分のもの | 自分のもの |
*ループを 1 つ鳴らすだけの最小アプリを Vite の本番ビルドにして brotli で計測。bench/music-size より。ループのサイズは単純計算で、96 kbps なら 1 秒あたり 12 kB です。
音声ファイル
ほとんどのゲームのデフォルトで、音楽が録音であるならこれが正解です。DAW からループを書き出し(または購入し)、Howler かそのままの Web Audio で鳴らします。
import { Howl } from "howler";
const theme = new Howl({ src: ["theme.ogg"], loop: true, volume: 0.6 });
theme.play();代償はサイズです。圧縮した音楽は 96 kbps で 1 秒あたり約 12 kB なので、1 分のループは約 720 kB。小さな Web ゲームなら、残り全部を合わせたより大きくなることもよくあります。ゲームポータルやモバイルでは、それが最初の音が鳴るまでの読み込み時間になります。ストリーミングは最初の再生を早めますが、ダウンロードの合計は減りません。
ゲームに反応する音楽にはステムが必要です。ドラム、ベース、メロディを別々のファイルにして同期再生し、フェードイン・フェードアウトさせます。これはうまく機能しますが、ダウンロードはステムの数だけ増えます。録音のテンポを変えるとピッチも変わってしまうので、タイムストレッチが必要です。これは CPU を使い、音がにじんだように聞こえることがあります。
ZzFXM:小さなトラッカー
Keith Clark による ZzFXM は、小さな JavaScript 作品向けの音楽ジェネレーターで、Frank Force の ZzFX サウンドジェネレーターの上に作られています。曲は楽器とパターンの配列で、MOD ファイルにやや似ています。ZzFXM はそれを音声データにレンダリングし、1 つのバッファとして再生します。js13k の 13 kB のようなサイズ制限向けに作られていて、曲を書くためのトラッカーツールもあります。
レンダリングは音楽が鳴る前に行われるので、長い曲は起動時に少し時間がかかり、音楽を変えるには再レンダリングが必要です。1 バイトでも惜しいジャムの作品なら、なかなか勝てる相手はいません。
Tone.js:フル機能の音楽フレームワーク
Tone.js はブラウザでインタラクティブな音楽を作るためのフレームワークです。シンセサイザー、サンプラー、エフェクト、そしてオーディオクロック上で音符を先にスケジュールする Transport を備えているので、フレームが落ちてもタイミングが保たれます。
import * as Tone from "tone";
const synth = new Tone.Synth().toDestination();
new Tone.Sequence((time, note) => synth.triggerAttackRelease(note, "16n", time), ["C4", "E4", "G4"], "16n").start(0);
Tone.getTransport().start();ゲームのサウンドトラックに必要なものよりはるかに多くのことができます。FM 合成やグラニュラー合成、畳み込み、録音した楽器を鳴らすサンプラー。その幅広さゆえに、最小アプリでも 51 kB になります。音楽のおもちゃ、シーケンサー、ジェネラティブな作品を作るなら、成熟した選択肢です。
plonk:コードで作る、ゲームのための音楽
plonk は私たちが作っている Web ゲーム向けの音楽エンジンです。曲はデータで、楽器と、テキストで書いた音符のパターンをセクションに並べたものです。それを Web Audio でその場で合成し、Tone.js と同じくオーディオクロック上で先にスケジュールします。サイズは 3.8 kB です。
import { Player } from "plonkjs";
const player = new Player();
player.play({
bpm: 112,
instruments: {
lead: { wave: "square", decay: 0.14, sustain: 0.35, echo: 0.3 },
kick: { wave: "sine", drop: 24, decay: 0.12, sustain: 0 },
},
sections: { a: { lead: "C5 . E5 G5 . E5 C5 .", kick: "x . . . x . . ." } },
order: ["a"],
});
player.tempo(1.12); // speed up without a jump
player.layer("kick", 0); // fade the drums outゲーム音楽がすることを中心に作られています。時間切れが迫ったら飛ばずにテンポを変える tempo()、ゲームのムードでトラックを出し入れする layer()、曲のキーとビートに合った効果音を鳴らす sfx()。そして plonkjs 0.3 からは、リズムに合わせてアニメーションさせる player.step もあります。曲はテキストなので、コーディングエージェントも書いたり編集したりでき、notes() を使えばスピーカーなしで確かめられます。
限界はシンセサイザーのものです。録音した楽器やボーカルは使えず、音色はチップチューンとシンセの範囲です。コードで描いた見た目の小さなゲームにはいちばん合うと考えていますが、オーケストラのスコアならファイルを使いましょう。
どの方法でも対処が必要なこと
自動再生。 ブラウザはプレイヤーがページを操作するまで音声を鳴らしません(MDN)。「press any key」のタイトル画面のように、最初のクリック、タップ、キー入力で音楽を開始するか、AudioContext を再開しましょう。
非表示のタブ。 プレイヤーがタブを切り替えたら、ゲームと音楽を一緒に止めましょう。visibilitychange を監視し、document.hidden のときに停止またはサスペンドします。ブラウザは非表示のタブでタイマーも遅くするので、コードからスケジュールしている音楽は音符が足りなくなります。
ミュートボタンと音楽の音量。 プレイヤーは、効果音とは別にこの 2 つがあることを期待します。音楽を専用のゲインノード(または Howler のサウンドごとの音量)に通し、設定を記憶しておきましょう。
すき間のないループ。 MP3 エンコーダーはファイルの最初と最後にわずかな無音を入れるので、MP3 のループはつなぎ目ですき間やクリックノイズの出ることがあります。ループには Ogg Vorbis か Opus を使うか、合成した曲に自分でループさせましょう。
ここで扱わないこと
空間オーディオ、セリフやボイス、効果音のデザインは、それぞれ別のテーマです。ライブラリのサイズは、ある 1 日時点のバージョンでの最小アプリのものです。実際のゲームには独自のコードが加わります。ZzFXM はパッケージとして公開されていないため計測していません。
plonk のプレイグラウンドでループを作り、コードとしてコピーして、ゲームに貼り付けてみてください。