The connector board of a Waldorf Rocket synthesizer: a 5-pin DIN MIDI socket next to a USB port and audio jacks

MIDI File Format: Technical Deep Dive

34 bytes, read like a detective.

Photo: Pete Brown, CC BY 2.0, Wikimedia Commons

Here's the smallest MIDI file that plays a note. Thirty-four bytes: middle C, one quarter note long, at 120 beats per minute.

4D 54 68 64  00 00 00 06  00 00  00 01  00 60
4D 54 72 6B  00 00 00 0C
00 90 3C 40
60 80 3C 40
00 FF 2F 00

The first four bytes are ASCII for MThd, which is the file introducing itself with a header chunk. The next four are a 32-bit big-endian length, 6, and it's always 6, because the header holds three 16-bit fields and never grew. 00 00 is the format, 0. 00 01 means one track. 00 60 is 96, the number of ticks in a quarter note, and that number is the ruler the whole file gets measured with.

Then comes a track: MTrk, 12 bytes long. From here to the end the pattern never changes: a delay, then an event. 00 means wait zero ticks. 90 is a status byte: the high nibble 9 means Note On, the low nibble 0 means channel 1 (channels run 0–15 inside the file and 1–16 on screen). 3C is note 60, middle C. 40 is velocity 64, a medium press. Then 60: wait 96 ticks, one quarter note. 80 3C 40: Note Off, channel 1, the same note, release velocity 64. And finally 00 FF 2F 00: wait zero, meta event, type 2F, length 0. That's End of Track, which every track has to end with.

Notice that nothing in the file said 120 BPM. When there's no tempo event you get the default, 500,000 microseconds per quarter note, which works out to 120 BPM, and 96 ticks at that tempo is half a second. One note, half a second, 34 bytes. Every MIDI file you've ever opened is this, repeated. (The smallest valid MIDI file is actually 8 bytes shorter: a header and a track that holds nothing but End of Track. Twenty-six bytes of silence.)

Everything else in the format answers a question this little file raises.

Why MThd and a length? Chunks

A MIDI file is a sequence of chunks, and a chunk is a 4-byte ASCII type, a 4-byte big-endian length, and then that many bytes of data. Only two types exist: MThd, exactly one, first; and MTrk, one per track. A reader that runs into a type it doesn't know just reads the length and skips it, which is how a program written in 1990 survives a file written in 2026. The length doesn't count the chunk's own 8-byte header.

Here are the header's three fields:

4D 54 68 64   'MThd'
00 00 00 06   length, always 6
ff ff         format: 0, 1 or 2
nn nn         number of track chunks (always 1 for format 0)
dd dd         division: the timing ruler

The division comes in two shapes. If bit 15 is 0, the lower 15 bits are ticks per quarter note: 01 E0 is 480, 03 C0 is 960. If bit 15 is 1, the file runs on SMPTE time: bits 8–14 hold the frame rate as a negative number (−24, −25, −29 for 29.97 drop-frame, −30) and bits 0–7 the ticks per frame. So E7 28 means −25 frames per second and 40 ticks per frame, which is exactly 1,000 ticks per second: one tick per millisecond.

Why 60 and not 96? Delta times

The delay before each event counts ticks since the previous event, not since the start of the song. 96 was written as the single byte 60 because it fits in 7 bits. Anything bigger uses a variable-length quantity: 7 bits of value per byte, most significant first, with the high bit set on every byte except the last. Four bytes at most, so the longest delay is 0x0FFFFFFF, or 268,435,455 ticks.

TicksBytes
000
1277F
12881 00
19281 40
8,192C0 00
16,383FF 7F
16,38481 80 00
268,435,455FF FF FF 7F

Decoding it takes four lines: start at zero; for each byte, shift the value left by 7 and add the low 7 bits; stop after the first byte whose high bit is clear. The reason for the trick is file size. A sixteenth note at 96 ticks per quarter is 24 ticks, so most delays fit in a single byte, and a one-byte delay sitting next to a two- or three-byte event is what keeps a whole song under 50 KB.

Why 90 and not "note on"? Status bytes and data bytes

