概要

シンセサイザー、キーボード等のコントローラー、ドラムマシンなど、 ユーザーエージェントはそのホストコンピューターやデバイスに接続された音楽機器を持っている場合があります。 広く採用されている、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 文書管理方法によって管理されます。

目次

1. 序文

このセクションは非基準情報です。

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を簡単に利用する事はできます)。

2. 準拠

この仕様中、非基準情報と書かれているセクションと同様に、全てのオーサリングガイドライン、図、例、注、は非基準情報です。 仕様内のその他の全ては基準情報です。

この仕様内のキーワード、MUSTSHOULDは[RFC2119]で規定されているように解釈されます。

この仕様で定義される適合基準は、このインターフェースを実装するユーザーエージェント単体に適用されます。

この仕様で定められているAPIの実装にECMAScriptを使用する場合、 この仕様で使用されているWeb IDL仕様[WEBIDL] で定義されるECMAScriptバインディングの作法で実装しなくてはなりません (MUST)。

3. 用語

タスクをキューに登録および、 単純なイベントの発行の概念は、[HTML5]で定義されています。

イベントハンドラー イベントハンドラーイベントタイプ および対応する EventHandler インターフェースは [HTML5] で定義されています。

Uint8Array インターフェース は [TYPED-ARRAYS]で定義されています。

octet は [WEBIDL]で定義されています。

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で定義されています。

4. MIDIデバイスへのアクセスの取得

4.1 requestMIDIAccess()

partial interface Navigator {
    Promise<MIDIAccess> requestMIDIAccess (optional MIDIOptions options);
};

4.1.1 メソッド

requestMIDIAccess

呼び出されると、ユーザーシステム上のMIDIデバイスへのアクセス要求を表すPromiseオブジェクトを返します。

MIDIアクセスの要求、特にシステムエクスクルーシブへのアクセスは、ユーザーに対してプロンプトを出し、 MIDIデバイスにアクセスする旨の許可を得なくてはなりません(SHOULD)。 シナリオによっては、この許可は暗黙的あるいは明示的に既に得られている事もあり、 この場合にはこのプロンプトは表示されないかも知れません。 もしユーザーが承諾するか、他の手段で許可されている場合、PromiseのresolveCallbackMIDISuccessCallbackとして呼び出されます (つまり、MIDIAccessオブジェクトとMIDIOptionsオブジェクトが引数となります)。 必須ではありませんが、下層のシステムはユーザーが特定のMIDIインターフェースをこのAPIを通じて選択できるように、 (個別の基準で選択して)選ぶ事もあります。 また、システムエクスクルーシブはプライバシー情報をより多く含んでいるため、そのサポートを要求されたかどうかに応じて、 システムはプロンプトメッセージを出す(あるいは出さない)を選択するかも知れません。

ユーザーが拒否したり、あるいは別の理由で呼び出しが許可されていない場合、(もし設定されていれば)Promiseの rejectCallbackDOMExceptionパラメーターと共に呼び出されます。

requestMIDIAccessメソッドが呼ばれた時、 ユーザーエージェントは以下のMIDIアクセスリクエストアルゴリズム を実行しなくてはなりません (MUST)。:

  1. 新しいPromiseオブジェクト、promiseを作成し、resolverをそれに結びついたリゾルバーとします。

  2. promiseを返し、以下のステップを非同期に実行します。

  3. 前もって行われているユーザー設定、セキュリティ上の理由、プラットフォームの制限などによって必要ならば、 下の失敗ステップにジャンプします。

  4. 前もって行われているユーザー設定などによって必要ならば、下の成功ステップにジャンプします。

  5. ユーザーエージェント固有の方法でユーザーにプロンプトを出し、 MIDIデバイスの制御を表すMIDIAccessオブジェクト、 即ちスクリプトの起点を渡す事に対する許可を得ます。 このプロンプトにはシステムエクスクルーシブのサポートを要求されているかどうかの条件が示され、 ユーザーはアクセスを有効にするか無効にするかを選択できます。

    もし拒否された場合、下の失敗ステップにジャンプします。 ユーザーが応答しない場合、このアルゴリズムはこのステップに留まったまま進みません。 許可された場合、次のステップに進みます。

  6. 成功: 新しいMIDIAccess オブジェクトを作成し、accessとします。 (ユーザーへのプロンプトが複数回表示されるかも知れませんのであまり実際的ではありませんが、 requestMIDIAccess()を複数回呼び出す事は可能です。 そしてこの場合、毎回MIDIAccessのインスタンスは同じではありません)

  7. accessを引数として、resolveraccept(value)メソッドが呼び出されます。

  8. これらのステップを終了します。

  9. 失敗: 新しいDOMException例外を作成し、errorとします。 この例外の.nameは その型は、もしユーザーの設定かセキュリティ設定により、 要求されたオプションのMIDIAccessインスタンスの作成を拒否された場合は"SecurityError"、 ユーザーのナビゲーションによりページが閉じられつつある場合は"AbortError"、 下層のシステムが何らかのエラーを発生した場合は"InvalidStateError"、 それ以外の場合は"NotSupportedError"としなくてはなりません。

  10. errorを引数として、resolverreject(value)メソッドを呼び出します。

