Pd Simple MIDI Message Format

Albert Gräf

Some of my Pd externals, such as pd-faust and pd-lv2plugin, process MIDI messages in a symbolic format which I call the Pd Simple MIDI Message Format or SMMF for short. These externals are written in the Pure programming language and thus require pd-pure to run. But the SMMF format itself isn't tied in any way to pd-pure, so I'm documenting it here and also provide some useful helper abstractions, so that anyone who needs to process MIDI data in Pd can use it for their own projects.

The idea of the SMMF format is quite simply to represent MIDI data from Pd's MIDI interface as Pd meta messages which can be passed around freely as a single stream of messages, while keeping together all the information of the original MIDI messages. Moreover, the format uses Pd's somewhat idiosyncratic order of the data bytes (in particular, the MIDI channel comes last), so that the translation from and to Pd's MIDI objects is easy. The format is summarized in the following table (n denotes a note or controller number, v the velocity or controller value, c the 1-based MIDI channel number):

Message Meaning
ctl v n c control change
note n v c note
pgm n c program change
polytouch v n c key pressure
touch v c channel pressure
bend v c pitch bend (14 bit value)
start, stop, cont system realtime messages
sysex b1 b2 ... system exclusive message

Note that most of these messages closely correspond to the inlets and outlets of Pd's MIDI objects, so converting between these and the SMMF format is straightforward. In addition, SMMF includes representations for system exclusive and some useful system real-time messages which don't have a direct counterpart in Pd. In this folder you can find two little helper patches (midi-input.pd and midi-output.pd) which handle the conversion, you might want to look at these and adjust them for your needs as you see fit.


While SMMF isn't tied to pd-pure, the format also makes it very easy to write MIDI externals in Pure. This is because the SMMF meta messages look exactly the same in Pure and can be processed conveniently using pattern matching. For instance, here's the Pure definition of the miditransp object which transposes MIDI note and polyphonic aftertouch messages. It takes a single creation argument, either a constant (number of semitones to transpose by), or an arbitrary Pure function to be applied to the note numbers.

miditransp k::number msg = miditransp (+k) msg;
miditransp f (note n v c) = note m v c if numberp m when m = f n end;
miditransp f (polytouch v n c) = polytouch v m c if numberp m when m = f n end;
miditransp f msg = msg otherwise;

Some other useful examples can be found in the examples folder, along with some demo patches. Note that in order to run these examples you need to have pd-pure installed. Also, some of the patches require externals from the cyclone library (available in pd-extended, pd-l2ork and pd-l2ork's cross-platform variant purr-data). The fluidsynth examples also need Frank Barknecht's fluid~ external, which is readily available only in pd-l2ork and purr-data at the time of this writing. You'll also need a GM-compatible soundfont to use with fluid~. (The examples assume FluidR3_GM2.sf2 by default, which is available in the package repositories of Arch and Ubuntu Linux and can be downloaded freely from various locations on the web. Just copy the file to the directory in which you launch Pd and you should be set.)


There are some long-standing bugs in Pd's MIDI subsystem (cf. issues #1272 and #1262 on the Pd project page) which you should be aware of. These have nothing to do with SMMF per se, but they affect the midi-input and midi-output helper abstractions distributed with this package and, as they don't really seem to be documented anywhere (apart from these bug reports and some really old mailing list posts), I'm doing that here.

  • Pd versions up to (and including) Pd 0.47-1 don't provide a reliable cross-platform way to output raw MIDI data like sysex messages. More precisely, there is a bug in Pd's ALSA back-end which makes the midiout object output malformed 1-byte messages. This bug has finally been fixed (as of rev. 25af32 in Pd's git repository), but at the time of this writing is still present in every (vanilla) Pd release on Linux out there, so you'll probably run into it sooner or later.

  • Pd's bendin object produces an unsigned value range of 0 thru 16383, while the bendout object expects a signed range of -8192 thru +8191. Which means that you have to translate the values when routing pitch bends from MIDI input to MIDI output. This bug appears to have been there forever and it affects all platforms. Because it has been around for so long, the bug can't even be fixed in vanilla any more, because of its staunch outlook on backwards compatibility.

Both issues have long been fixed in pd-l2ork and purr-data, which we recommend. If you prefer to use vanilla, you just need to be aware that the output of bendin will differ depending on which Pd variant you use. Or you may want to fix up midi-input.pd (subtract 8192 from bendin's first outlet) to make it output proper pitch bend values which are compatible with what pd-l2ork's bendin will give you. There's not much you can do about the first bug when running current vanilla Pd versions on Linux/ALSA, though; in this case we recommend updating to Pd 0.48 as soon as it comes out, or installing Pd from the current git sources for the time being.