2012年12月2日日曜日

WebMidiLinkで遊んでみた

概要

ブラウザ上で動作するソフトウェア音源をボチボチ見かけるようになりました。g200kgさんの発案したWebMidiLinkは、こういった音源をJavaScriptから制御するための仕様です。あまり難しいことは考えずに手軽に利用できるのが嬉しいところです。
ということで、拙作のJavaScript向け音楽ライブラリをWebMidiLinkに対応させて、SMFを再生してみました。

おさらい

WebMidiLinkの話に入る前に、いくつか関連技術について説明しておきます。


Web Audio API

JavaScriptからオーディオを制御するために導入されたAPIです。W3CでGoogleのChris Rogersを中心に仕様の検討が進められています。現在利用できるブラウザはChromeとSafari 6のみですが、Firefoxも現在着々と実装を進めています。g200kgさんが指摘しているように、ChromeとSafariで若干動作が異なる部分もありますが、基本的には実装をWebKitの中で共有しており、ChromeとSafariでは製品で利用しているWebKitのバージョンが異なるのが主な原因と思われます。
今までもオーディオを制御する事はできたじゃないか、と思われる方もいるかもしれませんが、この仕様の(個人的に)一番嬉しいところは、JavaScriptで直接波形をリアルタイム生成できるところです。つまり、JavaScriptでシンセサイザーを実装したりできるわけです。また、オシレータやフィルタ、ディレイといった基本的な音響処理がコンポーネントとして提供されており、これらを接続して音響プログラムを楽しむこともできます。このあたりはEijiさんのはじめてのWeb Audio APIが参考になると思います。

Web MIDI API

同様にMIDIを制御するために考案中のAPIです。同じくW3Cで仕様が議論されていますが、今のところ実装が存在しません。Editorの1人Chris Wilsonが、最近W3Cのpublic-audioの場でWebKit上で実装を進める意思のある旨を表明しました。
WebMidiLinkはこの仕様とは独立したアイデアで、今すぐに利用できるAPIでもあります。

WebMibiLink

WebMidiLinkについて簡単な仕様の説明とデモを紹介します。

仕様について

g200kgさんが考案した仕様で、Web Audio APIなどを使って作られたブラウザ上で動作するシンセサイザーを接続するための規格です。MIDIを基本としており、この仕様ではMIDI信号をどうやってJavaScript上で表現し、コンポーネント間でやりとりするかが規定されています。g200kgさんの仕様ページが、端的かつ具体的なサンプル付きで非常にわかりやすいため、仕様の具体的な説明は割愛します。
ところで、ソフトウェアで音源を実装する場合、一定サイズのバッファ単位で波形合成を行うため、波形合成のタイミングと再生されるタイミングの時間差は一定になりません。別の言い方をすると、波形合成が1秒ごとに行われた場合は、外部からのMIDI入力も1秒ごとに反映されることになります。この問題を解決するためには、MIDI信号に時間情報を載せてあげるか、ソフトウェア音源の波形合成をなるべく小さい単位で実施してあげる必要があります。WebMidiLinkでは特に時間をケアしていませんので、音源はなるべく小さい単位で合成しないと、カクカクの演奏になってしまいます。
今回試してみた範囲では、時間方向の精度はほぼ気にならないレベルでした。

SMF再生デモ

下の黒い領域にSMF(MID)ファイルを放り込んで下さい。下の枠に表示されているWebMidiLink対応音源で再生されます。利用する音源はドロップダウンメニューから選択できます。標準ではg200kgさんのGMPlayerがロードされています。
* * * * * * * * * * * * * * * *
DRAG SMF FILE TO HERE






デモの説明

デモを見て技術的な部分に興味を持った方、ぜひ以下を読んでみて下さい。

ライブラリについて

