Thread with 15 posts

jump to expanded post

today i have been writing a program that reads a midi file. as is typical for me, i decided to write my own parser.

so i've been consulting the “standard midi files specification” and “midi 1.0 detailed specification”, neither of which i had ever read before. it's been pretty fun! they're written in a refreshingly informal and thoughtful style that makes the purpose and form of everything clear. the protocol and file format are remarkably well-designed… very efficient encodings for example

Open thread at this post

things i appreciate about standard midi files (smf)

• it's a riff variant, like all good file formats!
• it doesn't waste space on optional or redundant info. the header chunk contains just three 16-bit integers: the format, track count and an elegantly bit-packed field that specifies the timing unit. the only other chunks are the tracks, and they contain nothing but events with attached time deltas. all optional data is specified using events; only one event (“end of track”) is mandatory.

Open thread at this post

some neat tricks standard midi files (smf) do to minimise the overhead versus raw midi data:

• delta times and event lengths use variable-length encoding. every event begins with a time delta, but it's usually a single byte!
• smf meta events steal their prefix encoding from midi system messages that ought not to be present in a midi file, so that the most common midi messages (e.g. note on/off) need no extra prefix
• common midi messages don't need a length prefix because they are fixed length

Open thread at this post

a typical midi message might be “on channel 15, depress key A4 with velocity 80”

midi can express this in three bytes:

9F 45 50

it packs the kind of message (9 = note on) and the channel number into the two nibbles of the first byte. the note number (decimal 69) and velocity are the second and third bytes respectively. efficient, right?

but if we depress two keys:

9F 45 50 46 50

2.5 bytes per message! the kind and channel number can be skipped, because they are unchanged :3

Open thread at this post

the 9F is a “status byte”. it's kinda like a packet header, except you only need one if your next message has a different channel or kind to the previous one. status bytes are distinguished from other bytes (“data bytes”) by whether the top bit is set. this is why 8-bit quantities are rare in midi. the note number and velocity are both 7-bit for example. 128 possible values is often plenty!

Open thread at this post

it's not limited to just two notes in succession of course, it can be any number. this trick, which is called “running status”, works on all kinds of “channel messages”, so e.g. you can also do this with pitch bends.

anyway, what if we want to do a “note off”? well, to press and immediately release A4 would be:

9F 45 50 8F 45 50

just like “note on”, it has a note number and a velocity.

but if you're addicted to running status, check this out:

9F 45 50 45 00

that's right.

velocity zero “note on”.

😎

Open thread at this post

and to wrap this up: you can do this inside an smf file too!

they went out of their way to support running status for midi messages in midi files… though every message must still be prefixed by a time delta, even if it's zero and even if the status is unchanged.

btw, smf format 1 (multi-track) files can potentially use running status even more than midi data on the wire, because you can put each channel in its own track, ensuring you never have to change channel and hence status byte… assuming you never need messages other than note on or note off, and don't care about release velocity :)

Open thread at this post
GEM is truly truly outrageous , @Seg@oldbytes.space
(open profile)

@hikari MIDI, an elegant protocol from a more civilized age

MIDI debuted in 1982, when Intel 8051 microcontrollers ruled the embedded world. it really had to be small!

SMF came a bit later, when 16-bit systems such as Atari STs, Mac Pluses and 8086 PCs were current kit and people wanted to transfer sequencer data between the various applications and platforms

Open remote post (opens in a new window)