diff --git a/index.html b/index.html index 8b49ea8..d90417a 100644 --- a/index.html +++ b/index.html @@ -3,13 +3,6 @@ Web MIDI API - - - +

- Some user agents have music devices, such as synthesizers, - keyboard and other controllers, and drum machines connected to their host computer or device. The widely adopted - Musical Instrument Digital Interface (MIDI) protocol enables - electronic musical instruments, controllers and computers to - communicate and synchronize with each other. MIDI does not transmit - audio signals: instead, it sends event messages about musical notes, - controller signals for parameters such as volume, vibrato and panning, - cues and clock signals to set the tempo, and system-specific MIDI - communications (e.g. to remotely store synthesizer-specific patch - data). This same protocol has become a standard for non-musical uses, + Some user agents have music devices, such as synthesizers, + keyboard and other controllers, and drum machines connected to their host computer or device. The widely adopted + Musical Instrument Digital Interface (MIDI) protocol enables + electronic musical instruments, controllers and computers to + communicate and synchronize with each other. MIDI does not transmit + audio signals: instead, it sends event messages about musical notes, + controller signals for parameters such as volume, vibrato and panning, + cues and clock signals to set the tempo, and system-specific MIDI + communications (e.g. to remotely store synthesizer-specific patch + data). This same protocol has become a standard for non-musical uses, such as show control, lighting and special effects control.

This specification defines an API supporting the MIDI protocol, enabling web applications to enumerate and select MIDI input and output devices on the client system and send and receive MIDI messages. It is intended to enable non-music MIDI applications as well as music ones, by providing low-level access to the MIDI devices available on the users' systems. The Web MIDI API is not intended to describe music or controller inputs semantically; it is designed to expose the mechanics of MIDI input and output interfaces, and the practical aspects of sending and receiving MIDI messages, without identifying what those actions might mean semantically (e.g., in terms of "modulate the vibrato by 20Hz" or "play a G#7 chord", other than in terms of changing a controller value or sending a set of note-on messages that happen to represent a G#7 chord).

-

- To some users, "MIDI" has become synonymous with Standard MIDI Files and General MIDI. That is not the intent of this API; the use case of simply playing back a .SMF file is not within the purview of this specification (it could be considered a different format to be supported by the HTML5 <audio> element, for example). The Web MIDI API is intended to enable direct access to devices that respond to MIDI - controllers, external synthesizers or lighting systems, for example. The Web MIDI API is also explicitly designed to enable a new class of applications on the web that can respond to MIDI controller inputs - using external hardware controllers with physical buttons, knobs and sliders (as well as musical controllers like keyboard, guitar or wind instrument controllers) to control web applications. +

