Web BluetoothからBluetooth MIDIデバイスを使う

#これは何？
Bluetooth MIDIをサポートする機器をWeb Bluetoothを使ってウェブブラウザと接続する方法を、サンプルコード、ライブラリを使って説明します。

# Web MIDI APIとどこが違うの？メリットは？
## OSとブラウザ、Web MIDI API、Web Bluetoothの関係
[Web MIDI API](https://www.w3.org/TR/webmidi/)はW3Cにて標準化が進められているMIDIデバイスとウェブブラウザを接続するためのAPIです。  
「MIDIデバイス」をもう少し正確に書くと**「USB MIDIデバイス」**であり、OSが提供しているMIDIデバイス用のAPIをウェブブラウザがJavaScriptのAPIとして提供している機能です。よって、コンピュータに接続されたUSB MIDIデバイスは、OSに認識されている必要がありますので、現状ではBluetooth MIDIデバイスをコンピュータと接続して利用するにはOS固有のユーティリティを使って事前に接続作業をしておく必要があります。

## 何がいいの？
### Bluetooth MIDI
Bluetooth MIDIの良いところは「MIDIデバイスを無線でコンピュータと接続して利用することができること」だと考えています。ただしメッセージの送信の遅延の問題がありますので利用シーンが選ばれているように感じます。（特にプロユース）

### 個人的なおもいで
Bluetooth MIDIに関しては[NAMM Show](https://en.wikipedia.org/wiki/NAMM_Show)にて[Miselu](http://miselu.com/)さんから力強い発表をされていたのが心に残っています！2013年か2014年だったと思います。
**MiseluさんのおかげでMIDIデバイスが無線になった**と個人的には受け止めています。無線大好きな私は心から感謝しております。ありがとうございます！

###Web Bluetoothを使ってBluetooth MIDIを使うメリット
先に書いた「OSに認識されている必要がある」の部分が実はかなり面倒で、精通したユーザでないと見たこともないメニューからBluetooth MIDI機器をOSに認識させて接続する必要があるのでエクスペリエンス的にはBadな状態です。しかし、Web Bluetoothを使えばウェブブラウザのみで、Bluetooth MIDI機器の接続・切断が行なえますのでエクスペリエンスがかなり向上します。


# デモサイト
まずはユーザとして利用するときの手軽さから体験してみてください。（Bluetooth MIDI機器が必須です・・・：[僕の使ってるデバイス](https://amzn.to/2ElxSmB)）

**[MIDI Message Viewer: デモサイト](https://ryoyakawai.com/apps/midimsgv/)**
<a href="https://ryoyakawai.com/apps/midimsgv/"><img width="485" alt="Screen Shot 2019-02-20 at 15.32.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/61221/dec46a58-59a3-f37d-f171-0b8acd8cc99f.png"></a>

Bluetoothのアイコンをクリック/タップすると機器の検索が開始されます。あとはウェブブラウザが出す指示に従えば接続が完了します。

# 早速コードを書いてみる
**「いいことしかないみたいだけど、それ難しいんでしょ？」**
と聞こえてきそうだった（というか、自分が何度もコードを書きたくなかった）ので、ライブラリとして使えるようにしました。**このライブラリはMIDIのINPUTのにしか現在は対応していない**ことをご了承ください。

上記のデモのコードはコレ↓です。
**[MIDI Message Viewr: GitHub](https://github.com/ryoyakawai/midimessageviewer)**

Bluetooth MIDIをWeb Bluetoothで使うための最短+αで書くと[コンナカンジ](https://github.com/ryoyakawai/midimessageviewer/blob/master/sample_qiita.html)↓になります。

```html:sample_qiita.html
<html>
  <head>
    <title>Bluetooth MIDI Over Web Bluetooth | Sample Code</title>
    <style>
     .start-ble {
       background-color: #bdbdbd;
       border: none;
       border-radius: 3px;
       color: #ffffff;
       padding: 15px 32px;
       text-align: center;
       text-decoration: none;
       display: inline-block;
       font-size: 16px;
       cursor: pointer;
       outline:0;
     }
     .connected {
       background-color: #4285f4 !important;
     }
     .message {
       width: 400px;
       padding: 20px;
     }
    </style>
  </head>
  <body>
    <button id="start-ble" class="start-ble">Connect BLE MIDI Device</button>
    <div id="message" class="message"></div>
    <script type="module">
     import { BLEMIDIUtils } from "./scripts/blemidiutils.js";
     import { MIDIMessageUtils } from "./scripts/midimessageutils.js";

     let startButton = document.querySelector("#start-ble");
     let msgArea = document.querySelector("#message");

     let bleMIDIUtls = new BLEMIDIUtils();
     let midiMsgUtls = new MIDIMessageUtils();

     bleMIDIUtls.setMIDIParser(midiMsgUtls.parseMIDIMessage.bind(midiMsgUtls));
     let state = bleMIDIUtls.getDeviceConnected();
     bleMIDIUtls.setnMidiEventHandleCallback( event => {
       // MIDIメッセージを受け取るとevent.detailにMIDIメッセージが格納され、
       // ここで受け取れますので、実行した動作をここに書くことが可能です。
       let out = [];
       for(let key in event.detail.property) {
         out.push(key + " :: " + event.detail.property[key]);
       }
       msgArea.innerHTML = out.join("<br />")
     });
     bleMIDIUtls.setConnectedBleCallback( event => {
       // 接続完了時に実行されます。
       // 例えば、接続されたことUIに反映させる動作の指定が可能です。
       startButton.innerHTML = "Disconnect BLE MIDI Device";
       startButton.classList.add('connected');
       console.log('[Device Connected]');
     });
     bleMIDIUtls.setDisconnectedBleCallback( event => {
       // 切断完了時に実行されます。
       // 例えば、切断されたことUIに反映させる動作の指定が可能です。
       startButton.innerHTML = "Connect BLE MIDI Device";
       startButton.classList.remove('connected');
       msgArea.innerHTML = "";
       console.log('[Device Disconnected]');
     });
     document.querySelector("#start-ble").addEventListener('mousedown', event => {
       // 検索開始、切断を行うコードの例です。
       // 以下は、ボタンが押されたときに検索開始、切断と同時にボタンの装飾を更新しています。
       if(!bleMIDIUtls.getDeviceConnected()) {
         bleMIDIUtls.startBle.bind(bleMIDIUtls)(event);
       } else {
         bleMIDIUtls.endBle.bind(bleMIDIUtls)(event);
       }
     }, false);
    </script>
  </body>
</html>
```

カスタムのウェブアプリの開発は`setnMidiEventHandleCallback()` に行いたい動作を書くことで実現可能になっています。



# まとめ
簡単にBluetooth MIDI機器をウェブブラウザに接続することができました。ササッとBluetoothでコントロールするアプリを作りたいとかある場合は是非使ってみてください👍