Alesis Quadraverb SysEx reference
This is a working reference for the MIDI System Exclusive implementation of the Alesis Quadraverb and Alesis Quadraverb Plus, written from the implementation behind the QVERB editor rather than transcribed from the manual. It covers the three opcodes the unit understands, the two different bit packings it uses, the 128-byte program layout, and the value convention that trips up most first implementations.
Message frame
Every message shares the same envelope:
F0 00 00 0E 02 <opcode> <data...> F7
00 00 0E is the Alesis manufacturer ID and 02 is the Quadraverb device ID. All data bytes are 7-bit, as MIDI requires — which is the reason for the packing schemes below.
Opcode 0x01 — parameter edit
F0 00 00 0E 02 01 <function> <page> <v1> <v2> <v3> F7
A single parameter change, applied to the edit buffer and audible immediately. The function selects the effect block and the page selects the parameter within it.
| Function | Block |
|---|---|
| 1 | Reverb |
| 2 | Delay |
| 3 | Pitch |
| 4 | EQ |
| 7 | Configuration |
| 8 | Mix |
| 9 | Modulation |
| 10 | Name |
The value is a 16-bit quantity spread across three 7-bit bytes. Note that this is not a plain MSB/LSB split — the bits are shifted, so a naive value & 0x7F / value >> 7 encoding sends the wrong number:
v1 = (lsb >> 1) & 0x7F v2 = ((lsb & 0x01) << 6) | ((msb >> 2) & 0x3F) v3 = ((msb & 0x03) << 5) & 0x7F
Opcode 0x02 — data dump
F0 00 00 0E 02 02 <program> <packed data...> F7
The unit sends this in reply to a dump request, and accepts it to write data back. The program byte selects what the payload contains: 0–99 for a stored program, 100 for the edit buffer, and any value above 100 for the whole bank.
| Scope | On the wire | Unpacked |
|---|---|---|
| Single program | 147 bytes | 128 bytes |
| All 100 programs | 14,629 bytes | 12,800 bytes |
Dump packing is a bitstream, not byte pairs
Dumps use a different scheme from parameter edits: seven 8-bit source bytes become eight 7-bit MIDI bytes, as one continuous 56-bit bitstream shifted out in 7-bit groups. Treat it as a bitstream and both directions become trivial:
// unpack 8 MIDI bytes -> 7 data bytes let bits = 0n; for (const b of packed) bits = (bits << 7n) | BigInt(b & 0x7f); const out = []; for (let shift = 48n; shift >= 0n; shift -= 8n) out.push(Number((bits >> shift) & 0xffn));
A bank dump is just this repeated: 12,800 data bytes as 1,829 groups. If your decoded program names look like shifted gibberish, the bitstream alignment is off by a group, not the byte order.
Opcode 0x03 — dump request
F0 00 00 0E 02 03 <program> F7
Same program selector as opcode 0x02. Requesting 100 returns the edit buffer, including changes not yet stored to a slot — the fastest way to read what a unit is currently doing, and the basis of the backup workflow.
Program data layout
Each program is 128 bytes. Offsets are relative to the start of the program, and the blocks sit at fixed addresses regardless of which configuration is active:
| Offset | Contents |
|---|---|
| 0x00–0x0C | EQ — low, mid and high frequency, bandwidth and amplitude. Reused as graphic-EQ bands in the graphic configuration. |
| 0x1A–0x21 | Pitch — mode, input, LFO waveform, speed, depth, feedback, detune. |
| 0x27–0x2F | Delay — mode, input, input mix, left/right time and feedback. |
| 0x32–0x41 | Reverb — mode, inputs, pre-delay, decay, diffusion, density, gate. |
| 0x44–0x4A | Configuration, mix routing and per-block output levels. |
| 0x50–0x67 | Eight modulation slots: source, target, amplitude. |
| 0x6A–0x77 | Program name, 14 characters. |
| 0x78–0x7B | Plus-only extras: ring mod mixes, pan speed and depth. |
| 0x7C–0x7F | Unused. |
Why some addresses have two names
The configuration byte at 0x44 reinterprets several fields. In the graphic-EQ configuration the EQ block's frequency and amplitude bytes become fixed-band levels (16 Hz, 32 Hz, 62 Hz and so on); in the resonator configuration the pitch LFO depth byte becomes resonator decay. Decode the configuration byte first, then interpret the rest — a parser that reads addresses unconditionally will produce plausible but wrong values on non-default configurations.
| Value | Configuration |
|---|---|
| 0 | EQ → Pitch → Delay → Reverb |
| 1 | Leslie → Delay → Reverb |
| 2 | Graphic EQ → Delay |
| 3 | 5-band EQ → Pitch → Delay |
| 4 | 3-band EQ → Reverb |
| 5 | Ring Mod → Delay → Reverb |
| 6 | Resonator → Delay → Reverb |
| 7 | Sampling |
Values are offset binary
This is the detail that makes an otherwise correct implementation sound wrong. Parameters are stored as offset binary, not two's complement: a control displayed as −99…+99 is stored as 0…198, with 99 meaning zero. Convert on the way in and out:
const toStored = (shown, min) => shown - min; const toDisplay = (stored, min) => stored + min;
Symptom of getting it wrong: gains that jump to an extreme at the midpoint of the range, and negative values that wrap to maximum.
Practical notes
- Parameter edits affect the edit buffer only. Storing to a slot is a separate action.
- The unit is slower than the wire. Throttle streams of edits — for example from a fader — or you will drop messages.
- Web MIDI requires explicit SysEx permission and an HTTPS origin;
file://will not do. - Read before write. Dump the current state before sending anything that overwrites a bank.
Related: backing up your patches, using a unit with a dead display, and Web MIDI setup. For manuals and archive material about the wider Alesis effects line, see quadraverb.nl.