The big idea: a digital brain for analog voices
Nothing digital ever touches the PRO-800's audio. Sixteen oscillators, eight filters and eight amplifiers on the voice board make the sound. They're analog circuits, steered by control voltages: a higher voltage on an oscillator raises its pitch, a higher voltage on a filter opens it.
The firmware's whole job is to decide those voltages and keep setting them, hundreds of times a second. When you play a note with vibrato, the firmware doesn't make a wobbling sound. It nudges the oscillator's control voltage up and down, and the analog oscillator wobbles by itself.
What's on the board
The firmware talks to the hardware directly, register by register, with no vendor libraries. Everything it knows about the board came from Behringer's published main-board schematic and from measuring the synth itself. The voice board's circuit isn't published, so its behaviour (how many DAC steps make an octave, where the amplifiers start to open) was measured with test firmware and recordings.
A few details are worth knowing because they shape everything else:
- Three converters for 41 voltages. One precise 16-bit DAC handles everything that must be in tune (both oscillators and the filter of each voice). Two 12-bit DACs built into the chip handle the volume of each voice and the nine controls all voices share.
- Seven plain switches. Saw and triangle on each oscillator, hard sync, and the two poly-mod routings are on/off lines. Square waves are switched by moving the pulse-width voltage to its very end.
- An ear on the voices. A comparator chip turns the voice signal into clean on/off edges the firmware can time. That's what makes autotune possible.
Three DACs, forty-one voltages
A DAC (digital-to-analog converter) turns a number into a voltage. But there are only three of them and 41 places that need a voltage. The trick is sample and hold: every destination has its own small capacitor (10 nF) that remembers a voltage, followed by a buffer amplifier so the voice board can read it without draining it.
To set one destination, the firmware:
- Puts the value on a DAC. For the 16-bit DAC80501 that means clocking out 24 bits, one at a time: exactly 48 µs, each bit timed from the chip's cycle counter.
- Picks the capacitor. Three address lines choose one of eight outputs on a multiplexer chip (a 74HC4051, an electronic rotary switch).
- Connects the DAC to the capacitor, and leaves it connected. The capacitor needs about 9 µs to settle and charge to 16-bit accuracy, but it isn't disconnected until something it's sampling is about to change, usually two bits before the end of the next value's frame. So the sampling hides inside the next write and costs no time of its own.
- Writes neighbours alongside. The three DACs feed different multiplexers, so while a pitch or cutoff samples at a voice's address, that voice's VCA (from an on-chip DAC) samples at the same address for free, and so does a shared control that happens to be due.
pro800 dac-test showed that on this board anything above about 0.6 MHz, about 1.65 µs per bit, garbles it, whatever drives the bus.| Multiplexer | Fed by | Holds |
|---|---|---|
| U25 | DAC80501 (16-bit) | Oscillator A pitch, voices 1–8 |
| U32 | DAC80501 | Oscillator B pitch, voices 1–8 |
| U43 | DAC80501 | Filter cutoff, voices 1–8 |
| U24 | On-chip DAC 2 (12-bit) | VCA level, voices 1–8 |
| U23 | On-chip DAC 1 (12-bit) | Poly-mod osc B amount, osc A and B level, noise, master volume, external filter |
| U15 | On-chip DAC 1 | Pulse width A and B, resonance |
The catch: capacitors leak. A held voltage slowly sags (droops), so the firmware can never stop. It visits every capacitor again and again, forever. Below is that refresh in slow motion, in the firmware's real order.
One loop, no operating system
There's no operating system and no task scheduler. The firmware is one loop that runs forever, doing the same jobs in the same order. Each trip around it is a pass:
- Read any MIDI that arrived over USB or the 5-pin MIDI IN (notes, controllers, and SysEx over USB), run the internal clock if that's the source, and advance the sequencer. MIDI clock doesn't wait for this: the interrupts handle it the moment it arrives.
- Scan the panel: the next step of the knob scan, the switches, the buttons, the VALUE encoder, Shift.
- Run the slow half of the engine: read the knobs, work out glide, drift, the macros and every route that doesn't need to be fast, and each voice's pitch and cutoff apart from what the envelopes and LFOs add.
- Update the display.
- Refresh the voltages, the long part, with four ticks inside it. Each tick reads MIDI again, advances the sequencer, moves every envelope and LFO one step, applies the routes from them, and writes the voltages that changed.
Only four things interrupt the loop: a 1 ms clock tick, the USB hardware and the MIDI IN socket's serial port (both timestamp each MIDI clock tick the moment it arrives), and the tuning comparator's edges (used only while tuning). Everything that touches the voices happens in the loop, so nothing can change a voice halfway through being worked out.
Why split the refresh like that? A pass takes about 2.4 ms with eight voices. If envelopes only moved once per pass, a snappy attack would be a staircase of 2.4 ms steps. So every envelope and LFO advances four times per pass, in the ticks, and the routes from them into pitch, cutoff and volume are applied there too:
| Voltage | Written | Updates about every (8 voices) | (1 voice) |
|---|---|---|---|
| VCA (each voice's volume) | at every tick | 0.6 ms | 0.3 ms |
| Filter cutoff | every other tick | 1.2 ms | 0.6 ms |
| Pitch A and B | two voices per tick | 2.4 ms | 1.2 ms |
| Shared CVs (mixer, PW, resonance…) | once per pass | 2.4 ms | 1.2 ms |
Silent voices only need their capacitors topped up, so one of them is refreshed each pass, in turn, and passes get shorter when fewer notes sound. MIDI is read before every tick, so a note starts within a tick of its message rather than a pass, and when a voice starts a new note its pitch is written first, before its VCA opens, so you never hear a blip of the previous note.
pro800 dac-test showed why it can't go faster: above about 0.6 MHz, about 1.65 µs per bit however the clock is split, the DAC receives wrong data. Something on the board, not in the code. So the firmware squeezes the frame to exactly 48 µs, hides the sampling inside the next frame and spreads the rest; a faster path would need a scope on the board.From a key press to a voltage
Let's follow one note: you press A4 (MIDI note 69) on a keyboard plugged into the MIDI IN socket, with a little vibrato going. (Over USB the note comes from a computer instead; the path from step 2 on is the same.)
- MIDI arrives. The chip's serial port (UART4) receives the three bytes at MIDI's 31,250 baud and queues them; the loop puts them back together into one message, including running status, where a keyboard leaves out repeated status bytes. Notes from USB arrive already packaged, and both go through the same code from here on.
- The sequencer looks first. If the patch's sequence is switched on for that key's layer, the key starts or transposes the sequence instead of playing a note directly.
- A voice is chosen. The layer mode decides which layer (or both) gets the note; that layer's voice mode (poly, mono or legato) and note priority decide which voice. In the per-channel modes (eight mono channels, MPE) the MIDI channel picks the voice directly. The voice records the note, its velocity and a fresh random value, and its four envelopes start.
- The engine works out pitch in semitones. For every voice it adds up the gliding note, pitch bend, LFOs, mod routes, unison spread and drift; the slow parts once a pass, the envelope and LFO parts in every tick. If a scale is set, the result snaps to it. Then each oscillator adds its own FREQ setting, and oscillator A adds the poly-mod envelope.
- The tuning table turns semitones into a number. Each of the 16 oscillators and 8 filters has its own measured table (next section).
- Sample and hold. The number goes onto the right capacitor, and the analog oscillator follows it.
Filter cutoff works the same way: the cutoff knob, keyboard tracking, LFOs, routes and drift are added in semitones, the filter envelope is added on the fast path, and the filter's own table turns the sum into a voltage. Because the filters are measured the same way as the oscillators, a cutoff can follow the keyboard exactly, and a self-oscillating filter plays in tune.
Autotune: measuring every oscillator
No two analog oscillators are alike. Send the same voltage to all sixteen and you get sixteen different pitches. Measured on this synth before tuning, they spread from 77 cents flat to 63 cents sharp, more than a semitone end to end:
So the firmware measures each one. Press Tune (or let it run by itself the first time) and, for each oscillator in turn, it:
- opens only that voice's VCA and plays a sawtooth on just that oscillator;
- sets its CV to one of 14 measuring points (0x2000, 0x3000 … 0xF000);
- listens through the tuning comparator: every falling edge of the saw is timestamped with the chip's 168 MHz cycle counter, about 6 ns resolution;
- takes the median interval between edges as the period, which ignores the odd stray edge from a noisy comparator.
The filters are measured the same way, self-oscillating at full resonance with both oscillators muted, and since 0.8.4 pro800 check verifies them too: on this synth the eight filters match each other within about 6 cents across the keyboard. The tuning signal is taken after each voice's VCA but before the master volume, so tuning is silent: you can turn the volume down and it still works. All of it takes about 25 seconds.
Inside the sound engine
Voices, layers and shared wires
The engine keeps two complete sets of the per-voice settings, called layers. Layer 1 plays voices 1–4 and layer 2 plays voices 5–8 (layer 1 gets all eight when layers are off, and a mono layer takes one voice and leaves the other seven to its partner). Some controls, though, are a single wire for all eight voices on the hardware. Those can't differ between layers, so they're shared.
The layer modes only change how notes are given out: off (layer 1 on all eight voices), split (layer 1 below a split note, layer 2 from it up), stack (every note on both layers) and channel (MIDI channel 2 plays layer 2, every other channel layer 1). Two more give one sound a voice per MIDI channel: 8CH (channels 1–8 each own one voice, mono, with their own bend, pressure and CC 74) and MPE (channel 1 is the master, channels 2–9 each play one voice with 48 semitones of bend).
Envelopes with an analog shape
Every voice has four ADSR envelopes: filter, amp, Env 3 and Env 4. By default they're shaped like the envelope chips in classic polysynths: the attack charges towards 1.5 and stops when it reaches 1, so it shoots up and eases into the top. Decay and release fall exponentially, and their times are measured to −60 dB, so a release that says 2 s really is gone at 2 s. Each envelope can also take a linear curve or a swell, add a delay and a hold (DAHDSR), start from key up instead of key down, or cycle; those are the same formulas with different stage orders.
Each time knob follows t = min + (max − min) · (212k − 1) / 4095 for a knob position k from 0 to 1. That puts the useful short times in the lower half of the knob instead of crushing them at the bottom: attack 0–10 s with 150 ms in the middle, decay and release 3 ms–20 s with 310 ms in the middle.
One more measured detail: the voice VCAs stay silent until their control voltage reaches about 7–9 % of its range. If the envelope were sent straight through, every release tail would cut off early. So the firmware maps the envelope onto the range from 7 % to full, and gives a silent voice exactly zero.
LFOs that follow a clock
MIDI clock sends 24 ticks per quarter note, and real clocks jitter. Jumping the LFO at every tick would make it step; ignoring the ticks would let it drift off the beat. So the USB and MIDI IN interrupts count and timestamp every tick the moment it arrives, the firmware averages the time between ticks to know the tempo, and between ticks it works out the position from the tick count plus the time since the last one. The LFO moves smoothly and stays on the grid. After MIDI Start, the next tick is the downbeat, so the LFO lines up with the bar; Continue and Song Position are honoured, and if the clock stops the LFO carries on at the last tempo. When the clock is the firmware's own (tap the tempo on Sync Clock) or the SYNC IN jack, a generator feeds the same tick counter, stamped from the cycle counter, so LFOs, looping envelopes and the sequencer always see one steady clock, and the Sync Clock LED blinks on its beat.
Each LFO keeps a phase, a position through its cycle from 0 to 1. In the per-voice retrigger mode, every voice keeps its own phase, started at its own note-on. That's cheap, because LFOs are added in software to each voice's pitch and cutoff. Pulse width is one shared wire, so LFO → PW always uses the shared phase. Each LFO also has a delay and a fade-in: a gain per voice that stays at zero after the note starts and then rises to 1, so vibrato can arrive late without a route.
The mod matrix: adding things up per voice
Each layer has 16 routes. A route is just three numbers: a source (one of 27), a destination (one of 46), and a depth from −99 to +99. For every voice, the engine evaluates each route and adds source × depth to the destination: routes from envelopes and LFOs into pitch, cutoff and the VCA in every tick, the rest once a pass. Because the sources are per voice too (that voice's velocity, its envelopes, its random value, its pressure, its place in the layer), one route gives every note its own amount.
A few destinations get special treatment so they're musical:
- Pitch routes use a squared depth curve: depth 10 is a quarter of a semitone, fine enough for vibrato, while 99 is still two octaves.
- VCA routes multiply the amp envelope instead of adding to it, so a route can never open a voice that isn't playing. Velocity → VCA at 99 is plain velocity sensitivity.
- LFO rate routes are per voice in per-voice mode (harder notes can have faster vibrato), and on a clock-synced LFO they sweep smoothly off the grid, then the LFO slides back onto the beat when the modulation stops.
- Envelope stages and glide are destinations too: a route scales that time by up to 16× either way, per voice, so velocity → attack time makes hard notes snap while soft ones swell.
- Macros are a source and a destination at once. Everything routed into Macro 1 is summed with a hand-set offset and the M TUNE knob, which is Macro 1's own knob now (master tune is gone; autotune keeps the voices in tune), and the macro fans out to any number of destinations. Macros are worked out once a pass.
- Morph fades every knob of the layer towards a second patch before the engine reads the knobs at all.
The panel: knobs, pickup and four digits
24 of the 26 knobs sit behind three 8-way multiplexers. Each knob has a 100 nF capacitor at the multiplexer, so after switching address the reading needs about 4 ms to settle. The scan doesn't wait for it: it steps to the next address every 4 ms, between passes, and reads all three multiplexers at once, so every knob is read every 32 ms. A small dead band ignores the last bit of jitter, and values are smoothed over 10 ms so a turn never zips.
Two sets of settings (layers), two LFOs and four envelopes all share the same physical knobs. So when a knob's job changes (you load a patch, switch layer, or hold Shift), it goes into pickup: the sound keeps the stored value until you turn the knob onto it or past it. Try it:
Display: 70.
Shift is the Sync Source button, held or latched with two quick presses. Under Shift the filter ADSR knobs edit Env 3 and the amp ADSR knobs Env 4, with pickup, and every other knob nudges a secondary value (LFO delay and fade, drift, unison detune, bend range, the macro offsets) by how far it moves, so nothing jumps and nothing needs picking up. The buttons get second jobs too: compare the edit with the stored patch, undo a load, save to the current slot, copy a layer, open a settings page, panic.
The four-digit, seven-segment display shows real units while you turn a knob: 737 Hz of cutoff, 1.25 seconds of attack, -12 semitones, or a clock division like 1-16. Several buttons have new jobs, since the stock arpeggiator and sequencer are gone:
| Button | Now does |
|---|---|
| Seq 1 / Seq 2 | Choose the layer the knobs edit |
| Arp Up-Dn | Choose LFO 1 or LFO 2 for the LFO knobs and buttons |
| Arp Assign | MOD ASSIGN: build mod routes from the panel; hold it to browse them |
| Sync Source | Shift: hold, or double-press to latch |
| Sync Clock | Tap the internal clock's tempo; hold to restart the bar; Shift + press cycles the clock source. Its LED blinks on the beat |
| Rec + Seq 1 | Record sequence steps from the notes you play |
| LFO Shape | Step through nine shapes |
| Settings | A menu on the number keys: sync, retrigger, layers, envelope modes and curves, bend range, detune, voice mode, drift |
| Perf | Load a plain init sound |
Where things are stored
There are two memories. The chip's own flash holds code. A separate EEPROM chip holds your sounds, and it's the only memory that survives a firmware update untouched.
A patch record holds both layers' knobs, Env 3 and 4, LFO 2, the latching buttons, all the settings (layer mode, LFO sync, retrigger, shapes, step patterns, delays and fades, envelope modes, curves, delays and holds, voice modes, drift, scale, morph target, macro offsets), both layers' 16 mod routes and a 16-character name, and in its second half the step sequence, with its own checksum so it can be written on its own. New fields take reserved bytes, and an older record reads them as zero, which always means "what older firmware did". The one break was 0.8.0, which went from 200 patches of 256 bytes to 128 records of 768: the first start of 0.8.0 wiped the old records (the EEPROM backups keep them).
The stock factory bank is left exactly where the stock firmware put it, and any factory sound can be converted into a slot. Before this firmware first wrote to the EEPROM, a full image of it was saved: writing that image back is the way home to stock.
MIDI in: USB, SysEx and the 5-pin socket
The USB driver is written from scratch for the chip's USB hardware and shows up as a standard class-compliant MIDI device. It reports Behringer's own IDs, the name "PRO 800" and the same serial number the stock firmware used, so a Mac treats it as the device it already knows. Notes play on any channel.
Everything beyond notes and controllers travels as SysEx, MIDI's "system exclusive" messages. They start with Behringer's header F0 00 20 32 00 01 24 00, then a command byte. For example, 08 00 asks for the firmware version, and the synth answers 09 00 00 09 00 (0.9.0). The firmware understands dozens of commands: read or set any parameter or setting, read the panel, list, load, save and rename patches, import factory sounds, read and write mod routes and the sequence, run autotune, report timing, and the two DAC probes.
The 5-pin MIDI IN socket works too, from 0.7.6. Its opto-isolator feeds the chip's UART4 serial port, which receives at MIDI's 31,250 baud and interrupts on every byte. Clock ticks go straight to the clock, timestamped like USB's; everything else is queued and turned into the same packets USB delivers. It carries notes, controllers, pressure, bend, program changes and clock, so a keyboard with a MIDI out plays the synth with no computer. SysEx stays on USB.
The USB socket itself is a device port, like a printer's: the synth waits for a computer to talk to it, and it can't power or host a USB keyboard. A USB-only controller needs a computer, or a small USB MIDI host box, in between.
Updating safely
The PRO-800 has a small bootloader at the start of its flash. It's write-protected and nothing here ever touches it, so the synth can always be recovered. It accepts an image of up to 128 kB and erases flash sectors 4 and 5 before programming it. Installing a firmware goes like this:
pro800 install does all of this in one command. The erase runs from RAM, because code can't run from the flash sector it's erasing.What happens at power-on
The bootloader jumps into the firmware with its own clocks, interrupts and peripherals still running, so the first job is to put the chip back into a known state. Then, in order:
- Disconnect every sample-and-hold. All multiplexer enables go high so no capacitor can sample garbage.
- Clocks. The 8 MHz crystal is multiplied up to 168 MHz, with the 48 MHz USB needs.
- Timers and memory. The 1 ms tick and tuning timer start; master volume is set to zero; the EEPROM, panel and patch store come up.
- Patch store and tuning tables. If the EEPROM is still in an older layout of ours, the patch area is formatted first (ForM, about 2 s). The tuning tables are loaded, and the engine starts.
- Charge every capacitor. The whole refresh runs 20 times.
- Display and LEDs. The power LED lights, and the version shows for a moment.
- No tuning tables, or tables from a firmware that wrote the voltages differently? Then it tunes now, silently, showing tUnE, before anything else.
- Load the last patch, and the clock source and tempo. First comes one full knob scan, so pickup starts from the real knob positions.
- MIDI IN and USB start. Then the main loop runs forever, refreshing the watchdog on every pass.
What firmware can't change
Firmware decides voltages and switches; it can't rewire the voice board. These limits are set by the hardware:
| Can't | Because | What works instead |
|---|---|---|
| A different waveform, pulse width or resonance per voice or per layer | Each is one wire or switch for all eight voices | Pitch, cutoff and volume are per voice, and a route to a shared control follows the newest note |
| Mix two waveforms of one oscillator at different levels | Waveform buttons are on/off lines | Put the second waveform on the other oscillator and use its level |
| Host a USB keyboard plugged straight into the synth | The USB socket is a device port, and the chip runs its USB in device mode | The 5-pin MIDI IN socket, or a computer or USB MIDI host box in between |
| Send the layers to separate outputs | The voice board sums all voices into one mono signal | Per-layer volume with the VCAs; a hardware mod would be needed for more |
| Digital FM or effects at audio rate | The firmware never sees the audio, and voltages update every 0.3–2.4 ms | The analog poly-mod path (osc B and the filter envelope to osc A and the filter) is audio rate |
Within those walls there's a lot of room. Most of what makes a sound move (pitch, cutoff and volume, per voice, from any combination of sources) is pure software. The companion page, New territory for sound design, is about what to do with that room.