A MIDI message is one status byte followed by one or two data bytes. A status byte has its high bit set (0x80 to 0xFF), and a data byte never does (0x00 to 0x7F). That rule comes straight from the 1983 cable protocol, it's why every MIDI value stops at 127, and it makes the stream self-synchronizing: drop into it anywhere you like and the next byte with its high bit set starts a message.

In a file, the first byte after a delay tells you which of three families you're in:

First byteFamily
0x80–0xEFA channel message: a note, a controller, an instrument change, a pitch bend
0xF0 or 0xF7System Exclusive: raw manufacturer-specific data
0xFFA meta event: information for the file, never sent down a cable. On a cable 0xFF means System Reset, which no file has a use for, so the file format took the byte.

Channel messages: the seven things a channel can be told

The high nibble of the status byte is the message, and the low nibble is the channel.

StatusMessageData bytesNotes
8nNote Offnote, release velocityrelease velocity is usually 64 or 0
9nNote Onnote, velocityvelocity 0 means Note Off
AnPolyphonic key pressurenote, pressureaftertouch on one key
BnControl Changecontroller, valueknobs, pedals, volume, pan: see below
CnProgram Changeprogramone data byte: 0–127 in the file, 1–128 in GM tables
DnChannel pressurepressureaftertouch for the whole channel
EnPitch Bendlow 7 bits, high 7 bitsthe one 14-bit value: 0–16,383, 8,192 means no bend

Notes. A note number runs from 0 to 127, one per semitone. 60 is middle C, 69 is A4 at 440 Hz. The bottom is note 0, C-1 at 8.18 Hz, which is below hearing; the top is 127, G9 at 12,544 Hz. The frequency of note n is

f = 440 × 2(n − 69) / 12 Hz

There's nothing in between two note numbers. A sound that's a quarter-tone sharp is note n plus pitch bend, and a bent guitar string is one note with a bend curve on it, not a series of new notes.

Velocity runs from 1 to 127 and means how hard the key was hit. The file gives it no unit, so each synth turns it into loudness and tone in its own way.

Program Change picks the instrument, and it's off by one: the byte 0x00 is GM program 1, Acoustic Grand Piano, and 0x18 (24) is program 25, Nylon Guitar. General MIDI groups the 128 programs into 16 families of 8:

ProgramsFamilyProgramsFamily
1–8Piano65–72Reed
9–16Chromatic percussion73–80Pipe
17–24Organ81–88Synth lead
25–32Guitar89–96Synth pad
33–40Bass97–104Synth effects
41–48Strings105–112Ethnic
49–56Ensemble113–120Percussive
57–64Brass121–128Sound effects

On channel 10 the note number isn't a pitch but a drum: 36 is the kick, 38 the snare, 42 a closed hi-hat, 46 an open hi-hat, 49 a crash, 51 a ride. To reach more than 128 sounds, a file sends Bank Select (controller 0, then controller 32) before the Program Change, which gives you 16,384 banks of 128.

Pitch Bend is the only 14-bit value in the whole format. The two data bytes are the low and high 7 bits, so value = high × 128 + low. 8,192 (00 40) is centre, 0 is full down and 16,383 is full up. How far "full" goes depends on the bend range, which is ±2 semitones by default and can be changed through RPN 0. One semitone up with the default range is 8,192 + 4,096 = 12,288, written E0 00 60.

Control Change is where the rest of a performance lives. These are the ones that matter:

ControllerMeaning
0, 32Bank Select, high and low byte
1Modulation wheel
7Channel volume
10Pan (64 = centre)
11Expression
64Sustain pedal (64 and above = down)
91, 93Reverb send, chorus send
101, 100, 6, 38RPN select and data entry (pitch-bend range, tuning)
120All Sound Off
121Reset All Controllers
123All Notes Off

Running status: the byte you are allowed to leave out

The spec ships with its own worked example, and it happens to demonstrate the format's one real trick. Three channels, four notes, 81 bytes. Here it is, line by line.

