音声ファイルなしで効果音を作る方法|Web Audio APIで「ピッ」「ポン」を鳴らす【JavaScript】
ゲームに効果音を入れたいけど、音のファイルを探したり作ったりするのは大変ですよね。
実は、音声ファイルを1つも用意しなくても、JavaScript だけで効果音は作れます。ブラウザに最初から入っている Web Audio API という機能を使います。
僕が AI の Claude と一緒に作ったカカポの森のブロック崩しの効果音も、すべてこの方法で作っています。この記事では、そのコードを使って作り方を解説します。
まずは聞いてみよう
ボタンを押すと、ブロック崩しで実際に使っている効果音が鳴ります。どれも音声ファイルは使っていません。(音が出るので、音量に気をつけてください)
いちばんシンプルな効果音のコード
まずは、ボタンを押すと「ピッ」と鳴るだけのコードです。メモ帳に貼り付けて sound.html という名前で保存し、ブラウザで開くと試せます。
sound.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>効果音のテスト</title>
</head>
<body>
<button id="play">ピッ</button>
<script>
let audio = null; // 音を鳴らす装置(最初のクリックで作る)
document.getElementById("play").addEventListener("click", () => {
if (!audio) {
audio = new AudioContext();
}
const now = audio.currentTime;
const osc = audio.createOscillator(); // 音のもと
const gain = audio.createGain(); // 音量のつまみ
osc.type = "square"; // 音色
osc.frequency.setValueAtTime(880, now); // 音の高さ(Hz)
gain.gain.setValueAtTime(0.05, now); // 音量(大きすぎないように小さめ)
gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.1); // 0.1秒でだんだん小さく
osc.connect(gain);
gain.connect(audio.destination);
osc.start(now);
osc.stop(now + 0.1);
});
</script>
</body>
</html>
やっていることは、次の4つです。
- オシレーター(音のもと)を作る:決まった高さの音を出し続ける部品です
- ゲイン(音量のつまみ)を作る:音の大きさを調整します
- つなぐ:「音のもと → 音量のつまみ → スピーカー」の順につなぎます
- 鳴らして、止める:
startで鳴らし始め、stopで止めます
使い回せる「beep」関数を作る
効果音をたくさん作るなら、音の高さや長さを変えられる関数にしておくと便利です。ブロック崩しでは、次の beep 関数を使っています。
// 音を1つ鳴らす
// freq:音の高さ(Hz) duration:長さ(秒) type:音色 volume:大きさ slideTo:終わりの高さ
function beep(freq, duration, type = "square", volume = 0.04, slideTo = null) {
if (muted || !audio) {
return;
}
const now = audio.currentTime;
const osc = audio.createOscillator(); // 音のもと
const gain = audio.createGain(); // 音量のつまみ
osc.type = type;
osc.frequency.setValueAtTime(freq, now);
if (slideTo) {
osc.frequency.exponentialRampToValueAtTime(slideTo, now + duration);
}
gain.gain.setValueAtTime(volume, now);
gain.gain.exponentialRampToValueAtTime(0.0001, now + duration); // だんだん小さく
osc.connect(gain);
gain.connect(audio.destination);
osc.start(now);
osc.stop(now + duration);
}
| 引数 | 意味 |
|---|---|
freq | 音の高さ(Hz)。数字が大きいほど高い音 |
duration | 音の長さ(秒) |
type | 音色。sine(やわらかい)、triangle(まるい)、square(ピコピコ)、sawtooth(ジリジリ) |
volume | 音量。0.03〜0.06 くらいがちょうどいい |
slideTo | 終わりの音の高さ。指定すると、音が上がったり下がったりする |
自分で音を作ってみよう
高さ・長さ・音色を変えて、どんな音になるか試してみてください。鳴らした音のコードも表示されます。
beep(660, 0.12, "triangle", 0.05);
効果音の作り方のコツ
1. 音を重ねると、ぐっとそれっぽくなる
ブロック崩しの効果音は、beep を組み合わせて作っています。
// ゲームで使う音
const sound = {
wall: () => beep(320, 0.03, "triangle", 0.03),
paddle: () => beep(520, 0.07, "triangle", 0.06),
leaf: () => beep(880, 0.05, "square", 0.025),
// …(中略)…
catchBerry: () => {
beep(988, 0.08, "triangle", 0.05);
setTimeout(() => beep(1319, 0.12, "triangle", 0.05), 70);
}, clear: () => {
[523, 659, 784, 1047].forEach((f, i) => {
setTimeout(() => beep(f, 0.14, "triangle", 0.05), i * 110);
});
},
};
- 実をキャッチ:高い音を2つ、少しずらして鳴らす(「ピロン」)
- ステージクリア:ドミソドの4つの音を順番に鳴らす(「ピロリロリン」)
- ミス:音を下げていく(
slideToで 440Hz → 110Hz)と、がっかり感が出る
2. 音量はだんだん小さくする
音量をいきなり 0 にすると「プツッ」というノイズが出ることがあります。exponentialRampToValueAtTime で、だんだん小さくして消すのがポイントです。なお、この関数は 0 にはできないので、0.0001 のような小さな数を使います。
3. 最初のクリックまで音は鳴らない
ブラウザには「人が操作するまで、勝手に音を出してはいけない」というルールがあります。そのため、最初にクリックやキー操作があったときに、音の装置を準備しています。
// ブラウザは「人が操作するまで音を出してはいけない」ルールなので、
// 最初の操作のときに音の装置を準備する
function unlockAudio() {
if (!audio) {
const AudioContextClass = window.AudioContext || window.webkitAudioContext;
if (AudioContextClass) {
audio = new AudioContextClass();
}
}
if (audio && audio.state === "suspended") {
audio.resume();
}
}
「効果音が鳴らない」ときは、まずここを疑ってみてください。
4. 音のオン・オフを用意する
電車の中など、音を出したくない場面もあります。ゲームには音のオン・オフのボタンを付けて、設定をブラウザに保存しておくと親切です。
まとめ
- Web Audio API を使えば、音声ファイルなしで効果音が作れる
- 「音のもと → 音量のつまみ → スピーカー」の順につないで鳴らす
- 音の高さ・長さ・音色を変えて、重ねたり、上げ下げしたりすると表現が広がる
- 最初のユーザー操作で音の装置を準備するのを忘れずに
ほかのしくみも知りたい人は、ブロック崩しの当たり判定の作り方もどうぞ。コードの全体は GitHub で公開しています。


