当サイトはアフィリエイト広告(PR)を利用しています

音声ファイルなしで効果音を作る方法|Web Audio APIで「ピッ」「ポン」を鳴らす【JavaScript】

音声ファイルなしで効果音を作る方法|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つです。

  1. オシレーター(音のもと)を作る:決まった高さの音を出し続ける部品です
  2. ゲイン(音量のつまみ)を作る:音の大きさを調整します
  3. つなぐ:「音のもと → 音量のつまみ → スピーカー」の順につなぎます
  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 で公開しています。

カカポの森のブロック崩しで遊ぶ(音が出ます)