Projects/Build a MIDI Parser

Build a MIDI Parser

Turn a byte-exact .mid file into a structured song you can assert against. Every lesson is one concrete spec with exact bytes and values: a variable-length quantity 0x81 0x00 decodes to 128, a note-on with velocity 0 is really a note-off, a bare data byte reuses the previous status (running status), set-tempo bytes 0x07 0xA1 0x20 mean 500000 microseconds per quarter note and 120 BPM, and 96 ticks at that tempo and division is exactly half a second. No audio - the deliverable is the parse tree, not sound.

30 lessonsSmall~20 min / lessonStandard MIDI FileVariable-length quantitiesRunning status
The project

What you'll build over the next 30 lessons

Over 30 lessons you build a working Standard MIDI File parser from scratch: a library that reads raw SMF bytes and returns a structured song of tracks and timed events. You start at the container - the MThd header chunk (format, track count, and the division field) and the MTrk track chunks framed by a 4-byte length - then decode the variable-length quantities that encode every delta-time, the classic tricky bit of the format.

From there you parse the event stream: the status byte whose high nibble is the message and low nibble the channel, note-off and note-on (with velocity-0 note-on treated as note-off), control change, program change, pressure, and 14-bit pitch bend, all with running status where a bare data byte reuses the previous status. You add meta events (set-tempo, time signature, key signature, track name, end-of-track) and system-exclusive data, then assemble tracks into a timed song: absolute ticks accumulated from deltas, a tempo map, note-on paired with its matching note-off into notes, and ticks converted to seconds and beats. The capstone parses an embedded format-1 file and reports its tracks, tempo in BPM, time signature, and note list with tick and second timings.

This is a parser and inspector, not a player: it turns bytes into a song model exactly, but it does no audio synthesis and no real-time playback - there is no sound at any point. It is a teaching-grade library built around the Standard MIDI File 1.0 specification, honest about where it stops: it reads the common format 0 and 1 files, treats the parsed structure as the product, and leaves synthesis, SMPTE-timed playback, and the long tail of rare meta and manufacturer SysEx messages as extensions. The finished repo also ships a small midinfo-style inspector that dumps the header, per-track events, tempo and time signature, and a note summary of any file.

build-a-midi-parser / lesson-01.md
Lesson 01 · The SMF container

Reading a big-endian length

A Standard MIDI File is a stream of chunks, and almost every size, count, and length in it is a 4-byte big-endian unsigned integer. Today you build the one helper that reads it - the workhorse the whole parser leans on.

The goal

Read a 4-byte big-endian unsigned integer from the front of a byte slice.

Start here - the target
TO DO
Scenario: Four big-endian bytes decode to their integer value
Giventhe four bytes 0x00 0x00 0x00 0x06
Whenthey are read as a big-endian unsigned 32-bit integer
Thenthe value is 6
Andthe bytes 0x00 0x00 0x01 0x00 read the same way give 256
Background

Everything in a Standard MIDI File is stored big-endian (most significant byte first), the same byte order used on the network. A chunk announces its length as a 4-byte field, so before you can walk a file at all you need to turn four bytes into a number. 0x00 0x00 0x00 0x06 is 0x06, which is 6 - a track chunk whose body is six bytes long.

This single helper is the backbone of the whole project: chunk lengths, and later the header’s own body length, are all big-endian 32-bit integers. Get it exactly right today - byte 0 shifted left 24, byte 3 not shifted at all - and every later lesson builds on it.

Make it work
// big-endian: the first byte is the most significant
func readU32(b []byte) uint32 {
return uint32(b[0])<<24 | uint32(b[1])<<16 |
uint32(b[2])<<8 | uint32(b[3])
}
CheckpointDONE
You can read a big-endian 32-bit length. Commit and stop here.
Scope & extensions

Where this project stops - and where to go next

The parser and midinfo inspector handle the full chunk/event/meta grammar and fail gracefully on corrupt input, but SMPTE-division timing and true multi-tempo-change second math are not implemented.

Extend it next
  • Integrate seconds across tempo-map segments instead of assuming the current tempo held since tick 0
  • Convert SMPTE division (frames per second, ticks per frame) to seconds, not just the metrical PPQN mode
  • Give the fixed-length meta decoders (set-tempo, time and key signature) their own specific truncation errors instead of a generic malformed-input message
  • Add a machine-readable inspector output mode (CSV like the real midicsv, or JSON)
  • Handle overlapping same-pitch notes with no intervening note-off instead of silently orphaning the first note-on
  • Explicitly out of scope, not merely unfinished: real playback - audio synthesis, MIDI-out device support, and real-time scheduling
Recommended reading

Books & references that go deeper

  • Standard MIDI Files 1.0 (RP-001) · MIDI Manufacturers Association

    The authoritative container specification: the MThd and MTrk chunk layout, the variable-length quantity encoding of delta-times, running status, and the full meta-event catalogue. Keep it open beside every lesson.

  • Summary of MIDI 1.0 Messages · The MIDI Association

    The status-byte and data-byte tables for every channel voice message - note-on/off, control change, program change, pressure, and pitch bend - and the system messages. The reference for how many data bytes each status takes.

  • Standard MIDI File Format · David Back (somascape)

    A readable, exact walkthrough of the file format with worked byte examples of chunks, variable-length quantities, running status, and meta events - the practical companion to the official spec.

  • Standard MIDI-File Format Spec 1.0 (annotated) · mirrored at McGill MUMT 306

    A clean HTML mirror of the original specification text, convenient for looking up a meta-event type byte or the division-field encoding without a PDF.

  • midicsv and csvmidi · John Walker (Fourmilab)

    A tool that losslessly converts a Standard MIDI File to and from a readable CSV of its events - the inspiration for the inspector this project finishes with, and a handy oracle for checking your own parse.