Engineering June 23, 2026

How do you pace Web MIDI SysEx for vintage synths?

Why Web MIDI SysEx needs deliberate sender pacing, and how to reliably flash vintage hardware from your browser without dropped packets or corrupted memory.

Web MIDI is a minor miracle. You open a browser tab, plug in a synthesizer built in 1983, and it just works. No drivers, no installers, no command-line tools.

But Web MIDI is also a disaster.

If you send data slightly too fast, the synthesizer crashes. Its LCD screen turns into random blocks, the buffer overflows, and the memory protect circuit blocks you from writing.

We spent the last month figuring out why this happens. It turns out, the problem isn’t the synthesizer’s CPU. It’s the way we write web software.

The 31,250 baud speed limit

Classic MIDI is slow. It runs at a fixed 31,250 baud—about 3,125 bytes per second on the wire. A full Yamaha DX7 bank is only 4 KB.

The synthesizer has plenty of time to receive 4 KB of data. The problem is that modern computers send USB packets at megabytes per second.

Without hardware flow control (there are no RTS/CTS pins on a standard MIDI cable), there is no way for the synth to tell the browser: "Slow down, I’m still writing the last preset block."

If you blast the entire file at once, the MIDI buffer overflows instantly.

The $5 adapter problem

Most people don't use professional MIDI interfaces. They buy cheap, $5 USB-to-MIDI adapters from Amazon.

These cheap adapters have tiny, bufferless microcontrollers. When you send a large batch of SysEx data, the adapter receives it at USB speeds, panics, and dumps it down the MIDI out pin as fast as possible.

This strips the gaps between MIDI packets, corrupts the SysEx headers, and results in nothing but garbage arriving at the synthesizer.

Remember this

Do not split SysEx messages into arbitrary byte chunks. Setting a JavaScript setTimeout of 60ms is not a real queue—it drifts under CPU load and corrupts memory. The browser needs to pace complete messages using performance.now() timestamps.

The scheduler is your queue

The fix is to use the Web MIDI API's built-in scheduler.

Instead of sending data immediately and hoping for the best, you must queue complete F0...F7 messages with calculated millisecond offsets:

// Pace complete F0…F7 messages with calculated offsets
function sendSysExWithPacing(midiOutput, messages) {
    const INTER_MESSAGE_DELAY_MS = 60; // Safe threshold for vintage CPUs
    let offset = 0;

    for (const message of messages) {
        midiOutput.send(message, performance.now() + offset);
        offset += INTER_MESSAGE_DELAY_MS;
    }
}

Decoding proprietary 80s structures

Once you get the connection working, you have to parse the bytes. In the 80s, the MIDI spec left the system exclusive format entirely up to the manufacturers.

This means every single synth has its own proprietary byte structure:

Why zero-install beats feature bloat

I originally built knob.monster because I was tired of dusty, unsigned desktop utilities that haven't been updated since 2008.

Many developers told me I should build a desktop app with Tauri or Electron. But zero-install is a feature for gear you only use twice a year.

By keeping the app in the browser, backups are instant. You don't have to download anything. You don't have to configure driver settings.

Pacing MIDI packets is a messy, hardware-specific problem. But once you solve it, you get a system that works everywhere.

Remember this

For vintage hardware audiences, technical honesty and export guarantees (like standard .syx files) win over modern visual polish. Give developers their data back, and they'll trust your platform.

Instant Cloud Backups

Tired of vintage SysEx headaches?

I built knob.monster to replace dusty desktop utilities. Connect your hardware synthesizer directly to a browser tab, click back up, and organize your presets in a modern, searchable cloud library. Lifetime licenses from $39 — not a subscription.

← Back to home