Web MIDI APIでシンセサイザーの入力を受け取ってみた

##はじめに
この記事は [SLP_KBITその２ Advent Calendar 2016](http://qiita.com/advent-calendar/2016/slp_kbit2) の24日目の記事です。

最近Web MIDI APIなるものを知りました。
これを使うとMIDIに対応しているデバイスをPCに接続するだけで、JavascriptでMIDIの入出力が行えるそうです。なにそれすごい。
そんなわけで早速シンセサイザーを使ってMIDIの入力を受け取ってみます。

##MIDIについて
MIDIは電子楽器の演奏データを通信するための規格です。
演奏情報の音を、[音の高さ(ノート)、音の強さ(ベロシティ)、音の長さ(デュレーション)表現する](https://www.studiorag.com/blog/fushimiten/midi-basic/3#a4-3)そうです。
詳しいことは[WebAudio Web MIDI API Advent Calendar 2016](http://qiita.com/advent-calendar/2016/webaudio)の[18日目](http://qiita.com/armorik83/items/efaeb1124591e84fe9d3)の記事が参考になりました。

##MIDIプロトコル
MIDIのプロトコルで扱うデータとして、[音のON/OFF、使用するチャンネル、音の強弱、音程の変化があります](https://html5experts.jp/ryoyakawai/16787/)。
WikipediaでMIDIを調べたところ他にもいろいろなデータを送信しているようですが、これらのデータがあれば最低限演奏に必要なものは揃っています。

##MIDIデバイスを繋げる(物理)
今回はJUNO-Giというシンセサイザーを使用します。
このシンセサイザーをUSBケーブルでPCに接続します。
![写真 2016-12-25 0 52 34.jpg](https://qiita-image-store.s3.amazonaws.com/0/61622/687be964-1fa4-0f1a-c3d4-4176a36009f5.jpeg)


##使用できるMIDIデバイスを表示する
htmlはこんな感じです。

```html:index.html
<html>
  <head>
    <meta charset="UTF-8" />
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script type="text/javascript" src="sample.js"></script>
    <title>Web MIDI API</title>
  </head>
  <body>
    <label>入力デバイス</label>
    <ul id="input">
    </ul>

    <label>出力デバイス</label>
    <ul id="output">
    </ul>

    <label id="data">00 00 00</label>
  </body>
</html>
```

###MIDIの有効化
ブラウザでMIDIを有効にするには、```requestMIDIAccess()```を使用します。
また、引数にMIDIの有効が成功したときと失敗したときのコールバックを指定します。

```js
navigator.requestMIDIAccess().then(successCallback,faildCallback);
```

###MIDIデバイスの表示
成功時のコールバックで、入力のMIDIデバイスと出力のMIDIデバイスを配列で記録します。
また、記録時にリストで表示も行います。


```js:sample.js
navigator.requestMIDIAccess().then(successCallback,faildCallback);

var midi = null;
var inputs = [];
var outputs = [];

// MIDI接続成功時
function successCallback(m){
  midi = m;
  // 入力MIDIデバイスの記録
  var it = midi.inputs.values();
  for(var o = it.next(); !o.done; o = it.next()){
    inputs.push(o.value);
    $("#input").append("<li>"+ o.value.name +"</li>");
  }

  // 出力MIDIデバイスの記録
  var ot = midi.outputs.values();
  for(var o = ot.next(); !o.done; o = ot.next()){
    outputs.push(o.value);
    $("#output").append("<li>"+ o.value.name +"</li>");
  }
}

// MIDI接続失敗時
function faildCallback(msg){
  console.log("[Error]:"+msg);
}
```
うまくいけば、ページ読み込み時に現在接続されているMIDIデバイスが表示されいるはずです。
今回はJUNO-Giというシンセサイザーを使用しているため、その名前が表示されます。

![キャプチャ.JPG](https://qiita-image-store.s3.amazonaws.com/0/61622/13558a12-6d80-c1c9-3a7c-6ad1634015b0.jpeg)

##MIDI入力の値を表示する
配列に記録している入力のMIDIデバイスに、入力が来たときの処理を登録します。

```js
// 入力MIDIデバイスから入力が来たときの処理の登録
for(var cnt=0;cnt < inputs.length;cnt++){
  inputs[cnt].onmidimessage = onMIDIEvent;
}
```
今回は送られてきた信号をブラウザ上で表示させます。

```js
//入力MIDIデバイスから入力が来たときの処理
function onMIDIEvent(e){
  var str = "";
  for(var i=0, out=[]; i<e.data.length; i++) {
    str = str + e.data[i].toString(16).substr(-2) + " ";
  }
  str = str;
  $("#data").text(str);
}
```
全体のコードは以下のようになります。

```js
navigator.requestMIDIAccess().then(successCallback,faildCallback);

var midi = null;
var inputs = [];
var outputs = [];

// MIDI接続成功時
function successCallback(m){
  console.log("asd");
  midi = m;
  // 入力MIDIデバイスの記録
  var it = midi.inputs.values();
  for(var o = it.next(); !o.done; o = it.next()){
    inputs.push(o.value);
    $("#input").append("<li>"+ o.value.name +"</li>");
  }

  // 出力MIDIデバイスの記録
  var ot = midi.outputs.values();
  for(var o = ot.next(); !o.done; o = ot.next()){
    outputs.push(o.value);
    $("#output").append("<li>"+ o.value.name +"</li>");
  }

  // 入力MIDIデバイスから入力が来たときの処理の登録
  for(var cnt=0;cnt < inputs.length;cnt++){
    inputs[cnt].onmidimessage = onMIDIEvent;
  }
}

// MIDI接続失敗時
function faildCallback(msg){
  console.log("[Error]:"+msg);
}

//入力MIDIデバイスから入力が来たときの処理
function onMIDIEvent(e){
  var str = "";
  for(var i=0, out=[]; i<e.data.length; i++) {
    str = str + e.data[i].toString(16).substr(-2) + " ";
  }
  str = str;
  $("#data").text(str);
}

```

##実行する
それでは実行してみます。
鍵盤を叩くたびに値が変わっているのがわかります。
![写真 2016-12-25 1 25 57.gif](https://qiita-image-store.s3.amazonaws.com/0/61622/2a28a09b-7835-1ee2-fe64-34b3253c3f3f.gif)


##おわりに
今回はMIDIの入力を受け取るところまで行いました。
この調子で今度は音の出力や可視化を行っていこうと思います。

##参考
###Web MIDI API
[MIDIデバイスの準備不要 ！Web MIDI APIを使いこなそう！](https://html5experts.jp/ryoyakawai/16787/)
[JavaScriptだけでMIDIで遊べる！最高に乱暴なWeb MIDI API利用方法](http://qiita.com/tadfmac/items/e26fdf1034ad6dad4504)
###MIDIの知識
[Web MIDI APIを扱うためのMIDI基礎知識](http://qiita.com/armorik83/items/efaeb1124591e84fe9d3)
[MIDIが良く分かる。バンドマンのためのDTMの基礎知識](https://www.studiorag.com/blog/fushimiten/midi-basic)