Two MIDI rigs, same room. The first has a noticeably longer delay but every hit lands in the same place relative to the one before it. The second has a shorter delay on average but each hit arrives somewhere in a range. Nearly every player will take the first one, and nearly every spec sheet will recommend the second. That gap between what gets measured and what gets felt is the subject of this post on MIDI controller latency jitter: latency is the offset, jitter is the scatter, and the scatter is what breaks your timing.
- Latency = how long an event takes. Jitter = how much that duration varies between events.
- Players adapt to offset, not to scatter. A stable delay is learnable within minutes; a varying one never is.
- Most jitter comes from independent clocks. Your read loop, the bus schedule, the OS scheduler and the audio callback are four clocks that are not synchronised.
- Wireless widens the distribution structurally, because the connection interval is negotiated and events may be skipped.
- Fix order: event-driven reads, wired transport, thread priority and power management, then timestamped sends.
What exactly is jitter in this context?
Jitter is the variance of a delay. If you press a pad a thousand times and measure how long each press took to produce a note, you get a distribution, not a number. The centre of that distribution is what charts call latency. The width of it is jitter, and it is the half most charts omit — which is the main reason two honest charts can disagree, as covered in how to read a controller latency chart.
The distinction matters because the two have different causes and different cures. Offset comes from stages that cost a fixed amount every time: converter conversion, a fixed audio buffer, a plugin's declared latency. Scatter comes from stages whose cost depends on when the event happened relative to some other schedule — and a gamepad MIDI chain is full of those.
Why do humans tolerate delay but not variance?
Because anticipation is the mechanism musicians use to play in time, and anticipation requires predictability rather than immediacy. A drummer playing to a monitor wedge several metres away is dealing with a delay they did not choose and cannot remove, and they play perfectly well — they shift their physical timing earlier by a stable amount and stop thinking about it. Organists in large buildings do the same thing with far longer delays.
What defeats that adaptation is a delay that changes between events. There is no stable amount to shift by, so every correction is wrong in a different direction, and the player ends up chasing the instrument. Subjectively this does not feel like latency at all — it feels like the instrument is "loose", "mushy", or "not responding properly", which is why people often misdiagnose jitter as a latency problem and go chasing buffer sizes that were never the issue.
The practical consequence: when evaluating a rig, play repeated single hits and listen for consistency, not speed. If every hit lands identically, you have an offset problem at worst and you will adapt. If they scatter, no amount of buffer reduction will fix the feel.
- Controller polling
- Bridge read loop
- OS scheduler
- Virtual MIDI port
- Audio buffer
Where does jitter come from in a gamepad MIDI chain?
Almost entirely from places where two unsynchronised schedules meet. Each handoff between clocks adds a wait whose length depends on the phase relationship between them, and phase relationships drift.
| Stage | Source of variance | Can you narrow it? |
|---|---|---|
| Controller firmware scan | Internal scan loop phase relative to your press; debounce windows | No, unless firmware exposes it |
| Transport scheduling | Press phase relative to the bus schedule or connection event | Partly: wired narrows it; interval choice narrows it |
| Wireless retransmission | Interference causing a packet to be retried at the next connection event | Partly: channel environment, distance, going wired |
| Your read loop | A timer that is independent of report arrival — a second sampling stage | Yes, and this is the biggest self-inflicted one |
| OS thread scheduling | When your thread next gets CPU; preemption by other work | Yes: priority, power profile, background load |
| Virtual MIDI delivery | Driver and host MIDI thread wake-ups | Partly, by using timestamped sends |
| Audio callback boundary | Event arrival phase within the current block | Yes: smaller blocks narrow the quantisation of event placement |
Read the fourth row twice. A bridge that sleeps for a fixed period, wakes, reads whatever is there and goes back to sleep has inserted a sampling stage that is not synchronised to the one below it. The two schedules beat against each other, and the resulting spread is larger than either stage would produce alone. It is also completely avoidable.
How do I stop my own code adding jitter?
Make the arrival of data wake your code, rather than waking your code and hoping data arrived. Every platform provides this, and using it removes an entire variance source at no cost.
// WRONG - two unsynchronised clocks beating against each other
while (running) {
sleep_us(1000); // your clock
read_latest_state(&state); // the bus has its own clock
emit_midi_if_changed(&state);
}
// RIGHT - the report arrival IS the clock
while (running) {
// blocks until the transport actually delivers a report
int n = read(hidraw_fd, buf, sizeof buf);
if (n <= 0) continue;
uint64_t t_in = monotonic_now_ns(); // stamp as early as possible
decode_report(buf, n, &state);
emit_midi_if_changed(&state, t_in);
} On Linux the file descriptor from hidraw or an evdev node is pollable and blocks until a genuine event exists, with the event semantics defined in the kernel input event codes documentation. On macOS, GameController delivers value-changed callbacks through the element handlers on GCPhysicalInputProfile. On Windows, GameInput readings arrive timestamped, which is one of the concrete advantages it has over the snapshot model of XInputGetState. The full stack comparison is in GameInput versus XInput and the macOS GameController deep dive.
Why does wireless add scatter rather than just delay?
Because of three mechanisms, all of them structural rather than incidental. First, the link operates on a connection interval negotiated between device and host and expressed in 1.25 ms units by the Link Layer, as specified in the Bluetooth Core Specification — so data waits for the next connection event rather than the next bus frame. Second, peripheral latency permits the device to skip connection events when it has nothing to say, which saves battery and means the first event after a quiet period can arrive later than the steady-state case. Third, the 2.4 GHz band is shared, so a corrupted packet is retried at a subsequent connection event rather than immediately.
Those three together produce a wider distribution than a wired interrupt endpoint, and they do it by design rather than by fault. That is why the honest formulation is "a wireless link introduces a negotiated interval that is structurally longer and more variable than a USB frame schedule", not a specific millisecond figure — the actual number depends on what your two devices negotiated, your host's Bluetooth stack, and the RF environment of the room you are standing in. Bluetooth MIDI for gamepads covers the mitigation side, and wired versus Bluetooth covers when it is worth the trade.
One practical note that catches people out: re-pairing a controller can result in a different negotiated interval than last time. If a rig that felt fine last week feels loose this week and nothing else changed, that is a candidate explanation, and plugging in a cable will confirm it in thirty seconds.
How do I measure jitter rather than guess at it?
Play a long, steady figure against a click, record it, and look at the distribution of note positions. Not a musical phrase — straight repeated hits, because a phrase mixes your own timing variance with the rig's and you cannot separate them afterwards.
- Set a metronome to a comfortable tempo and record a minute of straight eighths from one pad into a MIDI track.
- Export the MIDI and compute each note's offset from the nearest grid line, in milliseconds.
- Take the mean of those offsets. That is your bias — the part you adapt to, and it includes your own playing bias.
- Take the standard deviation and the 5th-to-95th percentile span. That is the part that matters.
- Repeat with the same controller on a cable instead of wireless. The bias may barely move. The spread usually does.
Do the same test again with a class-compliant USB MIDI keyboard as an anchor. The spread you get from the keyboard is your floor — the contribution of your DAW, audio stack and your own hands. Anything above that floor on the gamepad run is attributable to the input path, which is exactly the number you wanted.
Can timestamps remove jitter?
They can remove jitter that occurs after the stamp, which is a meaningful chunk. Platform MIDI APIs let you attach an intended time to an event rather than relying on when the host happened to receive it. CoreMIDI builds this into its packet model, documented on MIDIPacket and used by MIDISendEventList, so a message delayed by a thread wake-up can still be placed at the time it was meant to occur.
What timestamps cannot do is recover variance that happened before your code saw the input. If the report sat waiting for the next connection event, that variance is already baked in and no amount of downstream scheduling will undo it. This is why the ordering matters: narrow the input-side distribution first, then use timestamps to stop re-widening it on the way out.
There is a subtlety worth knowing when you move to timestamped sends: scheduling an event slightly in the future trades a small, constant added delay for a large reduction in scatter. Given the perceptual argument at the top of this post, that trade is usually worth making — a few extra milliseconds of stable offset in exchange for a visibly tighter distribution is a good deal for a player.
What about MIDI clock jitter, as opposed to input jitter?
Different problem, same principle. MIDI clock in MIDI 1.0 is a stream of single-byte timing messages, defined in the summary of MIDI 1.0 messages, sent at a fixed count per quarter note. Because those bytes travel in the same serial stream as everything else, a flood of Control Change traffic can delay them — and a delayed clock byte is a tempo wobble in whatever is slaved to it.
This is the practical argument for the send-on-change discipline described in USB polling rate explained. A stick sweep that emits a CC on every poll is not just wasteful; on a bandwidth-constrained link it is actively pushing your clock around. If your gamepad is the clock master, as in MIDI clock sync from gamepad buttons, keep the CC traffic lean or move the clock to a separate port entirely. Routing multiple ports is covered in routing one controller into two DAWs.
A fix list in priority order
- Event-driven reads. Deletes a whole variance source. Costs nothing.
- Wired transport. Narrower distribution by construction, not by tuning.
- Power management off, thread priority up. Stops the OS parking the thread that carries your timing.
- Send on change, with per-CC rate limiting. Keeps the stream clear for the messages that matter.
- Timestamped MIDI sends. Prevents re-widening after the stamp.
- Smaller audio buffer. Finer placement of events within the render, and lower offset as a bonus.
- Nothing else on the audio device. Browsers and conferencing apps are a common hidden cause of sporadic spikes.
If you want a stage-by-stage tuning walkthrough with the actual settings, which stage is slowing you down and the latency tuning docs are the companions to this post. For how the two concepts interact with controller design, see what actually makes a MIDI controller fast.
FAQ
What is the difference between latency and jitter?
Latency is how long an event takes to travel through the chain, while jitter is how much that travel time varies from one event to the next.
Which is worse for playing in time, latency or jitter?
Jitter, because a player can learn to anticipate a constant delay within minutes but has nothing stable to anticipate when the delay changes on every hit.
What causes jitter in a gamepad MIDI chain?
Chiefly the interaction of independent clocks, such as a bridge timer that is not synchronised with the transport schedule, plus thread scheduling, power management and wireless retransmission.
Does quantising in my DAW fix jitter?
It fixes the recorded result but not the playing experience, because quantisation runs after the fact and does nothing about the inconsistent feedback you receive while performing.
Why does my rig feel tight some days and loose on others?
Usually because something changed in the machine rather than the controller, such as a power profile, a thermal state, a background process, or a different Bluetooth negotiation after re-pairing.
Can MIDI timestamps remove jitter?
They can remove jitter introduced after the timestamp is taken, because the host can place the event at the stamped time, but they cannot recover variance that occurred before your code saw the input.
Put it into practice
Record one minute of straight eighths from a single pad, export the MIDI, and look at the spread rather than the average. That single number tells you more about whether your rig is worth playing than any chart you will find. Download Universal Controller MIDI, switch it to event-driven input, plug in a cable, and run the test again — the delta is the whole argument of this post made audible.