パラメーターNull可オプショナル説明
optionsMIDIOptions
戻り値の型: Promise<MIDIAccess>

4.2 MIDIOptions ディクショナリ

このディクショナリはrequestMIDIAccess要求に渡される、オプション設定を保持します。

dictionary MIDIOptions {
    boolean sysex;
};

4.2.1 ディクショナリ MIDIOptions メンバー

sysex boolean

このメンバーはそのMIDIAccessオブジェクトによって システムエクスクルーシブメッセージの送受信を行う事を要求、 または許可する事を表します。 このメンバーがtrueに設定されたオプションがrequestMIDIAccessに渡され、 しかし、(ポリシーまたはユーザーアクションによって)、システムエクスクルーシブのサポートが否定された場合、 アクセス要求は失敗し"SecurityError"エラーが発生します。 もし、このサポートを要求しない(そして許可された)場合に、 ユーザーがシステムエクスクルーシブメッセージを送信しようとした時には例外が発生し、 そのポートでシステムエクスクルーシブメッセージを受信した時には全て無反応のままマスクされます。

resolveCallbackに渡されるパラメーターのoptionsでは、 このメンバーはシステムエクスクルーシブがMIDIAccess上で許可されている事を表します。

4.3 MIDIInputMap インターフェース

interface MIDIInputMap {
    readonly maplike<DOMString, MIDIInput>;
};

4.3.1 マップライク

これは値が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);
    }

4.4 MIDIOutputMap インターフェース

interface MIDIOutputMap {
    readonly maplike<DOMString, MIDIOutput>;
};

4.4.1 マップライク

これは値が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);
    }

4.5 MIDISuccessCallback

callback MIDISuccessCallback = void (MIDIAccess access, MIDIOptions options);

4.5.1 コールバック MIDISuccessCallback パラメーター

access MIDIAccess

スクリプトからユーザーのMIDIデバイスにアクセスするために作成された、MIDIAccessオブジェクトです。 このオブジェクトはそれぞれのMIDIデバイスを列挙し、アクセスを得るために使用されます。

注: この仕様での、"MIDIデバイス"という用語はホストシステム上で使用可能なMIDIインターフェースを指します。 例えば、もしハードウェアのMIDIアダプターが1つだけホストシステムに接続されている時、 例え幾つかのMIDI対応機器(シンセサイザーやドラムマシン)がそのアダプターのMIDIポートに繋がれていても、 それは1つのデバイスとして列挙されます。

options MIDIOptions

このパラメーターはこのMIDIAccess オブジェクトで有効にするオプションを表します。

5. MIDIAccess インターフェース

このインターフェースはMIDI入力および出力デバイスをリストアップして、 それぞれのデバイスへのアクセスを得るためのメソッドを持ちます。

interface MIDIAccess : EventTarget {
    readonly    attribute MIDIInputMap  inputs;
    readonly    attribute MIDIOutputMap outputs;
                attribute EventHandler  onstatechange;
    readonly    attribute boolean       sysexEnabled;
};

5.1 属性

inputs MIDIInputMap, readonly 型
システムで使用可能なMIDI入力ポートです。
onstatechange EventHandler

