Main Content

MIDI Device Interface

MIDI

This tutorial introduces the Musical Instrument Digital Interface (MIDI) protocol and how you can use Audio Toolbox™ to interact with MIDI devices. The tools described here enable you to send and receive all MIDI messages as described by the MIDI protocol. If you are interested only in sending and receiving Control Change messages with a MIDI control surface, see MIDI Control Surface Interface. If you are interested in using MIDI to control your audio plugins, see MIDI Control for Audio Plugins. To learn more about MIDI in general, consult The MIDI Manufacturers Association.

MIDI is a technical standard for communication between electronic instruments, computers, and related devices. MIDI carries event messages specific to audio signals, such as pitch and velocity, as well as control signals for parameters and clock signals to synchronize tempo.

MIDI Devices

A MIDI device is any device capable of sending or receiving MIDI messages. MIDI devices have input ports, output ports, or both. The MIDI protocol defines messages as unidirectional. A MIDI device can be real-world or virtual.

Audio Toolbox enables you to create an interface to a MIDI device using mididevice. To create a MIDI interface to a specific device, use mididevinfo to query your system for available devices. Then create a mididevice object by specifying a MIDI device by name or ID.

mididevinfo
MIDI devices available:
  ID  Direction  Interface   Name
   0   output    MMSystem   'Microsoft MIDI Mapper'
   1    input    MMSystem   'USB MIDI Interface '
   2   output    MMSystem   'Microsoft GS Wavetable Synth'
   3   output    MMSystem   'USB MIDI Interface '
device = mididevice('USB MIDI Interface ')
device = 

  mididevice connected to
     Input: 'USB MIDI Interface ' (1)
    Output: 'USB MIDI Interface ' (3)

You can specify a mididevice object to listen for input messages, send output messages, or both. In this example, the mididevice object receives MIDI messages at the input port named 'USB MIDI Interface ', and sends MIDI messages from the output port named 'USB MIDI Interface '.

MIDI Messages

A MIDI message contains information that describes an audio-related action. For example, when you press a key on a keyboard, the corresponding MIDI message contains 3 bytes:

  1. The first byte describes the kind of action and the channel. The first byte is referred to as the Status Byte.

  2. The second byte describes which key is pressed. The second byte is referred to as a Data Byte.

  3. The third byte describes how hard the key is played. The third byte is also a Data Byte.

This message is a Note On message. Note On is referred to as the message name, command, or type.

In MATLAB®, a MIDI message is packaged as a midimsg object and can be manipulated as scalars or arrays. To create a MIDI message, call midimsg with a message type and then specify the required parameters for the specific message type. For example, to create a note on message, specify the midimsg Type as 'NoteOn' and then specify the required inputs: channel, note, and velocity.

channel = 1;
note = 60;
velocity = 64;
msg = midimsg('NoteOn',channel,note,velocity)
msg = 

  MIDI message:
    NoteOn          Channel: 1  Note: 60  Velocity: 64  Timestamp: 0  [ 90 3C 40 ]

For convenience, midimsg displays the message type, channel, additional parameters, timestamp, and the constructed message in hexadecimal form. Hexadecimal is the preferred form because it has a straightforward interpretation:

Sending and Receiving MIDI Messages

To send and receive MIDI messages, use the mididevice object functions midisend and midireceive. When you create a mididevice object, it begins receiving data at its input and placing it in a buffer.

To retrieve MIDI messages from the buffer, call midireceive.

receivedMessages = midireceive(device)
receivedMessages = 

  MIDI message:
    NoteOn          Channel: 1  Note: 36  Velocity: 64  Timestamp: 15861.9  [ 90 24 40 ]
    NoteOn          Channel: 1  Note: 36  Velocity: 0   Timestamp: 15862.1  [ 90 24 00 ]
The MIDI messages are returned as an array of midimsg objects. In this example, a MIDI keyboard key is pressed.

To send MIDI messages to a MIDI device, call midisend.

