MIDI is an industry standard music technology protocol that connects products from many different companies including digital musical instruments, computers, tablets, and smartphones. MIDI is used every day around the world by musicians, DJs, producers, educators, artists, and hobbyists to create, perform, learn, and share music and artistic works.
MIDI music can be stored in standard files. Here’s what they look like and how they work and how we can ‘play’ the files.
What is MIDI?
MIDI (Musical Instrument Digital Interface) is a technical standard that describes a protocol, digital interface and connectors and allows a wide variety of electronic musical instruments, computers and other related devices to connect and communicate with one another. A single MIDI link can carry up to sixteen channels of information, each of which can be routed to a separate device.
MIDI carries event messages that specify notation, pitch and velocity, control signals for parameters such as volume, vibrato, audio panning, cues, and clock signals that set and synchronize tempo between multiple devices. These messages are sent to other devices where they control sound generation and other features. This data can also be recorded into a hardware or software device called a sequencer, which can be used to edit the data and to play it back at a later time. These recordings are usually in Standard MIDI File (SMF) format.
Advantages of MIDI include compactness (an entire song can be coded in a few kilobytes), ease of modification, and manipulation and choice of instruments.
Standard MIDI Files (SMF)
The Standard MIDI File (SMF) is a file format that provides a standardized way for MIDI sequences to be saved, transported, and opened in other systems. The compact size of these files has led to their widespread use in computers, mobile phone ring tones, web page authoring and greeting cards. They are intended for universal use and include such information as note values, timing and track names. Lyrics may be included as metadata, and can be displayed by karaoke machines.
The SMF specification was developed and is maintained by the MIDI Manufacturers Association (MMA). All the MIDI specifications are listed on their website (link here).
SMFs are created as an export format of software sequencers or hardware workstations. They organize MIDI messages into one or more parallel tracks, and timestamp the events so that they can be played back in sequence.
The MD_MIDIFile library is designed to parse a SMF for an Arduino application. Two of the examples that come with the library read the SMF and display the contents to the serial monitor.
The Structure of a SMF
A standard MIDI file is composed of “chunks”. It starts with a header chunk and is followed by one or more track chunks. The header chunk contains data that pertains to the overall file. Each track chunk defines a logical track.
Each track chunk defines a logical track and contains events to be processed at specific time intervals. Events can be one of three types – MIDI, System Exclusive (SysEx) and Meta events.
Note that the status bytes associated with System Common messages (0xF1 to 0xF6 inclusive) and System Real Time messages (0xF8 to 0xFE inclusive) are not valid within a MIDI file. For the rare occasion when they do need to be included in the file, they should be embedded within a SysEx escape sequence.
A chunk always has three components at the start of the chunk, which are:
- A four character track ID string. Header chunk IDs are “MThd“, Track chunks “MTrk“.
- A four-byte unsigned value specifying the size of the chunk in bytes.
- The actual data for the chunk.
The file grammar below (from here) is useful to understand the overall structure of the file in a programmer-friendly format, and is more fully explained below. In this grammar <descriptor:length> means ‘length’ bytes, most significant byte first, and <descriptor:v> means variable length argument format, described below.
The Header Chunk
The header chunk contains the arrangement’s setup data, which may include tempo and instrumentation, and information such as the song’s composer. The header also specifies which of three SMF formats applies to the file:
- A type 0 file contains the entire performance, merged onto a single track
- A type 1 files may contain any number of tracks, running synchronously.
- A type 2 files may contain any number of tracks, running asynchronously.
Processing type 0 and 1 files is nearly identical, whilst type 3 is rarely used and hard to manage on limited hardware systems.
If the time division value is is positive, then it represents the units per beat. For example, +96 would mean 96 ticks per beat. If the value is negative, delta times are in SMPTE compatible units.
The Track Chunk
The track chunk is the literal identifier string, a length indicator for the size of the track (in bytes, expressed as a variable length value), and event data for the track.
A track event consists of a delta time since the last event (expressed as a variable length value), and one of three types of events.
MIDI Event (status bytes 0x8n – 0xE0n)
These correspond to the standard Channel MIDI messages, such as note-on or note-off. In this case ‘n‘ is the MIDI channel (0 – 15). This status byte will be followed by 1 or 2 data bytes, as is usual for the particular MIDI message. Any valid Channel MIDI message can be included in a MIDI file.
If the first (status) byte is less than 128 (hex 80), this implies that running status is in effect, and that this byte is actually the first data byte (the status carrying over from the previous MIDI event). This can only be the case if the immediately previous event was also a MIDI event, ie SysEx and Meta events interrupt (clear) running status.
MIDI events may be processed by the calling program through a callback.
Meta Event (status byte 0xFF)
Meta events are various non-MIDI data relevant to managing the MIDI playback, which would not be in the MIDI data stream itself. The META event has a type indicator, length field expressed as a variable length value, and the actual event data.
The list of meta event data includes are Sequence number, Text, Copyright notice, Sequence or track name, Instrument name, Lyric text, End of track, Tempo setting, SMPTE offset, Time signature, and Key signature.
System Exclusive (SYsEx) Event (status bytes 0xF0 and 0xF7)
There are a couple of ways in which system exclusive messages can be encoded – as a single message (using the 0xF0 status), or split into packets (using the 0xF7 status). The 0xF7 status is also used for sending escape sequences, when the resulting MIDI data stream would include the 0xF0.
SysEx events are specific to particular devices and, in principle, can only be decoded by those devices. It is a way of including proprietary information in a MIDI stream.
Variable Length Values
Several values in SMF events are encoded as variable length quantities. This is a special encoding that uses a minimum number of bytes to represent the value in an attempt to compress the data stream.
A variable length value uses the 7 least significant bits (LSB) of a byte to represent the whole or part of the value. The most significant bit (MSB) is an “escape” or “continuation” bit. All but the last byte of a variable length value have the MSB set and the last byte has the MSB cleared. The byte stream always presents the MSB first.
- Variable Length 0x7F = Real value 0x7F (127)
- Variable Length 0x81 0x7F = Real value 0xFF (255)
- Variable Length 0x82 0x80 0x00 = Real Value 0x8000 (32768)
In Part 2 we’ll cover the issue of keeping time.