新しいポートが接続された、あるいは既存のポートのstate属性が変化した時に呼ばれるハンドラーです。

このイベントハンドラーは、MIDIConnectionEvent型に対応し、 MIDIAccessインターフェースを実装した全てのオブジェクトでサポートされなくてはなりません(MUST)。

ユーザーエージェントは、これまで有効でなかったMIDIポートが有効になった時、あるいは既存のポートのstate属性が変化した時にはいつでも、 次のステップを実行しなくてはなりません(SHOULD ):

  1. 新たに有効になったポート、 あるいはその既存のポートに対応するMIDIPortportとします。
  2. MIDIConnectionEvent型のeventを新たに作成し、 そのport属性にportをセットします。
  3. eventをイベントオブジェクトとしてMIDIAccessstatechangeイベントを発行します。
outputs MIDIOutputMap, readonly 型
システムで使用可能なMIDI出力ポートです。 
sysexEnabled boolean, readonly 型
この属性は、このMIDIAccess上でシステムエクスクルーシブのサポートが有効かどうかを示します。

6. 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 ();
};

6.1 属性

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型のイベントハンドラーは MIDIPortインターフェースを 実装するすべてのオブジェクトでサポートされなくてはなりません(MUST)。

state MIDIPortDeviceState, readonly 型
デバイスの状態です。
type MIDIPortType, readonly 型

そのポートが入力ポートか出力ポートかを区別する識別子です。 MIDIOutputの場合、 これは"output"にならなくてはなりません(MUST)。 MIDIInputの場合、 これは"input"にならなくてはなりません(MUST)。

version DOMString, readonly , nullable 型

ポートのバージョンです。

6.2 メソッド

close

MIDIPortに対応するMIDIデバイスを 明示的に使用不能にします(この後状態は"open"から"connected"になります)。 このメソッドの呼び出しが成功すると (新しいハンドラーの設定による暗黙的なopen()にかかわらず)MIDIメッセージはMIDI入力ポートのMIDIMessageEventハンドラーに もう伝達されなく事に注意してください。

下層の実装はこの呼び出しに対して何もする必要がないかも知れません。 しかしながら下層の実装によってはMIDIデバイスへの共有アクセスをサポートしていないかも知れないため、 明示的なclose()呼び出しはMIDIアプリケーションに他のアプリケーションにデバイスへのアクセス を取得する事が可能な事を保証します。

呼び出された時、このメソッドはユーザーのシステム上で指定のMIDIポートへのアクセス 要求をあらわすPromiseオブジェクトを返します。 ポートがクローズされた時、(つまり排他的なアクセスのシステムではそのポートが他の アプリケーションから使用可能になった時)、PromiseのresolveCallbackMIDIPortを 引数として呼び出されます。 もしポートが切断された場合、(設定されていれば)PromiseのrejectCallbackが 呼び出されます。

close()メソッドが呼び出された時、ユーザーエージェントは MIDIPortクローズのアルゴリズム を実行しなくてはなりません(MUST):

  1. 新たにPromiseオブジェクト、promiseを作成し、resolverを 対応するリゾルバーとします。

  2. promiseを返却し、次のステップを非同期に実行します。

  3. portを与えられたMIDIPortオブジェクトとします。

  4. もし、portが既に閉じられている(その.connection"closed"、例えばそのポートがまだ暗黙的にも明示的にも オープンされていない、あるいはこのMIDIPortclose()が既に呼ばれている)場合、下のclosed ラベルに飛びます。

  5. もしそのポートが入力ポートの場合、次のステップに進みます。 もし出力ポートで.state"connected"で ない場合、すべての保留されている送信データをクリアし、次のステップに進みます。 タイムスタンプが未来のシステム内の保留されている送信データをすべてクリアし、 次のステップに進む前にタイムスタンプが過去または現在のすべての送信メッセージの送信を終了します。

  6. 下層のシステムをオープンしているならポートへのアクセスをすべてクローズし、 下層システムのブロックしているリソースを解放します。

  7. 成功: MIDIPortのconnection属性を"closed"に 変更し、新しいMIDIConnectionEventMIDIAccessstatechangeハンドラーおよび、MIDIPortstatechangeハンドラーに発行します。

  8. クローズ: resolveraccept(value)メソッドをportを引数として呼び出します。

  9. これらのステップの実行を終了します。

  10. 失敗: DOMExceptionを新たに作成し、errorとします。 ポートが切断された場合、この例外の.nameは"InvalidStateError"でなくてはなりません。

  11. resolverreject(value)メソッドを errorを引数として呼び出します。