4D 54 68 64 00 00 00 06   MThd, length 6
00 00                     format 0
00 01                     one track
00 60                     96 ticks per quarter note
4D 54 72 6B 00 00 00 3B   MTrk, 59 bytes follow
00 FF 58 04 04 02 18 08   wait 0 | time signature 4/4, 24 clocks per metronome click, 8 thirty-seconds per quarter
00 FF 51 03 07 A1 20      wait 0 | tempo 500,000 us per quarter note = 120 BPM
00 C0 05                  wait 0 | channel 1 plays program 5 (GM 6, Electric Piano 2)
00 C1 2E                  wait 0 | channel 2 plays program 46 (GM 47, Harp)
00 C2 46                  wait 0 | channel 3 plays program 70 (GM 71, Bassoon)
00 92 30 60               wait 0 | channel 3 | note 48 (C3) on, velocity 96
00 3C 60                  wait 0 | no status byte: still channel 3 Note On | note 60 (C4), velocity 96
60 91 43 40               wait 96 | channel 2 | note 67 (G4) on, velocity 64
60 90 4C 20               wait 96 | channel 1 | note 76 (E5) on, velocity 32
81 40 82 30 40            wait 192 (two bytes: 81 40) | channel 3 | note 48 off
00 3C 40                  wait 0 | running status: channel 3 Note Off | note 60 off
00 81 43 40               wait 0 | channel 2 | note 67 off
00 80 4C 40               wait 0 | channel 1 | note 76 off
00 FF 2F 00               end of track

Now look at 00 3C 60. It has no status byte. That's running status: when the first byte of an event is a data byte, the message reuses the previous status byte. A run of notes on one channel then costs 2 bytes each instead of 3, and that's why so much software turns notes off with a Note On at velocity 0 rather than a real Note Off: it keeps the status byte the same, so it never has to be repeated. Running status carries across delays. The spec says a meta or SysEx event cancels it, but a careful parser remembers the last channel status anyway, because some files assume it survives.

Notice how little the file actually knows. It knows that a C3 and a C4 start together and that a G4 joins them a quarter note later. It doesn't know they form a C major chord, and it doesn't know that the bassoon is being asked to play two notes at once, which a real bassoon can't do.

Meta events: what the cable never carried

A meta event is FF, then a type byte, a variable-length length, and the data. It only ever exists in files.

TypeNameData
00Sequence number2 bytes
01Textany text
02Copyrighttext
03Track nametext
04Instrument nametext
05Lyrictext, usually one syllable per event; this is how .kar works
06Markertext
07Cue pointtext
20MIDI channel prefix1 byte
21MIDI port1 byte; not in the spec, used by everyone to get past 16 channels
2FEnd of tracklength 0; mandatory, the last event of every track
51Set tempo3 bytes: microseconds per quarter note
54SMPTE offset5 bytes: hour, minute, second, frame, fractional frame
58Time signature4 bytes: numerator, denominator as a power of two, MIDI clocks per metronome click, thirty-second notes per 24 MIDI clocks
59Key signature2 bytes: sharps (positive) or flats (negative) from −7 to 7, then 0 for major or 1 for minor
7FSequencer-specificmanufacturer ID, then anything

Tempo is stored as microseconds per quarter note, not as BPM, so BPM = 60,000,000 ÷ tempo. 07 A1 20 is 500,000, which is 120 BPM; 0F 42 40 is 1,000,000, or 60 BPM. Three bytes cap the value at 16,777,215, so the slowest tempo a MIDI file can express is about 3.58 BPM.

A 4/4 time signature is FF 58 04 04 02 18 08: four beats, a denominator of 2² = 4, 24 clocks per click, 8 thirty-seconds per quarter. 6/8 with the click on the dotted quarter is FF 58 04 06 03 24 08. Key signatures take two bytes: 00 00 is C major, 00 01 A minor, 02 00 D major (two sharps), FE 00 B-flat major (two flats).

System Exclusive: the escape hatch

F0, a variable-length length, then the raw bytes including the closing F7. It carries whatever a manufacturer wants it to, and the length is there so a reader can skip it. The one most files carry is the General MIDI reset, which puts a synth into a known state before the song starts: F0 05 7E 7F 09 01 F7. Roland's GS reset and Yamaha's XG reset do the same for their extensions. An F7 event has the same shape and carries raw bytes with no leading F0, for messages that have been split into packets.

From ticks to seconds

A tick lasts tempo ÷ division microseconds, so the time of an event is the sum of its delays, each one converted through whatever tempo is in force at that point:

Δtseconds = Δticks × tempoµsdivision × 106

At 480 ticks per quarter and 120 BPM a tick is 1.04 ms; at 140 BPM (tempo 428,571) it's 0.89 ms. In a format 1 file the tempo map lives in the first track and applies to every track, so a player merges the tracks by absolute tick and then walks through the tempo changes.

That resolution is why audio-to-MIDI conversion loses nothing you can hear in the timing. A note onset found in the audio gets rounded to the nearest tick, which is about a millisecond at 480 ticks per quarter, well under what the ear can tell apart. What the format can't hold is everything in between the notes: the timbre, the room, the noise.

A parser in 50 lines

Everything above fits on a page of Python. This reads any format 0 or 1 file and prints its notes with absolute ticks, running status included.

import struct, sys

def read_vlq(data, i):
    value = 0
    while True:
        b = data[i]; i += 1
        value = (value << 7) | (b & 0x7F)
        if not b & 0x80:
            return value, i

def parse(path):
    data = open(path, "rb").read()
    assert data[:4] == b"MThd"
    fmt, ntracks, division = struct.unpack(">HHH", data[8:14])
    print(f"format {fmt}, {ntracks} track(s), {division} ticks per quarter note")
    i = 14
    for _ in range(ntracks):
        assert data[i:i+4] == b"MTrk"
        length = struct.unpack(">I", data[i+4:i+8])[0]
        i += 8
        end = i + length
        tick, status = 0, None
        while i < end:
            delta, i = read_vlq(data, i)
            tick += delta
            b = data[i]
            if b == 0xFF:                              # meta event
                kind = data[i+1]
                n, i = read_vlq(data, i+2)
                payload = data[i:i+n]; i += n
                if kind == 0x51:
                    print(f"{tick:6}  tempo {60_000_000 / int.from_bytes(payload, 'big'):.1f} bpm")
                elif kind == 0x03:
                    print(f"{tick:6}  track name: {payload.decode('latin-1')}")
                continue
            if b in (0xF0, 0xF7):                      # system exclusive
                n, i = read_vlq(data, i+1); i += n
                continue
            if b & 0x80:                               # a new status byte...
                status, i = b, i + 1                   # ...otherwise running status
            kind, ch = status >> 4, (status & 0x0F) + 1
            nbytes = 1 if kind in (0xC, 0xD) else 2
            d = data[i:i+nbytes]; i += nbytes
            if kind == 0x9 and d[1] > 0:
                print(f"{tick:6}  ch {ch:2}  note on  {d[0]:3}  vel {d[1]}")
            elif kind in (0x8, 0x9):
                print(f"{tick:6}  ch {ch:2}  note off {d[0]:3}")
            elif kind == 0xC:
                print(f"{tick:6}  ch {ch:2}  program  {d[0]:3}")
        i = end

parse(sys.argv[1])

Run it on the 81-byte file above and you get the tempo, three program changes, four notes switching on, and four notes switching off at tick 384.

Where parsers die

  • Note On with velocity 0 is a Note Off. Miss this and no note in most files ever ends.
  • Everything is off by one somewhere: programs are 0–127 in the file and 1–128 in GM tables; channels are 0–15 in the file and 1–16 on screen. The drum channel is status nibble 9: 99 24 7F is a kick on "channel 10".
  • Running status survives across delays. The spec says a meta or SysEx event cancels it; some files do not honour that, so track the last channel status regardless.
  • Trust the chunk length, not End of Track, to find the next chunk. Some files lack the End of Track event; some have junk after it.
  • In a format 1 file, put tempo changes in the first track. The spec puts the tempo map there, and players disagree about tempo events found anywhere else.
  • Two Note Ons for the same pitch on the same channel before a Note Off: the spec does not say which Note Off ends which, and players disagree. Exporters should never write them.
  • Text is ASCII according to the spec and Latin-1, Shift-JIS or UTF-8 in real files. Guess, and do not crash.
  • There is no checksum and no compression. One wrong length byte makes the rest of the file unreadable, and nothing will tell you which byte.

Sources

Got the audio? Get the MIDI.

Upload any recording — guitar, piano, vocals, a full mix — and download the MIDI file. Free.

Convert audio to MIDI →

Continue reading