+ To some users, "MIDI" has become synonymous with Standard MIDI Files and General MIDI. That is not the intent of this API; the use case of simply playing back a .SMF file is not within the purview of this specification (it could be considered a different format to be supported by the HTML `

The Web MIDI API is also expected to be used in conjunction with other APIs and elements of the web platform, notably the Web Audio API. This API is also intended to be familiar to users of MIDI APIs on other systems, such as Apple's CoreMIDI and Microsoft's Windows MIDI API. @@ -81,7 +63,7 @@

Introduction

The Web MIDI API specification defines a means for web developers to enumerate, manipulate and access MIDI devices - for example, interfaces that may provide hardware MIDI ports with other devices plugged in to them and USB devices that support the USB-MIDI specification. Having a Web API for MIDI enables web applications that use existing software and hardware synthesizers, hardware music controllers and light systems and other mechanical - apparatus controlled by MIDI. This API has been defined with this wide variety of use cases in mind. + apparatus controlled by MIDI. This API has been defined with this wide variety of use cases in mind.

The approaches taken by this API are similar to those taken in Apple's CoreMIDI API and Microsoft's Windows MIDI API; that is, the API is designed to represent the low-level software protocol of MIDI, in order to enable developers to build powerful MIDI software on top. The API enables the developer to enumerate input and output interfaces, and send and receive MIDI messages, but (similar to the aforementioned APIs) it does not attempt to semantically define or interpret MIDI messages beyond what is necessary to robustly support current devices. @@ -103,7 +85,7 @@

Introduction

Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the - ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]], + ECMAScript Bindings defined in the Web IDL specification [[WEBIDL]], as this specification uses that specification and terminology.

@@ -111,30 +93,29 @@

Introduction

Terminology

- The concepts - queue a task and the terms - event handlers and - - event handler event types and corresponding EventHandler interface are defined in [[!HTML5]].

+ The concepts queue a + task and the terms + event handler and + + event handler event types and corresponding EventHandler, interface are defined in [[HTML]].

- The Web Audio API and its associated interfaces and concepts are defined in [[!webaudio]]. + The Web Audio API and its associated interfaces and concepts are defined in [[webaudio]].

- The Event interface and how to - fire an event are defined in [[!DOM]]. + The Event interface and how to fire an event are defined in [[DOM]].

- The DOMHighResTimeStamp interface is defined in [[!HIGHRES-TIME]]. + The DOMHighResTimeStamp interface is defined in [[hr-time]].

- The terms MIDI, MIDI device, MIDI input port, MIDI output port, MIDI interface, MIDI message, MIDI System Real-Time message and system exclusive are defined in [[!MIDI]]. + The terms MIDI, MIDI device, MIDI input port, MIDI output port, MIDI interface, MIDI message, MIDI System Real-Time message and system exclusive are defined in [[MIDI]].

- Promise objects are defined in [[!ECMASCRIPT]]. + Promise objects are defined in [[ECMASCRIPT]].

- The DOMException is defined in [[WEBIDL]]. + The DOMException is defined in [[WEBIDL]].

@@ -174,12 +155,12 @@

Extensions to the Navigator interface

Requesting MIDI access SHOULD prompt the user for access to MIDI devices, particularly if system exclusive access is requested. In some scenarios, this permission may have already been implicitly or - explicitly granted, in which case this prompt may not appear. - If the user gives express permission or the call is otherwise - approved, the vended Promise is resolved. The - underlying system may choose to allow the user to select - specific MIDI interfaces to expose to this API (i.e. pick - and choose interfaces on an individual basis), although + explicitly granted, in which case this prompt may not appear. + If the user gives express permission or the call is otherwise + approved, the vended Promise is resolved. The + underlying system may choose to allow the user to select + specific MIDI interfaces to expose to this API (i.e. pick + and choose interfaces on an individual basis), although this is not required. The system may also choose to prompt (or not) based on whether system exclusive support is requested, as system exclusive access has greater privacy and @@ -221,7 +202,7 @@

Extensions to the Navigator interface

Prompt the user in a user-agent-specific manner for permission to provide the entry script's origin with a MIDIAccess object representing - control over user's MIDI devices. This prompt may + control over user's MIDI devices. This prompt may be contingent upon whether system exclusive support was requested, and may allow the user to enable or disable that access. @@ -311,7 +292,7 @@

MIDIOutputMap Interface

};

The MIDIOutputMap is a maplike interface whose value is a MIDIOutput instance and key is its ID.

-

This type is used to represent all the currently available MIDI output ports. This enables: +

This type is used to represent all the currently available MIDI output ports. This enables:

    // to tell how many entries there are:
     var numberOfMIDIOutputs = outputs.size;
 
@@ -394,24 +375,24 @@ 

MIDIPort Interface

id

- A unique ID of the port. This can be used by developers to - remember ports the user has chosen for their application. The - User Agent MUST ensure that the id - is unique to only that port. The User Agent SHOULD ensure that - the id is maintained across instances of the - application - e.g., when the system is rebooted - and when a - device is removed from the system. Applications may want to - cache these ids locally to re-create a MIDI setup. - Some systems may not support completely unique persistent - identifiers; in such cases, it will be more challenging to - maintain identifiers when another interface is added or removed - from the system. (This might throw off the index of the - requested port.) It is expected that the system will do the - best it can to match a port across instances of the MIDI API: - for example, an implementation may opaquely use some form of - hash of the port interface manufacturer, name and + A unique ID of the port. This can be used by developers to + remember ports the user has chosen for their application. The + User Agent MUST ensure that the id + is unique to only that port. The User Agent SHOULD ensure that + the id is maintained across instances of the + application - e.g., when the system is rebooted - and when a + device is removed from the system. Applications may want to + cache these ids locally to re-create a MIDI setup. + Some systems may not support completely unique persistent + identifiers; in such cases, it will be more challenging to + maintain identifiers when another interface is added or removed + from the system. (This might throw off the index of the + requested port.) It is expected that the system will do the + best it can to match a port across instances of the MIDI API: + for example, an implementation may opaquely use some form of + hash of the port interface manufacturer, name and index as the id, so that a reference to that port id is likely - to match the port when plugged in. Applications may use the + to match the port when plugged in. Applications may use the comparison of id of MIDIPorts to test for equality.

manufacturer
@@ -453,31 +434,31 @@

MIDIPort Interface

open

- Makes the MIDI device corresponding to the MIDIPort explicitly + Makes the MIDI device corresponding to the MIDIPort explicitly available. Note that this call is NOT required in order to use the MIDIPort - calling send() on a MIDIOutput or attaching a MIDIMessageEvent handler on a MIDIInput will - cause an implicit open(). The underlying implementation may not need + cause an implicit open(). The underlying implementation may not need to do anything in response to this call. However, some underlying implementations may not be able to support shared access to MIDI devices, so using explicit open() and close() calls will enable MIDI applications to predictably control this exclusive access to devices.

- When invoked, this method returns a Promise object representing a + When invoked, this method returns a Promise object representing a request for access to the given MIDI port on the user's system.

-

If the port device has a state of - "connected", +

If the port device has a state of + "connected", when access to the port has been obtained (and the port is ready for - input or output), the vended Promise is resolved. + input or output), the vended Promise is resolved.

-

If access to a connected port is not available (for example, the port is +

If access to a connected port is not available (for example, the port is already in use in an exclusive-access-only platform), the Promise is rejected (if any) is invoked.

-

If open() is called on a port that is +

If open() is called on a port that is "disconnected", - the port's .connection will transition to + the port's .connection will transition to "pending", until the port becomes "connected" or all references to it are dropped. @@ -487,133 +468,133 @@

MIDIPort Interface

    -
  1. Let promise be a new Promise object and +

  2. Let promise be a new Promise object and resolver be its associated resolver.

  3. -
  4. Return promise and run the following steps +

  5. Return promise and run the following steps asynchronously.

  6. -
  7. Let port be the given - MIDIPort +

  8. Let port be the given + MIDIPort object.

  9. -
  10. If the device's connection is already "open" - (e.g. open() has already been called on this MIDIPort, or the - port has been implicitly opened), jump to the step labeled +

  11. If the device's connection is already "open" + (e.g. open() has already been called on this MIDIPort, or the + port has been implicitly opened), jump to the step labeled success below.

  12. -
  13. If the device's connection is "pending" - (i.e. the connection had been opened and the device was - subsequently disconnected), jump to the step labeled +

  14. If the device's connection is "pending" + (i.e. the connection had been opened and the device was + subsequently disconnected), jump to the step labeled success below.

  15. -
  16. If the device's state is "disconnected", - change the connection attribute of the - MIDIPort to - "pending", - and enqueue a new MIDIConnectionEvent - to the statechange - handler of the MIDIAccess and to the statechange - handler of the MIDIPort +

  17. If the device's state is "disconnected", + change the connection attribute of the + MIDIPort to + "pending", + and enqueue a new MIDIConnectionEvent + to the statechange + handler of the MIDIAccess and to the statechange + handler of the MIDIPort and jump to the step labeled success below.

  18. -
  19. Attempt to obtain access to the given MIDI device in the +

  20. Attempt to obtain access to the given MIDI device in the system. If the device is unavailable (e.g. is already in use by another process and cannot be opened, or is disconnected), jump to the step labeled failure below. If the device is available and access is obtained, continue the following steps.

  21. -
  22. Change the connection attribute of the MIDIPort to - "open", and enqueue a new MIDIConnectionEvent - to the statechange - handler of the MIDIAccess and to the statechange +

  23. Change the connection attribute of the MIDIPort to + "open", and enqueue a new MIDIConnectionEvent + to the statechange + handler of the MIDIAccess and to the statechange handler of the MIDIPort.

  24. -
  25. If this port is an output port and has any pending data - that is waiting to be sent, asynchronously begin sending that +

  26. If this port is an output port and has any pending data + that is waiting to be sent, asynchronously begin sending that data.

  27. -
  28. success: Call resolver's - accept(value) method with port as +

  29. success: Call resolver's + accept(value) method with port as value argument.

  30. Terminate these steps.

  31. -
  32. failure: Let error be a new +

  33. failure: Let error be a new DOMException. This exception's .name should be "InvalidAccessError" if the port is unavailable.

  34. -
  35. Call resolver's reject(value) method +

  36. Call resolver's reject(value) method with error as value argument.

close

- Makes the MIDI device corresponding to the - MIDIPort explicitly + Makes the MIDI device corresponding to the + MIDIPort explicitly unavailable (subsequently changing the state from "open" to "closed"). - Note that successful invocation of this method will result in MIDI - messages no longer being delivered to MIDIMessageEvent handlers on a - MIDIInput (although setting a new handler will cause an + Note that successful invocation of this method will result in MIDI + messages no longer being delivered to MIDIMessageEvent handlers on a + MIDIInput (although setting a new handler will cause an implicit open()).

-

The underlying implementation may not need to do anything in response - to this call. However, some underlying implementations may not be able +

The underlying implementation may not need to do anything in response + to this call. However, some underlying implementations may not be able to support shared access to MIDI devices, and the explicit close() call enables MIDI applications to ensure other applications can gain access to devices.

-

When invoked, this method returns a Promise object representing a +

When invoked, this method returns a Promise object representing a request for access to the given MIDI port on the user's system. When the port has been closed (and therefore, in exclusive access - systems, the port is available to other applications), the vended - Promise is resolved. If the port is + systems, the port is available to other applications), the vended + Promise is resolved. If the port is disconnected, the Promise is rejected.

When the close() method is called, the user agent MUST run the algorithm to close a MIDIPort:

    -
  1. Let promise be a new Promise object and +

  2. Let promise be a new Promise object and resolver be its associated resolver.

  3. -
  4. Return promise and run the following steps +

  5. Return promise and run the following steps asynchronously.

  6. -
  7. Let port be the given +

  8. Let port be the given MIDIPort object.

  9. -
  10. If the port is already closed (its .connection is "closed" - - e.g. the port has not yet been implicitly or explicitly opened, - or close() - has already been called on this MIDIPort), jump to the step +

  11. If the port is already closed (its .connection is "closed" + - e.g. the port has not yet been implicitly or explicitly opened, + or close() + has already been called on this MIDIPort), jump to the step labeled closed below.

  12. -
  13. If the port is an input port, skip to the next step. If - the output port's .state - is not "connected", - clear all pending send data and skip to the next step. Clear - any pending send data in the system with timestamps in the - future, then finish sending any send messages with no timestamp - or with a timestamp in the past or present, prior to proceeding +

  14. If the port is an input port, skip to the next step. If + the output port's .state + is not "connected", + clear all pending send data and skip to the next step. Clear + any pending send data in the system with timestamps in the + future, then finish sending any send messages with no timestamp + or with a timestamp in the past or present, prior to proceeding to the next step.

  15. -
  16. Close access to the port in the underlying system if open, +

  17. Close access to the port in the underlying system if open, and release any blocking resources in the underlying system.

  18. -
  19. Change the connection - attribute of the MIDIPort to "closed", and enqueue - a new MIDIConnectionEvent to the statechange - handler of the MIDIAccess and to the statechange +

  20. Change the connection + attribute of the MIDIPort to "closed", and enqueue + a new MIDIConnectionEvent to the statechange + handler of the MIDIAccess and to the statechange handler of the MIDIPort.

    -
  21. closed: Call resolver's - accept(value) method with +

  22. closed: Call resolver's + accept(value) method with port as value argument.

  23. Terminate these steps.

  24. @@ -637,7 +618,7 @@

    MIDIPort Interface

  25. Let event be a newly constructed - MIDIConnectionEvent, with the port + MIDIConnectionEvent, with the port attribute set to the port.

  26. @@ -668,7 +649,7 @@

    MIDIInput Interface

    If the handler is set and the state attribute is not "opened", underlying implementation tries to make the port available, and change the state attribute to "opened". If succeeded, MIDIConnectionEvent is delivered to the corresponding MIDIPort and MIDIAccess.

- +

Whenever the MIDI port corresponding to the MIDIInput finishes receiving one or more MIDI messages, the user agent MUST @@ -734,21 +715,21 @@

MIDIOutput Interface

If data is a system exclusive message, and the MIDIAccess did not enable system exclusive access, throw an InvalidAccessError exception.

- If the port is "disconnected", + If the port is "disconnected", throw an InvalidStateError exception.

- If the port is "connected" - but the connection is "closed", - asynchronously try to open the port. + If the port is "connected" + but the connection is "closed", + asynchronously try to open the port.

sequence<octet> data
- The data to be enqueued, with each sequence entry representing a single byte of data. + The data to be enqueued, with each sequence entry representing a single byte of data.
optional DOMHighResTimeStamp timestamp
@@ -764,7 +745,7 @@

MIDIOutput Interface

MIDIPortType Enum

- +
           enum MIDIPortType {
             "input",
@@ -832,7 +813,7 @@ 

MIDIPortConnectionState Enum

MIDIMessageEvent Interface

An event object implementing this interface is passed to a MIDIInput's onmidimessage handler when MIDI messages are received. Note that the DOM Event timeStamp attribute is defined as a DOMHighResTimeStamp, and represents the high-resolution time of when the event was received or is to be sent.

-        [SecureContext], [Constructor(DOMString type, optional MIDIMessageEventInit eventInitDict)]
+        [SecureContext, Constructor(DOMString type, optional MIDIMessageEventInit eventInitDict)]
         interface MIDIMessageEvent: Event {
           readonly attribute Uint8Array data;
         };
@@ -861,33 +842,33 @@ 

MIDIMessageEventInit Dictionary

MIDIConnectionEvent Interface

-

An event object implementing this interface is passed to a - MIDIAccess' onstatechange handler when a new port becomes available - (for example, when a MIDI device is first plugged in to the computer), - when a previously-available port becomes unavailable, or becomes - available again (for example, when a MIDI interface is disconnected, - then reconnected) and (if present) is also passed to the onstatechange - handlers for any MIDIPorts +

An event object implementing this interface is passed to a + MIDIAccess' onstatechange handler when a new port becomes available + (for example, when a MIDI device is first plugged in to the computer), + when a previously-available port becomes unavailable, or becomes + available again (for example, when a MIDI interface is disconnected, + then reconnected) and (if present) is also passed to the onstatechange + handlers for any MIDIPorts referencing the port.

-

When a MIDIPort is in - the "pending" - state and the device is reconnected to the host system, prior to - firing a statechange - event the algorithm to open a MIDIPort is run on it to attempt to reopen the port. If this - transition fails (e.g. the Port is reserved by something else in the - underlying system, and therefore unavailable for use), the connection - state moves to "closed", else it transitions back to "open". This is - done prior to the statechange event for - the device state change so that the event will reflect the final +

When a MIDIPort is in + the "pending" + state and the device is reconnected to the host system, prior to + firing a statechange + event the algorithm to open a MIDIPort is run on it to attempt to reopen the port. If this + transition fails (e.g. the Port is reserved by something else in the + underlying system, and therefore unavailable for use), the connection + state moves to "closed", else it transitions back to "open". This is + done prior to the statechange event for + the device state change so that the event will reflect the final connection state as well as the device state.

Some underlying systems may not provide notification events for device - connection status; such systems may have long time delays as they poll - for new devices infrequently. As such, it is suggested that heavy + connection status; such systems may have long time delays as they poll + for new devices infrequently. As such, it is suggested that heavy reliance on connection events not be used.

-        [SecureContext], [Constructor(DOMString type, optional MIDIConnectionEventInit eventInitDict)]
+        [SecureContext, Constructor(DOMString type, optional MIDIConnectionEventInit eventInitDict)]
         interface MIDIConnectionEvent: Event {
           readonly attribute MIDIPort port;
         };
@@ -996,7 +977,7 @@ 

Sending MIDI Messages to an Output Device

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 ); // Inlined array creation- note off, middle C, + output.send( [0x80, 60, 0x40], window.performance.now() + 1000.0 ); // Inlined array creation- note off, middle C, // release velocity = 64, timestamp = now + 1000ms. }
@@ -1149,12 +1130,12 @@

Security and Privacy Considerations of MIDI

It's also useful to examine what scenarios are enabled by MIDI, mapped against these features:

  1. Receiving short messages. This is the most attractive scenario for Web MIDI, as it enables getting input from keyboards, drum pads, guitars, wind controllers, DJ/controllerist controllers, and more, and use those messages as input to control instruments and features in the Web Audio API as well as other control scenarios (MIDI is the protocol of choice for the multi-billion-dollar music production industry for getting physical controllers like knobs and buttons attached to your computer, both in pro/prosumer audio and media applications as well as consumer applications like Garageband.) -
  2. Sending short messages - it’s tempting to say sending is significantly less interesting, as the scenario of attached output devices like hardware synthesizers is less common in today's market. The major exception to this is that many of the MIDI controllers have external host control of their indicator lights, and this makes them dramatically more useful. For example, the very popular Novation Launchpad controller uses MIDI note on/off messages sent to it to turn on/off and change colors of the buttons. The same is true of nearly all DJ controllers. +
  3. Sending short messages - it’s tempting to say sending is significantly less interesting, as the scenario of attached output devices like hardware synthesizers is less common in today's market. The major exception to this is that many of the MIDI controllers have external host control of their indicator lights, and this makes them dramatically more useful. For example, the very popular Novation Launchpad controller uses MIDI note on/off messages sent to it to turn on/off and change colors of the buttons. The same is true of nearly all DJ controllers.
  4. Sending and receiving SysEx - obviously, for more advanced communication with high-end hardware devices, SysEx is required. Unfortunately, some common MIDI commands are also sent as system exclusive messages (MIDI Machine Control, for example - generic start/stop/rew/ffw commands) - and many devices use system exclusive to program patches, send advanced controller messages, download firmware, etc., which are much-demanded scenarios for Web MIDI. Some devices use sysex as a direct control protocol, as they can pack more data into a single “message”, and most devices use SysEx as way to save and restore patches and configuration information on less-expensive computer storage. Several of the major music hardware producers have expressed strong interest in using Web MIDI to provide web-based configuration and programming interfaces to their hardware. In short, disabling sysex altogether does not only disable high-end scenarios.
-

In short: the additional fingerprinting exposure of enumerating MIDI devices is directly analogous to the Gamepad API’s additional fingerprinting exposure through gamepad enumeration; typical users will only have at most a few devices connected, their configuration may change, and the information exposed is about the interface itself (i.e., no user-configured data). -

The additional security concern for receiving short messages is also small - it’s analogous to listening to keyboard, mouse, mobile/laptop accelerometer, touch input or gamepad events; there is no additional information exposed, and all messages other than clock signals must be initiated by the user. -

The additional concerns about sending short messages are analogous to any audio output - you cannot overwrite user information or expose use information, but you can make sounds happen, change patches, or (in rare configurations) toggle lights - but non-destructively, and not persistently. +

In short: the additional fingerprinting exposure of enumerating MIDI devices is directly analogous to the Gamepad API’s additional fingerprinting exposure through gamepad enumeration; typical users will only have at most a few devices connected, their configuration may change, and the information exposed is about the interface itself (i.e., no user-configured data). +

The additional security concern for receiving short messages is also small - it’s analogous to listening to keyboard, mouse, mobile/laptop accelerometer, touch input or gamepad events; there is no additional information exposed, and all messages other than clock signals must be initiated by the user. +

The additional concerns about sending short messages are analogous to any audio output - you cannot overwrite user information or expose use information, but you can make sounds happen, change patches, or (in rare configurations) toggle lights - but non-destructively, and not persistently.

System Exclusive, on the other hand, has a much less bounded potential, and it seems that distinguishing requests for SysEx separately in the API is a good idea, in order to more carefully provide user security hooks. The suggested security model explicitly allows user agents to require the user's approval before giving access to MIDI devices, although it is not currently required to prompt the user for this approval - but it also detailed that system exclusive support must be requested as part of that request.