パラメーターなし。
戻り値の型: Promise<MIDIPort>
open

MIDIPortに対応するMIDIデバイスを明示的に 使用可能にします。 この呼び出しはMIDIPortを使用するために 必須のものではない事に注意してください - MIDIOutputsend() の呼び出し、またはMIDIInputPortにMIDIMessageEventハンドラーを設定する事で暗黙的にopen()を実行する 事ができます。 下層の実装はこの呼び出しに対して何もする必要がないかも知れません。 しかしながら下層の実装によってはMIDIデバイスへの共有アクセスをサポートしていないかも知れないため、 明示的なopen()およびclose()呼び出しを使う事でMIDIアプリケーションがデバイスへの排他アクセスを予想して 制御する事が可能になります。

呼び出された時、このメソッドは与えられたユーザーシステムのMIDIポートへのアクセス要求を表す Promiseオブジェクトを返します。

もしそのポートが"connected" 状態であってポートへのアクセスが取得できれば(そしてそのポートで入出力が可能になれば)、 PromiseのresolveCallbackMIDIPortオブジェクトを引数として 呼び出されます。

connected状態のポートへのアクセスができなかった場合(例えば、排他的アクセスシステムの プラットフォームでそのポートが既に使用中になっていた場合)、Promiseは(設定されていれば) rejectCallbackを呼び出します。

もしcode>"disconnected" 状態のポートに対してopen()が呼び出された場合、 そのポートの.connectionは ポートが"connected" 状態に移行するかすべての参照が無くなるまで、 "pending"に遷移します。

このメソッドが呼び出された時、ユーザーエージェントは MIDIPortオープンのアルゴリズムを実行します (MUST):

  1. 新しいPromiseオブジェクト、promiseを作成し、 結び付けられるリゾルバーをresolverとします。

  2. promiseを返却し、次のステップを非同期的に実行します。

  3. portを与えられたMIDIPortオブジェクトとします。

  4. もしデバイスの状態が既に"open" の場合、(例えば このMIDIPortのopen()が既に呼ばれている、または暗黙的にオープンされている場合)、 下のopenedラベルのステップにジャンプします。

  5. もしデバイスの状態が"pending" の場合(例えば既にオープンされ、その後デバイスが切断されている場合)、 下のopenedラベルのステップにジャンプします。

  6. もしデバイスの状態が"disconnected"の場合、 MIDIPortstate属性は "pending"に変化し、 新しいMIDIConnectionEventMIDIAccessstatechangeハンドラーと MIDIPortstatechangeハンドラーに発行され、 下のopenedラベルのステップにジャンプします。

  7. システム内のMIDIデバイスへのアクセスの取得を試みます。 もしそのデバイスが使用不能の場合(例えば、既に他のプロセスで使用されていてオープンできない、あるいは切断された場合) 下の失敗ラベルのステップにジャンプします。 もしそのデバイスが使用可能でアクセスを取得できた場合、次のステップを続けます。

  8. 成功: MIDIPortのstate属性を"opened"に変更し、 新しいMIDIConnectionEventMIDIAccessstatechangeハンドラーと MIDIPortstatechangeハンドラーに 発行します。

  9. もしこのポートが出力ポートで何らかの送信待ちの保留データを持っている場合、 そのデータの送信を非同期に開始します。

  10. opened: resolveraccept(value)メソッドをportを 引数として呼び出します。

  11. これらのステップの実行を終了します。Terminate these steps.

  12. 失敗: 新たなDOMExceptionerrorを作成します。 この例外の.nameは、もしポートが使用不能の場合、"InvalidAccessError"、 また、ポートが切断されている場合は"InvalidStateError"となります。

  13. resolverreject(value)メソッドを errorを引数として呼び出します。

パラメーターなし。
戻り値の型: Promise<MIDIPort>

