前回に引き続き Web MIDI API Wrapper についての説明です。今回は具体的な MIDI メッセージの送信の方法になります。

本題の前に、またまた MIDI ってどこで使われているかコーナーです。 MIDI には Show Control(MSC) という仕様があります。 前回の Universal Studio の Water World も MSC の一例でした。今回もその続きです。 そして Showといえば、Las Vegas かな?っていう勝手な想いがありまして、 今回はそこで利用されている例です。映画 Ocean’s Eleven って御存知ですか?? Las Vegas のカジノに泥棒に入るっていうストーリーですが、 最後のシーンで噴水ショーがが出てくるんです。あれが Las Vegas の ベラージオ (Bellagio) のショーというのは有名だと思います。なんと、あのコントロールのオリジナルのシステムは MIDI なんですよ〜!!

さて、本題です。前回もお伝えしましたが、Web MIDI API Wrapperは基本的な以下のメッセージに対応にしています。

  • NoteOn:音を鳴らす
  • NoteOff:音を止める
  • PitchBend:ピッチを上下させる
  • Sustain:ダンパーペダルの操作
  • Modulation:揺らぎ
  • AllSoundOff:残響、Sustainを含め即時に全ての音を止める
  • ResetAllController:PitchBend、After-Touchなどのコントローラを初期値に戻す
  • AllNoteOff:発音している音を全て止める

ということで、まずは NoteOn/NoteOff についてです。 NoteOnは「音を発音させてね」、NoteOffは「発音している音を停止させてね」 を知らせる Message です。えっ「コンピュータで音を鳴らすんだから、 例えばNoteOnの時にどれだけ長さ(時間)音を出すか指定しちゃえばいいじゃない。」 という印象をお持ちの方もいらっしゃると思いますが、もともと MIDI というのは電子楽器と電子楽器を つなげ相互にコントロールを可能とする Protocol なので、コンピュータなら最初から音を出す時間を指定できちゃいますが、 リアルタイムの演奏ではそれはできないですよね〜、というところから NoteOn、NoteOff に分かれているのです。

