2026年5月26日 · 技術解説

AudioContext と GainNode の基本

audiocontext-basics の記事アイキャッチ画像

Web Audio API でブラウザ上の音を扱うとき、最初に出会うのが AudioContextGainNode です。この2つを理解することは、シンセサイザー・音楽プレイヤー・効果音処理など、すべての音声機能の出発点になります。この記事では、最小限のコードでこの2つの基本を解説します。

AudioContext とは何か

AudioContext は「音声処理の作業場」のような存在です。すべての音声ノード(音源・加工・出力)はこのコンテキストの中に作られ、つながり合って動作します。1ページに通常1つだけ作るのが基本です。

const audioCtx = new AudioContext();
console.log(audioCtx.sampleRate); // 44100 もしくは 48000

sampleRate は1秒間に何回サンプルを生成するかという数値で、ブラウザやデバイスによって 44.1kHz か 48kHz が一般的です。

オートプレイ制限への対処

2018年以降、ほとんどのブラウザは「ユーザー操作なしでの音声再生」をブロックします。AudioContext は最初、suspended 状態で生成されるため、明示的に resume() しないと音が出ません。

button.addEventListener('click', async () => {
  if (audioCtx.state === 'suspended') {
    await audioCtx.resume();
  }
  // ここから音を鳴らす処理
});

「再生ボタンが押されたら resume する」という流れが、Web Audio アプリの定型パターンです。

GainNode で音量を操る

GainNode はその名のとおり「ゲイン(音量倍率)」を担当するノードです。値は通常 0〜1 の範囲(1で原音そのまま、0で無音)です。

const gain = audioCtx.createGain();
gain.gain.value = 0.5; // 50%の音量

注意点として、ノードを destination に接続するまで音は出ませんaudioCtx.destination がスピーカー出力にあたります。

ノードを接続する

Web Audio はノードグラフ(有向グラフ)です。音源 → 加工 → 出力という流れで connect() を使って接続します。

const osc = audioCtx.createOscillator();
osc.frequency.value = 440; // A4

osc.connect(gain).connect(audioCtx.destination);

osc.start();
osc.stop(audioCtx.currentTime + 1); // 1秒後に停止

このコードを実行すると、440Hz のサイン波が音量50%で1秒間鳴ります。connect() をチェーンできるのが便利です。

滑らかな音量変化

gain.gain.value = 0.5 のように直接代入することもできますが、急な音量変化は「プチッ」というノイズを発生させることがあります。これを避けるには、専用のオートメーションメソッドを使います。

// 0秒で0、0.1秒かけて1.0までフェードイン
gain.gain.setValueAtTime(0, audioCtx.currentTime);
gain.gain.linearRampToValueAtTime(1.0, audioCtx.currentTime + 0.1);

主な選択肢は以下の3つです:

  • setValueAtTime(value, time): 指定時刻に瞬時に変更
  • linearRampToValueAtTime(value, time): 直線的に変化
  • exponentialRampToValueAtTime(value, time): 指数的に変化(人間の聴覚に自然)

複数の音源をミックスする

GainNode は「合流点」として使うこともできます。複数の音源を1つの GainNode に接続すれば、合算した音量で出力されます。

const masterGain = audioCtx.createGain();
masterGain.gain.value = 0.7;
masterGain.connect(audioCtx.destination);

[osc1, osc2, osc3].forEach(o => o.connect(masterGain));

シンセサイザーやDAW的なアプリでは、楽器ごとに個別のGainを持ち、最後にマスターGainで束ねる構造が定番です。

注意したい落とし穴

1. AudioContext を毎回作らない

クリックのたびに new AudioContext() を作ると、リソースが解放されないまま増えていきます。1ページ1つを使い回しましょう。

2. start() は1回しか呼べない

OscillatorNode は使い捨てのノードです。start() を呼んだ後に再生する場合は、新しいオシレータを作り直す必要があります。

3. 完了したノードは自動で解放されない

ノード自体はガベージコレクタに任せますが、長時間動くアプリでは disconnect() を明示的に呼ぶと安全です。

動作確認用の最小コード

<button id="play">再生</button>
<script>
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
document.getElementById('play').addEventListener('click', async () => {
  if (audioCtx.state === 'suspended') await audioCtx.resume();

  const osc = audioCtx.createOscillator();
  const gain = audioCtx.createGain();
  osc.frequency.value = 440;
  gain.gain.setValueAtTime(0, audioCtx.currentTime);
  gain.gain.linearRampToValueAtTime(0.3, audioCtx.currentTime + 0.05);
  gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.5);
  osc.connect(gain).connect(audioCtx.destination);
  osc.start();
  osc.stop(audioCtx.currentTime + 0.5);
});
</script>

このコードをHTMLファイルに保存してブラウザで開けば、ボタンを押すたびに440Hzのビープが0.5秒間鳴ります。Web Audio API の入口として、まずはこの「音を鳴らせた」体験を踏むのが大事です。

次のステップ

AudioContext と GainNode の基本が分かれば、次は音作りに進めます。オシレータの波形を変えると音色がどう変わるのか、フィルタで質感をどう作るのか — Web Audio の世界はここから広がっていきます。