T'SoundSystemという自前ライブラリのJavaScript版に追加機能としてSMF再生やWebMidiLinkを実装しました。元々はネイティブ実装されてTSSCPなどに使われていた、MML処理系一式+チップチューンエミュレーションのライブラリです。Google Codeにてソース一式公開しています。
T'SoundSystemでは、MasterChannel、Channel、Playerという概念があります。一番わかり易いのがPlayerで、各種ファイルフォーマットを解析して再生する役目を担います。今回はSMF対応のSmfPlayerを利用します。Channelは音源を表し、Playerにより操作されます。SmfPlayerからの操作を意図したMidiChannelがあったのですが、今回はMidiChannelから派生したWebMidiLinkMidiChannelを用意しました。最後のMasterChannelは波形合成を管理します。波形合成のストリーム管理と合成粒度を制御しつつ、Playerへのタイマーを提供しています。波形合成の粒度をPlayerが求める粒度と一致させることができるので、時間にブレのない演奏を実現します。また、複数のChannelを登録した場合には、ミキサーの役目も担います。WebMidiLinkでは、ソフトウェア音源のみを仮定しているわけではなく、また波形合成も各音源の責任によって行われます。よって、今回はPlayerへのタイマーのみを提供する、TimerMasterChannelを用意しました。

利用の仕方

以下にサンプルコードを掲載しますが、とっても簡単。WebMidiLink対応音源をiframeで埋め込む場合の例を示します。

<iframe id="wml" src="[WebMidiLink対応音源のURL]"></iframe>
// まずはWebMidiLinkMidiChannelを作成します。
// 引数にはMIDI信号を送るためのメッセージポートの口を指定します。
// これにより、受け取った演奏信号をWebMidiLinkに変換して出力します。
var midi = new WebMidiLinkMidiChannel(document.getElementById("wml").contentWindow);
// SmfPlayerを作成し、デフォルト音源として先ほど作成したmidiを登録します。
var smf = new SmfPlayer();
smf.setDevice(SmfPlayer.TRACK_DEFAULT, midi);
// TimerMasterChannelを作成します。
// SmfPlayerのsetMasterChannelで登録してあげると、登録されたMidiChannel
// 全てを指定されたMasterChannelに登録します。
// またPlayerのタイマーとしても自動的にMasterChannelを利用するようにします。

smf.setMasterChannel(new TimerMasterChannel(TimerMasterChannel.MODE_DEFAULT));
// 最後に再生。引数はMIDIデータを含むArrayBufferを与えて下さい。
smf.play(midi_data);

ArrayBufferについて

比較的最近に導入された仕様なので、知らない人向けに簡単に説明しておきますと、要するにJavaScriptで効率的にバイナリを扱うための仕組みだと思って下さい。例えば、Web経由で取得したSMFファイルをArrayBufferとして読み込むためには、以下の様なコードを書きます。簡単ですね!
var xhr = new XMLHttpRequest();xhr.open("get", "foo.mid", true);
xhr.responseType = "arraybuffer";
xgr.onload = function () {
    smf.play(xhr.response);
};
xhr.send(); 

バックグラウンドでの演奏について

このページ上でのデモはTimerMasterChannelの動作モードがMODE_INTERVALになっています。つまり、古典的なsetIntervalを使ってタイマーを実現しているのですが、1つ問題があります。Chromeで実行しているとタブを切り替えた際に演奏が極端に遅くなります。これを回避する方法はいくつかあり、TimerMasterChannelにも実装されています。引数として、MODE_TIMER_WORKERを指定すれば、バックグラウンドじの動作も安定します。MODE_DEFAULTでも現在はMODE_TIMER_WORKERが選ばれるようになっています。

まとめ

以上、駆け足でしたが、Web Audio APIと、それを使ったMIDIベースのソフトウェア音源の取り組みWebMidiLinkを紹介させて頂きました。また、どさくさに紛れて拙作ライブラリのT'SoundSystemも紹介しました。
これをきっかけにブラウザ上での音系アプリ開発に興味を持ってくれる人が1人でもいますように・・・。
なお、この記事はWeb Music Developers JP Advent Calendar 2012の一環として執筆されました。

17 件のコメント:

Unknown さんのコメント...

単純にChromeバージョン45以降のブラウザで、WEBサーバーに置いたMIDIファイルをWEBページで再生したいのですが、簡単にできる方法をご存知でしたら、ご教授お願いします。
基本的には、FirefoxやIEやSafariなどですと、Windows Media Player プラグインで、再生可能なんですが、ChromeがNPAPIを非サポートしているのでこの方法が使えません。

Chromeでは、唯一WEB MIDI API位しかないのではないかと思うのです。
MIDI.JSみたいなものもあるようですが・・・。

ブラウザ判別も必要となると思われます。

よろしくお願いいたします。

とよしま さんのコメント...

