Web Audio APIで、簡単なシンセサイザーを作ってみる  / 1: まずは音を鳴らす

# Web Audio APIを触ってみた
音楽好きとしては、やはり何か惹かれるWeb Audio API。
[timbre.js](http://mohayonao.github.io/timbre.js/)のような素晴らしいライブラリも公開されているので、そういうものを扱えば簡単に楽しめるとは思いますが、勉強も兼ねて、あえて素のWeb Audio APIを書いてみました。
偉そうなタイトルにしましたが、僕自身まったくの手探り状態なので、間違いやアドバイスがありましたら、ぜひコメントでご教示いただければ幸いです。

## 役に立ちそうなページ
* [Web Audio API - Web API インターフェイス | MDN](https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API) - APIリファンレンス
* [Web Audio API の基礎 - HTML5 Rocks](http://www.html5rocks.com/ja/tutorials/webaudio/intro/) - 
日本語訳されたチュートリアルページ
* [Web Audio API (日本語訳)](http://g200kg.github.io/web-audio-api-ja/) - W3Cドキュメントの日本語翻訳版

# まずは音を鳴らしてみる

キーボードを押すとサイン波が出てくる、簡単なピアノのようなものを作りました。
キーボードのZキー　〜　,キーあたりを押すと、音が鳴ります。

実際の動作例は[こちら](https://jsfiddle.net/scnb3csn/2/)で確認できます。

```javascript:synth.app
'use strict';

// Web Audio APIを利用するためのインスタンス生成
var audioContext = new AudioContext();
// キーごとにMIDIノートナンバーを割り振る
var keymap = {
  // Zキー = C4
  90: 60,
  // Sキー = C#4
  83: 61,
  // Xキー = D4
  88: 62,
  // Dキー = D#4
  68: 63,
  // Cキー = E4
  67: 64,
  // Vキー = F4
  86: 65,
  // Gキー = F#4
  71: 66,
  // Bキー = G4
  66: 67,
  // Hキー = G#4
  72: 68,
  // Nキー = A4
  78: 69,
  // Jキー = A#4
  74: 70,
  // Mキー = B4
  77: 71,
  // ,キー = C5
  188: 72
};

// キーダウンした際の処理
document.onkeydown = function(keyDownEvent) {
  // キー押しっぱなしの状態で発火した場合は、動作を終了する
  if (keyDownEvent.repeat === true) {
    return;
  }

  // オシレーターを作成
  var osciillatorNode = audioContext.createOscillator();
  // MIDIノートナンバーを周波数に変換
  var freq = 440.0 * Math.pow(2.0, (keymap[keyDownEvent.keyCode] - 69.0) / 12.0);

  // オシレーターの周波数を決定
  osciillatorNode.frequency.value = freq;
  // オシレーターを最終出力に接続
  osciillatorNode.connect(audioContext.destination);
  // オシレーター動作
  osciillatorNode.start();

  // キーを離した際に音が止まるよう、イベントを登録する
  document.addEventListener('keyup', checkKeyUp);

  // キーを離したかどうかチェック
  function checkKeyUp(keyUpEvent) {
    // 離したキーが、押下したキーで無い場合は処理を行わない
    if (keyUpEvent.keyCode !== keyDownEvent.keyCode) {
      return;
    }

    // オシレーターを停止する
    osciillatorNode.stop();
    // 自身のイベントを削除
    document.removeEventListener('keyup', checkKeyUp);
  }
};
```

---
#　解説
上から順番に解説していきたいと思います。


```
// Web Audio APIを利用するためのインスタンス生成
var audioContext = new AudioContext();
```
Web Audio APIを利用するためには、まずは`AudioContext`を作成する必要があります。
はじめの一歩。

```
// キーごとにMIDIノートナンバーを割り振る
var keymap = {
  // Zキー = C4
  90: 60,
  // Sキー = C#4
  83: 61,
  ....
  ...

```
キーボードのZキー　〜 ,キーあたりを鍵盤として使うため、キーごとにMIDIノートナンバーを割り振りました。
直接周波数を指定してもいいかなと思いましたが、業界の標準に従っといたほうが何かと後で楽そうです。
A = 441Hzとかへ変更するのも楽にできそうだし。


```
// キーダウンした際の処理
document.onkeydown = function(keyDownEvent) {
  // キー押しっぱなしの状態で発火した場合は、動作を終了する
  if (keyDownEvent.repeat === true) {
    return;
  }
```
キーボードのキーが押下された場合は、これ以降のイベントが発火します。
しかしキーを押しっぱなしにしていると、`window.onkeydown`は押している間に何回も発火してしまうので、
発火させるのはキーを最初に押した一回だけに限定する必要があります。
`keyDownEvent.repeat`で、押した初回の発火なのか、押しっぱなし発火なのか判定できますので、
押しっぱなし発火の場合は以降の処理を行わないようにします。

```
  // オシレーターを作成
  var osciillatorNode = audioContext.createOscillator();
  // MIDIノートナンバーを周波数に変換
  var freq = 440.0 * Math.pow(2.0, (keymap[keyDownEvent.keyCode] - 69.0) / 12.0);

  // オシレーターの周波数を決定
  osciillatorNode.frequency.value = freq;
```
最初に生成した`audioContext`から、`createOscillator()`を実行して、オシレーター(音波の発生装置)を作成します。
また、押下されたキー番号から、対応するMIDIノートナンバーを周波数に変換し、`frequency.value`に鳴らす周波数を指定します。
オシレーターの音は、ちゃんと周波数で指定する必要があるようです。

```
  // オシレーターを最終出力に接続
  osciillatorNode.connect(audioContext.destination);
  // オシレーター動作
  osciillatorNode.start();
```
ここで音がなります！
  `osciillatorNode.start()`でオシレーターを動作させることができますが、これ単体だけ実行しても音はなりません。
オシレーターの音が、どこへ向かっていくのか、きちんと指定する必要があります。
`osciillatorNode.connect()`で、どこへ接続するのか、指定が可能です。
今回は、最終的な出力先である、`audioContext.destination`を選びました。
実際の楽器でも、ギター→エフェクター→アンプ　とつないでいくのと、同じような考え方ですね。

```
  // キーを離した際に音が止まるよう、イベントを登録する
  document.addEventListener('keyup', checkKeyUp);

  // キーを離したかどうかチェック
  function checkKeyUp(keyUpEvent) {
    // 離したキーが、押下したキーで無い場合は処理を行わない
    if (keyUpEvent.keyCode !== keyDownEvent.keyCode) {
      return;
    }

    // オシレーターを停止する
    osciillatorNode.stop();
    // 自身のイベントを削除
    document.removeEventListener('keyup', checkKeyUp);
  }
```
キーを離した際に音を停止するように、キーのリリースを監視するイベントを登録します。
別のキーが離された時に、音が停止しないように、処理の前にきちんと離されたキーの照合を行います。

`osciillatorNode.stop()`で音を止めることができます。
また、最後にキー停止イベントそのものを削除することを忘れないように。

#　次回は...

いきなりそれっぽいのがすぐできてしまいました。
いきなりポリフォニーで音が鳴らすことができて、ちょっとびっくりです。

次回は、キーをリリースした際にブツブツ言わないように、
また、多彩な音が出せるようにするため、ADSRエンベロープを作成してみようと思います。

次回！！！

[Web Audio APIで、簡単なシンセサイザーを作ってみる / 2: 音をフェードアウトさせる](http://qiita.com/tomoya_ozawa/items/bfd09b436075af916833)