この記事は、Web MIDI APIを題材にした連載の第二回目です。(第一回目はこちら)
第一回目はWeb MIDI APIでMIDI Inputデバイス、Outputデバイスを列挙し、利用する実装方法を説明してきましたが、詳細の実装の説明までできていませんでした。第二回ではx-webmidiというPolymer Elementを使い、第一回で実装した部分、また実装ができていなかったHotplugを含めて、お手軽に実装してしまう方法をご説明します。
前回に引き続き、今回もMIDIデバイスの準備は不要な内容になっていますので、最後までお試しいただけると嬉しいです。
Polymerとは?
「Web Componentsを簡単・便利にするライブラリ」です。Polymerを使うと簡単にWeb ComponentsのElementを作成することが可能です。本サイトHTML5Expert.jpでも連載記事がありますので、ぜひご覧ください。
そして今回は、Web MIDI APIをPolymer Element化したx-webmidiを使って、以下の2つのアプリの実装をしていきます。
- InputからOutputにMIDIメッセージを中継するアプリ
- SMF(Standard MIDI File)を再生するアプリ
x-webmidiとは?
Web MIDI APIは、外部のMIDIデバイスとUSB-MIDIで接続するAPIです。API自体には「デバイスをリストする」、「デバイスへMIDIメッセージを送信する」、「デバイスからのMIDIメッセージを受信を行う」、また、接続に関しては「Hotplug」が、それぞれサポートされています。
しかし、これらを実装するのは少し手間がかかります。自分自身の体験としては、複数アプリケーションを書いていると「アイデアをアプリケーションに落としこむ時、MIDIデバイスの制御の部分に労力をかけるのは極力抑えたい」と思うようになりました。そこで考えついたのが、Polymerを使って基本的な操作はElementにしてしまう方法です。そして生まれたのが「x-webmidi 」です。
さっそく実装してみよう
環境整備
連載第一回目の環境整備と同じです。ここでは手短に説明します。
Polymer本体、今回利用するx-webmidiをそれぞれダウンロードします。
開発するディレクトリを作成して、ダウンロードした2つのファイルを解凍し、以下の構成になるように配置してください。その後、同一ディレクトリにindex.htmlを作成します。
以上で環境整備は完了です。
では、実際に実際に開発を行っていきましょう。
InputからOutputにMIDIメッセージを中継するアプリ
作成する index.html のコード全体はこちらになります。それでは順に説明していきます。
<script src="bower_components/webcomponentsjs/webcomponents.js"></script> <link rel="import" href="bower_components/x-webmidi/x-webmidirequestaccess.html"> <link rel="import" href="bower_components/x-webmidi/extras/wm-webmidilink/wm-webmidilink.html"> <link rel="import" href="bower_components/x-webmidi/extras/wm-pckeyboard/wm-pckeyboard.html"> <x-webmidirequestaccess input output></x-webmidirequestaccess><wm-webmidilink id="wmlink"></wm-webmidilink> <wm-pckeyboard id="pckeyboard"></wm-pckeyboard>
- 1行目:Web ComponentsのPolyfillを読み込み
- 2〜4行目:Web MIDI API(x-webmidi)、仮想MIDI Outputデバイス(wm-webmidilink)、仮想のInputデバイス(wm-pckeyboard)のPolymer ElementをImport
- 5行目:x-webmidiをアクティベート
x-webmidiの属性は以下の通りです。
- input: MIDI Inputデバイスを利用する場合に追加
- output: MIDI Outputデバイスを利用する場合に追加
- sysex: System Exclusive メッセージを使う場合に追加
今回、System Exclusive メッセージは使わないので、inputとoutputのみを記述します。
- 7行目:wm-webmidilinkをアクティベート
- 8行目:wm-pckeyboardをアクティベート
以上で準備は完了です。次にMIDIデバイスのリスト表示を行います。
input: <x-webmidiinput id="midi-input" additionalid="pckeyboard" autoselect="PC-Keyboard" autoreselect></x-webmidiinput><br> output: <x-webmidioutput id="midi-output" additionalid="wmlink" autoselect="GMPlayer(WebMIDILink)" autoreselect></x-webmidioutput> <br>x-webmidiinputとx-webmidioutputの属性は以下の通りです。
- additionalid: 仮想のデバイスを追加する場合、そのタグのIDで指定します
- autoselect : 自動選択して欲しMIDIデバイス名を指定します
- autoreselect : 現在指定しているデバイスが切断され再接続した場合に自動選択します
今回は仮想のデバイスを追加するため、属性 additionalid に、input側はpckeyboard(wm-pckeyboardタグのID名)、output側はwmlink(wm-webmidilinkタグのID名)をそれぞれ指定しています。最後に入力されたMIDIメッセージを表示する場所を作ります。
<div id="msg" style="margin:30px;"></div>
Inputから受け取ったMIDIメッセージを中継するためのJavaScriptを記述していきます。
var output=document.getElementById("midi-output"); window.addEventListener("midiin-event:midi-input", function(event){ for(var i=0, out=[]; i<event.detail.data.length; i++) out.push(("00"+event.detail.data[i].toString(16)).substr(-2)); var div_msg=document.getElementById("msg"); var ex_msg=div_msg.innerHTML.split("<br>"); while(ex_msg.length>19) ex_msg.pop(); div_msg.innerHTML=out.join(" ")+"<br>" + ex_msg.join("<br>"); if(output.checkOutputIdx()!="false") { output.sendRawMessage(event.detail.data); } });
- 1行目:MIDI OutputのObjectを取得
- 2行目:MIDI InputからのメッセージはEventとして飛んできますので、EventListenerをつける。Event名は”midiin-event:”に続き x-webmidiinput タグで指定したIDになる。MIDI Inputデバイスから入力したMIDIメッセージは event.detail.data。
- 3行目:「MIDIメッセージを表示する場所」に表示して、分かりやすいように16進数の文字列にキャスト
- 4行目:「MIDIメッセージを表示する場所」のElementを取得
- 5, 6行目:「MIDIメッセージを表示する場所」の表示を新しいメッセージから順に並べるのと同時に表示する行数を絞る
- 7行目:MIDIメッセージを「MIDIメッセージを表示する場所」に表示
- 8〜10行目:Outputデバイスが選択されていたら、選択されているデバイスに対してInputから入力されたMIDIメッセージを送信。
これで、InputからOutputにMIDIメッセージを中継することができました。
SMF(Standard MIDI File)を再生するアプリ
次にMIDIというと必ず出てくるであろうSMF(Standard MIDI File)の再生です。
SMFはMIDIメッセージ1つ1つに時間情報を付加して、規定のフォーマットにまとめたバイナリファイルです。ここで付加された時間通りにMIDIメッセージを音源モジュールに送ることで、自動演奏ができる仕組みになっています。
SMFをWebブラウザ上で再生するには、SMFのバイナリを読み解いて(パース)、付加されている時間通りにMIDIメッセージを音源モジュールに送信する、という手順になります。しかし、このバイナリファイルをパースするためにはSMFのフォーマットを勉強しないといけません。この問題を解決するべく、SMFのバイナリをパースする部分を、「wm-smfplayer」というPolymerのElementにしてみました。このElemetでSMFを再生するアプリを作ってみます。
作成する index.html のコード全体はこちらになります。それでは順に説明していきます。
<script src="bower_components/webcomponentsjs/webcomponents.js"></script> <link rel="import" href="bower_components/x-webmidi/x-webmidirequestaccess.html"> <link rel="import" href="bower_components/x-webmidi/extras/wm-webmidilink/wm-webmidilink.html"> <link rel="import" href="bower_components/x-webmidi/extras/wm-smfplayer/wm-smfplayer.html"> <x-webmidirequestaccess input output sysex></x-webmidirequestaccess>
- 1〜3行目:「InputからOutputにMIDIメッセージを中継するアプリ」と同じ
- 4行目:SMFをパースするElementを読み込む。SMFの中にはSystem Exclusiveが入っている場合があるので属性を書いています。
<wm-webmidilink id="wmlink"></wm-webmidilink> <wm-smfplayer id="smfplayer" midifile="contents/ys2_op_gm.mid" latency="1200"></wm-smfplayer>続いて、wm-webmidilinkタグを記述して仮想のOutputデバイスをアクティベートし、SFMをパースする wm-smfplayer タグを記述しています。wm-smfplayerの属性は以下の通りです。
- midifile: SMFのURL(パス)
- latency : MIDIメッセージをバッファする時間
Latencyを指定してMIDIメッセージをバッファリングすることで、より時間に正確な再生が可能になります。
次に、MIDI Outputデバイスのリスト表示、SMFの再生制御のためのボタンを追加します。
output: <x-webmidioutput id="midi-output" additionalid="wmlink" autoselect="GMPlayer(WebMIDILink)" autoreselect></x-webmidioutput> <br><button id="startPlay" disabled>Start</button> <button id="stopPlay" disabled>Stop</button> <br> <button id="allSoundOff" disabled>All Sound Off</button>
最後に、SMF再生中に取得したMIDIメッセージを、選択されたMIDI Outputデバイスに送信するためのJavaScriptを記述していきます。
var out_elem=document.getElementById("midi-output") var output=null; out_elem.addEventListener("midioutput-updated:midi-output", function(event){ output=out_elem.getOutputDevice(); document.getElementById("startPlay").removeAttribute("disabled"); document.getElementById("stopPlay").removeAttribute("disabled"); document.getElementById("allSoundOff").removeAttribute("disabled"); }, false); var smfPlayer=document.getElementById("smfplayer"); document.getElementById("startPlay").addEventListener("mousedown", function(){ if(output!=null) smfPlayer.startPlay(output); }); document.getElementById("stopPlay").addEventListener("mousedown", function(){ smfPlayer.stopPlay(); }); document.getElementById("allSoundOff").addEventListener("mousedown", function(){ var output=document.getElementById("midi-output").getOutputDevice(); smfPlayer.allSoundOff(); });
各行での処理の内容は以下の通りです。
- 1行目:MIDI OutputのElementのObjectを取得
- 2行目:変数outputの初期化
- 3〜8行目:MIDI Outputがユーザに選択したObjectの取得、再生制御のボタンの有効化
- 9行目:wm-smfplaymerのElementのObjectを取得
- 10-19行目:それぞれの再生制御ボタンが押された時の動作
以上で、実装完了です。
おわりに
今回はWeb MIDI APIをPolymerのElementにしたx-webmidiを使用して、2つのアプリケーションを作りました。そして、第一回目と比べるとコードの量が減るとともに、その多くがJavaScriptによる手続き型の実装ではなく、HTMLによる宣言型の実装になりました。宣言型で書くことで見通しがよく、手軽に実装できるようになります。
ここで「手軽になった」ということは、「アイデアを具現化するまでの道のりが短くなった」ということを示していて、実際に開発を行う際は、考えついたアイデアの実現のみに集中してすることができるようになります。
次回は、MIDIはMusical Instrument Digital Interfaceの略称ではありますが、文字通りの音楽という枠を超えて別の分野でも利用可能、という実例をご紹介しようと思います。
お楽しみに!