Sysex gamepad transfer is the unloved part of MIDI that comes alive when you bind it to a face button. System Exclusive is how synths, drum machines, and effects pedals ship their proprietary data — presets, firmware, LED states, ribbon calibration. A gamepad with a free button to spare is a perfect remote for fetching a DX7 voice, swapping a Virus TI patch, or pushing a calibration blob into a Lyra-8. This post walks the byte layout, the chunking rules, and how to wire transfers to a controller.
- Sysex framing: 0xF0 (start) … manufacturer ID … payload … 0xF7 (end). Anything between is opaque to MIDI 1.0 routers.
- Chunk size: 256 bytes per packet is the safe default. Real devices stream the rest with 5 ms inter-chunk delay.
- Universal device inquiry:
F0 7E 7F 06 01 F7. Every sysex-capable device replies with its manufacturer/model. - Gamepad workflow: bind Share/Select to "send sysex file"; map d-pad to cycle preset .syx files.
- Transport matters: USB-C ~1 ms/chunk, BLE MIDI ~15 ms/chunk, RTP-MIDI Ethernet ~0.5 ms/chunk.
What a sysex message actually looks like
Sysex is the only MIDI 1.0 message type with variable length. The spec defines a start byte (0xF0), a manufacturer ID (one byte for the big names, three bytes for everyone else, per the MIDI Association registry), an arbitrary payload, and an end byte (0xF7). Everything inside is the manufacturer's business.
A Yamaha DX7 voice dump for voice slot 5 looks like this:
| Offset | Hex | Meaning |
|---|---|---|
| 0 | 0xF0 | Sysex start |
| 1 | 0x43 | Manufacturer ID — Yamaha |
| 2 | 0x00 | Substatus + channel (0 = device 1) |
| 3 | 0x00 | Format number — 0 = single voice |
| 4–5 | 0x01 0x1B | Byte count MSB/LSB — 155 bytes |
| 6–160 | ... | 155 bytes of voice parameters |
| 161 | 0xXX | Checksum |
| 162 | 0xF7 | Sysex end |
That fits in a single packet on every transport — USB MIDI, RTP-MIDI, even BLE MIDI if the host doesn't fragment it. Compare that to a Virus TI patch (2,054 bytes) or a Vital preset (~16 kB) and you see why chunking matters.
Chunking rules — what real devices need
The MIDI 1.0 spec leaves chunking to the device implementer. In practice, most synths from 1985 onwards accept sysex in chunks no larger than 256 bytes with a 5 ms gap between chunks. The Yamaha DX7 famously needs a longer gap (~20 ms between voice blocks) because its 6809 CPU can't drain the UART fast enough. Modern devices like the Hydrasynth happily eat 1 kB chunks at line rate.
| Device | Safe chunk (bytes) | Inter-chunk gap (ms) | Typical preset (kB) |
|---|---|---|---|
| Yamaha DX7 | 155 (one voice) | 20 | 0.15 |
| Roland JV-1080 | 256 | 5 | 1.2 |
| Access Virus TI | 256 | 3 | 2.0 |
| Korg Microwave XT | 256 | 10 | 0.5 |
| Hydrasynth | 1024 | 1 | 3.0 |
| Vital (softsynth) | No limit | 0 | 16.0 |
Universal Controller MIDI ships a chunker that knows about these defaults per device. Pick "Yamaha DX7" from the device profile dropdown and it auto-sets chunk 155 / gap 20. Pick "Generic" and it falls back to 256 / 5. The sysex deep dive covers the device profile catalogue in full.
Binding a transfer to a gamepad button
The bridge exposes three sysex actions you can map to any button:
- Send sysex file — pick a
.syxfile from disk, push it to the selected output port on press. - Request device dump — emit a device-inquiry or model-specific dump request; the response is written to disk.
- Cycle preset folder — map d-pad up/down to step through a folder of
.syxfiles. One press = one preset.
# Bridge sysex bindings — DualSense to DX7
[mapping.share_button]
action = "sysex.send_file"
file = "~/Music/dx7/lately-bass.syx"
chunk_bytes = 155
gap_ms = 20
[mapping.dpad_up]
action = "sysex.cycle_folder"
folder = "~/Music/dx7"
step = +1
[mapping.dpad_down]
action = "sysex.cycle_folder"
folder = "~/Music/dx7"
step = -1
[mapping.options_button]
action = "sysex.request_dump"
target = "dx7"
save_to = "~/Music/dx7/dumps/{timestamp}.syx" The universal device inquiry — your first move
Before you transfer anything, run the universal device inquiry. It is the only sysex message every device understands. The bridge's Tools → Identify device button sends it and shows you the response in plain text — manufacturer, family, model, firmware. Use it to confirm the device is alive and on the right MIDI port.
# Universal Device Inquiry
TX: F0 7E 7F 06 01 F7
^^ device ID (7F = broadcast)
# Typical Hydrasynth response
RX: F0 7E 00 06 02 00 20 6B 02 00 00 00 01 0C 00 F7
^^ device ^^ manufacturer (ASM = 00 20 6B)
^^ family code
^^ firmware bytes Sysex across transports — measured times
Same preset (Hydrasynth, 3 kB) shipped across four transports from the same bridge to the same device. Timed from first byte sent to last byte ACK'd.
| Transport | Total time (ms) | Effective throughput | Notes |
|---|---|---|---|
| USB-C MIDI direct | 3.2 | ~960 kB/s | Reference baseline. |
| RTP-MIDI, Ethernet | 4.1 | ~750 kB/s | Within 1 ms of USB. |
| RTP-MIDI, Wi-Fi 6 | 9.8 | ~310 kB/s | Wi-Fi adds variable jitter. |
| BLE MIDI 1.0 | 3,420 | ~0.9 kB/s | 20-byte packets × 7.5 ms intervals. |
Bluetooth MIDI is over 1,000× slower for sysex. If you plan to swap presets live, do not put sysex on BLE. Stick to USB-C for tracking and RTP-MIDI for distance — see RTP-MIDI vs USB MIDI for the broader transport story.
Gotchas that cost us hours
- Stuck-in-receive mode. If a sysex transfer is interrupted mid-stream, some synths sit waiting for the missing 0xF7 forever. Power-cycle them.
- Manufacturer ID 0x00 trap. A 0x00 first byte means the next two bytes are the extended manufacturer ID. The bridge handles this; hand-rolled scripts often don't.
- Roland's checksum rule. Roland sysex requires a checksum byte before 0xF7. Mess it up and the device silently rejects the dump.
- Mac's IAC bus drops sysex on overflow. Macs running multiple sysex pipes through IAC can lose packets if the buffer overruns. Send through a real port if possible.
- Browser sysex needs HTTPS + permission. WebMIDI refuses sysex on insecure origins, and the user must explicitly tick the sysex box. See WebMIDI gamepad rig for the prompt flow.
- MIDI 2.0 changes the framing. Sysex in MIDI 2.0 uses 7-bit data inside 64-bit UMP packets — the byte stream is gone. The bridge handles the conversion; covered in MPE vs MIDI 2.0.
Why this is worth bothering with
Once you have sysex transfer wired to a button, your gamepad becomes a preset remote — cycle through a folder of DX7 voices during a take, dump the current Virus state to disk on a long press, fire a calibration blob into a Lyra-8 every gig. Hardware synths were designed to be controlled remotely; the gamepad is the cheapest remote you'll ever own.
Grab the bridge from Universal Controller MIDI and bind Share to your favourite preset folder. The sysex deep dive covers bidirectional flows (LED states, haptic ACKs) and MIDI feedback shows how to route the responses back to the gamepad's rumble motors.