サウンド
ファイルから効果音を鳴らし、音楽をストリーミングし、plonk で音楽と効果音をコードで書き、プレイヤーが音量を決められるようにします。すべて @debuffjp/audio の Audio 1 つを通るので、音量の設定は 1 か所で全体に効きます。
import { Audio } from "@debuffjp/audio";
const audio = new Audio(); // ゲームに 1 つブラウザは、プレイヤーがクリックやタップ、キー入力をするまでページの音を出しません。Audio は最初の入力で自動的に音を出せる状態になるので、自分で処理する必要はありません。音を出せるようになると audio.unlocked が true になります。たいていのゲームは、キーかクリックを待つタイトル画面があれば十分です。
サウンドファイル
ファイルはほかのアセットと同じく assets/ に置いて読み込み、それぞれ一度だけデコードします。
import { Assets } from "@debuffjp/assets";
const assets = new Assets(await (await fetch("assets/manifest.json")).json());
await assets.load("default");
await audio.decode("coin", assets.audio("coin")); // assets/coin.ogg
audio.play("coin");
audio.play("coin", { volume: 0.8, rateJitter: 0.05 });| オプション | 内容 |
|---|---|
volume | この音の音量。デフォルトは 1 です。 |
rate | 再生速度。1 で元の音程、2 で 1 オクターブ上です。 |
rateJitter | 再生のたびに rate へランダムに足し引きする量。0.05 にすると、何度も聞く音が毎回まったく同じにはなりません。 |
pan | 左右の位置。-1(左)から 1(右)までです。 |
loop | 止めるまで繰り返します。 |
bus | "sfx"(デフォルト)か "music"。音量を参照してください。 |
play はボイスを返します。ループする音を止めるときに使います。フェードの秒数も指定できます。
const engine = audio.play("engine", { loop: true, volume: 0.4 });
engine.stop(0.3);デコードしていない ID で play を呼ぶとエラーになり、足りない decode の呼び出しを教えてくれます。
長い曲
音楽や環境音のファイルは大きく、decode は音全体をメモリに持ちます。stream は代わりに <audio> 要素で再生するので、すぐに始まり、スマートフォンでも軽く済みます。
const music = audio.stream(assets.url("music/theme"), { volume: 0.7 }); // music バス、デフォルトでループ
music.volume(0.3, 1); // 1 秒かけて 0.3 まで下げる(会話ウィンドウの間など)
music.pause();
music.resume();
music.stop(2); // 2 秒かけてフェードアウト長い曲は、assets.load() で読み込まないフォルダ(assets/music/ など)へ置きましょう。同じファイルを二度ダウンロードせずに済みます。assets.url はファイルを取得せずにアドレスだけを返します。最初のクリックやキー入力より前に始めたストリームは、その入力で再生が始まります。
コードで作る音楽と効果音
plonk は曲を数行のデータとして書き、その場で合成するので、音声ファイルは要りません。効果音は曲の調で鳴るので、音階を上っていくコンボも音楽とぶつからずになじみます。npm install plonkjs で入れたら、ゲームの音量に従うように music バスへつなぎます。
import { Player } from "plonkjs";
import { theme } from "./theme"; // plonk の Song
const player = new Player({ context: audio.ctx, destination: audio.bus("music") });
player.play(theme, { fade: 1 });
const POP = { wave: "sine", drop: 7, decay: 0.12, sustain: 0, volume: 0.3 } as const;
player.sfx(POP, { degree: 5 }); // 曲の音階の 5 番目の音- plonk をはじめるで最初の曲を書きます。
- ゲームに反応する音楽では、ゲームの出来事に合わせてテンポやレイヤーを変えます。
- ゲームのサウンドデザインでは、ミックス、変化のつけ方、調に合った効果音を扱います。
0.24.2 から、ゲームに音が必要で、ほかのツールを指定していなければ、コーディングエージェントは plonk を使います(サウンドを作る)。
仮の効果音
audio.synth は、オシレーター 1 つと音程のスライドで短いビープ音やザップ音、打撃音を作ります。まだ音がないゲームで、イベントが起きているかを耳で確かめるために使い、あとでファイルか plonk の効果音に置き換えましょう。
audio.synth({ freq: 660, freqEnd: 220, decay: 0.15 }); // 下がっていく音
audio.synth({ wave: "noise", freq: 400, freqEnd: 80, decay: 0.3, volume: 0.2 }); // 砕ける音| オプション | 内容 |
|---|---|
freq、freqEnd | 始まりと終わりの音程(Hz)。 |
attack、decay | フェードインとフェードアウトの秒数。 |
wave | "square"(デフォルト)、"sine"、"triangle"、"sawtooth"、"noise"。 |
volume、bus | play と同じです。volume のデフォルトは 0.3 です。 |
音量
音は "sfx" と "music" の 2 つのバスを通り、どちらも "master" に流れます。どれも 0 から 1 で設定できます。変化はなめらかにつながるので、スライダーを動かしてもプツッという音は出ません。
audio.volume("music", 0.5);
audio.volume("master", muted ? 0 : 1); // ミュートは音楽と効果音の両方に効くプレイヤーの設定は保存して、再読み込みしても残るようにしましょう。platformer テンプレートでは次のようにしています。
import { Storage } from "@debuffjp/core";
const save = new Storage("my-game", { volume: 10 });
audio.volume("master", save.get("volume") / 10);
function setVolume(v: number) {
save.set("volume", Math.max(0, Math.min(10, v)));
audio.volume("master", save.get("volume") / 10);
}自分の Web Audio のノードをゲームの音量に従わせるには、audio.bus("sfx") か audio.bus("music") につなぎます。audio.ctx は AudioContext で、audio.buffer(id) はデコード済みの音を返すので、自分のノードで再生できます。
空間の中の音
ある場所から聞こえ、遠いほど小さく、壁の向こうではこもる音には Earshot を使いましょう。debuff で Earshot を使うでは、タイルマップから壁を作り、sfx バスで再生します。
テスト
debuff test はブラウザなしでゲームを実行するので、音は聞こえません。音声の呼び出しは受け付けられ、何もしません。音が鳴ることをテストするには、音を鳴らすきっかけになるゲームの状態を確かめます。スピーカーなしで音楽を確かめたいときは、plonk が曲の音符をデータとして一覧にします(スピーカーなしで音楽をテストする)。良い音かどうかは、やはり耳で判断しましょう。