MIDI & Event Queues

MIDI in plug-ins

Classic plug-in API designs are based around three assumptions regarding MIDI:

  • MIDI is outdated and will eventually disappear
  • Event abstraction will lead to better resolution of pitch and expression
  • Event abstraction will also take the load off developers

Appearing at some point between 2000 and 2010 i.e. during the development of 2nd-gen plug-in formats, the end of the MIDI protocol was assumed to be approaching: Software would take over and plug-in developers would be quite content with a set of handed down restrictions.

But this did not happen. Hardware became stronger and more diverse than ever, with novel controllers and paradigms that still embrace MIDI. While alternative protocols such as OSC have emerged, none actually managed to define the standard method of communication for audio plug-ins. Instead, MIDI has been evolving by way of MPE, with the prospect of a “MIDI 2.0” eventually addressing much of the criticism. New MIDI technologies such as MTS-ESP are solving the remaining problems where old paradigms hamper diversity.

Common Denominator

Instead of embracing the novel options offered by 2nd generation plug-in formats, developers felt their plug-ins had to remain compatible with the first generation: Noble attempts including time-stamped parameter changes, floating point pitches, novel means of expression etc. remained largely ignored. Aspiring developers turned to newly established frameworks (such as JUCE) instead, as these ensure compatibility without the burden of having to learn multiple complex plug-in SDKs.

However, even popular frameworks such as JUCE were unable to take advantage of improvements in the new plug-in formats. It is clearly impossible to cater for all the different paradigms in any modular codebase. Having relieved developers from the burden of low level MIDI, a common denominator had to be found. This, often enough, turned out to be exactly the same as if it were plain old MIDI.

Concurrent Event Queues and Ambiguity

Which raises another problem: To achieve sample accuracy or even control rate accuracy, developers have to zip these abstracted events from their various sources into a single queue. Not only does this cost more time to process than a single event queue, it also creates ambiguity. Here’s an example:

MIDI events

Sample 83 - Channel 01 - MIDI Control Change 64 - Value 64
Sample 83 - Channel 01 - NoteOff - Value C4

At sample 83 in the process buffer, the Hold pedal is pressed before Note C4 is released. Clearly, the note C4 will be held by the pedal. But here is what this looks like in an abstracted format:

SetParameter( … )
SetParameter( … )
SetParameter( “Hold pedal”, 64, 83 )
SetParameter( … )
…
SetNote( … )
SetNote( Note_C4, false /* off */, 83 )
SetNote( … )

In the 2nd-gen formats, what used to be MIDI events can now be drawn from different sources, and the intended order may not be preserved. Parameters could arrive first (or whatever abstracts such events), or notes could arrive first. The plug-in is unable to distinguish between the following:

Sample 83 - Channel 01 - MIDI Control Change 64 - Value 64
Sample 83 - Channel 01 - NoteOff - Value C4

and

Sample 83 - Channel 01 - NoteOff - Value C4
Sample 83 - Channel 01 - MIDI Control Change 64 - Value 64

There is a 50% chance that the data will be interpreted in the wrong order.

One could say that two such events would seldom “collide” on the same timestamp in the real world. That may be true for live performance on a keyboard, but it is certainly not true for hard-quantized MIDI in a DAW. Nor is it true for music created with a mouse rather than with a MIDI keyboard – a current trend. In a recent survey conducted by u-he, about 25% of their synth plug-in users mainly enter notes and draw expression curves with the mouse.

Conclusion for CLAP

Our take from this:

  • MIDI is alive!
  • To avoid ambiguity, plug-ins need a single event queue
  • Event abstraction in 2nd-gen formats make plug-in development neither easier nor “safer”

Enter CLAP, which offers full low-level MIDI support for MIDI-based code, e.g. plug-ins that generate MIDI.

CLAP has all event types zipped into a single queue. The order of events is therefore unambiguous, whether it be MIDI, high-level notes, parameter events, or timing events. All event types share a common layout and a common scheme, making event handling in CLAP elegant and fundamentally consistent.

Having MIDI and a high level event scheme side by side is not a step backwards: CLAP promotes diversity, acknowledging that plug-in developers wish to have the choice.