はじめてWeb Audio APIに触ってみる

2017/12/4追記
[実際に動くサンプルです。](https://hibikinekage.github.io/web-audio-api-test/)


普段はDTMとかで音楽に触れています響音カゲです。Web Audio APIというものを知り、ブラウザでどこまでできるのかやってみたくなったのでいろいろいじってみることにしました。

「初めて触る人でもこんなに簡単に音が出るよ！」って感じの紹介記事です。

# とりあえず動かしてみる
サイン波、三角波、矩形波、ノコギリ波の4種類の波形を鳴らしてみます。

```index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Web Audio API Test</title>
  <link rel="stylesheet" href="./index.css">
</head>

<body>
  <button onclick="playOsc('sine')">Sin</button>
  <button onclick="playOsc('triangle')">Triangle</button>
  <button onclick="playOsc('square')">Square</button>
  <button onclick="playOsc('sawtooth')">Sawtooth</button>
  <button onclick="stopOsc()">Stop</button>
  <input id="gain" type="range" />
  <script src="./play-osc.js"></script>
</body>

</html>
```
```play-osc.js
// AudioContextを取得
window.AudioContext = window.webkitAudioContext || window.AudioContext;
const audioCtx = new AudioContext();

let play = false;
let osc;
let gain;
let gainCtx;

document.getElementById('gain').onchange = (e) => {
  console.log(e.target.valueAsNumber);
  gain = convertRangeValue(e);
  if (typeof gainCtx !== 'undefined') {
    gainCtx.gain.value = gain;
  }
};

function convertRangeValue(e) {
  return e.target.valueAsNumber / 100;
}

function playOsc(waveformType = 'sine') {
  if (!play) {
    osc = audioCtx.createOscillator();
    gainCtx = audioCtx.createGain();
    osc.connect(gainCtx);
    gainCtx.connect(audioCtx.destination);
    osc.frequency.value = freq;
    gainCtx.gain.value = gain;
    console.log(gainCtx);
    osc.start();
    play = true;
  }
  osc.type = waveformType;
}

function stopOsc() {
  if (play) {
    osc.stop();
    play = false;
  }
}
```
## 実行結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/152713/6819f910-8386-aba8-c4e0-4d302e3a185e.png)

音が出た！

# AttackとReleaseをつけてみる
次はアタックとリリースで音の立ち上がりと終わりに音量の変化をつけてみます。

```index.html
  <!-- 追加 -->
  <p>attack:<input id="attack" type="range" /></p>
  <p>release:<input id="release" type="range" /></p>
```

```play-osc.js

let attack = 0.5;
let release = 0.5;

function convertRangeValue(e) {
  return e.target.valueAsNumber / 100;
}

document.getElementById('attack').onchange = (e) => {
  attack = convertRangeValue(e);
}

document.getElementById('release').onchange = (e) => {
  release = convertRangeValue(e);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function playOsc(waveformType = 'sine') {
  if (!play) {
    osc = audioCtx.createOscillator();
    gainCtx = audioCtx.createGain();
    osc.connect(gainCtx);
    gainCtx.connect(audioCtx.destination);
    osc.frequency.value = 440;
    gainCtx.gain.value = 0;  // 0からスタートさせて
    console.log(gainCtx);
    gainCtx.gain.linearRampToValueAtTime(gain, audioCtx.currentTime + attack); // gainの値まで上げる
    osc.start();
    play = true;
  }
  osc.type = waveformType;
}

function stopOsc() {
  if (play) {
    gainCtx.gain.linearRampToValueAtTime(0, audioCtx.currentTime + release);  // ゆるやかにゼロにする
    play = false;
  }
}
```

## 実行結果
アタックとリリースだけですが音量変化がつきました！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152713/681aaf83-b7ea-e626-f9ed-c0746f350182.png)

# 音程を変えてみる
次に音程を変えてみます。

```play-osc.js
let freq = 440;

document.getElementById('freq').onchange = (e) => {
  freq = convertRangeValue(e) * 950 + 50; // 20Hz~1000Hzまでマッピングしてみる
  if (typeof osc !== 'undefined') {
    osc.frequency.value = freq;  // 音程変える
  }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function playOsc(waveformType = 'sine') {
  if (!play) {
    osc = audioCtx.createOscillator();
    gainCtx = audioCtx.createGain();
    osc.connect(gainCtx);
    gainCtx.connect(audioCtx.destination);
    osc.frequency.value = freq;  // 音程セット
    gainCtx.gain.value = 0;
    console.log(gainCtx);
    gainCtx.gain.linearRampToValueAtTime(gain, audioCtx.currentTime + attack);
    osc.start();
    play = true;
  }
  osc.type = waveformType;
}
```

## 実行結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/152713/794b2aba-863a-979d-272e-2c749cd9c6e4.png)

これであなたのおうちのスピーカーが何Hzまで出るかチェックできますね！

# 感想
ブラウザにオシレーターが乗っかる時代が来るなんて今まで想像できませんでした。Audio Streamをいじれるのでいろいろインタラクティブなサウンドコンテンツを作れそうで面白いです。そのうち簡単な打ち込みツール作りたいです。

[ソースコード](https://github.com/HibikineKage/web-audio-api-test)