Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
Some user agents have connected music devices, such as synthesizers, keyboard and other controllers, and drum machines. 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. At the same time, the Web MIDI API is not intended to become a semantic controller platform; 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.
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 - external synthesizers or lighting systems, for
example, or even the software synthesizers that are built in to many
common operating systems. 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.
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 and High-Resolution Time. 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.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document was published by the Audio Working Group as a second Public Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-audio@w3.org (subscribe, archives). All feedback is welcome.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
MIDIAccess
InterfaceMIDIPort
InterfaceMIDIEvent
InterfaceThis section is non-normative.
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 a 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.
The Web MIDI API is not intended to directly implement high-level concepts such as sequencing; it does not directly support Standard MIDI Files, for example, although a Standard MIDI File player can be built on top of the Web MIDI API. It is also not intended to semantically capture patches or controller assignments, as General MIDI does; such interpretation is outside the scope of the Web MIDI API (though again, General MIDI can easily be utilized through the Web MIDI API).
This section is non-normative.
The Web MIDI API consists of the following set of interfaces and objects, as well as some supporting interfaces:
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words must, must not, required, should, should not, recommended, may, and optional in this specification are to be interpreted as described in [RFC2119].
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
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], as this specification uses that specification and terminology.
The concepts queue a task and fires a simple event are defined in [HTML5].
The terms event handlers and event handler event types are defined in [HTML5].
The term Uint8Array is defined in [TYPED-ARRAYS].
The term DOMHighResTimeStamp is defined in [HIGHRES-TIME].
The terms MIDI, MIDI device, MIDI input port, MIDI interface, MIDI message and MIDI output port are defined in [MIDI].
There are two primary security and privacy concerns with adding the Web MIDI API to the web platform:
These issues will be further explored prior to this specification becoming a Recommendation. In the meantime, 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. It is noted that some web systems (e.g. Java) give access to MIDI interfaces without prompting, although this may not be the security model that this specification eventually uses.
MIDIAccess
InterfaceThis interface provides the methods to enumerate MIDI input and output devices, and obtain access to an individual device.
[NoInterfaceObject]
interface MIDIAccess {
sequence<MIDIPort
> enumerateInputs ();
sequence<MIDIPort
> enumerateOutputs ();
MIDIInput
getInput (MIDIPort or DOMString or short target);
MIDIOutput
getOutput (MIDIPort or DOMString or short target);
};
enumerateInputs
sequence<MIDIPort
>
enumerateOutputs
sequence<MIDIPort
>
getInput
MIDIPort
requested
as a MIDIInput
instance.
When the
getInput()
is invoked, the user agent must run the following steps:
Let target be the
argument.
If the target is a DOMString,
target will be a MIDIPort
whose MIDIPort
fingerprint
matches the supplied
DOMString. If target is a short, target
will be a
that matches the supplied
index in the sequence returned by MIDIPort
enumerateInputs()
.
If the target parameter is a DOMString and there is no MIDIPort
that matches the fingerprint, or if the target parameter is a
short outside the bounds of available MIDI inputs, throw a
REFERENCE_ERROR
exception.
If target is not a
instance, or if the MIDIPort is not a valid MIDI input
port, throw a MIDIPort
TYPE_ERROR
exception.
If target is not available for access, throw a
REFERENCE_ERROR
exception.
If made necessary by the underlying system APIs, reserve the corresponding port for use within the current process.
Return a MIDIInput
object corresponding to the
target argument.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
target | MIDIPort or DOMString or short | ✘ | ✘ | The input port to be requested. |
MIDIInput
getOutput
MIDIPort
requested
as a MIDIOutput
instance.
When the
getOutput()
is invoked, the user agent must run the following steps:
Let target be the
argument.
If the target is a DOMString,
target will be a MIDIPort
whose MIDIPort
fingerprint
matches the supplied
DOMString. If target is a short, target
will be a
that matches the supplied
index in the sequence returned by MIDIPort
enumerateOutputs()
.
If the target parameter is a DOMString and there is no MIDIPort
that matches the fingerprint, or if the target parameter is a
short outside the bounds of available MIDI inputs, throw a
REFERENCE_ERROR
exception.
If target is not a
instance, or if the MIDIPort is not a valid MIDI output
port, throw a MIDIPort
TYPE_ERROR
exception.
If target is not available for access, throw a
REFERENCE_ERROR
exception.
If made necessary by the underlying system APIs, reserve the corresponding port for use within the current process.
Return a MIDIOutput
object corresponding to the
target argument.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
target | MIDIPort or DOMString or short | ✘ | ✘ | The output port to be requested. |
MIDIOutput
MIDIPort
InterfaceThis interface represents a MIDI input or output port.
enum MIDIPortType {
"input",
"output"
};
Enumeration description | |
---|---|
input | If a MIDIPort is an input port, the type member must be this value. |
output | If a MIDIPort is an output port, the type member must be this value. |
[NoInterfaceObject]
interface MIDIPort : EventTarget {
readonly attribute DOMString fingerprint;
readonly attribute DOMString manufacturer;
readonly attribute DOMString name;
readonly attribute MIDIPortType
type;
readonly attribute DOMString version;
};
fingerprint
of type DOMString, readonly
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 fingerprint
is unique to only that port. The User Agent should ensure that
the fingerprint 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 fingerprints 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, storing the port interface manufacturer, name and
index in the fingerprint, and attempting to find any ports with
that name to consider as a match. Applications may use the
comparison of fingerprints of MIDIPorts to test for equality.
manufacturer
of type DOMString, readonlyThe manufacturer of the port.
name
of type DOMString, readonlyThe system name of the port.
type
of type MIDIPortType
, readonly
A descriptor property to distinguish whether the port is an
input or an output port.
For
,
this must be MIDIOutput
"output"
.
For
,
this must be MIDIInput
"input"
.
version
of type DOMString, readonlyThe version of the port.
MIDIInput
InterfaceMIDIInput
implements MIDIPort
;
[NoInterfaceObject]
interface MIDIInput {
[TreatNonCallableAsNull]
attribute callback? onmessage;
};
Whenever the MIDI port corresponding to the
sends one or more MIDI messages, the UA must
run the following steps:
MIDIInput
Let port
be the
.
MIDIInput
Let event
be a newly constructed
, with the MIDIEvent
timestamp
attribute set to the time the message was received by the system, and
with the data
attribute set to a UInt8Array of MIDI data
bytes representing a single MIDI message.
Fire an event named message
at the port
, using the event
as the event object.
MIDIOutput
InterfaceMIDIOutput
implements MIDIPort
;
All instances of the
type are defined to also implement the MIDIOutput
MIDIPort
interface.
[NoInterfaceObject]
interface MIDIOutput {
void send (sequence<short> data, optional DOMHighResTimeStamp? timestamp);
};
send
Enqueues the message to be sent to the corresponding MIDI port. The underlying implementation will (if necessary) coerce each member of the sequence to an unsigned 8-bit integer. The use of sequence rather than a UInt8Array enables developers to use the convenience of output.send( [ 0x90, 0x45, 0x7f ] );
rather than having to create a UInt8Array, e.g. output.send( new UInt8Array( [ 0x90, 0x45, 0x7f ] ) );
- while still enabling use of UInt8Arrays for efficiency in large MIDI data scenarios (e.g. reading Standard MIDI Files and sending sysex messages).
The data must contain any number of valid, complete MIDI messages. Running status is not allowed in the data, as underlying systems may not support it.
If data is not a valid sequence, does not contain a valid MIDI message,
or if timestamp
is passed but is not a valid DOMHighResTimeStamp, throw a TYPE_ERROR
exception.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
data | sequence<short> | ✘ | ✘ | The data to be enqueued, with each sequence entry representing a single byte of data. |
timestamp | DOMHighResTimeStamp | ✔ | ✔ |
The time at which to begin sending the data to the port. If timestamp is not present, zero or null, the data is to be sent as soon as possible.
|
void
MIDIEvent
InterfaceAn event object implementing this interface is passed to a MIDIInput's onmessage handler when MIDI messages are received.
[NoInterfaceObject]
interface MIDIEvent : Event {
readonly attribute DOMHighResTimeStamp timestamp;
readonly attribute Uint8Array data;
};
data
of type Uint8Array, readonlyA Uint8Array containing the MIDI data bytes of a single MIDI message.
timestamp
of type DOMHighResTimeStamp, readonlyA DOMHighResTimeStamp
specifying when the event occurred.
This section is non-normative.
The following are some examples of common MIDI usage in JavaScript.
This section is non-normative.
This example shows how to request access to the MIDI system.
var midi = null; // global MIDIAccess object function onMIDISuccess( midiAccess ) { console.log( "MIDI ready!" ); midi = midiAccess; // store in the global (in real usage, would probably keep in an object instance) } function onMIDIFailure(msg) { console.log( "Failed to get MIDI access - " + msg ); } navigator.getMIDIAccess( onMIDISuccess, onMIDIFailure );
This example enumerates the input and output ports, printing information to the console log.
function enumerateInputsAndOutputs( midiAccess ) { var inputs = midiAccess.enumerateInputs(); var outputs = midiAccess.enumerateOutputs(); var i; for (i=0; i<inputs.length; i++) { console.log( "Input port #" + i + ": type:'" + inputs[i].type + "' fingerprint:'" + inputs[i].fingerprint + "' manufacturer:'" + inputs[i].manufacturer + "' name:'" + inputs[i].name + "' version:'" + inputs[i].version + "'" ); } for (i=0; i<outputs.length; i++) { console.log( "Output port #" + i + ": type:'" + outputs[i].type + "' fingerprint:'" + outputs[i].fingerprint + "' manufacturer:'" + outputs[i].manufacturer + "' name:'" + outputs[i].name + "' version:'" + outputs[i].version + "'" ); } }
This example prints incoming MIDI messages on a supplied input port to the 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 ) { var input = midiAccess.getInput( indexOfPort ); input.onmessage = onMIDIMessage; }
This example sends a middle C note on message immediately on MIDI channel 1 (MIDI channels are 0-indexed, but generally referred to as channels 1-16), and queues a corresponding note off message for 1 second later.
function sendMiddleC( midiAccess, indexOfPort ) { var output = midiAccess.getOutput( indexOfPort ); output.send( [0x90, 60, 0x7f] ); // note on, middle C, full velocity - omitting the timestamp means send immediately. output.send( [0x80, 60, 0x40], window.performance.now() + 1000.0 ); // note off, middle C, release velocity = 64, // timestamp = now + 1000ms. }
This example loops all input messages on the first input port to the first output port - including system exclusive messages.
var midi = null; // global MIDIAccess object var output = null; function echoMIDIMessage( event ) { if (output) output.send( event.data, event.timestamp ); } function onMIDISuccess( midiAccess ) { console.log( "MIDI ready!" ); try { var input = midiAccess.getInput( 0 ); output = midiAccess.getOutput( 0 ); input.onmessage = echoMIDIMessage; } catch (e) { console.log("Exception! Couldn't get i/o ports." + e ); } } function onMIDIFailure(msg) { console.log( "Failed to get MIDI access - " + msg ); } navigator.getMIDIAccess( onMIDISuccess, onMIDIFailure );