Web MIDI APIを触ってみた

# gloops AdventCalender 5日目

[gloops advent calender](http://qiita.com/advent-calendar/2016/gloops) 5日目です:hand_splayed_tone2::sunglasses:
4日目@t_furuyaさんのは[VisualStudioCodeでGo言語開発環境を作ってみた](http://qiita.com/t_furuya/items/753419d178c81600ce78)でした！

VSCodeいいですよね！何も入れなくてもmdとかも書けてお気に入りです
今日書いた記事のWeb MIDI APIもVSCodeでコーディングしました！

さて、今回のタイトルのWeｂ MIDI APIなんですが、名前は知ってはいたけど触ったことがなくちょうどいい機会だったので触ってみました
初歩的な部分ではありますがご覧あれ〜

## MIDIとは

ちょっと調べてみると、MIDIはMusical Instrument Digital Interfaceの略のです。略を見てわかるように電子楽器をつなげる共通企画のようですね。

なるほど、じゃあWeb MIDI APIはWebで電子楽器をつなげて使うためのAPIか。

## 早速やろうと思ったが・・・

大変なことに気づきました。

**MIDIデバイスなんて持ってないじゃん。。。**

と焦ってぐぐったら出てきました

仮想MIDIキーボードです
https://github.com/mohayonao/virtual-midi-keyboard

Electronで作っているようですね！
詳しくは読んでないですが、使わせていただきますm(_ _)m

`npm install`して`start`したらすぐにキーボードが起動してくれました

<img width="600" alt="スクリーンショット 2016-12-04 21.17.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/46072/a79f7285-9bbc-e916-973f-77d761ed939c.png">

## 使ってみよう

### つなげる

まず、ブラウザとMIDIデバイスを接続してみましょう

```js:app.js
(function () {
	// MIDIデバイス
	var midiDevices = {
		inputs: {},
		outputs: {}
	};
	// 成功したときの処理
	function requestSuccess(data) {
		console.log('success!!!', data);
	}
	// 失敗したときの処理
	function requestError(error) {
		console.error('error!!!', error);
	}
	// MIDIデバイスにアクセスする
	function requestMIDI() {
		if (navigator.requestMIDIAccess) {
			navigator.requestMIDIAccess().then(requestSuccess, requestError);
		} else {
			requestError();
		}
	}
	requestMIDI();
})();
```

`requestMIDI`でMIDIデバイスにアクセスしてます
`navigator.requestMIDIAccess`を呼ぶとPromise型で返ってくるので成功時と失敗時の処理を登録しておきましょ

一応非対応だった場合は`requestError`を呼んでエラーにしちゃってます
ちなみに今のブラウザの対応状況は[コチラ](http://caniuse.com/#search=Web%20MIDI%20API)
この記事を書いてるときはChromeとOperaだけって感じですね
<img width="600" alt="スクリーンショット 2016-12-04 14.34.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/46072/491e46c2-3449-9128-352c-58298f337003.png">

### デバイスからの入力を受け取る

受け取ったときのメソッドを用意しましょう

```js:app.js
// Inputを受け取ったときのイベント
function inputEvent(e) {
	console.log('Input!!!', e);
}
```

成功したときの処理を変更します

```js:app.js
// 成功したときの処理
function requestSuccess(data) {
	// Inputデバイスの配列を作成
	var inputIterator = data.inputs.values();
	for (var input = inputIterator.next(); !input.done; input = inputIterator.next()) {
		var value = input.value;
		// デバイス情報を保存
		midiDevices.inputs[value.name] = value;
		// イベント登録
		value.addEventListener('midimessage', inputEvent, false);
	}

	// Outputデバイスの配列を作成
	var outputIterator = data.outputs.values();
	for (var output = outputIterator.next(); !output.done; output = outputIterator.next()) {
		var value = output.value;
		// デバイス情報を保存
		midiDevices.outputs[value.name] = value;
	}
}
```

最初に用意しておいた`midiDevices`の中にデバイス情報を保存しておきましょう
そして、MIDIデバイスからinputがあったときのイベント登録をします

これで実行するして鍵盤を叩くと`Input`とログが出てきますね

### データを処理しよう

最後に、`inputEvent`を更新しましょう

```js:app.js
// Inputを受け取ったときのイベント
function inputEvent(e) {
	var target = e.target;
	var device = midiDevices.outputs[target.name];
	var message = '';
	var numArray = [];
	// 2桁の16進数にして表示する
	event.data.forEach(function(val) {
		numArray.push(('00' + val.toString(16)).substr(-2));
	});
	message = numArray.join(' ');
	// InputしたDeviceに結果を送信する
	device.send(e.data);

	// 2桁の16進数を表示
	console.log(message);
}
```

dataの中に入ってるものは以下です

* 1つ目 : ノートオン信号・チャンネル(n = チャンネル)
  * ノートオン時は9n
  * ノートオフ時は8n
* 2つ目 : ノートナンバー(音の高さ)
* 3つ目 : ベロシティ(鍵盤を離す速さ)

実際に出力されたログはこんな感じになります
<img width="306" alt="スクリーンショット 2016-12-04 21.26.12 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/46072/4833e1b9-231e-32f3-c229-125b741b642b.png">

この共通化されたデータで電子楽器がどんな音をだすのかを判別してるんですね

これでサンプルは完成です！

## 終わりに
導入はかなり簡単でした
最近ではBlutoothを使ってのデータのやり取りもできるようです
これはかなり夢が広がりますね！
音楽だけでなく、いろいろなものにも使えそうなので今後はもっと深いところまで触りたいです

明日は@Ak_Suzukiさんです！