MIDIPortに対応する MIDIポートの状態属性が変化した時はいつでも、 ユーザーエージェントは以下のステップを実行します(SHOULD) :

  1. portMIDIPortとします。

  2. 新たなMIDIConnectionEventeventを作成してport属性をそのポートに設定します。

  3. MIDIPortstatechange、および MIDIAccessstatechange イベントをeventをイベントオブジェクトとして発行します。

6.3 MIDIInput インターフェース

interface MIDIInput : MIDIPort {
                attribute EventHandler onmidimessage;
};

6.3.1 属性

onmidimessage EventHandler

このイベントハンドラーはMIDIMessage型に対応し、 MIDIInputインターフェース を実装する全てのオブジェクトでサポートされなくてはなりません (MUST)。

もしハンドラーが設定され、状態属性が"opened"でない場合、下層の実装はポートを使用可能にしようとし、 状態属性を"opened"にします。 もし成功すればMIDIConnectionEvent イベントが対応するMIDIPortMIDIAccessに対して発行されます。

MIDIInputに対応するMIDIポートが 1つ以上のMIDIメッセージを受信した際にはいつでも、ユーザーエージェントは以下のステップを実行しなくてはなりません (MUST):

  1. portを対象のMIDIInputとします。

  2. もしMIDIAccess がシステムエクスクルーシブを許可されておらず、そのメッセージがシステムエクスクルーシブの場合はこの手順を中断します。

  3. 新たにMIDIMessageEvent を作成してeventとし、 timestamp属性はシステムがメッセージを受信した時刻、 data属性は単一のMIDIメッセージを表すUint8ArrayのMIDIデータのバイト配列に設定します。

  4. eventportに対して midimessageイベントを発行します。

特に注意を要するのは、入力ストリームの他のメッセージの途中でMIDIシステムリアルタイムメッセージが発生した時です。 この場合、そのシステムリアルタイムメッセージは発生する度にディスパッチされ、通常のメッセージはそれが完結するまで バッファされます (完結後ディスパッチされます)。

6.4 MIDIOutput インターフェース

interface MIDIOutput : MIDIPort {
    void send (sequence<octet> data, optional double timestamp);
    void clear ();
};

6.4.1 メソッド

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可オプショナル説明
datasequence<octet> キューに登録されるデータ。シーケンスの各エントリーは1バイトのデータを表します。
timestampdouble ポートにデータの送信を開始する時刻です (DOMHighResTimeStamp - ドキュメントへのナビゲーション開始からの相対時間でミリ秒で表されます)。 もしtimestampが存在しない場合、 または0(あるいは既に過ぎた時刻)を指定された場合、データは可能な限り即時に送信されます。
戻り値の型: void

7. MIDIMessageEvent インターフェース

MIDIメッセージを受信した時、このインターフェースを実装したイベントオブジェクトが、MIDIInputのonmidimessageハンドラーに渡されます。

[Constructor(DOMString type, optional MIDIMessageEventInit eventInitDict)]
interface MIDIMessageEvent : Event {
    readonly    attribute double     receivedTime;
    readonly    attribute Uint8Array data;
};

7.1 属性

data Uint8Array, readonly 型

1つのMIDIメッセージのデータのバイト列を含むUint8Arrayです。

receivedTime double, readonly 型

イベントがいつ発生したのかを示すDOMHighResTimeStampです。

DOM4イベントオブジェクトは現在時刻を表すtimeStampメンバーを持っていますが、 その精度は低く、(DOMTimeStampは整数値でミリ秒を表します)、 また異なる時刻0の原点を取ります(DOMTimeStampは1970年1月1日 00:00:00 UTCからのミリ秒)。 そのため、MIDIアプリケーションで使用するには適切ではありません。

7.2 MIDIMessageEventInit インターフェース

dictionary MIDIMessageEventInit : EventInit {
    double     receivedTime;
    Uint8Array data;
};

7.2.1 ディクショナリ MIDIMessageEventInit メンバー

data Uint8Array 型

1つのMIDIメッセージのデータのバイト列を含むUint8Arrayです。

receivedTime double 型

イベントがいつ発生したのかを示すDOMHighResTimeStampです。