SMFを再生するライブラリをJSで書いて、Web Midi Linkを音源として再生させればお望みの機能は実現できるかと思います。Polymerを使えば再利用も簡単にできるかと思います。
例えば、みたいなタグを定義して演奏させる事もできるはずです。

既に存在しているライブラリですと、Web Midi LinkをPolymer化したものはこの辺
https://github.com/ryoyakawai/x-webmidi/tree/master/extras/wm-webmidilink
にあるのですが、SMF再生を含めてとなると、まだ誰も作っていないかもしれません。
SMF再生のライブラリ自体は既にいくつも出てきているかと思います。

お急ぎでなければ、僕の方でそのうちPolymerコンポーネント化した物を作ってみます。

Unknown さんのコメント...

こんにちは。
返事が遅れてすみません。

Web MIDI APIのサンプルサイトなどで、Chrome ver.45(Windows10です)ブラウザによる試聴をしてみましたが、内蔵(Microsoft Software Synth)MIDI音源による再生ができず。
Chromeでの「このサイトでのMIDIへのアクセスが許可されていない。」となり、例外にも記述できず、Chromeのバグなのかはわかりませんが、万人向けではないと判断しました。

全然急いでおりませんので、お待ちしております。どうぞよろしくお願いします。

とよしま さんのコメント...

Windowsの内臓音源は、特定のシーケンスを送る事でWindowsのドライバレベルでクラッシュする問題が見つかっています。このため、ウェブから自由に利用できるようにする事は地名的なセキュリティ問題になりかねない(サイバーテロの踏み台になるなど)との理由でブラックリストされています。

また、System Exclusiveを利用する際にはデバイスのファームウェア書き換えなど致命的な操作が可能となっていますので、HTTPSなどで中間車による書き換え攻撃ができない事を確認した上でのユーザからのパーミッションが義務付けられています。HTTPSを必須とする使要件は近年導入された強力なAPIには共通の要請で、古いAPI(例えばgeolocation)などにも順次適用されていく事が合意されつつあります。

例外にも記述できず、というのが何を意味するのかわからなかったのですが、MIDIの利用がJava Script実行中のサイトに対して許可されているかどうかは、Permissions APIを使って判別可能です。
http://qiita.com/yoichiro@github/items/5d699abd2e261107a7e5#permissions-api-for-the-web
この記事が参考になるかもしれません。また利用不可能の時にはrequestMIDIAccessのPromiseがrejectで返ってくるはずです。許可されていない場合にはSecurityErrorになります。

また、ホームページ上に公開されているWeb MIDIのサンプルは、未だに(正式にWeb MIDIをリリースした)Chrome 43以前の実験的な仕様、あるいはセキュリティ的に厳格でない仕様を元に書かれている事があります。特に個人ページの過去のブログなどは修正される事は稀ですので、記事の公開された時期を確認したり、不明な点はコミュニティで質問したり、W3Cの仕様やMDNなど一次情報源として頂くのが良いかと思います。

SMF再生については、Kawaiさんがさっそくサンプルを作って公開しています。
https://plus.google.com/+RyoyaKAWAI/posts/bQXvwYaSYL9

とよしま さんのコメント...

あぁ・・・地名的→致命的ですね。

とよしま さんのコメント...

他にも誤字いっぱいでした。ごめんなさい。

・中間車→中間者
いわゆるMITM攻撃の事ですね

・使要件→要件
せっかくなので参考URLを。
https://www.chromium.org/Home/chromium-security/prefer-secure-origins-for-powerful-new-features
https://w3c.github.io/webappsec/specs/powerfulfeatures/

Unknown さんのコメント...

こんにちは。

サウンドフォントを使ったMIDI再生しかできないのであれば、あきらめるしかないかもしれません。
Core2Duo程度の低スペックでも再生できるものでないと、重すぎてきれいに再生できないようです。
ご紹介の参考サイトをChormeで閲覧してみましたが、音飛びや正確な時間で再生されない(音がずっと延びる)などが発生し、単純に複数のMIDIファイルを切り替えて再生するには無理そうです。
一応どのようなサイトかといいますと、MP3とMIDIを試聴/ダウンロードできるサイトで、オリジナルのものを含めて複数あります。
より多くの方に試聴してもらいたいという主旨のサイトです。

MP3の方は、HTML5のaudioタグを使用して切り替え再生できるようにしております(
HTML5未対応の場合は、flash playerを使っています)。