midisend(device,msg)

MIDI Message Types

The type of MIDI message you create is defined as a character vector or string. To create a MIDI message, specify it by its type and the required property values. For example, create a Channel Pressure MIDI message by entering the following at the command prompt:

channelPressureMessage = midimsg('ChannelPressure',1,20)
channelPressureMessage = 

  MIDI message:
    ChannelPressure Channel: 1  ChannelPressure: 20  Timestamp: 0  [ D0 14 ]
After you create a MIDI message, you can modify the properties, but you cannot modify the type.
channelPressureMessage.ChannelPressure = 37
channelPressureMessage = 

  MIDI message:
    ChannelPressure Channel: 1  ChannelPressure: 37  Timestamp: 0  [ D0 25 ]

The table summarizes valid MIDI message types.

The Audio Toolbox provides convenience syntaxes to create multiple MIDI messages used in sequence and to create arrays of MIDI messages. See midimsg for a complete list of syntaxes.

MIDI Message Timing

The MIDI protocol does not define message timing and assumes that messages are acted on immediately. Many applications require timing information for queuing and batch processing. For convenience, the Audio Toolbox packages timing information with MIDI messages into a single midimsg object. All midimsg objects have a Timestamp property, which is set during creation as an optional last argument or after creation. The default Timestamp is zero.

The interpretation of the Timestamp property depends on how a MIDI message is created and used:

  • When receiving MIDI messages using midireceive, the underlying infrastructure assigns a timestamp when receiving MIDI messages. Conceptually, the timing clock starts when a mididevice object is created and attached as a listener to a given MIDI input port. If another mididevice is attached to the same input port, it receives timestamps from the same timing clock as the first object.

  • When sending MIDI messages using midisend, timestamps are interpreted as when to send the message.

    If there have been no recent calls to midisend, then midisend interprets timestamps as relative to the current real-world time. A message with a timestamp of zero is sent immediately. If there has been a recent call to midisend, then midisend interprets timestamps as relative to the largest timestamp of the last call to midisend. The timestamp clock for midisend is specific to the MIDI output port that mididevice is connected to.

    Consider a pair of MIDI messages that turn a note on and off. The messages specify that the note starts after one second and is sustained for one second.

    Create Note On and Note Off messages. To create the Note Off message, use the 'NoteOn' MIDI message type and specify zero velocity. (If you want to specify a velocity, use the 'NoteOff' message type.) For more information, see midimsg.

    OnMsg = midimsg('NoteOn',1,59,64);
    OffMsg = midimsg('NoteOn',1,59,0);

    To send on and off messages using a single call to midisend, specify the timestamps of the messages relative to the same start time.

    OnMsg.Timestamp = 1;
    OffMsg.Timestamp = 2;
    midisend(device,[OnMsg;OffMsg]))

    To send the Note Off message separately, specify the timestamp of the Note Off message relative to the largest timestamp of the previous call to midisend.

    OnMsg.Timestamp = 1;
    OffMsg.Timestamp = 1;
    midisend(device,OnMsg)
    midisend(device,OffMsg)

    The "start" time, or reference time, for midisend is the max between the absolute time and the largest timestamp in the last call to midisend. For example, consider that x, the arbitrary start time, is equal to the current absolute time. If there is a 1.5-second pause between sending the note on and note off messages, the resulting note duration is 1.5 seconds.

    OnMsg.Timestamp = 1;
    OffMsg.Timestamp = 1;
    midisend(device,OnMsg)
    pause(1.5)
    midisend(device,OffMsg)

    Usually, MIDI messages are sent faster than or at real-time speeds so there is no need to track the absolute time.

    For live performances or to enable interrupts in a MIDI stream, you can set timestamps to zero and then call midisend at appropriate real-world time intervals. Depending on your use case, you can divide your MIDI stream into small repeatable time chunks.

See Also

Classes

Functions

Related Topics

External Websites