sendNoteOn(portNo, ch, note, velocity, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • note:鳴らすnote番号を指定
  • velocity:鳴らすnoteのvelocityを指定
  • time:音を鳴らすタイミング(いつ音を鳴らすかをミリ秒で指定)

NoteOnのvelocityに関して:velocityを直訳すると「速さ、速力」ですが、MIDI機器側では音の強弱に割り当てられている場合がほとんどです。数値の目安は1:ppp、64:mpとmfの中間、127:fff というのが目安です。 note番号に関して:中央のC(C4:ド)を60として白鍵、黒鍵関係なく鍵盤1つに対して数字が割り当てられています。 よって、88鍵ですと21〜108まで割り当てられていることになります。 例えばC4の右隣の白鍵D4は62、その間にある黒鍵は61です。note番号の図 右にスクロールすると見えてきます。

sendNoteOff(portNo, ch, note, velocity, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • note:停止するnote番号を指定
  • velocity:停止するnoteのvelocityを指定
  • time:音を停止するタイミング(いつ音を鳴らすかをミリ秒で指定)
  • NoteOffのvelocityに関して:鍵盤から手を離す速度と認識する機器もあり、その場合は音の余韻の長さを指定できます。NoteOnのvelocityをゼロにしてNoteOffの代わりにすることも可能です。

sendProgramChange(portNo, ch, programNo, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • programNo:変更する音色番号
  • time:適応するタイミング(いつ音色を変更するかミリ秒で指定)
setPitchBendValue(portNo, min, max, center);
  • portNo:設定するMIDI機器(Port)を指定
  • min:PitchBendの最小値
  • max:PitchBendの最大値
  • center:PitchBendの中央値(PitchBendがかかっていない状態)
  • PitchBendに関して:範囲は16383と決まっていますが、MIDI機器によって中央を0、または中央が8192と違う場合があります。Web MIDI API Wrapperの初期設定値は中央:8192、最小:0、最大:16383 としています。
  • sendPitchBend(portNo, ch, value, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • value:適応するPitchBendの値を指定
  • time:適応するタイミング(いつPitchBendを適応すかをミリ秒で指定)

数値に関してはここが参考になると思います。

sendSustainStatus(portNo, ch, status, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • status:Sustainの指定を”on”、”off”で指定
  • time:適応するタイミング(いつSustainを適応すかをミリ秒で指定)

Sustainとは:ピアノで言うと一番右のペダルを踏んだ時の効果です。

sendModulationValue(portNo, ch, value, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • value:Modulationのかけ具合を数値で指定
  • time:適応するタイミング(いつModulationを適応すかをミリ秒で指定)

Modulationとは:音の揺らぎです。

endAllSoundOff(portNo, ch, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • time:適応するタイミング(いつallSoundOffを適応すかをミリ秒で指定)
  • Sustainが動作していて、残響があったとしても即座に全ての音を停止する。AllNoteOffよりも強力。

sendAllNoteOff(portNo, ch, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • time:適応するタイミング(いつallNoteOffを適応すかをミリ秒で指定)

その名の通りで、全てのNoteOnをNoteOffにする。よって、Sustainが動作していて残響ある場合はこの範囲ではない。

sendResetAllController(portNo, ch, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • ch:送信先のMIDI機器(portNoで指定)のチャンネルを指定
  • time:適応するタイミング(いつResetAllControllerを適応すかをミリ秒で指定)

PitchBend, After-Touch等のコントローラを初期値に戻す。

sendRaw(portNo, msg, time);
  • portNo:送信先のMIDI機器(Port)を指定
  • msg:送信するMIDIメッセージをArray型で指定
  • time:適応するタイミング(いつSustainを適応すかをミリ秒で指定) 生のMIDIメッセージを送ることができます。例えばSysExを送信します。
initializePerformanceNow();

時間を初期化して、現在をスタート時間とします。再生する前に必ず実行してください。

さて、以上が Web MIDI API Wrapper が現状サポートしている MIDI メッセージになります。それでは引き続き実際に、 NoteOn/NoteOff と ProgramChange で馴染みのあるだろうこんなのを作ってみました。

/** 
 * 前回からの引き続きですので、Constructor は引き継いていでいます。
 * 詳しくは前回のPOSTを御覧ください。 
 */
wmaw.initializePerformanceNow();
wmaw.sendProgramChange(0, 0, 12, 0);

wmaw.sendNoteOn(0, 0, 62, 127, 0);
wmaw.sendNoteOff(0, 0, 62, 0, 120);

wmaw.sendNoteOn(0, 0, 69, 127, 120);
wmaw.sendNoteOff(0, 0, 69, 0, 240);

wmaw.sendNoteOn(0, 0, 74, 127, 240);
wmaw.sendNoteOff(0, 0, 74, 0, 360);

詳しく見てみます。

  • 5行目:時間を初期化
  • 6行目:音色を12(マリンバ)に変更
  • 8, 9行目:D4(レ)を120ms鳴らす
  • 11, 12行目:A4(ラ)を120ms鳴らす
  • 14, 15行目:D5(レ)を120ms鳴らす

ということが行われています。 実際にどうなるかというのは デモページ のここ▼に実装してありますので試してみてください。多分聞いたことがあると思いますよ。

では今回はこの辺にして、次回は初心に戻り、素で Web MIDI API を使う場合について説明していこうと思います!!

お楽しみに^^v

[更新履歴] 2013/08/26 sendRaw() の説明を追加しました。

Google Chrome Canary には Web MIDI API の MIDI INPUT 機能が実装されていますが、 MIDI OUT 機能の実装はまだでした。が、それがもうすぐ来そうな予感です。 つまり Web MIDI API が完全体としてブラウザに実装されるということです。 何がいいかと言うと、JavaScript でプログラムを書けばブラウザから MIDI 機器をブリブリ操作できるようになるところです。 「MIDI 機器をコンピュータから操作する場合って CubaseLogicVision とかの DAW からでしょ?」という固定概念がありそうですが、これからはWebブラウザから MIDI 機器を操作する時代がやってくるのです^^ 「でもそのJavaScriptとか操作って難しいんでしょ〜?」ってあたりは、 先日公開した Web MIDI API Wrapper を使うと簡単に解決できると思いますよ! (このブログで説明もしています)

さて、本題の「もうすぐ来るよ」なところです。Google Chrome にはいくつかバージョンがあり、 ここで登場するものを説明すると、オープンソースの Chromium、正式公開じゃないから何が起こるか分からないバーションの Google Chrome Canary、そして安定バージョンの Google Chrome。なので API は最初に Chromium に実装され公開されます。そして今回 Web MIDI API の MIDI OUTPUT 機能の実装がされたのが Chromium です。ですので、近いうちには Google Chrome Canary に来そうだと思う訳です。

この MIDI OUTPUT の場合 SystemExclusive(SysEx)を使った場合のセキュリティの懸念があり、SysExを使うことを宣言すると許可を求めるダイアログが上がってきます。その状況がこれ▼になります。

Web MIDI API での指定はこんな感じです。

navigator.requestMIDIAccess( {sysex:true} ).then( MIDISuccessCallback, MIDIErrorCallback );

「セキュリティの懸念って何?」というとこですが、 SysEx という MIDI Message はF0Hで始まりF7Hで終わる可変長で、楽器メーカー各社が独自に定めることのできるメッセージで、利用される代表例がユーザーがシンセサイザのプリセット音色のパラメータを変更して作成した音色データのバックアップだったりします。(同じメーカーであっても機種によって設定できるパラメータの数等に違いがあり出力フォーマットを統一することが困難な為、独自にフォーマットを定義できる SysEx を使います。)ここで、例えばシンセサイザが接続されたコンピュータ上のブラウザで動作している MIDI アプリケーションが音色パラメータを無断で SysEx を使って吸い出しサーバーに保存していたとしたらどうでしょう?このユーザーがアクセスする毎に照合するようにしたら個人名までは分からないですが「このユーザーは昨日アクセスしてきて、アレやってた人だ」というような特定ができちゃうことになりますよね。こういったことを未然に防止する為に、Web MIDI API ではアプリケーションが事前に SysEx を使うか否かを宣言し、ユーザーからの許可を取った上でしか利用できないという制限をしています。

ちなみに、SysExについて「楽器メーカー各社が独自に定めることのできるメッセージ」 と書きましたが、SysEx を使うためには MIDI を管理する団体に届け出をして Manufactuere ID を取得する必要があり、 日本国内からは AMEI(Association of Musical Electronics Industry:音楽電子事業協会)、日本以外からは MMA(MIDI Manufacturers Association)へ、ということになります。

現状で Manufactuere ID を保有している団体のリストです。

いろいろ脱線してしまいましたが、という具合で Web MIDI API はもうすぐブラウザにやってきますよ!!!

(Web MIDI API Wrapper の説明の狭間に割り込んだPOSTになってしまいました(・ω<))

2013年7月1日にChrome CanaryにMIDI InputがやってきたWeb MIDI API。そろそろOutputも来るはずですが、今のところJazz-PluginをインストールしてWeb MIDI API Shimを使って動かします^^ でも「MIDIって難しいんでしょ?」という声が聞こえて聞こえてきそうなので、聞こえてくる前にWrapperなるものを作ってみました。

Web MIDI API Wrapper

Wrapperの話に入る前に「MIDIってなんぞ?」ってところを少し書きます。一言で言うと 「メーカの枠を超え、電子楽器と電子楽器を接続する為のプロトコル」なんです。 歴史は30年前のNAMM Show(National Association of Music Merchants Show)という楽器の見本市でお披露目され (今年はちょうど30周年に加えテクニカルグラミー賞を受賞)、その後電子楽器の接続のみならず照明機器のコントロール、通信カラオケ、携帯電話の着信音の制作など幅広く利用、応用されています。有名なのは、HollywoodにあるUniversal StudiosのWaterworldのアトラクションで、ライトと演出の同期、キュー出しにMIDIが使われています。そのアトラクションがこれ▼です。(12分00秒辺りが同期とか必要そう)

Wrapperの説明に入ります。 今のところ、とりあえずMIDIを意識せずともアプリケーションを簡単に構築できるように、基本的な以下のメッセージに対応にしています。

  • NoteOn:音を鳴らす
  • NoteOff:音を止める
  • PitchBend:ピッチを上下させる
  • Sustain:ダンパーペダルの操作
  • Modulation:揺らぎ
  • AllSoundOff:残響、Sustainを含め即時に全ての音を止める
  • ResetAllController:PitchBend、After-Touchなどのコントローラを初期値に戻す
  • AllNoteOff:発音している音を全て止める

使い方はこんな感じです。 まずは WebMIDIAPI.js と WebMIDIAPIWrapper.js にリンクします。(今回は都合上、前準備だけになってしまいました。。。)

<script src="[PathToJS]/WebMIDIAPI.js"></script>
<script src="[PathToJS]/WebMIDIAPIWrapper.js"></script>

次にConstructorを作ります。

var wmaw = new WebMIDIAPIWrapper( false );

続いて MIDI Input 、 MIDI Output が指定されたときの EventHandler を指定します。

wmaw.setMidiInputSelect=function() {
  /* MIDI Input の選択リストを表示する EventHandler */
  /* 選択リストから MIDI Input が選択された時の EventHandler もここに書く*/
}
wmaw.setMidiOutputSelect=function() {
  /* MIDI Output の選択リストを表示する EventHandler */
  /* 選択リストから MIDI Output が選択された時の EventHandler もここに書く*/
}

最後に Web MIDI API を Fire する。

wmaw.init();

これで MIDI Input、Output デバイスのリストが表示され、デバイスを選択できる状態になります。デバイスを選択した状態でMIDIメッセージを送れば音がなったりします。例えばこんな感じ▼

wmaw.sendNoteOn(0, 0, 69, 60, 0);
wmaw.sendNoteOff(0, 0, 69, 60, 500);

これでA4の音が500msecの間、60の強さ(最大127)で鳴ります。

ここから!というところですが、この先を書くと長くなりそうなので今回はここまでにして、次回はMIDIメッセージの送信について書こうと思います!!

お楽しみに^^

7月19日に GoogleJapan で行われた DemoPartySpeechJammer+というアプリケーションを展示させていただきました。以前 SpeechJammer というのを作って公開していたのですが、何かが起こったみたいでアクセスがとても伸びていまして、ならばもう少し楽しくできないか??という発想で続編的なのをりました。

まず、SpeechJammer の説明です。2012年のイグノーベル賞アコースティック部門を受賞したアルゴリズム、および物理ガジェットです。(注:アルゴリズムの発明者は産総研にいらっしゃる栗原一貴氏で私ではありません。)アルゴリズムは「集めた音を0.2秒後に再生をする」という極めてシンプルなものですが「集める音」を自分の会話の声として「0.2秒前の自分の会話が再生される」のを実際に体験すると、違和感を感じ会話をストップしたくなってしまいます。名前の由来もここにあると思います。ユースケースとしては「ちょっとおしゃべりな人に静かにしていただきたいときに使う」という感じになります。 ただ、「0.2秒前の自分の会話が再生される」というのに違和感はあるのですが、何か楽しさもあるんです、不思議と。そこで「もっと面白くできないかな〜??しかもブラウザ上で。」と考えたところ「0.2秒前の会話にサウンドエフェクトをかけて再生してまえ!あと0.2秒前の映像も流してしまえ!」と思いつき実装をしてみました。個人的には理由はわかりませんが、暇つぶしに遊んでしまう、おもちゃ的な楽しさがあると感じています。

技術的には、マイク入力・カメラの扱いで getUserMedia() (WebRTC)、サウンドエフェクトには WebAudioAPI、あと細かいところですがノブには polymer/WebComponents (@agektmr氏作)を使っています。(Web MIDI API も使いたかったのですがアイデア不足の為、今回は組み込めませんでした。。。orz)SpeechJammer+ のソースコードは github で公開しているので、気になる方はこちらからどうぞ!!
ソースコード>
そして、LiveDemoはこちらになります LiveDemo
ライブデモは Google Chrome(ブラウザ)での動作を、またハウリングを起こしやすいので、ヘッドホンをしてお試しください。映像のプレイバックは力技でやっていまして、遅延が時間とともに酷くなりますので、おまけ程度ということでお願いします。。。

DemoPartyについては、MAKERな方々が集まってワィワィやる的なイベントでした。 すっごく楽しかったです。そしてウダーの宇田さん、オタマトーンで明和電機さんもいらっしゃってデモ兼プレゼンテーションをされていました。 私もプレゼンテーションをさせていただきましたが、デモで音声を出せなくちょっと残念でした&準備不足ですみませんでした、、、orz
こんな感じでプレゼンテーション(@tyoneさん、写真ありがとうございました!!)▼

MAKER Conferenceには1度だけ参加経験はあるものの、展示する側としてMAKER系のイベントに参加するのは初めてでしたので、かなりドキドキでした。終わってみると展示する側として参加して、また違った楽しみ方があることを知りました。ホント、楽しかったです。こんな素敵な場を提供くださったGoogleの皆様本当にありがとうございました!!

ついにMIDI機器をブラウザで扱える日を迎えました!!そうです、Web MIDI APIです。W3C的にはもうすぐLC(Last Call:最終草案)の段階で、ここを迎えるには「2つ以上のブラウザに実装されている」ことが条件になってる1つをGoogleさんが90%以上(sendが未実装なので)超えてくださいました。感謝感謝です!!! オリジナルの記事はこちら!!

まずは仕様の変更点。

(0) 変更じゃないけど、まだflag付きです。

chrome://flags/#enable-web-midi
をenableにしてください。しかしながら、send() は未実装です。

(1) requestMIDIAccess の引数が変更されました。

  • 変更前 navigator.requestMIDIAccess( successCallback, failureCallback );
  • 変更後 navigator.requestMIDIAccess({sysex:true/false}).then( successCallback, failureCallback );

SysExで楽器の情報をDumpできちゃので、それを明示的に指定するのが目的だと思われます。今後、{sysex:true} になってる場合、ユーザに許可を求めるダイアログが出るかもしれないです。

(2) event名 message が midimessage に変更されました。

(3) getInputs() -> getInput(id)、getOutputs() -> getOutput(id)が、1段階になりました。

inputs()、outputs() するとMIDI機器のリストが配列が返ってきて、配列のIDを指定することでそのMIDI機器を扱えるようになります。
※ この変更で扱いが更に手軽になりました。

変更点は以上です。 Chris Wilson氏のPolifillもこれらの変更に対応済みでした。


そして今回は「Web MIDI API!!」と騒いでる自分も何かできないか??と考えた結果、需要があるか分かりませんが事始めにテストでも書いてみることにしました。というのも、先月 Test the Web Forward という「Web標準の仕様書を見て実際にテストを書いてContributeしちゃおう!!」というイベントに参加してきまして、その応用でもあります。このイベントで重要なのは「みんなでテストを書いてContributeすることで、ブラウザ間のInteroperabilityを高めよう」というところだと私は理解しました。


そしてWeb MIDI APIのテストはこれ Web MIDI API Test
※スゴイモノではありませんのでびっくりしないでください(><)
OSX の Chrome Canary以外で動作させるには、http://jazz-soft.net/ の Jazz-Plugin のインストールが必須です。

このテストを使って、以下の組み合わせで動作することを確認をしました。(全てPolyfillを使ってのテストになります)ここに書いてないのは試していないだけなので、情報をいただけるとありがたいです(・ω<)

  • OSX: Chrome(27.0.1453.116)、Firefox(22)、Safafi(6.0.5 (8536.30.1))、Opera(15.0.1147.132)
  • Windows8: IE10、Firefox(22)、Chrome(27.0.1453.110)