8. 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;
};

8.1 属性

port MIDIPort, readonly 型

接続または切断されたポートです。

8.2 MIDIConnectionEventInit インターフェース

dictionary MIDIConnectionEventInit : EventInit {
    MIDIPort port;
};

8.2.1 ディクショナリ MIDIConnectionEventInit メンバー

port MIDIPort

接続または切断されたポートです。

9. JavaScriptでのWeb MIDI API 使用例

このセクションは非基準情報です。

JavaScriptでの一般的なMIDIの使い方の例を次に示します。

9.1 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 );

9.2 システムエクスクルーシブサポートを伴った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( { sysex: true } ).then( onMIDISuccess, onMIDIFailure );

9.3 入力および出力のリスティング

このサンプルは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 + "'" );
  }
}

9.4 MIDI入力の扱い方

このサンプルは入力の任意の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;});
}

9.5 出力デバイスへのMIDIメッセージの送信

このサンプルは中央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.
}

9.6 単純なループバック

このサンプルは、システムエクスクルーシブメッセージを含め、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 );

9.7 単純なモノフォニックサイン波MIDIシンセサイザー

このサンプルは全ての使用可能な入力ポートで受信したノートメッセージで、 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 );
      }
    }

10. MIDIのセキュリティとプライバシーに関する考察

WebプラットフォームにWeb MIDI APIを加えるにあたって、2つの基本的なセキュリティとプライバシーに関する懸案事項があります:

  1. ユーザーのMIDIインターフェースの列挙を可能にする事は潜在的にフィンガープリンティングのターゲットになります (特定のMIDIインターフェースの接続によってユーザーを一意に識別するという意味です)。 この文脈で注意するべきは、MIDIインターフェースの列挙である事です。 つまり、MIDIインターフェースに接続されている、例えば、個別のサンプラーやシンセサイザーは それらのデバイスがUSB(USB-MIDIデバイスは典型的に自身のMIDIインターフェースを持ち、列挙されます)接続でない限り、列挙されません。 フィンガープリンティングの対象となるインターフェースはMIDI"ポート"と同義で(そこに接続されているデバイスではありません)、 APIからMIDIインターフェースに対する個別のデバイスの名前、製造者、その内容の詳細は不明なid、が得られます。

    大量のMIDIデバイスが接続されているシステムはあまり多くありません。 通常それらのシステムではUSBハブにUSB-MIDIで大量に接続するような事はせず、典型的にはハードウェアMIDIインターフェースを使用します。 この場合、もちろんMIDI"デバイス"としてはハードウェアMIDIインターフェースだけが列挙され、 一方そこに接続されているシンセサイザー、サンプラー、その他は列挙されません。 少数のデバイスを接続した場合、ここに公開される情報の量は他のAPI、例えばゲームパッドAPIなどと同等です。 大多数のシステムでは接続しているMIDIインターフェースの数は比較的少ないです。

  2. 使用可能なポートの識別によるフィンガープリンティングに関する事項とは別に、MIDIメッセージの送受信に関する事項があります。 これらの課題について、以下でより深く掘り下げます。

MIDIポートに対してできる事を簡単に分類すると:

  1. ショートメッセージ(SysExを除く全てのメッセージ)の送信
  2. ショートメッセージ(SysExを除く全てのメッセージ)の受信
  3. SysExメッセージの送信。 SysExメッセージは("Roland Jupiter-80シンセサイザーのパッチデータ"のような) 他のデバイスには適用できないデバイス固有メッセージに加えて、 MIDIタイムコードおよびMIDIサンプルダンプスタンダードのような共通で認識されるものの両方を含みます。
  4. SysExメッセージの受信

