MIDI file format

MIDI files contain MIDI messages, along with timing information.

This page describes MIDI files, but the MIDI messages themselves are out-of-scope.

Extension.mid
MIME typeaudio/midi

BytesΔtMessage
4D546864 00000006Header chunk start : length = 6
0001→ track_format = .simultaneous_tracks
0003→ num_tracks = 3
0180→ time_config = { .ticks_per_quarter_note, 384 }
4D54726B 00000050Track chunk start : length = 80
00 FF03 090.sequence_or_track_name (9 bytes) : "SomeTitle"
536F6D655469746C65
00 FF01 090.text (9 bytes) : "creator: "
63726561746F723A20
00 FF01 1E0.text (30 bytes) : "LilyPond 2.24.2 "
4C696C79506F6E6420322E32342E32
202020202020202020202020202020
00 FF5804 04 02 18 080.time_signature
00 FF5103 0F 42 40 980.set_tempo
00 FF2F 000.end_of_track
4D54726B 0000005ATrack chunk start : length = 90
00 FF03 060.sequence_or_track_name (6 bytes) : "upper:"
75707065723A
00 C0 0C0.program_change : SoundSet.marimba (0C)
00 C0 0C0.program_change : SoundSet.marimba (0C)
00 FF04 070.instrument_name (7 bytes) : "marimba"
6D6172696D6261
00 FF59 0200000.key_signature : TODO
00 903C5A0NoteOn(C4, v=90)
8300 903C00384NoteOn(C4, v=0)
00 90405A0NoteOn(E4, v=90)
8300 904000384NoteOn(E4, v=0)
00 90435A0NoteOn(G4, v=90)
8300 904300384NoteOn(G4, v=0)
8300 903C5A384NoteOn(C4, v=90)
00 90405A0NoteOn(E4, v=90)
00 90435A0NoteOn(G4, v=90)
8C00 903C00TODONoteOn(C4, v=0)
00 9040000NoteOn(E4, v=0)
00 9043000NoteOn(G4, v=0)
00 FF2F000.end_of_track
4D54726B 00000052Track chunk start : length = 82
00 FF03 060.sequence_or_track_name (6 bytes) : "lower:"
6C6F7765723A
00 C1 0C0.program_change : SoundSet.marimba (0C) on channel 2
00 C1 0C0.program_change : SoundSet.marimba (0C) on channel 2
00 FF04 070.instrument_name (7 bytes) : "marimba"
6D6172696D6261
00 FF590200000.key_signature : TODO
00 91305A0NoteOn(C3, v=90, channel=2)
8300 913000384NoteOn(C3, v=0, channel=2)
00 91305A0NoteOn(C3, v=90, channel=2)
8300 913000384NoteOn(C3, v=0, channel=2)
00 91305A0NoteOn(C3, v=90, channel=2)
8300 913000384NoteOn(C3, v=0, channel=2)
00 91305A0NoteOn(C3, v=90, channel=2)
8300 913000384NoteOn(C3, v=0, channel=2)
00 91305A0NoteOn(C3, v=90, channel=2)
8C00 913000TODONoteOn(C3, v=0, channel=2)
00 FF2F000.end_of_track

A MIDI file consists of one header chunk ("MThd") followed by one or more track chunks ("MTrk").

A track chunk starts with "MTrk" + length:

4D54726B    "MTrk"
0000ABCD    u32 -> length of the remainder of this chunk

...which is followed by one or more events.

Each event consists of a time delta (in ticks) plus the raw bytes of a MIDI message.

The last event must be an .end_of_track MIDI message (FF2F00).

Header chunks contain three things:

pub const Header = struct {
    track_format: TrackFormat,
    num_tracks: u16,
    time_config: TimeConfig,
};

4D546864    "MThd" (chunk type)
00000006    u32 -> len = 6
    0001    u16 -> track_format = TrackFormat.SimultaneousTracks
    0003    u16 -> num_tracks = 3
    E728    u16 -> time_config = TimeConfig.withMillisecondTicks()

u16EnumJSONDescription
0.one_track"one_track"
1.simultaneous_tracks"simultaneous_tracks"
2.independent_tracks"independent_tracks"