Search guides and the APICtrl K
  1. API reference
  2. MIDI and OSC

midi_clock.h

MIDI clock: tempo and transport from the wire.

#include <sonore/midi_clock.h>
On this page

Design notes

Why this exists

A plugin inside a DAW is told the tempo: the host fills in a transport structure and every wrapper here passes it through. A plugin driven from a MIDI cable is told nothing. It receives a single byte, 0xF8, twenty-four times per quarter note, and whatever it wants to know about tempo it has to work out from how fast they arrive.

That is the case this covers: a hardware sequencer, a drum machine, another computer, or the standalone build being clocked by any of them.

Estimating a tempo from arrival times

The naive reading (one interval, converted directly) is unusable. MIDI clock is jittery by construction: it travels over a serial link at 31250 baud, it queues behind whatever else is being sent, and USB adds its own millisecond of scheduling. A tempo read from single intervals jumps by several BPM continuously, and a delay time computed from it warbles.

So the estimate is smoothed, and the amount of smoothing is the entire design decision here:

  • Too little, and the tempo audibly wanders while the source is steady.
  • Too much, and a real tempo change takes seconds to follow, which is worse: the sequencer has already moved and the plugin has not.

A one-pole over the last couple of dozen clocks lands close to a quarter note of averaging: enough that jitter disappears, short enough that a deliberate change arrives within a beat.

What a one-pole cannot do is tell a glitch from a change. One dropped byte doubles an interval and one duplicate splits it, and at 120 BPM those read 60 and 240 -- well inside any sane tempo range, and each pulled the estimate by several BPM. So a reading more than a quarter away from the current tempo is held back: a glitch happens once, a real change repeats, and four consistent readings in a row are believed outright.

Not a replacement for host transport

When a host provides a transport, believe the host. It knows the tempo exactly, it knows the bar position, and it is not guessing from arrival times. This is for when there is nothing better.

Types 1

Tempo and transport, derived from the realtime bytes in a MIDI stream and the Song Position Pointer that goes with them.

Call process() once per block with that block's MIDI and its length. Nothing allocates and nothing blocks; this is safe on the audio thread.

↑↓ to move↵ to openEvery public name in the headers, and every guide