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.
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.
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.
Read a 4-byte big-endian unsigned integer from the front of a byte slice.
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.
// big-endian: the first byte is the most significantfunc readU32(b []byte) uint32 {return uint32(b[0])<<24 | uint32(b[1])<<16 |uint32(b[2])<<8 | uint32(b[3])}
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.
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.
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.
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.
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.
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.