ブラウザとMIDIデバイスをHTMLタグで接続する

この記事は [WebAudio Web MIDI API Advent Calendar 2016](http://qiita.com/advent-calendar/2016/webaudio) の17日目です。

今回の目的はズバリこれ。

**「ブラウザとMIDIデバイスを簡単につなげる」**

Chrome 43からChromeををインストールしたら設定無しでWeb MIDI APIが利用できるようになりました。2015年6月くらいの出来事です。（[DTM Stationの記事](http://www.dtmstation.com/archives/51942052.html)）
個人的にはこの時点でたくさんのWeb MIDI APIを使ったアプリを書いていたのですが、毎回**「あれっ？これ書かなかったっけ？」**というデジャブがいつもありました😅 お陰で覚えてしまった訳ですが**「もっと簡単になるようにどうにかしたい」**という気持ちが抑えきれずにいろいろと試行錯誤をした結果最終的に落ち着いている`x-webmidi`の使い方を簡単に説明しようと思います。

（MIDIデバイス必須の記事です。お手元に無い皆様には大変申し訳ありません・・・）

#WebMIDIAPIWrapper
最初に作ったのが[WebMIDIAPIWrapper](https://github.com/ryoyakawai/WebMIDIAPIWrapper)です。これはJavaScriptのPrototypeとして作成しました。
MIDIメッセージの送信はもちろんのこと、受信したメッセージがどのメッセージなのかも分かるようにし作りました。
が、実装にそこそこ手間がかかる感があり、なんとかできないか？と常に思っていました。


#Polymer
私のPOSTでは毎回登場するPolymer。Web Componentsのラッパみたいなもので、カスタムのHTMLタグを作ることができます。
このPolymerを知ったことをキッカケに、
**「タグだけ書いたらMIDIデバイス使えたら便利」**
という夢から刷新することを考え始めました。

Polymerについて詳しくはこちら▶[「基礎からわかる Web Components 徹底解説 〜仕様から実装まで理解する〜」](https://html5experts.jp/series/web-components-2/)

#x-webmidi
刷新したのが[x-webmidi](https://github.com/ryoyakawai/x-webmidi)。夢通りHTMLタグのみで実装ができるようになっています。
**「Polymerのエレメント？それ難しいんでしょ？」**
と聞こえて来そうですがとても簡単です。順を追って説明します。

##実装
（Google Chromeでの動作を想定して書いています）

**0. bowerをご存知な方**

````shell:shell
$ bower install --save x-webmidi;
````

以上で、以下の1, 2, 3は省略することが可能です。

**1. Polymerをダウンロード**
[ここから入手](https://github.com/Polymer/polymer/archive/master.zip)します。

**2. x-webmidiをダウンロード**
[ここから入手](https://github.com/ryoyakawai/x-webmidi/archive/master.zip)します。

**3. ダウンロードしたファイルを配置する**
`bower_components`というディレクトリを作成します。

````shell:shell
$ mkdir bower_components;
````

1, 2でダウンロードしたファイルをunzip。
unzipすると`poymer-master`または`x-webmidi-master`というディレクトリが出来上がりますので、名前から`-master`を削除して、`bower_components` に移動します。

````shell:shell
$ unzip polymer.zip;
$ unzip x-webmidi.zip;
$ mv polymer-master bower_components/polymer;
$ mv webaudio-controls-master bower_components/webaudio-controls;
````

**4. 入力デバイスからのメッセージを表示**
`index.html`とか適当な名前でファイルを作成し以下のHTMLを記述します。

````html:html
<html>
  <head></head>
  <body>
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="bower_components/x-webmidi/x-webmidirequestaccess.html">
    <x-webmidirequestaccess sysex input output></x-webmidirequestaccess>

    MIDI INPUT: <x-webmidiinput id="midiinput"></x-webmidiinput><br>

    <div id="printout"></div>

    <script type="text/javascript">
     const midiinput=document.querySelector("#midiinput");
     midiinput.addEventListener("midiin-event:midiinput", (event) => {
         const out=[];
         for(const index in event.detail.property) {
             out.push(index + " : " + event.detail.property[index]);
         }
         document.querySelector("#printout").innerHTML=out.join("<br>");
     });
    </script>

  </body>
</html>
````

MIDI入力デバイスからのMIDIメッセージの取得は以上で完了です。

MIDI入力デバイスを接続して、操作すると以下のようなメッセージが表示されるはずです。
<img width="250" alt="Screen Shot 2016-12-16 at 1.44.15 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/61221/0c5824a9-ac29-5a76-7f01-73889cbb2214.png">

画像に表示されている値の説明は以下です。
- `raw` : 生MIDIメッセージ
- `type` : メッセージのタイプ（channel / systemCommon / systemRealtime）
- `statusNum` : StatusByte
- `channel` : チャンネル番号（0 - 15）
- `subType` : メッセージの種類名 (noteOn / noteOff / controller 等、全17種類)
- `noteNumber` : 押下した鍵盤番号
- `velocity` : velocity
- `frequency` : noteNumberの周波数
- `intl` : ノートの名前（International形式）

`subType`によって出力は変わりますので是非試してみてください🎹
ちなみに、MIDIメッセージに関しての説明は
[11日目のWebAudio Web MIDI API Advent Calendar 2016](http://qiita.com/amichang/items/00405ad3bb1d6be0b5e1)
に書かれていますので、そちらをご参照ください！

**5. 入力デバイスからのメッセージを出力デバイスにバイパス**
以下のようなコードにします。

````html:html
<html>
  <head></head>
  <body>
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="bower_components/x-webmidi/x-webmidirequestaccess.html">
    <x-webmidirequestaccess sysex input output></x-webmidirequestaccess>

    MIDI INPUT: <x-webmidiinput id="midiinput"></x-webmidiinput><br>
    MIDI OUTPUT: <x-webmidioutput id="midioutput"></x-webmidioutput>

    <div id="printout"></div>

    <script type="text/javascript">
     const midiinput=document.querySelector("#midiinput");
     midiinput.addEventListener("midiin-event:midiinput", (event) => {
         const out=[];
         for(const index in event.detail.property) {
             out.push(index + " : " + event.detail.property[index]);
         }
         document.querySelector("#printout").innerHTML=out.join("<br>");
         document.querySelector("#midioutput").sendRawMessage(event.detail.data);
     });
    </script>

  </body>
</html>
````

追加したのは以下の2行です。

````html:9行目
MIDI OUTPUT: <x-webmidioutput id="midioutput"></x-webmidioutput>
````

````javascript:21行目
document.querySelector("#midioutput").sendRawMessage(event.detail.data);
````

`MIDI INPUT`に加えて、`MIDI OUTPUT`が画面には表示されます。
それぞれを選択状態にをすると、`MIDI INPUT`のメッセージが`MIDI OUTPUT`へ流れるようになりました。


#まとめ
非常に簡単な説明になっていますが、`x-webmidi`を使うと非常に簡単にMIDIデバイス（Inputデバイス、Outputデバイス）をブラウザに接続して、Webアプリケーション内で利用できることが分かりましたか？
ということで、MIDIデバイスをブラウザに接続してみたいけど難しそうでイマイチ手を出せていない方、とか、何度もWeb MIDI APIのコードを書きたくない方は是非ご利用ください😃

ということで、よいWeb MIDIライフをっ🎹