Web Audio API - Javascript

Web Audio とは

Web ブラウザ上で音を生成・処理・再生するためのAPIです。

音の作成

Web Audio では、音の高さは、周波数で指定します。

周波数で音を扱うのは不便なので、MIDIノート番号を利用して周波数を計算します。

MIDIノート番号が 69 なら 「ラ」の 440Hz です。

MIDIノート番号に、12 を足したり引いたりした数がオクターブ違いの音です。

MIDIノート番号から周波数の変換は次のようにします。

function m_to_f(midi) {
  return 440 * Math.pow(2, (midi - 69) / 12);
}
// m_to_f:midi to frequency

音の長さを求めるには次のようにします。

function to_duration(tempo, length) {
  return (60 / tempo) * (4 / length);
}

音を鳴らす最低限のプログラム

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>sample</title>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <button type="button" id="btn">button</button>
</body>
</html>

script.js

window.addEventListener('load', function(){
  let btn = document.getElementById('btn');
  btn.addEventListener('click', function(){
    let audio = new AudioContext(); // AudioContext オブジェクトの作成
    let oscillator = audio.createOscillator(); // オシレータの初期化
    oscillator.connect(audio.destination); // 出力先に接続
    oscillator.start(0); // 音源の再生
    oscillator.stop(0 + 0.1); // 音源の停止
  })
});

destination:

宛先、行き先

Oscillator:

発振器

「 oscillator.connect(audio.destination) 」で、出力先(destination)に接続します。

音程を変えてみる

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>sample</title>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <button type="button" id="btn">button</button>
</body>
</html>

script.js

window.addEventListener('load', function(){
  let btn = document.getElementById('btn');
  btn.addEventListener('click', function(){
    let audio = new AudioContext();
    let oscillator = audio.createOscillator();
    oscillator.frequency.setValueAtTime(440, 0);
    oscillator.frequency.setValueAtTime(880, 2);
    oscillator.connect(audio.destination);
    oscillator.start(); // 音源の再生
    oscillator.stop(5); // 音源の停止
  })
});

frequency :

周波数

「 setValueAtTime 」で音の周波数と開始される時間が指定できます。

「 oscillator.frequency.setValueAtTime(440, 0) 」だと、0 秒になったら 440Hz にします。

「 oscillator.frequency.setValueAtTime(880, 2) 」だと、開始から2秒後に 880Hz にします。

音量を変える

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>sample</title>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <button type="button" id="btn">button</button>
</body>
</html>

script.js

window.addEventListener('load', function(){
  let btn = document.getElementById('btn');
  btn.addEventListener('click', function(){
    let audio = new AudioContext();
    let gainNode = audio.createGain();
    let oscillator = audio.createOscillator();
    let currTime = audio.currentTime;
    
    oscillator.frequency.setValueAtTime(440, 0);
    
    gainNode.gain.setValueAtTime(0, currTime);
    gainNode.gain.linearRampToValueAtTime(1, currTime + 3);

    oscillator.connect(gainNode).connect(audio.destination);
    oscillator.start(currTime); // 音源の再生
    oscillator.stop(currTime + 3); // 音源の停止
  })
});

音の変化のメソッドには次のようなものがあります。

メソッド 内容
setValueAtTime(value, startTime) startTime になったら値を value にする
linearRampToValueAtTime(value, endTime) endTime に丁度 value になるように現在値から直線的に変化させる
exponentialRampToValueAtTime(value, endTime) endTime に丁度 value になるように現在値から指数的に変化させる

発振器の周波数を変更する

指定する値には次の4つがあります。

内容
sine 正弦波(規定値)
square 矩形波
sawtooth のこぎり派
triangle 三角派

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>sample</title>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <button type="button" id="btn">button</button>
</body>
</html>

script.js

window.addEventListener('load', function(){
  let btn = document.getElementById('btn');
  btn.addEventListener('click', function(){
    let audio = new AudioContext();
    let gainNode = audio.createGain();
    let oscillator = audio.createOscillator();
    let currTime = audio.currentTime;

    oscillator.type='sawtooth';
    oscillator.frequency.setValueAtTime(440, 0);

    gainNode.gain.setValueAtTime(1, currTime);
    gainNode.gain.exponentialRampToValueAtTime(30, currTime + 5);

    oscillator.connect(gainNode).connect(audio.destination);
    oscillator.start(currTime); // 音源の再生
    oscillator.stop(currTime + 5); // 音源の停止
  })
});