そのそれぞれが持つインパクトは:

  1. ショートメッセージの送信: ノートオン/ノートオフ/コントローラーメッセージは接続された機器や(MacやWindowsが)デフォルトで持っている仮想シンセサイザーから、 音の再生を行います。 これ自体に情報開示の課題はありません。 既に<audio>タグ、Flash、Web Audioを使えばインタラクション無しで音を出す事ができます。 接続されているデバイスの中には業務用の照明コントロールシステムがあるかも知れません。その場合、それはステージの照明を制御できます。 しかしながらこれは極めて稀であり、知られているどんなシステムにも、ショートメッセージによって最終的にダメージを受けたり情報を流出するものはありません。 最悪、悪意のあるページが照明を点滅させたりした場合、ユーザーはページを閉じて照明コントローラーをリセットできます。
  2. ショートメッセージの受信: ノートオン/ノートオフ/コントローラーメッセージの受信はどんな情報の開示やセキュリティの問題も 引き起こしません。 識別に使用できるデータはなく、単にコントローラーのメッセージのストリームであり、 (クロック型のメッセージを除いて) これらの全てはMIDIデバイスでのユーザーの操作によるものです。 これはキーボードやマウスのイベントに非常に似ています。
  3. SysExの送受信。 これは最大の課題です。 なぜならそれは、SysExメッセージに対するシステム固有の反応を探して使用可能なハードウェアを識別したり、 それを使ってデータ、例えばサンプラーに保存されているサンプルをダウンロードする事ができ、 あるいはそのデータを入れ替える(サンプルやデバイスのパッチを消去する)事も可能です (とは言え、これらのシナリオは特定の機器に対するコードを書く必要があります)。 また、幾つかのサンプラーはシステムエクスクルーシブメッセージでサンプルの録音の開始が可能です。 そのためもしサンプラーに専用のマイクが接続されている場合(実際には一般的ではありませんが可能ではあります)、 それは特定のデバイスが短時間の音を録音して、ユーザーの介在なしにネットワークにアップロードする事が可能かも知れません (デバイスからのオーディオストリームを流す事はできず、ほとんどのサンプラーのメモリー量には限界があります。 またMIDIサンプルダンプSysExによるデータ転送は(7ビットへの変換が必要な)低速なものです。 そのため、長時間に渡って盗聴されるような事は起こらないでしょう)。 明らかにフィンガープリンティングの方が問題であり、 パッチ情報/保存されているサンプル/ユーザー設定により、 システムを一意に識別する事が可能です (繰り返しますが、"全てのパッチを取得してハッシュする"標準化された方法はありませんので、 これには多くのデバイス固有のコードが必要です)。 この事は、システムエクスクルーシブメッセージがセキュリティカテゴリに分類されるべきものである事を示唆しています。

これらの機能に対して、MIDIによってどんなシナリオが可能になるのかを確認する事も有用です:

  1. ショートメッセージの受信。これはWeb MIDIに取って最も魅力的なもので、キーボード、ドラムパッド、ギター、 管楽器コントローラー、DJコントローラー、 その他色々な機器からの入力によって楽器をコントロールでき、 他のコントロールシナリオと同様にWeb Audio APIで使う事もできます (MIDIは何十億ドルもの規模の音楽制作産業で使われているプロトコルであり、 Garagebandのようなコンシューマーアプリケーションだけでなく、 プロ/プロシューマー向けのオーディオ/メディアアプリケーションで使われる、 コンピューターに接続するためのツマミやボタンを持った物理的なコントローラーが多数存在します)
  2. ショートメッセージの送信。 送信に関しては、魅力として言えば、かなり少なくなります。 出力デバイスにハードウェアシンセサイザーのようなものを接続すると言うシナリオは現在のマーケットではそれほど一般的ではありません。 ただ大きな例外として、多くのMIDIコントローラーが、 インジケーターライトの外部ホストコントロールを持っている事でこれが劇的に有用なものに変わります。 例えば、非常に一般的なNovationのLaunchpadコントローラーはMIDIノートオン/オフメッセージの送信によって ボタンの点灯/消灯や色の変化を行う事ができます。ほとんど全てのDJコントローラーも同様です。
  3. SysExの送受信。 明らかにハイエンドハードウェア機器での高度な通信では、SysExが必要になります。 残念ながら、幾つかの共通MIDIコマンド(例えば、一般的なスタート/ストップ/巻き戻し/早送りコマンドであるMIDIマシンコントロールなど) もシステムエクスクルーシブメッセージとして送られます。 そして多くのデバイスではプログラムパッチ、高度なコントローラーメッセージ、 ファームウェアダウンロードなどにシステムエクスクルーシブを使用しており、 それはWeb MIDIのシナリオとしても強く要求される事です。 デバイスによってはSysExを直接制御プロトコルとして使用します。 それは多くのデータを1つの"メッセージ"にパックできるため、 多くのデバイスはSysExをパッチや設定データの保存/読み込みのための安価なコンピューターストレージとして使用します。 ハードウェアに対してWeb MIDIを使って、Webベースの設定やプログラミングインターフェースを提供する事に強い興味を持っている メジャーな音楽ハードウェア生産者もいます。 簡単に言えば、SysExを使えなくすると、ハイエンドのシナリオが使えなくなるだけではないという事です。