内蔵音源が使えないんですね・・。残念です。

とよしま さんのコメント...

紹介したSMF再生に関してはWeb MIDI APIとは一切関係ない話になってきます。
ウェブ標準としてはWeb Audio API(http://webaudio.github.io/web-audio-api/)を提供しているので、その上に任意の音源を実装して再生に利用すれば良い事になります。サウンドフォント云々といった制約は一切ありません。音源の性能に関しては製作者の腕次第、といったところです。将来的にはVSTiのように多くのフリー音源が出回るようになると面白いのですが。既にWeb Audioをキーに検索すると色々なシンセサイザーが見つかると思いますが、ウェブに合わせた性能チューニングとかは考えていない実験的な物も多いです。

ちなみにWeb MIDI APIに関しては下記のスペックにある通り、GM音源を想定したSMFファイルの再生は視野に入っていません。そのような機能は既存のAPIの上にライブラリ等として実装可能である、という立場をとっており、標準化メンバーが想定している主なユースケースはハードウェア(楽器)との通信です。
https://webaudio.github.io/web-midi-api/

いずれにせよ、ウェブの世界では既にWindowsユーザ(デスクトップユーザ)は唯一の多数派ではなくなっていますので、Windowsの内臓音源に依存したサイトの構築は「より多くの方に」といった趣旨には合わないかもしれません。楽曲にリアルタイム性を持たせたり、音楽制作環境を構築するといった用途でなければ、事前にmp3等の波形データに落とした物を再生するのが妥当かと思います。

Unknown さんのコメント...

こんにちは。

> GM音源を想定したSMFファイルの再生は視野に入っていません。

確かにそのように書いてありますね。

> そのような機能は既存のAPIの上にライブラリ等として実装可能である

この部分なんです。では具体的にWindows マシン上の内蔵MIDI音源による再生を実現する方法ってどうなの?ってことなんです。
プレーヤー表示やピアノロール表示などは必要ありません。MIDIファイルの配布をしていますから、切り替えて試聴できる環境を構築したいだけなんです。
元々がオリジナル曲のMIDIファイルを提供する目的のサイトなんです。ぼくのサイトではありませんが、知人のサイトでして、ピアノの先生でもあり、趣味でジャズセッションなんかもしている方のサイト。
MIDIファイルでなければならない理由もちゃんとあるんです。

ChromeがMIDI機器をブラウザ上で接続制御できる機能を有することは、将来的にみて大きな財産なのかもしれません(僕はDAWソフトウェアに通信機能を設ければいいのではと思っており、ブラウザ上で実現する必要性に疑問も感じますが)。
でも、単純にMIDI再生できる機能を実装してもらいたかった。Chrome BookやAndroidマシンなど内蔵MIDI音源がないものについては承知しておりますが、そのような端末の場合は、MP3で聴いてもらうしかありません。これも承知の上です。

ごめんなさい。ここで愚痴を言っても始まりませんね。
ただ、簡単にMIDIファイル再生ができる手法が知りたかった・・・ユーザーです。

Unknown さんのコメント...

あ、すみません。
現状は、ブラウザや試聴マシンに応じてMIDIは聴けませんとか、MP3のみ試聴できますとかコメントを入れております。

とよしま さんのコメント...

Flashのような十分にメンテされたNPAPIですら頻繁に致命的なセキュリティ問題が見つかっているのはご存知の通りです。これだけ利用されているプラグインが存在していてもセキュリティ担保のコストにペイしなくなってきている、というのがChromeやFirefoxがNPAPI廃止を決断した背景ではないでしょうか(個人の意見です)。ウェブから流れてきたコンテンツをOSへ横流しするのはもはや現実的ではなくなっています。内臓MIDI音源に関して存在するセキュリティの問題も根は同じです。

一方でSMF/GMの再生という目的に関しては既存APIの上で実現可能です。需要が大きければ、いずれ良いライブラリが出てくるでしょう。内臓音源のサポートはSMF/GM再生の手段の1つに過ぎませんし、セキュリティや互換性の問題を考えれば将来性のある方針ではないと思います。

紹介して頂いたユースケースにおいても、配布ファイルがMIDIである事は理解しましたが、MIDI形式のままオンラインで視聴できるようにする必然性はないように思えました。

さらに詳しい議論は以下のスレッドからたどる事ができますが、僕自身は内臓音源については否定的な立場を取っています。
https://github.com/WebAudio/web-midi-api/issues/151

Unknown さんのコメント...

結局のところ・・・

スクリプトによるOSとブラウザバージョン判別し、Windowsである時、Chrome ver.45以降の場合、Windows 付属のソフトウェアMIDI音源(あるいは外部MIDI音源でも構わないんですけど、Windows既定のMIDI音源になっているもの)でのMIDIファイル再生はできないということで良いのですよね。

今後Chrome用のPPAPIタイプのMIDI再生プラグインでも出ない限り・・・。

MIDIを内蔵音源で再生したものをMP3化して、試聴させるというのもありかと思いますが、レンタルサーバーですので、容量は有限です。
何故MIDIなのっていう部分は、ごく一部ではありますが、需要があるからです。

今回はあきらめます。

とよしま さんのコメント...

ありゃりゃ、うまく話が噛み合っていなかったみたいです。

Web MIDI APIを使えばJavaScriptでSMFファイルをデコードしながらシステムに繋がっている任意のMIDIデバイスを使って演奏する事ができます。SMFをデコードするようなライブラリは既にいくつも存在していますし、自分でコードを書く場合でも(開発者であれば)比較的簡単に作成可能です。

ただし、以下の制限があります。
・Windows規定の音源の自動選択はできません。デバイス一覧が取得できるので、プログラムで選ぶかユーザに選ばせるかする必要があります。
・Windows付属のソフトウェアMIDI音源の利用はできません(繰り返しになりますが、セキュリティ問題が存在するためブラックリストされています)

ですので、これらの制限が問題であれば、諦めるしかないと思います。許容できるのであれば諦める必要はないと思います。

とよしま さんのコメント...
このコメントは投稿者によって削除されました。
とよしま さんのコメント...

同じ内容を二度投稿してしまったため1つ前の投稿を削除。

PPAPIタイプのプラグインについても誤解があるようなので軽く補足しておきます。結論を言えば内蔵MIDIを利用するプラグインは現状では作成不可能です。詳しく説明すると、PPAPIプラグインはSFIサンドボックスと呼ばれるある種の仮想マシン上で実行されます(ただし実機とほぼ同等に高速)。この仮想マシンの中からはOSが提供するAPIへのアクセスは一切許されていません。利用可能なAPIについては以下のリンクに詳しく書かれていますがMIDIは含まれません。
https://developer.chrome.com/native-client/pepper_stable

視聴とMIDI配布については、既にmp3での視聴も併用しているのでしたら、mp3に一本化するだけですのでファイル容量の増加に繋がるような事はないかと思います。万が一増加して個人の手に負えないようでしたらSoundCloudやYouTubeなどを利用するのも手です。あるいはGoogle Driveなどの無料ストレージサービスを利用すれば1000曲くらいはどうにかなるんじゃないでしょうか。

Unknown さんのコメント...

こんばんは。

MIDIとMP3での配布については、確かにおっしゃる通りです。
僕のサイトでしたらそうしているでしょう。

が、当該サイトのオーナーはJAVAスクリプトの基本もわからない女性です。
なので分散してファイルを置くのは無理かと考えております。
MP3を置いているのは、Cubase+VSTiによる演奏のものもダウンロード/試聴できるようにしているためで、Windows 付属のソフトウェアMIDI音源によるものを置いているわけではありません。

MIDIが必要な理由は書きたくなかったのですが、HTMLメールメッセージ(OutlookExpressやWindows メール/Windows Live メールで送受信可能)につけるBGMとしてファイル容量が小さくて利用できるからです。

単にオリジナル曲を聴いてもらいたいだけのサイトではないのです。

さて、DTMなどを行っている人でなければ、通常のユーザーは、外部MIDI音源を別途用意していないと思います。しかもWindows Vista以降(特に8以降)は、デフォルトMIDI OUTデバイスを簡単に設定できなくなっています(いわゆるMIDI MAPPERのデフォルト)。
なので内蔵音源(あるいはデフォルト設定されたMIDI音源)でのプラグイン再生があればということでした。

Unknown さんのコメント...

あ、すみません。

いろいろと考えてくださったのに、愚痴っぽくなりましたことをお詫びいたします。

ありがとうございました。