ACIDCAT . FILE FORMAT REFERENCE

MIDI Anatomy

Standard MIDI FileSMF 1.0
rev 2026.06
magic "MThd"
endian big
container MThd + MTrk
format 0 / 1 / 2

A Standard MIDI File is one MThd header chunk followed by one or more MTrk track chunks. MThd is 14 bytes; each MTrk is a stream of events, every event prefixed by a variable-length delta time. The clever field is division: its top bit flips the meaning of the other fifteen. Hover to light bytes or bits, click a + for its table. Color marks kind (see the key).

file regions

One header, then the tracks. Events use compact encodings (VLQ deltas, running status) that a parser must track byte by byte.

▸MThd0x00 . 14 bytes . drawn below

Format, track count, and timing division. The length is always 6 (extra header bytes are legal and skipped). See the byte map below.

▸MTrkone per track
header"MTrk" + u32 big-endian byte length
eventsdelta-time (VLQ) + event, repeated to end-of-track
the track header (8 bytes)

The only length in the file, and it is a byte count, not an event count.

▸VLQ delta timethe variable encoding

Seven payload bits per byte; the high bit set means another byte follows. A VLQ is capped at 4 bytes (28 payload bits), so the largest delta is 0x0FFFFFFF. A parser that loses sync here misreads everything after it. running-status bookkeeping is exactly where a one-byte desync turns into wrong note counts rather than an error.

a two-byte delta time, bit by bit

Seven bits of payload per byte. The eighth says whether another byte follows.

▸running statusthe omitted byte

Consecutive channel events with the same status may drop the repeated status byte; the parser must remember the last one. Most exporters use it.

▸channel voice messagesstatus 0x80-0xEF . SSSS CCCC

High nibble is the message type, low nibble the channel (0-15). Types 8n-Bn and En carry two data bytes, Cn and Dn one. Note On with velocity 0 means Note Off.

8nnote off: key, velocity
9nnote on: key, velocity (velocity 0 = note off)
Anpolyphonic aftertouch: key, pressure
Bncontrol change: controller, value
Cnprogram change: program (one data byte)
Dnchannel aftertouch: pressure (one data byte)
Enpitch bend: 14-bit LSB+MSB, (msb<<7)|lsb - 8192 = signed offset, 0 = center
▸meta eventsFF type len data
FF 51tempo: microseconds per quarter (bpm = 60e6 / us)
FF 54SMPTE offset: hr mn se fr ff; hr packs 0rrhhhhh, bits 6-5 = frame rate (00=24, 01=25, 10=29.97, 11=30 fps), low 5 bits = hour
FF 58time signature
FF 59key signature: sharps/flats count + minor flag
FF 01-07text family: text, copyright, track name, instrument, lyric, marker, cue point
FF 2Fend of track (required)
▸sysexF0 / F7 + VLQ length

In a file, F0 and F7 are followed by a VLQ byte length, then the payload; F7 carries escapes and continuations. Both cancel running status, same as meta events.

F0<length VLQ> <data> -- standard sysex
F7<length VLQ> <data> -- escape / continuation
MThd header

14 bytes. Example: format 1, 3 tracks, 480 ticks per quarter note.

division field

The 16-bit timing field, expanded. Top bit chooses the scheme; here it is 0, so the rest is ticks per quarter note.

magic"SMF2CLIP"packetUMP . 1-4 x 32b wordsendianbig (in files)timingDelta Clockstamp

MIDI 2.0 does not extend the .mid file -- that format is frozen at 1.0. It replaces the wire and the file with the Universal MIDI Packet: 1 to 4 big-endian 32-bit words whose top nibble, the Message Type, alone fixes the packet size. That makes a UMP stream self-delimiting -- no length prefixes -- so the same bytes parse whether they arrive from a file or a pipe. A MIDI Clip File (.midi2) is just an 8-byte SMF2CLIP magic then one of those streams. Hover to light bytes, click a + for its table.

Scope note, honestly: real .midi2 files are still rare (the spec is 2023, few producers). The format's home today is the live stream layer shipping in Windows MIDI Services, ALSA UMP and CoreMIDI -- and because UMP is self-delimiting, the same grammar decodes off a file or a captured stream.

message types

The top 4 bits of word 1. The MT alone fixes the packet size, so a reader stays synchronized even through message types it does not understand.

0x0Utility -- NOOP, JR clock/timestamp, DCTPQ, Delta Clockstamp (32b)
0x1System real-time & common (32b)
0x2MIDI 1.0 channel voice -- 7-bit, wrapped verbatim (32b)
0x3Data / SysEx7 (64b)
0x4MIDI 2.0 channel voice -- 16-bit velocity, 32-bit controllers (64b)
0x5Data / SysEx8, Mixed Data Set (128b)
0xDFlex Data -- Set Tempo, Time Signature, metadata text (128b)
0xFUMP Stream -- endpoint discovery, Start / End of Clip (128b)
MIDI 2.0 Note On

Example: group 1, channel 1, note 60 (middle C), velocity 0x8000, no attribute. Two 32-bit words, big-endian (Message Type 0x4).

MIDI Clip File (.midi2)

No chunks. An 8-byte magic, then a big-endian UMP stream: a Configuration Header (mandatory DCTPQ, optional tempo / time signature / metadata) and the Clip Sequence, bracketed by Start and End of Clip. A Delta Clockstamp precedes essentially every message.