# サウンド

ファイルから効果音を鳴らし、音楽をストリーミングし、[plonk](/ja/plonk/) で音楽と効果音をコードで書き、プレイヤーが音量を決められるようにします。すべて `@debuffjp/audio` の `Audio` 1 つを通るので、音量の設定は 1 か所で全体に効きます。

```ts
import { Audio } from "@debuffjp/audio";

const audio = new Audio(); // ゲームに 1 つ
```

ブラウザは、プレイヤーがクリックやタップ、キー入力をするまでページの音を出しません。`Audio` は最初の入力で自動的に音を出せる状態になるので、自分で処理する必要はありません。音を出せるようになると `audio.unlocked` が `true` になります。たいていのゲームは、キーかクリックを待つタイトル画面があれば十分です。

## サウンドファイル {#files}

ファイルはほかのアセットと同じく `assets/` に置いて読み込み、それぞれ一度だけデコードします。

```ts
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"`。[音量](#volume)を参照してください。 |

`play` はボイスを返します。ループする音を止めるときに使います。フェードの秒数も指定できます。

```ts
const engine = audio.play("engine", { loop: true, volume: 0.4 });
engine.stop(0.3);
```

デコードしていない ID で `play` を呼ぶとエラーになり、足りない `decode` の呼び出しを教えてくれます。

## 長い曲 {#streaming}

音楽や環境音のファイルは大きく、`decode` は音全体をメモリに持ちます。`stream` は代わりに `` 要素で再生するので、すぐに始まり、スマートフォンでも軽く済みます。

```ts
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}

[plonk](/ja/plonk/) は曲を数行のデータとして書き、その場で合成するので、音声ファイルは要りません。効果音は曲の調で鳴るので、音階を上っていくコンボも音楽とぶつからずになじみます。`npm install plonkjs` で入れたら、ゲームの音量に従うように music バスへつなぎます。

```ts
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 をはじめる](/ja/plonk/getting-started)で最初の曲を書きます。
- [ゲームに反応する音楽](/ja/plonk/reacting)では、ゲームの出来事に合わせてテンポやレイヤーを変えます。
- [ゲームのサウンドデザイン](/ja/plonk/sound-design)では、ミックス、変化のつけ方、調に合った効果音を扱います。

0.24.2 から、ゲームに音が必要で、ほかのツールを指定していなければ、コーディングエージェントは plonk を使います（[サウンドを作る](/ja/docs/agents#making-sound)）。

## 仮の効果音 {#synth}

`audio.synth` は、オシレーター 1 つと音程のスライドで短いビープ音やザップ音、打撃音を作ります。まだ音がないゲームで、イベントが起きているかを耳で確かめるために使い、あとでファイルか plonk の効果音に置き換えましょう。

```ts
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 です。 |

## 音量 {#volume}

音は `"sfx"` と `"music"` の 2 つのバスを通り、どちらも `"master"` に流れます。どれも 0 から 1 で設定できます。変化はなめらかにつながるので、スライダーを動かしてもプツッという音は出ません。

```ts
audio.volume("music", 0.5);
audio.volume("master", muted ? 0 : 1); // ミュートは音楽と効果音の両方に効く
```

プレイヤーの設定は保存して、再読み込みしても残るようにしましょう。platformer テンプレートでは次のようにしています。

```ts
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)` はデコード済みの音を返すので、自分のノードで再生できます。

## 空間の中の音 {#positional}

ある場所から聞こえ、遠いほど小さく、壁の向こうではこもる音には [Earshot](/ja/earshot/) を使いましょう。[debuff で Earshot を使う](/ja/earshot/debuff)では、タイルマップから壁を作り、sfx バスで再生します。

## テスト {#testing}

`debuff test` はブラウザなしでゲームを実行するので、音は聞こえません。音声の呼び出しは受け付けられ、何もしません。音が鳴ることをテストするには、音を鳴らすきっかけになるゲームの状態を確かめます。スピーカーなしで音楽を確かめたいときは、plonk が曲の音符をデータとして一覧にします（[スピーカーなしで音楽をテストする](/ja/plonk/testing)）。良い音かどうかは、やはり耳で判断しましょう。

[API リファレンス](/api/@debuffjp/audio/)