簡単に言えば: MIDIデバイスの列挙で晒される事になる、付加的なフィンガープリンティングは、 そのままゲームパッドAPIによるゲームパッドの列挙による付加的なフィンガープリンティングに類似しています。 典型的なユーザーではせいぜい数個のデバイスが接続され、それらが設定されても、 晒される情報はそのインターフェース自体のものです(即ちユーザーが設定したデータではありません)。

ショートメッセージの受信に関するセキュリティ上の懸案も小さいものです。 それはキーボード、マウス、モバイル/ラップトップの加速度センサー、タッチ入力、ゲームパッドイベントのリストアップに類似しています。 付加的に晒される情報はなく、クロック信号以外の全てのメッセージはユーザーの操作で発生します。

ショートメッセージの送信に関する懸案は全てのオーディオ出力に類似しています。 ユーザーの情報を上書きしたりユーザーの情報を読み取る事はできず、ただ、音を出し、パッチを変更し、 (稀な設定では)照明を点灯/消灯します。しかしこれは破壊的ではなく、永続するものではありません。

その一方、システムエクスクルーシブは潜在的に制限の少ないものであるため、APIの中でより注意深く、 ユーザーのセキュリティの留め金として、区別してSysExの要求をする事は良い考えです。 提案されているセキュリティモデルではユーザーエージェントがMIDIデバイスへのアクセスの前に明示的に ユーザーの許可を求める事を許してはいますが、 今の所、この許可を得るためにプロンプトを出す事は必須ではありません。 しかしその一方、システムエクスクルーシブのサポートに関してはリクエストの中でそれを要求しなくてはならない事を詳細に定めています。

A. リファレンス

A.1 基準リファレンス

[DOM-LEVEL-3-CORE]
Arnaud Le Hors; Philippe Le Hégaret; Lauren Wood; Gavin Nicol; Jonathan Robie; Mike Champion; Steven B Byrne et al. Document Object Model (DOM) Level 3 Core Specification. 7 April 2004. W3C Recommendation. URL: http://www.w3.org/TR/DOM-Level-3-Core/
[DOM4]
Anne van Kesteren; Aryeh Gregor; Ms2ger; Alex Russell; Robin Berjon. W3C DOM4. 10 July 2014. W3C Last Call Working Draft. URL: http://www.w3.org/TR/dom/
[HIGHRES-TIME]
Jatinder Mann. High Resolution Time Specification. 18 October 2012. W3C Editor's Draft. URL: http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html
[HTML5]
Ian Hickson; Robin Berjon; Steve Faulkner; Travis Leithead; Erika Doyle Navara; Edward O'Connor; Silvia Pfeiffer. HTML5. 28 October 2014. W3C Recommendation. URL: http://www.w3.org/TR/html5/
[MIDI]
Musical Instrument Digital Interface (MIDI) November 2001. MIDI Manufacturers Association. Complete MIDI 1.0 Detailed Specification ISBN 0-9728831-0-X URL: http://www.midi.org/techspecs/index.php
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[TYPED-ARRAYS]
David Herman; Kenneth Russell. Typed Array Specification. 26 June 2013. Khronos Working Draft. URL: https://www.khronos.org/registry/typedarray/specs/latest/
[WEBIDL]
Cameron McCormack. Web IDL. 19 April 2012. W3C Candidate Recommendation. URL: http://www.w3.org/TR/WebIDL/
[webaudio]
Paul Adenot; Chris Wilson; Chris Rogers. Web Audio API. 10 October 2013. W3C Working Draft. URL: http://www.w3.org/TR/webaudio/