この文書は、W3Cの文書 "「Web MIDI API」 W3C Working Draft 17 March 2015" の日本語訳です。
Web MIDI APIの正式な文書は英語版のみであり、日本語訳には翻訳に起因する誤りが含まれている場合があります。
正式な文書はhttp://www.w3.org/TR/webmidi/にあります。
翻訳元の文書はまだワーキングドラフト(Working Draft)です。現状ではまだ説明が不足している部分があったり、今後も頻繁に更新される可能性がある事に注意してください。
注: 現在ネイティブのWeb MIDI APIの実装が進んでいるのはChromeだけであり、それ以外の環境で動作させるには Polyfill(WebMIDIAPIShim)とJazzPluginが必要になります。
日本語訳GitHub : https://github.com/g200kg/web-midi-api-ja
日本語訳公開URL : http://g200kg.github.io/web-midi-api-ja/
Tatsuya Shinyagaito @ g200kg
誤りその他があればGitHubページ、下のサイト経由などで連絡をお願いいたします。
http://www.g200kg.com/
2015年3月18日
Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
シンセサイザー、キーボード等のコントローラー、ドラムマシンなど、 ユーザーエージェントはそのホストコンピューターやデバイスに接続された音楽機器を持っている場合があります。 広く採用されている、Musical Instrument Digital Interface (MIDI) プロトコルは電子楽器、 コントローラー、コンピューター間で相互に通信と同期を可能にするものです。 MIDIはオーディオ信号は送信しません: その代わりに音符に関するイベントメッセージ、音量やビブラートやパンニングなどのパラメーターのコントローラー信号、 キューやテンポを合わせるためのクロック、あるいはそのシステム固有の (例えばリモートに保存されているシンセサイザー固有のパッチデータなど) 通信を行います。 このプロトコルは照明装置や特殊効果の制御を行うショーコントロールのような、音楽以外での分野でも標準となっています。
この仕様はMIDIプロトコルをサポートするAPIを定義し、Webアプリケーションがクライアントシステム上のMIDI入出力デバイスを列挙、選択し、 MIDIメッセージを送信および受信する事を可能にします。 ユーザーのシステム上にあるMIDIデバイスへの低レベルアクセスが可能になる事によって、音楽に関するものだけでなく、 非音楽関係のMIDIアプリケーションも構築できるようになります。 一方でWeb MIDI APIは、音楽やコントローラーの入力の意味を表現するものではありません; これはMIDI入力と出力インターフェースのメカニズムに触れる事ができ、 MIDIメッセージをその動作の意味を認識する事なく、送信および受信するという実用的な側面のために設計されています (例えば、"20Hzでビブラートを掛ける"や"G#7の和音を演奏する"と言うような、 コントローラーの値が変わった事やG#7の和音を演奏した時の一組のノートオンメッセージという以上の意味を持ちません)。
ユーザーの一部では、"MIDI"は、スタンダードMIDIファイルおよびジェネラルMIDIと同義語として使われています。 それはこのAPIの意図する所ではありません; 単純に.SMFファイルを再生する、という使用例はこの仕様の範囲ではありません (それは例えばHTML5の <audio>要素のような異なったフォーマットのものとしては考慮されるかも知れません)。 Web MIDI APIは MIDIに対応するデバイス、例えば外部のシンセサイザーや照明システム、あるいは多くのオペレーティングシステム に組み込まれているソフトウェアシンセサイザーへの直接的なアクセスを可能にする事を意図しています。 Web MIDI APIはまた明らかに、MIDIコントローラーからの入力に反応するという新種のWeb上のアプリケーションを可能にするために設計されています。 Webアプリケーションを制御するために、(キーボード、ギター、管楽器コントローラーなどの楽器コントローラーとー同様に) 物理的なボタンやツマミやスライダーなどを使った、外部ハードウェアコントローラーが使用される事になるでしょう。
Web MIDI APIはまた、Webプラットフォームの他のAPIや要素、特にWeb Audio APIと組み合わせて使われる事を想定しています。 また、このAPIはApple社のCoreMIDIやMicrosoft社のWindows MIDI APIなど、他のシステムのMIDI APIに精通しているユーザーに向けたものです。
このセクションは、この文書の公開時における状況を記述したものです。 他の文書がこの文書に取って代わるかもしれません。 現在のW3Cの刊行物およびこの技術レポートの最新版のリストは、 http://www.w3.org/TR/にある、W3C technical reports indexから見つけることができます。
この文書はAudio Working Groupによって、ワーキングドラフトとして公開されました。 この文書はW3C Recommendationとなることを意図しています。 この文書にコメントしたい場合は以下で受け付けます。 public-audio@w3.org (subscribe, archives). どんなコメントでも歓迎します。
ワーキングドラフトとしての公開はW3Cメンバーによる承認を意味するものではありません。 これは草案文書であり、いつでも他の文書によって改訂、置き換えあるいは廃止される可能性があります。 この文書を作業中のもの以外として引用する事は不適切です。
この文書は5 February 2004 W3C Patent Policyの基に運用されるグループによって作成されました。 W3Cはグループの成果物から作成された特許開示リストを維持しています。 また、このページは特許開示の手順についても提示しています。 特許について実際の知識を持ち、 それが基本的な請求事項を含むと考える者は、 W3C Patent Policy 6節に従って情報を開示しなくてはなりません。
この文書は2014年8月1日 W3C 文書管理方法によって管理されます。
このセクションは非基準情報です。
Web MIDI API仕様はWeb開発者がMIDIデバイス、 例えば機器が接続されるハードウェアMIDIポートやUSB-MIDI仕様をサポートしたUSB機器などのインターフェース、 に対して列挙、操作、アクセスを行う手段を定義しています。 MIDIに対するWeb APIを持つ事で、Webアプリケーションは既存のソフトウェアやハードウェアのシンセサイザー、ハードウェアの音楽コントローラー、 照明システムやその他のMIDIで制御される機器/機械を使う事ができるようになります。 このAPIは広い範囲の使用例を念頭に定義されています。
このAPIが取るアプローチはApple社のCoreMIDIやMicrosoft社のWindows MIDI APIに似ています; つまり、APIは開発者がその上に有用なMIDIソフトウェアを構築できるように、 MIDIの低レベルのソフトウェアプロトコルを表すように設計されていると言う事です。 APIは開発者が入出力インターフェースを列挙し、MIDIメッセージを送受信する事を可能にしますが、 (前述の他のAPIと同様に)現存するデバイスを確実にサポートするために必要な範囲を超えて、 MIDIメッセージの意味を定義したり解釈する事は行いません。
Web MIDI APIはシーケンサーなどの高レベルの概念を直接実装する事は意図していません; 例えば、スタンダードMIDIファイルは直接サポートされませんが、Web MIDI APIの上にスタンダードMIDIファイルプレーヤーを構築する事は可能です。 また、ジェネラルMIDIが行っているようにパッチやコントローラーのアサインを意味的に定める事も意図しません; それらの解釈はWeb MIDI APIの範囲外です(繰り返しになりますが、Web MIDI APIを通してジェネラルMIDIを簡単に利用する事はできます)。
この仕様中、非基準情報と書かれているセクションと同様に、全てのオーサリングガイドライン、図、例、注、は非基準情報です。 仕様内のその他の全ては基準情報です。
この仕様内のキーワード、MUST、 SHOULDは[RFC2119]で規定されているように解釈されます。
この仕様で定義される適合基準は、このインターフェースを実装するユーザーエージェント単体に適用されます。
この仕様で定められているAPIの実装にECMAScriptを使用する場合、 この仕様で使用されているWeb IDL仕様[WEBIDL] で定義されるECMAScriptバインディングの作法で実装しなくてはなりません (MUST)。
タスクをキューに登録および、 単純なイベントの発行の概念は、[HTML5]で定義されています。
イベントハンドラー、
イベントハンドラーイベントタイプ および対応する
EventHandler
インターフェースは [HTML5]
で定義されています。
Uint8Array インターフェース は [TYPED-ARRAYS]で定義されています。
Web Audio API およびそれに関連するインターフェース、概念は[webaudio]で定義されています。
Event インターフェースは [DOM4]で定義されています。
DOMError インターフェースは [DOM-LEVEL-3-CORE]で定義されています。
DOMHighResTimeStamp インターフェースは [HIGHRES-TIME] で定義されています。
MIDI, MIDI デバイス、 MIDI 入力ポート, MIDI 出力ポート、 MIDI インターフェース, MIDI メッセージ、 MIDI システムリアルタイムメッセージ、 システムエクスクルーシブ は [MIDI] で定義されています。
Promise インターフェースは現在 the WHATWG DOM specificationで定義されています。
呼び出されると、ユーザーシステム上のMIDIデバイスへのアクセス要求を表すPromiseオブジェクトを返します。
MIDIアクセスの要求、特にシステムエクスクルーシブへのアクセスは、ユーザーに対してプロンプトを出し、
MIDIデバイスにアクセスする旨の許可を得なくてはなりません(SHOULD)。
シナリオによっては、この許可は暗黙的あるいは明示的に既に得られている事もあり、
この場合にはこのプロンプトは表示されないかも知れません。
もしユーザーが承諾するか、他の手段で許可されている場合、PromiseのresolveCallbackが
として呼び出されます (つまり、MIDISuccessCallback
オブジェクトとMIDIAccess
オブジェクトが引数となります)。
必須ではありませんが、下層のシステムはユーザーが特定のMIDIインターフェースをこのAPIを通じて選択できるように、
(個別の基準で選択して)選ぶ事もあります。
また、システムエクスクルーシブはプライバシー情報をより多く含んでいるため、そのサポートを要求されたかどうかに応じて、
システムはプロンプトメッセージを出す(あるいは出さない)を選択するかも知れません。
MIDIOptions
ユーザーが拒否したり、あるいは別の理由で呼び出しが許可されていない場合、(もし設定されていれば)Promiseの
rejectCallbackがDOMException
パラメーターと共に呼び出されます。
requestMIDIAccess
メソッドが呼ばれた時、
ユーザーエージェントは以下のMIDIアクセスリクエストアルゴリズム
を実行しなくてはなりません
(MUST)。:
新しいPromiseオブジェクト、promiseを作成し、resolverをそれに結びついたリゾルバーとします。
promiseを返し、以下のステップを非同期に実行します。
前もって行われているユーザー設定、セキュリティ上の理由、プラットフォームの制限などによって必要ならば、 下の失敗ステップにジャンプします。
前もって行われているユーザー設定などによって必要ならば、下の成功ステップにジャンプします。
ユーザーエージェント固有の方法でユーザーにプロンプトを出し、 MIDIデバイスの制御を表す
オブジェクト、
即ちスクリプトの起点を渡す事に対する許可を得ます。
このプロンプトにはシステムエクスクルーシブのサポートを要求されているかどうかの条件が示され、
ユーザーはアクセスを有効にするか無効にするかを選択できます。
MIDIAccess
もし拒否された場合、下の失敗ステップにジャンプします。 ユーザーが応答しない場合、このアルゴリズムはこのステップに留まったまま進みません。 許可された場合、次のステップに進みます。
成功:
新しい
オブジェクトを作成し、accessとします。
(ユーザーへのプロンプトが複数回表示されるかも知れませんのであまり実際的ではありませんが、
requestMIDIAccess()を複数回呼び出す事は可能です。
そしてこの場合、毎回MIDIAccessのインスタンスは同じではありません)
MIDIAccess
accessを引数として、resolverのaccept(value)
メソッドが呼び出されます。
これらのステップを終了します。
失敗: 新しいDOMException
例外を作成し、errorとします。
この例外の.nameは
その型は、もしユーザーの設定かセキュリティ設定により、
要求されたオプションのMIDIAccessインスタンスの作成を拒否された場合は"SecurityError"
、
ユーザーのナビゲーションによりページが閉じられつつある場合は"AbortError"
、
下層のシステムが何らかのエラーを発生した場合は"InvalidStateError"
、
それ以外の場合は"NotSupportedError"
としなくてはなりません。
errorを引数として、resolverのreject(value)
メソッドを呼び出します。
パラメーター | 型 | Null可 | オプショナル | 説明 |
---|---|---|---|---|
options |
| ✘ | ✔ |
Promise<MIDIAccess
>
MIDIOptions
ディクショナリ このディクショナリはrequestMIDIAccess要求に渡される、オプション設定を保持します。
dictionary MIDIOptions {
boolean sysex;
};
MIDIOptions
メンバー sysex
boolean型このメンバーはそのMIDIAccess
オブジェクトによって
システムエクスクルーシブメッセージの送受信を行う事を要求、
または許可する事を表します。
このメンバーがtrueに設定されたオプションがrequestMIDIAccess
に渡され、
しかし、(ポリシーまたはユーザーアクションによって)、システムエクスクルーシブのサポートが否定された場合、
アクセス要求は失敗し"SecurityError"
エラーが発生します。
もし、このサポートを要求しない(そして許可された)場合に、
ユーザーがシステムエクスクルーシブメッセージを送信しようとした時には例外が発生し、
そのポートでシステムエクスクルーシブメッセージを受信した時には全て無反応のままマスクされます。
resolveCallbackに渡されるパラメーターのoptions
では、
このメンバーはシステムエクスクルーシブがMIDIAccess上で許可されている事を表します。
MIDIInputMap
インターフェース interface MIDIInputMap {
readonly maplike<DOMString, MIDIInput
>;
};
これは値がMIDIInputのインスタンスで、キーはそのIDになっているマップ風のインターフェースです。
この型は現在使用可能なすべてのMIDI入力ポートを表すのに使用されます。これにより、次の書き方を可能にします
// エントリーが幾つあるかを得る: var numberOfMIDIInputs = inputs.size; // それぞれのポートを<select>ボックスに追加する inputs.forEach( function( key, port ) { var opt = document.createElement("option"); opt.text = port.name; document.getElementById("inputportselector").add(opt); }); // あるいはECMAScript 6ではこのような書き方もできます: for (let input of inputs.values()) { var opt = document.createElement("option"); opt.text = input.name; document.getElementById("inputportselector").add(opt); }
MIDIOutputMap
インターフェース interface MIDIOutputMap {
readonly maplike<DOMString, MIDIOutput
>;
};
これは値がMIDIOutputのインスタンスで、キーがそのIDになっているマップ風のインターフェースです。
この型は現在使用可能なすべてのMIDI出力ポートを表すのに使用されます。これは次のような書き方を可能にします
// エントリーが幾つあるかを得る: var numberOfMIDIOutputs = outputs.size; // それぞれのポートを<select> ボックスに追加する outputs.forEach( function( key, port ) { var opt = document.createElement("option"); opt.text = port.name; document.getElementById("outputportselector").add(opt); }); // あるいはECMAScript 6ではこのような書き方もできます: for (output of outputs.values()) { var opt = document.createElement("option"); opt.text = input.name; document.getElementById("inputportselector").add(opt); }
MIDISuccessCallback
callback MIDISuccessCallback = void (MIDIAccess
access, MIDIOptions
options);
MIDISuccessCallback
パラメーター access
MIDIAccess
型
スクリプトからユーザーのMIDIデバイスにアクセスするために作成された、
オブジェクトです。
このオブジェクトはそれぞれのMIDIデバイスを列挙し、アクセスを得るために使用されます。
MIDIAccess
注: この仕様での、"MIDIデバイス"という用語はホストシステム上で使用可能なMIDIインターフェースを指します。 例えば、もしハードウェアのMIDIアダプターが1つだけホストシステムに接続されている時、 例え幾つかのMIDI対応機器(シンセサイザーやドラムマシン)がそのアダプターのMIDIポートに繋がれていても、 それは1つのデバイスとして列挙されます。
options
MIDIOptions
型
このパラメーターはこのMIDIAccess
オブジェクトで有効にするオプションを表します。
MIDIAccess
インターフェース このインターフェースはMIDI入力および出力デバイスをリストアップして、 それぞれのデバイスへのアクセスを得るためのメソッドを持ちます。
interface MIDIAccess : EventTarget {
readonly attribute MIDIInputMap
inputs;
readonly attribute MIDIOutputMap
outputs;
attribute EventHandler onstatechange;
readonly attribute boolean sysexEnabled;
};
inputs
MIDIInputMap
, readonly 型onstatechange
EventHandler型 新しいポートが接続された、あるいは既存のポートのstate属性が変化した時に呼ばれるハンドラーです。
このイベントハンドラーは、MIDIConnectionEvent
型に対応し、
インターフェースを実装した全てのオブジェクトでサポートされなくてはなりません(MUST)。
MIDIAccess
ユーザーエージェントは、これまで有効でなかったMIDIポートが有効になった時、あるいは既存のポートのstate属性が変化した時にはいつでも、 次のステップを実行しなくてはなりません(SHOULD ):
MIDIPort
をport
とします。
MIDIConnectionEvent
型のevent
を新たに作成し、
そのport
属性にportをセットします。
event
をイベントオブジェクトとしてMIDIAccess
にstatechange
イベントを発行します。
outputs
MIDIOutputMap
, readonly 型 sysexEnabled
boolean, readonly 型 MIDIPort
インターフェース これはMIDI入力または出力ポートを表すインターフェースです。
enum MIDIPortType {
"input",
"output"
};
列挙値の説明 | |
---|---|
input | もしMIDIPortが入力ポートの場合、typeメンバーはこの値でなくてはなりません(MUST)。 |
output | もしMIDIPortが出力ポートの場合、typeメンバーはこの値でなくてはなりません(MUST)。 |
enum MIDIPortDeviceState {
"disconnected",
"connected"
};
列挙値の説明 | |
---|---|
disconnected | MIDIPortが表すデバイスがシステムから切断されました。 デバイスがシステムから切断された場合、それは関連する入力や出力のマップには現れません。 |
connected | MIDIPortが表すデバイスが接続され、入力および出力ポートのマップに現れます。 |
enum MIDIPortConnectionState {
"open",
"closed",
"pending"
};
列挙値の説明 | |
---|---|
open | MIDIPortが表すデバイスがオープンされ(暗黙的、または明示的にかかわらず)、 使用可能になりました。 |
closed |
MIDIPortが表すデバイスがオープンされていません、あるいは明示的にクローズされました。MIDIPortが(open() によって)明示的にオープンされるか(入力ポートに対してmidimessage イベントハンドラーが追加されるか、出力ポートに対してsend()を呼び出すことで)
暗黙的にオープンされるまで、これはデバイスのデフォルトの状態です。
|
pending |
MIDIPortが表すデバイスが(暗黙的にまたは明示的に)オープンされましたが、
デバイスはその後切断され、使用できない状態です。
もしそのデバイスがstatechange イベントより前に再接続されれば、
システムはデバイスの再オープンを(MIDIPortをオープンするアルゴリズムに従って)
試みなければなりません。これによって接続状態は"open"または"closed"に遷移します。
|
interface MIDIPort : EventTarget {
readonly attribute DOMString id;
readonly attribute DOMString? manufacturer;
readonly attribute DOMString? name;
readonly attribute MIDIPortType
type;
readonly attribute DOMString? version;
readonly attribute MIDIPortDeviceState
state;
readonly attribute MIDIPortConnectionState
connection;
attribute EventHandler onstatechange;
Promise<MIDIPort
> open ();
Promise<MIDIPort
> close ();
};
connection
MIDIPortConnectionState
, readonly 型 id
DOMString, readonly 型
ポートのユニークIDです。 開発者はこれを、ユーザーがアプリケーション内で選択したポートを記憶しておくために使用できます。
ユーザーエージェントはid
がそのポートだけのユニークなものである事を保証しなくてはなりません
(MUST)。
ユーザーエージェントはそのid
がアプリケーションのインスタンスをまたいで、
例えば、システムがリブートした時、
デバイスがシステムから取り外された時にも維持される事を保証しなくてはなりません(SHOULD)。
アプリケーションはMIDI設定を再現するため、これらのidをローカルにキャッシュしようとするかも知れません。
システムによっては完全に永続的なユニーク性を持つ識別手段をサポートしていないかも知れず、
そのような場合、別のインターフェースが接続されたりシステムから切断された時に識別を維持し続けるのは難易度が高くなるでしょう
(これによって要求されたポートのインデックスがずれるかも知れません)。
システムはMIDI APIのインスタンスをまたいだポートのマッチングに最善の方法を取る事が期待されます:
例えばある実装ではポートインターフェースの製造者、名前、インデックスをなんらかの形でハッシュしてidとし、不透明な手段で
使用して、ポートが接続された時にポートのidが一致するものを参照するかも知れません。
アプリケーションはMIDIPortのidの比較を品質のテストのために使用するかも知れません。
manufacturer
DOMString, readonly , nullable 型ポートの製造者名です。
name
DOMString, readonly , nullable 型ポートのシステム名です。
onstatechange
EventHandler 型 存在していたポートの状態が変化した時、または接続された時に呼び出されるハンドラーです。
このstatechange
型のイベントハンドラーは
インターフェースを
実装するすべてのオブジェクトでサポートされなくてはなりません(MUST)。
MIDIPort
state
MIDIPortDeviceState
, readonly 型 type
MIDIPortType
, readonly 型 そのポートが入力ポートか出力ポートかを区別する識別子です。
の場合、 これはMIDIOutput
"output"
にならなくてはなりません(MUST)。
の場合、
これはMIDIInput
"input"
にならなくてはなりません(MUST)。
version
DOMString, readonly , nullable 型ポートのバージョンです。
close
MIDIPort
に対応するMIDIデバイスを
明示的に使用不能にします(この後状態は"open"から"connected"になります)。
このメソッドの呼び出しが成功すると
(新しいハンドラーの設定による暗黙的なopen()にかかわらず)MIDIメッセージはMIDI入力ポートのMIDIMessageEventハンドラーに
もう伝達されなく事に注意してください。
下層の実装はこの呼び出しに対して何もする必要がないかも知れません。 しかしながら下層の実装によってはMIDIデバイスへの共有アクセスをサポートしていないかも知れないため、 明示的なclose()呼び出しはMIDIアプリケーションに他のアプリケーションにデバイスへのアクセス を取得する事が可能な事を保証します。
呼び出された時、このメソッドはユーザーのシステム上で指定のMIDIポートへのアクセス
要求をあらわすPromiseオブジェクトを返します。
ポートがクローズされた時、(つまり排他的なアクセスのシステムではそのポートが他の
アプリケーションから使用可能になった時)、PromiseのresolveCallback
が
を
引数として呼び出されます。
もしポートが切断された場合、(設定されていれば)PromiseのrejectCallbackが
呼び出されます。
MIDIPort
close()
メソッドが呼び出された時、ユーザーエージェントは
MIDIPortクローズのアルゴリズム
を実行しなくてはなりません(MUST):
新たにPromiseオブジェクト、promiseを作成し、resolverを 対応するリゾルバーとします。
promiseを返却し、次のステップを非同期に実行します。
portを与えられたMIDIPort
オブジェクトとします。
もし、portが既に閉じられている(その.connection
が
"closed"
、例えばそのポートがまだ暗黙的にも明示的にも
オープンされていない、あるいはこのMIDIPort
でclose()
が既に呼ばれている)場合、下のclosed
ラベルに飛びます。
もしそのポートが入力ポートの場合、次のステップに進みます。
もし出力ポートで.state
が
"connected"
で
ない場合、すべての保留されている送信データをクリアし、次のステップに進みます。
タイムスタンプが未来のシステム内の保留されている送信データをすべてクリアし、
次のステップに進む前にタイムスタンプが過去または現在のすべての送信メッセージの送信を終了します。
下層のシステムをオープンしているならポートへのアクセスをすべてクローズし、 下層システムのブロックしているリソースを解放します。
成功: MIDIPortのconnection
属性を"closed"
に
変更し、新しい
をMIDIConnectionEvent
のMIDIAccess
statechange
ハンドラーおよび、
のMIDIPort
statechange
ハンドラーに発行します。
クローズ:
resolverのaccept(value)
メソッドをportを引数として呼び出します。
これらのステップの実行を終了します。
失敗:
DOMException
を新たに作成し、errorとします。
ポートが切断された場合、この例外の.nameは"InvalidStateError"
でなくてはなりません。
resolverのreject(value)
メソッドを
errorを引数として呼び出します。
Promise<MIDIPort
>
open
MIDIPort
に対応するMIDIデバイスを明示的に
使用可能にします。
この呼び出しはMIDIPort
を使用するために
必須のものではない事に注意してください -
MIDIOutput
のsend()
の呼び出し、またはMIDIInputPortにMIDIMessageEventハンドラーを設定する事で暗黙的にopen()を実行する
事ができます。
下層の実装はこの呼び出しに対して何もする必要がないかも知れません。
しかしながら下層の実装によってはMIDIデバイスへの共有アクセスをサポートしていないかも知れないため、
明示的なopen()およびclose()呼び出しを使う事でMIDIアプリケーションがデバイスへの排他アクセスを予想して
制御する事が可能になります。
呼び出された時、このメソッドは与えられたユーザーシステムのMIDIポートへのアクセス要求を表す Promiseオブジェクトを返します。
もしそのポートが"connected"
状態であってポートへのアクセスが取得できれば(そしてそのポートで入出力が可能になれば)、
PromiseのresolveCallbackが
オブジェクトを引数として
呼び出されます。
MIDIPort
connected状態のポートへのアクセスができなかった場合(例えば、排他的アクセスシステムの プラットフォームでそのポートが既に使用中になっていた場合)、Promiseは(設定されていれば) rejectCallbackを呼び出します。
もしcode>"disconnected"
状態のポートに対してopen()
が呼び出された場合、
そのポートの.connection
は
ポートが"connected"
状態に移行するかすべての参照が無くなるまで、
"pending"
に遷移します。
このメソッドが呼び出された時、ユーザーエージェントは MIDIPortオープンのアルゴリズムを実行します (MUST):
新しいPromiseオブジェクト、promiseを作成し、 結び付けられるリゾルバーをresolverとします。
promiseを返却し、次のステップを非同期的に実行します。
portを与えられたMIDIPort
オブジェクトとします。
もしデバイスの状態が既に"open"
の場合、(例えば このMIDIPortのopen()が既に呼ばれている、または暗黙的にオープンされている場合)、
下のopenedラベルのステップにジャンプします。
もしデバイスの状態が"pending"
の場合(例えば既にオープンされ、その後デバイスが切断されている場合)、
下のopenedラベルのステップにジャンプします。
もしデバイスの状態が"disconnected"
の場合、
MIDIPort
のstate
属性は
"pending"
に変化し、
新しいMIDIConnectionEvent
が
の
MIDIAccess
statechange
ハンドラーと
MIDIPort
のstatechange
ハンドラーに発行され、
下のopenedラベルのステップにジャンプします。
システム内のMIDIデバイスへのアクセスの取得を試みます。 もしそのデバイスが使用不能の場合(例えば、既に他のプロセスで使用されていてオープンできない、あるいは切断された場合) 下の失敗ラベルのステップにジャンプします。 もしそのデバイスが使用可能でアクセスを取得できた場合、次のステップを続けます。
成功: MIDIPortのstate
属性を"opened"
に変更し、
新しい
をMIDIConnectionEvent
の
MIDIAccess
statechange
ハンドラーと
MIDIPort
の
statechange
ハンドラーに
発行します。
もしこのポートが出力ポートで何らかの送信待ちの保留データを持っている場合、 そのデータの送信を非同期に開始します。
opened:
resolverのaccept(value)
メソッドをportを
引数として呼び出します。
これらのステップの実行を終了します。Terminate these steps.
失敗:
新たなDOMException
、errorを作成します。
この例外の.nameは、もしポートが使用不能の場合、"InvalidAccessError"
、
また、ポートが切断されている場合は"InvalidStateError"
となります。
resolverのreject(value)
メソッドを
errorを引数として呼び出します。
Promise<MIDIPort
>
に対応する
MIDIポートの状態属性が変化した時はいつでも、
ユーザーエージェントは以下のステップを実行します(SHOULD) :
MIDIPort
port
を
とします。
MIDIPort
新たな
、MIDIConnectionEvent
event
を作成してport
属性をそのポートに設定します。
MIDIPort
の
statechange
、および
MIDIAccess
の
statechange
イベントをevent
をイベントオブジェクトとして発行します。
MIDIInput
インターフェース interface MIDIInput : MIDIPort
{
attribute EventHandler onmidimessage;
};
onmidimessage
EventHandler型
このイベントハンドラーはMIDIMessage
型に対応し、
インターフェース
を実装する全てのオブジェクトでサポートされなくてはなりません
(MUST)。
MIDIInput
もしハンドラーが設定され、状態属性が"opened"
でない場合、下層の実装はポートを使用可能にしようとし、
状態属性を"opened"
にします。
もし成功すれば
イベントが対応するMIDIConnectionEvent
MIDIPort
とMIDIAccess
に対して発行されます。
に対応するMIDIポートが
1つ以上のMIDIメッセージを受信した際にはいつでも、ユーザーエージェントは以下のステップを実行しなくてはなりません
(MUST):
MIDIInput
port
を対象の
とします。
MIDIInput
もし
がシステムエクスクルーシブを許可されておらず、そのメッセージがシステムエクスクルーシブの場合はこの手順を中断します。
MIDIAccess
新たに
を作成してMIDIMessageEvent
event
とし、
timestamp
属性はシステムがメッセージを受信した時刻、
data
属性は単一のMIDIメッセージを表すUint8ArrayのMIDIデータのバイト配列に設定します。
event
portに対して
midimessage
イベントを発行します。
特に注意を要するのは、入力ストリームの他のメッセージの途中でMIDIシステムリアルタイムメッセージが発生した時です。 この場合、そのシステムリアルタイムメッセージは発生する度にディスパッチされ、通常のメッセージはそれが完結するまで バッファされます (完結後ディスパッチされます)。
MIDIOutput
インターフェース interface MIDIOutput : MIDIPort
{
void send (sequence<octet> data, optional double timestamp);
void clear ();
};
clear
MIDIOutput
のキューからまだ送られていないすべての保留中の送信データをクリアします。
実装はMIDIストリームが正常な状態に維持される事を保証する必要があり、もし出力ポートがsysexメッセージの途中にあった場合は
sysexを終端するバイト(0xf7)が送信されなくてはなりません。
void
send
対応するMIDIポートのキューに送信するメッセージを登録します。 実装は(もし必要なら)シーケンスの各メンバーを強制的にunsigned 8ビット整数にします。 Uint8Arrayでなくシーケンスを使う事で、開発者はoutput.send( new Uint8Array( [ 0x90, 0x45, 0x7f ] ) );のようにUint8Arrayを作る事なく、output.send( [ 0x90, 0x45, 0x7f ] );のような便利な書き方ができます (例えばスタンダードMIDIファイルを読んだり、SysExメッセージを送信するような) 大きなMIDIデータを使うシナリオではUint8Arrayを使う方が効率的ですが)。
dataは1つ以上の有効な完結したMIDIメッセージを含む事ができます。 下層のシステムがサポートしていない可能性があるのと同様、data中にランニングステータスは使用できません。
もし、dataが有効なシーケンスでない、あるいは有効なMIDIメッセージを含んでいない場合、TypeError
例外が発生します。
もしdataがシステムエクスクルーシブメッセージで、
がシステムエクスクルーシブへのアクセスが許可されていない場合、
MIDIAccess
InvalidAccessError
例外が発生します。
もしポートが"disconnected"
状態
の場合、InvalidStateError
例外が発生します。
もしポートが"connected"
状態
であるがコネクションが"closed"
の場合、
ポートのオープンを非同期で試みます。
パラメーター | 型 | Null可 | オプショナル | 説明 |
---|---|---|---|---|
data | sequence<octet> | ✘ | ✘ | キューに登録されるデータ。シーケンスの各エントリーは1バイトのデータを表します。 |
timestamp | double | ✘ | ✔ |
ポートにデータの送信を開始する時刻です (DOMHighResTimeStamp -
ドキュメントへのナビゲーション開始からの相対時間でミリ秒で表されます)。 もしtimestamp が存在しない場合、
または0(あるいは既に過ぎた時刻)を指定された場合、データは可能な限り即時に送信されます。
|
void
MIDIMessageEvent
インターフェース MIDIメッセージを受信した時、このインターフェースを実装したイベントオブジェクトが、MIDIInputのonmidimessageハンドラーに渡されます。
[Constructor(DOMString type, optional MIDIMessageEventInit eventInitDict)]
interface MIDIMessageEvent : Event {
readonly attribute double receivedTime;
readonly attribute Uint8Array data;
};
data
Uint8Array, readonly 型 1つのMIDIメッセージのデータのバイト列を含むUint8Arrayです。
receivedTime
double, readonly 型 イベントがいつ発生したのかを示すDOMHighResTimeStamp
です。
DOM4イベントオブジェクトは現在時刻を表すtimeStampメンバーを持っていますが、 その精度は低く、(DOMTimeStampは整数値でミリ秒を表します)、 また異なる時刻0の原点を取ります(DOMTimeStampは1970年1月1日 00:00:00 UTCからのミリ秒)。 そのため、MIDIアプリケーションで使用するには適切ではありません。
MIDIMessageEventInit
インターフェース dictionary MIDIMessageEventInit : EventInit {
double receivedTime;
Uint8Array data;
};
MIDIMessageEventInit
メンバー data
Uint8Array 型1つのMIDIメッセージのデータのバイト列を含むUint8Arrayです。
receivedTime
double 型イベントがいつ発生したのかを示すDOMHighResTimeStamp
です。
MIDIConnectionEvent
インターフェース
新しいポートが使用可能になった時、(例えばMIDIデバイスが最初にコンピューターに接続された時)、
以前使用可能だったポートが使用不能になった時、または再度使用可能になった時、
(例えばMIDIインターフェースが切断され、また接続された時)、
このインターフェースを実装したイベントオブジェクトがMIDIAccessのonstatechangeハンドラーに渡されます。
また(もしあれば)そのポートを参照するMIDIPort
のonstatechangeハンドラー
にも渡されます。
MIDIPort
が
"pending"
状態にあり、
そのデバイスがホストシステムに再接続された時は、
statechange
イベントが
発行される前に
MIDIPortオープンのアルゴリズムが実行され、
再オープンを試みます。
もしこの遷移が失敗した場合は (例えばそのポートが下層システムの何かで予約され使用できないなど)、
接続状態は"closed"に遷移し、そうでなければ"open"に遷移します。
これはそのデバイスの状態変化のstatechange
イベント発行に先立って行わます。そのためイベントではデバイスの状態と同様に最終的な接続状態を反映
します。
下層のシステムによってはデバイスの接続状態に関するイベントを提供しない場合があります。そのような システムでは新しいデバイスをまれにしかポーリングせず、大きなディレイが発生するかも知れません。 このような事情で、接続イベントに大きくは依存しないほうが良いでしょう。
[Constructor(DOMString type, optional MIDIConnectionEventInit eventInitDict)]
interface MIDIConnectionEvent : Event {
readonly attribute MIDIPort
port;
};
port
MIDIPort
, readonly 型 接続または切断されたポートです。
MIDIConnectionEventInit
インターフェース dictionary MIDIConnectionEventInit : EventInit {
MIDIPort
port;
};
MIDIConnectionEventInit
メンバー port
MIDIPort
型接続または切断されたポートです。
このセクションは非基準情報です。
JavaScriptでの一般的なMIDIの使い方の例を次に示します。
このサンプルはMIDIシステムへのアクセス要求の方法を示しています。
var midi = null; // グローバルなMIDIAccessオブジェクト function onMIDISuccess( midiAccess ) { console.log( "MIDI ready!" ); midi = midiAccess; // グローバルに保存します (実際の使用ではおそらくオブジェクトのインスタンスに保持します) } function onMIDIFailure(msg) { console.log( "Failed to get MIDI access - " + msg ); } navigator.requestMIDIAccess().then( onMIDISuccess, onMIDIFailure );
このサンプルはシステムエクスクルーシブの送受信を含めたMIDIシステムへのアクセス要求の方法を示しています。
var midi = null; // // グローバルMIDIAccessオブジェクト function onMIDISuccess( midiAccess ) { console.log( "MIDI ready!" ); midi = midiAccess; // グローバルに保存します (実際の使用ではおそらくオブジェクトのインスタンスに保持します) } function onMIDIFailure(msg) { console.log( "Failed to get MIDI access - " + msg ); } navigator.requestMIDIAccess( { sysex: true } ).then( onMIDISuccess, onMIDIFailure );
このサンプルはES6のfor...of表記を使って入力、出力ポートのリストを取得し、その情報をconsole logに出力します。 (訳注:まだ説明とサンプルコードに不一致が見られます)
function listInputsAndOutputs( midiAccess ) { for (var input in midiAccess.inputs) { console.log( "Input port [type:'" + input.type + "'] id:'" + input.id + "' manufacturer:'" + input.manufacturer + "' name:'" + input.name + "' version:'" + input.version + "'" ); } for (var output in midiAccess.outputs) { console.log( "Output port [type:'" + output.type + "'] id:'" + output.id + "' manufacturer:'" + output.manufacturer + "' name:'" + output.name + "' version:'" + output.version + "'" ); } }
このサンプルは入力の任意の1つのポートで受信したメッセージをconsole.logに出力します。
function onMIDIMessage( event ) { var str = "MIDI message received at timestamp " + event.timestamp + "[" + event.data.length + " bytes]: "; for (var i=0; i<event.data.length; i++) { str += "0x" + event.data[i].toString(16) + " "; } console.log( str ); } function startLoggingMIDIInput( midiAccess, indexOfPort ) { midiAccess.inputs.forEach( function(entry) {entry.value.onmidimessage = onMIDIMessage;}); }
このサンプルは中央Cのノートオンメッセージを MIDIチャンネル1(MIDIチャンネルのインデックスは0から始まりますが一般的には1~16と表されます)に送信し、 対応するノートオフメッセージを1秒後に送るようにキューに登録します。
function sendMiddleC( midiAccess, portID ) { var noteOnMessage = [0x90, 60, 0x7f]; // note on, middle C, full velocity var output = midiAccess.outputs.get(portID); output.send( noteOnMessage ); //omitting the timestamp means send immediately. output.send( [0x80, 60, 0x40], window.performance.now() + 1000.0 ); // インライン配列作成 - ノートオフ, 中央C, // リリースベロシティ = 64, タイムスタンプ = now + 1000ms. }
このサンプルは、システムエクスクルーシブメッセージを含め、1番目の入力ポートで受信したメッセージを1番目の出力ポートに出力します。
var midi = null; // グローバル MIDIAccess オブジェクト var output = null; function echoMIDIMessage( event ) { if (output) { output.send( event.data, event.timestamp ); } } function onMIDISuccess( midiAccess ) { console.log( "MIDI ready!" ); var input = midiAccess.inputs.entries.next(); if (input) input.onmidimessage = echoMIDIMessage; output = midiAccess.outputs.values().next().value; if (!input || !output) console.log("Uh oh! Couldn't get i/o ports."); } function onMIDIFailure(msg) { console.log( "Failed to get MIDI access - " + msg ); } navigator.requestMIDIAccess().then( onMIDISuccess, onMIDIFailure );
このサンプルは全ての使用可能な入力ポートで受信したノートメッセージで、 Web Audio APIを使ったモノフォニックのサイン波オシレーターのエンベロープと周波数を制御し、 非常に単純なシンセサイザーを作っています。 ノートオンとノートオフメッセージがサポートされていますが、サスティンペダル、ベロシティ、ピッチベンドなどはサポートされていません。 このサンプルはwebaudiodemos.appspot.comでも公開されています。
var context=null; // the Web Audio "context" object var midiAccess=null; // the MIDIAccess object. var oscillator=null; // the single oscillator var envelope=null; // the envelope for the single oscillator var attack=0.05; // attack speed var release=0.05; // release speed var portamento=0.05; // portamento/glide speed var activeNotes = []; // the stack of actively-pressed keys window.addEventListener('load', function() { // patch up prefixes window.AudioContext=window.AudioContext||window.webkitAudioContext; context = new AudioContext(); if (navigator.requestMIDIAccess) navigator.requestMIDIAccess().then( onMIDIInit, onMIDIReject ); else alert("No MIDI support present in your browser. You're gonna have a bad time.") // set up the basic oscillator chain, muted to begin with. oscillator = context.createOscillator(); oscillator.frequency.setValueAtTime(110, 0); envelope = context.createGain(); oscillator.connect(envelope); envelope.connect(context.destination); envelope.gain.value = 0.0; // Mute the sound oscillator.start(0); // Go ahead and start up the oscillator } ); function onMIDIInit(midi) { midiAccess = midi; var haveAtLeastOneDevice=false; var inputs=midiAccess.inputs.values(); for ( var input = inputs.next(); input && !input.done; input = inputs.next()) { input.value.onmidimessage = MIDIMessageEventHandler; haveAtLeastOneDevice = true; } if (!haveAtLeastOneDevice) alert("No MIDI input devices present. You're gonna have a bad time."); } function onMIDIReject(err) { alert("The MIDI system failed to start. You're gonna have a bad time."); } function MIDIMessageEventHandler(event) { // Mask off the lower nibble (MIDI channel, which we don't care about) switch (event.data[0] & 0xf0) { case 0x90: if (event.data[2]!=0) { // if velocity != 0, this is a note-on message noteOn(event.data[1]); return; } // if velocity == 0, fall thru: it's a note-off. MIDI's weird, y'all. case 0x80: noteOff(event.data[1]); return; } } function frequencyFromNoteNumber( note ) { return 440 * Math.pow(2,(note-69)/12); } function noteOn(noteNumber) { activeNotes.push( noteNumber ); oscillator.frequency.cancelScheduledValues(0); oscillator.frequency.setTargetAtTime( frequencyFromNoteNumber(noteNumber), 0, portamento ); envelope.gain.cancelScheduledValues(0); envelope.gain.setTargetAtTime(1.0, 0, attack); } function noteOff(noteNumber) { var position = activeNotes.indexOf(noteNumber); if (position!=-1) { activeNotes.splice(position,1); } if (activeNotes.length==0) { // shut off the envelope envelope.gain.cancelScheduledValues(0); envelope.gain.setTargetAtTime(0.0, 0, release ); } else { oscillator.frequency.cancelScheduledValues(0); oscillator.frequency.setTargetAtTime( frequencyFromNoteNumber(activeNotes[activeNotes.length-1]), 0, portamento ); } }
WebプラットフォームにWeb MIDI APIを加えるにあたって、2つの基本的なセキュリティとプライバシーに関する懸案事項があります:
大量のMIDIデバイスが接続されているシステムはあまり多くありません。 通常それらのシステムではUSBハブにUSB-MIDIで大量に接続するような事はせず、典型的にはハードウェアMIDIインターフェースを使用します。 この場合、もちろんMIDI"デバイス"としてはハードウェアMIDIインターフェースだけが列挙され、 一方そこに接続されているシンセサイザー、サンプラー、その他は列挙されません。 少数のデバイスを接続した場合、ここに公開される情報の量は他のAPI、例えばゲームパッドAPIなどと同等です。 大多数のシステムでは接続しているMIDIインターフェースの数は比較的少ないです。
MIDIポートに対してできる事を簡単に分類すると:
そのそれぞれが持つインパクトは:
これらの機能に対して、MIDIによってどんなシナリオが可能になるのかを確認する事も有用です:
簡単に言えば: MIDIデバイスの列挙で晒される事になる、付加的なフィンガープリンティングは、 そのままゲームパッドAPIによるゲームパッドの列挙による付加的なフィンガープリンティングに類似しています。 典型的なユーザーではせいぜい数個のデバイスが接続され、それらが設定されても、 晒される情報はそのインターフェース自体のものです(即ちユーザーが設定したデータではありません)。
ショートメッセージの受信に関するセキュリティ上の懸案も小さいものです。 それはキーボード、マウス、モバイル/ラップトップの加速度センサー、タッチ入力、ゲームパッドイベントのリストアップに類似しています。 付加的に晒される情報はなく、クロック信号以外の全てのメッセージはユーザーの操作で発生します。
ショートメッセージの送信に関する懸案は全てのオーディオ出力に類似しています。 ユーザーの情報を上書きしたりユーザーの情報を読み取る事はできず、ただ、音を出し、パッチを変更し、 (稀な設定では)照明を点灯/消灯します。しかしこれは破壊的ではなく、永続するものではありません。
その一方、システムエクスクルーシブは潜在的に制限の少ないものであるため、APIの中でより注意深く、 ユーザーのセキュリティの留め金として、区別してSysExの要求をする事は良い考えです。 提案されているセキュリティモデルではユーザーエージェントがMIDIデバイスへのアクセスの前に明示的に ユーザーの許可を求める事を許してはいますが、 今の所、この許可を得るためにプロンプトを出す事は必須ではありません。 しかしその一方、システムエクスクルーシブのサポートに関してはリクエストの中でそれを要求しなくてはならない事を詳細に定めています。