BRUME
vdev
Brume · Reference Manual · rev dev

Reference
Manual.

A complete description of Brume's synthesis engines, modulation, effects, and Lua scripting surface.

Overview

Brume is a multi-timbral instrument built on a CM5 reference platform. It runs four synthesis engines across four independent parts, each with six voices of polyphony (24 total), a state-variable filter per voice, dedicated modulation routing, and a shared effects chain. The entire interface runs on a 10.1-inch touchscreen.

The four engines correspond to four distinct approaches to electronic sound design: a six-operator FM engine with twelve data-driven algorithm topologies and a per-voice FM-index envelope; an additive harmonic engine with spectral scanning; a triangle-core timbral engine with wave-multiplier shaping; and a granular engine that generates pitched clouds of micro-oscillator grains.

Character

Brume runs four synthesis engines with a shared voice tail (state-variable filter, amp envelope, modulation router), so patches stay coherent across very different sources. Each engine has its own mechanism for continuous spectral change: algorithm routing and per-voice FM-index envelopes in FM, a scanning window in Harmonic, cascaded wavefolding in Timbral, grain scatter in Granular. No samples sit anywhere in the signal path; every voice is generated from live math.

The lineage worth naming is the Buchla 259 and Serge wavefolder tradition, the DX family’s phase-modulation surface, and the patch-on-a-small-computer approach of Norns and Plaits, rendered in software and unified under a single touchscreen. The default transition shape is Caffeinated, a pseudo-random walk, which sets the bias for the whole instrument: engines reveal themselves over tens of seconds rather than on first press, and loops rarely repeat quite the same way.

Interface

The top menu bar provides access to all pages: the four engine mode tabs (FM, HARMONIC, TIMBRAL, GRANULAR) on the left, and navigation pages (MOD, MIX, MIDI, SYS, LIBRARY, SCRIPT) on the right. Tapping a mode tab selects that engine for editing on the synth page.

Each synth page reflects live engine state. Parameter readouts update as values change, the signal-flow panel traces the shape of each box's input and output, and the MOD page shows LFO phase and sequencer positions as they advance.

Signal path

MIDI IN CHANNEL MAP FM HARMONIC TIMBRAL GRANULAR MOD MATRIX LFO · ENV · VEL FILTER MIXER LEVEL · PAN · MUTE SEND BUSES SATURATOR CHORUS DELAY REVERB LUA FX SCRIPT FX + MASTER LIMITER · STEREO AUDIO OUT

FM Oscillator

The FM engine is a six-operator phase-modulation synthesizer in the DX7 / Digitone lineage. Each operator is a sine wave; twelve data-driven algorithms determine which operators modulate which, and which are summed into the filter as carriers. A global FM index scales modulator contributions uniformly; a per-voice index envelope lets each note's FM depth decay independently, so a fresh attack rings brightly while held notes settle into their sustained partials, and a chord stab hit mid-sustain never re-brightens the already-ringing voices.

Brume FM engine page on the MOD sub-tab: FM index plus per-voice index envelope sliders on the left, SIGNAL FLOW diagram on the right showing six sine operators routed through the active algorithm topology, summed carriers, filter, and output. SCOPE meter and MODULATION panel below.
FM engine. Click to zoom.
6 OPS sine operators · FDBK (z⁻¹) ALGORITHM routing STACK · DOUBLE · TWIN · TRIO · FAN-IN · BRANCH HYBRID · ADDITIVE · PAIRS · TOWER · FUNNEL · CHAIN CARRIERS Σ selected ops FILTER OUT

ALGO tab: topology and feedback

ParameterRangeDefaultDescription
ALGO12 optionsSTACKAlgorithm selector. Each algorithm is a data-driven routing table: a bitmask per operator describing which other operators feed its phase, plus a carriers bitmask for which ops are summed into the filter. Tap to cycle: STACK (deep 6-op cascade, one carrier, classic bright FM bell), DOUBLE (two parallel modulator chains into one carrier), TWIN (two independent 3-op stacks), TRIO (three 2-op stacks), FAN-IN (five modulators all feeding one carrier), BRANCH (shared modulator tree), HYBRID (mix of series + parallel), ADDITIVE (all ops are carriers, no modulation), PAIRS (three 2-op modulator+carrier pairs), TOWER (asymmetric cascade with a side branch), FUNNEL (many-to-one convergence), CHAIN (linear chain with every op audible).
FDBK0 – 10.3Global feedback. Routes OP6's previous sample back into its own phase (and, where the algorithm nominates a self-feedback operator, into that operator's phase), warming the tone toward saw-like spectra at higher values.

RATIOS tab: per-operator frequency

ParameterRangeDefaultDescription
OP1–OP6 RATIO0.25 – 161.0 / 2.0 / 3.0 / 4.0 / 5.0 / 6.0Per-operator frequency ratio relative to the played note. Integer ratios produce harmonic spectra; non-integer ratios (e.g. 2.83, 5.17) produce the inharmonic, bell-like spectra that define classic FM timbres. Log-scaled, so a small knob nudge at the low end moves cents rather than octaves.

LEVELS tab: per-operator output and modulation

ParameterRangeDefaultDescription
OP1–OP6 LEVEL0 – 1tapered 0.8 → 0.1Per-operator level. For operators the algorithm marks as carriers, this is the output amplitude summed into the filter; for modulator operators, it scales the phase-modulation depth imparted on downstream operators. Defaults taper from OP1 to OP6 so a fresh patch doesn't start with harsh cascaded modulation.

MOD tab: FM index and per-voice index envelope

ParameterRangeDefaultDescription
FM INDEX0 – 100.7Global FM depth. Scales every modulator operator's contribution uniformly; at 0 the output is just the sum of the algorithm's carriers with no FM at all.
ENV DEPTH0 – 100Depth of the per-voice FM-index envelope added on top of the static FM INDEX floor. At 0 the envelope is off and each voice sees exactly FM INDEX. At higher values each voice's attack opens with extra FM depth that decays to its sustain level independently of other voices, producing the DX7-style tine character where a chord stab played into a held sustain doesn't re-brighten the already-sustaining notes.
ENV ATTACK0 – 5000 ms2 msAttack time of the FM-index envelope.
ENV DECAY0 – 5000 ms800 msDecay time from peak down to sustain.
ENV SUSTAIN0 – 10Sustain level of the FM-index envelope, relative to ENV DEPTH.
ENV RELEASE0 – 5000 ms400 msRelease time after note-off.

Harmonic Oscillator

The Harmonic engine generates sound through additive synthesis, combining eight individually controllable harmonics with spectral shaping tools. A Gaussian scanning window sweeps across the harmonic series, isolating or blending partials as its center and width change.

Brume Harmonic engine page: eight harmonic-level sliders (H1–H8) on the left; cyan SIGNAL FLOW on the right showing FM OSC, 8 HARMONICS, SCAN WINDOW (center + width), FILTER, OUT.
Harmonic engine. Click to zoom.
FM OSC · ratio FUNDAMENTAL H1 H2 H3 H4 H5 H6 H7 H8 TILT ODD / EVEN SPREAD SCAN WINDOW center + width FILTER OUT

SCAN tab: spectral scanning and waveform morph

ParameterRangeDefaultDescription
CENTER0 – 10.5Position of the scanning window across the harmonic series. At 0 the window centers on the fundamental; at 1 it centers on the 8th harmonic.
WIDTH0 – 11.0Width of the scanning window. Intermediate values produce a Gaussian falloff from the center.
MORPH0 – 10Per-harmonic waveform morph. Coupled to the scan window, so harmonics near the center receive more morph.
SPREAD0 – 10Phase randomization between harmonics. Thickens the sound without changing its spectral content.

Timbral Oscillator

The Timbral engine starts from a triangle-wave core and shapes it through a wave-multiplier circuit that transitions from soft saturation to cascaded wavefolding as the timbre control increases. An expanded symmetry parameter tilts the triangle core before it enters the shaper.

Brume Timbral engine page on the FILTER sub-tab: cutoff, resonance, and filter envelope sliders on the left; amber SIGNAL FLOW on the right showing FM OSC, TRIANGLE (symmetry tilt), WAVE MULT (timbre × stages, with feedback), +SUB OSC ÷2, FILTER, OUT.
Timbral engine. Click to zoom.
FM OSC · linear TRIANGLE · symmetry tilt WAVE MULT · timbre × stages FB · z⁻¹ + SUB OSC ÷ 2 SUM FILTER OUT

SHAPE tab: wave multiplier and feedback

ParameterRangeDefaultDescription
TIMBRE0 – 10Wave multiplier drive. At 0 the output is a pure triangle. From 0 to 0.3 a soft-clip saturator rounds the peaks; above 0.3 a triangle wavefolder blends in.
SYMMETRY-1 – 10Triangle tilt and asymmetric bias. Positive values stretch the rising slope; negative values produce the inverse.
STAGES1 – 41Number of wavefolding stages. Each stage cascades another triangle-fold pass, densifying the harmonic spectrum.
FEEDBK0 – 10Self-modulation feedback. The oscillator's previous output sample modulates its own frequency, producing growling textures at higher values.

Granular Oscillator

The Granular engine generates pitched clouds of micro-oscillator grains: short bursts of waveform output (1–500 ms) that overlap to produce evolving textures. Unlike sample-based granular systems, Brume synthesizes each grain from scratch.

Brume Granular engine page on the CLOUD sub-tab: density, size, scatter, spread, drift, and position sliders on the left; magenta SIGNAL FLOW on the right showing GRAIN CLOUD (density × scatter, drift), MORPH WAVE (sin to tri to saw to sq, with FM sidecar), GRAIN ENV (size + shape), NORMALIZE 1/√n, FILTER, OUT.
Granular engine. Click to zoom.
MORPH WAVE · sin → tri → saw → sq FM HANN GAUSS TRAP window GRAIN CLOUD · density × scatter DRIFT NORMALIZE · 1 / √n FILTER OUT

CLOUD tab: grain generation

ParameterRangeDefaultDescription
DENSITY0 – 10.3Grain spawn rate. Maps from 1 to 200 grains per second. Spawn timing includes a 30% jitter.
SIZE0 – 10.2Grain duration. Maps from 1 ms to 500 ms. Each grain's actual length varies by ±20%.
SCATTER0 – 10Pitch randomization per grain. At maximum, each grain's pitch is randomized within ±2 octaves of the fundamental.
SPREAD0 – 10Stereo pan randomization per grain.
DRIFT0 – 10Slow pitch random walk applied to the base frequency. Creates gradual, organic pitch wandering.

SVF Filter & Envelope

Each voice includes a state-variable filter operating in lowpass mode, with a dedicated ADSR envelope that modulates the cutoff frequency. The filter and envelope parameters are identical across all four engines.

ParameterRangeDefaultDescription
CUTOFF20 – 20,000 HzvariesFilter cutoff. Smooth resonant rolloff above this frequency.
RESO0 – 10.1Resonance. Values near 1.0 produce self-oscillation.
ENV DEP0 – 10.3Envelope depth. Modulates cutoff above its static value.

Modulation: LFOs and step sequencers

Brume Modulation page on the FM part: LFO 1 and LFO 2 controls (shape, rate, mode) and SEQ 1 step values on the left; LFO PREVIEW canvas on the right showing both LFO shapes traced in real time.
MOD page. Per-part LFO and sequencer controls with real-time preview.

Each of Brume's parts has an independent modulation router with two LFOs and two step sequencers. These four sources can be assigned to any synthesis parameter through the MOD page.

Evaluation formula The raw source value (0–1) passes through the response shape, is centered to ±0.5, then scaled by depth. The resulting offset is added to the parameter's base value and clamped to its valid range.

Shape library · 24 transitions

Brume’s LFOs, step sequencer transitions, and modulation assignment response curves all draw from the same 24-shape library, ported from the Formfactor plugin. Each shape has a descriptive name (shown large) and its engineering enum name (shown below) for scripting and patch editing. The default shape is Caffeinated (ChaosHeavy), a pseudo-random walk chosen as the default because it’s the most musically surprising of the 24.

Mixer

MIX page: MIXER section at top with horizontal level bars per part (FM, HARMONIC, TIMBRAL, GRANULAR), a master row, and per-part mute / solo buttons. EFFECTS section below shows the master FX chain (Saturator, Delay, Chorus, Reverb selected, Output) with the Reverb tab's controls visible (type selector, predelay, decay, damping, mix).
MIX page. Per-part levels, master, and the master FX chain.

The MIX page provides a four-channel mixer with horizontal faders for each part (FM, Harmonic, Timbral, Granular), along with mute and solo controls. Each part’s level defaults to 0.8 and can be adjusted from 0 to 1. Each part also has independent delay and reverb send levels that control how much of the signal reaches the shared delay and reverb buses. A master volume control governs the final output level before the limiter. All level changes are smoothed to prevent clicks.

Effects

The EFFECTS panel on the MIX page provides four processing stages organized as tabbed controls: Saturator, Chorus, Delay, and Reverb. Saturator and Chorus operate as inserts on the dry master bus, processing all parts equally. Delay and Reverb operate as send effects, where each part’s independent send level controls how much signal reaches the effect. This architecture follows the model used in hardware instruments like the Elektron Digitone, where a dry bass line can coexist with a heavily reverbed pad without one treatment bleeding into the other.

Saturator

ParameterRangeDefaultDescription
TYPESoft / Hard / Tape / TubeSoftSaturation algorithm. Soft uses tanh waveshaping; Hard clips at ±1; Tape applies asymmetric soft clipping; Tube adds even harmonics via polynomial distortion.
DRIVE0 – 10Pre-gain into the saturation circuit. At 0 the signal passes clean; at 1 the input is boosted 5× before shaping.
MIX0 – 11Dry/wet blend.

Chorus

ParameterRangeDefaultDescription
RATE0.1 – 5 Hz0.5LFO speed controlling the modulation of the internal delay lines. Left and right voices run at slightly offset rates for stereo width.
DEPTH0 – 10.3Modulation depth. Higher values produce more pronounced pitch variation and wider stereo field.
MIX0 – 10Dry/wet blend.

Delay

The stereo delay supports both free-running millisecond timing and tempo-synced musical divisions. When a sync division is selected, the delay time auto-calculates from the transport BPM. The delay uses cross-channel ping-pong routing with a damping filter in the feedback path to darken successive repeats.

ParameterRangeDefaultDescription
SYNCFREE / MIDI / 1/1 – 1/8tFREETempo sync mode. FREE uses the TIME slider directly. MIDI and the musical divisions (including dotted and triplet variants) derive the delay time from the current transport BPM.
TIME10 – 2000 ms300Delay time in free mode. Overridden when a sync division is active.
FEEDBACK0 – 0.950.3Amount of delayed signal fed back into the input. Values above 0.8 produce long, building repeats.
DAMPING0 – 10.3High-frequency rolloff in the feedback loop. At 0 the repeats stay bright; at 1 they darken rapidly, simulating tape degradation.
MIX0 – 10Dry/wet blend.

Reverb

Four reverb algorithms are available, each built from networks of allpass diffusers and parallel comb filters with damped feedback. All algorithms share the same parameter set; the internal topology and delay lengths differ to produce distinct spatial characters.

ParameterRangeDefaultDescription
TYPEPlate / Room / Hall / SpringPlatePlate (Dattorro): dense, bright, classic studio plate character. Room: shorter delays, clearer early reflections, intimate. Hall: long diffusion chains, expansive tail. Spring: allpass cascade with metallic chirp and resonant character.
PREDELAY0 – 200 ms20Delay before the reverb onset. Separates the dry signal from the reverb tail, preserving transient clarity at higher values.
DECAY0.1 – 82.0Reverb tail length. Controls the feedback coefficient in the comb filter network. Higher values produce longer, more sustained reverberation.
DAMPING0 – 10.4High-frequency absorption in the reverb tail. Low values produce bright, shimmering tails; high values simulate absorptive room surfaces.
MIX0 – 10Dry/wet blend.

MIDI

MIDI page: connected MIDI ports listed at top (nanoKONTROL2 plus the f_midi USB gadget); ENGINE-to-MIDI-channel routing rows on the left with live note-count indicators (FM showing 4 notes, HARMONIC showing 1 note); a CLOCK section below the routing with a BPM readout (132, synced) and a SOURCE selector (Off, Master, Sync — with Sync selected); CC MAPPING on the right with per-engine sub-tabs (FM selected) listing existing bindings (CC 3 to FmIndex, CC 4 to FmFeedback, CC 74 to Op2Ratio); LEARN and RESET buttons at the bottom.
MIDI page. Port connections, per-engine channel routing, clock-source controls, and CC binding list. The LEARN flow is shown in the next two screenshots.

Brume receives MIDI over USB from any class-compliant device (control surfaces, keyboards, sequencers) and from the Meridian USB bridge to a host DAW (see below). All sources feed the same engine in parallel, so a controller plugged into a USB-A port and the DAW’s MIDI output over Meridian both reach Brume simultaneously without any routing setup. DIN 5-pin gear connects through any class-compliant USB-to-DIN bridge (e.g. iConnectMIDI4+).

The MIDI page has three sections: channel routing on the left (a part-centric list where each part shows its assigned MIDI channel; tap the channel box to cycle through CH 1–16 or NONE), CC mapping in the middle (the LEARN workflow plus the list of persisted CC→parameter bindings), and the clock controls on the right. Multiple parts can share the same channel for layered playback, and a single channel can be reassigned at any time without stopping playback.

Note-off messages use a promiscuous release strategy: when a note-off arrives on any part, Brume also releases that note on all other parts. This prevents stuck notes when channel assignments change during a performance. MIDI CC messages 120 (All Sound Off) and 123 (All Notes Off) are recognized and release all active voices on the targeted part.

Default routing Channel 1 → FM (Part 1), Channel 2 → Harmonic (Part 2), Channel 3 → Timbral (Part 3), Channel 4 → Granular (Part 4). Channels 5–16 are unassigned by default.

CC Mapping: LEARN workflow

The CC MAPPING panel binds incoming MIDI CCs to Brume’s synthesis parameters. Brume ships with sensible defaults (CC 1 → Filter Cutoff, CC 2 → Filter Resonance, CC 7 → Master Volume, CC 11 → Filter Envelope Depth, plus a few part-specific bindings), and the LEARN workflow lets you add or override any binding directly from the touchscreen. No keyboard required.

The flow has two states:

MIDI Learn LISTENING state. An amber banner at the top of the CC MAPPING list reads 'LISTENING FOR MIDI CC… (turn a knob or tap LEARN to cancel)'. The LEARN button at the bottom now glows amber and reads 'LISTENING…'; RESET sits next to it. Channel routing on the left is unchanged.
1. Tap LEARN. The card enters LISTENING and any incoming CC on the active channel captures.
MIDI Learn DETECTED state. The amber-framed card at the top of CC MAPPING shows 'DETECTED · CH 1 · CC 16 · val 8' with a DESTINATION grid of parameter names below (FmIndex highlighted). CANCEL and SAVE BINDING buttons at the bottom of the card; existing CC bindings are still listed underneath.
2. CC captured. The card flips to DETECTED, showing the channel, CC number, and value, with every bindable destination for the active engine. Pick one and tap SAVE BINDING; the mapping lands in the list below and persists to ~/.brume/cc-bindings.json.
ActionBehavior
Tap LEARNArms capture mode. The button glows orange and an inline card appears at the top of the binding list reading “LISTENING FOR MIDI CC… (turn a knob or tap LEARN to cancel)”.
Move a knob / faderCapture is continuous: the card updates to show the most recent CH / CC / value, so you can wiggle the intended control and confirm Brume sees the right one. Useful when DAW transport sync is also emitting CCs in the background.
Pick a destinationThe card’s DESTINATION grid lists every parameter for the part the captured CC’s channel routes to (or every FX-slot parameter when an FX target is picked). Tap one to select; it highlights in the part color.
Tap SAVE BINDINGWrites the binding and disarms capture. The new mapping takes effect immediately.
Tap CANCELDiscards the in-progress capture without writing anything.
Tap RESETTwo-tap confirm. Wipes all CC bindings, FX bindings, and channel routing back to factory defaults. Use when an experiment goes sideways.
Persistence All CC bindings (including channel routing and FX-slot bindings) are written atomically to ~/.brume/cc-bindings.json on every change and reloaded at startup. The file is human-readable; advanced users who need keyboard-typed CC numbers (touchscreen-only LEARN doesn’t expose a number pad) can edit it by hand over SSH.

Transport & Clock

The CLOCK window on the MIDI page controls Brume's internal transport, which drives tempo-synced delay divisions and step sequencer timing. Three clock modes determine how the transport derives its tempo:

ModeBehavior
OffInternal clock at the configured BPM. No MIDI clock is sent or received.
MasterInternal clock at the configured BPM. Brume sends MIDI clock (24 PPQN) to connected devices.
SyncBrume syncs to incoming MIDI clock messages. The BPM is estimated from the tick interval and smoothed to avoid jitter. MIDI Start, Stop, and Continue messages are recognized.

The BPM slider ranges from 20 to 300 and affects all tempo-dependent features: delay sync divisions, step sequencer beat triggers, and future arpeggiator patterns. When the clock is in Sync mode, the BPM display shows the estimated tempo from the incoming MIDI clock source.

Controllers

Brume supports external hardware control surfaces through two independent paths. Recognised surfaces are identified by their USB / ALSA port name on connect and get a built-in binding tailored to the actual Brume UI, with no configuration step. Any other MIDI controller can still be bound through the MIDI Learn flow on a CC-by-CC basis. The two paths coexist: a recognised surface does not block Learn from working on other controllers connected at the same time.

The tradeoff: a built-in binding covers the full surface out of the box but is fixed by the firmware; MIDI Learn is fully user-defined but scales one CC at a time. Power users can also reach the Lua scripting layer (see Extending Brume with Lua) to define per-CC behaviour that neither path provides.

Supported surfaces

Brume ships built-in support for two control surfaces: the Korg nanoKONTROL2 and the Novation Launch Control XL 3. Both are recognised on connect by their ALSA port name, then routed around the MIDI Control Matrix directly to the UI. A screen-follows binding maps the top encoder / knob row to the active sub-tab’s parameters, so switching engines or sub-tabs silently rebinds those controls to whatever is on screen.

The Korg nanoKONTROL2 is detected by the substring nanokontrol2 in the port name. Eight knobs and four faders cover the active sub-tab plus the MIX and MOD pages; Track and Marker buttons cycle engines and sub-tabs respectively.

Full factory-preset mapping: CC numbers and per-control action
ControlCCAction
Top-row knobs 1–816–23First eight parameters of the currently-visible sub-tab on any engine. Tabs with fewer than eight params leave the higher knobs idle. Continuous value, no press edge.
Faders 1–40–3Mixer level for FM / Harmonic / Timbral / Granular respectively. Mirrors the MIX page fader per strip; changes are reflected on the MIX page in real time.
Faders 5–84–7Reserved.
S buttons 1–432–35Exclusive solo toggle for FM / Harmonic / Timbral / Granular. Pressing S on part N mutes the other three parts; pressing the same S again un-solos. Press edge only.
M buttons 1–448–51Per-part mute toggle. Press edge only.
S / M buttons 5–8, R 1–836–39, 52–55, 64–71Reserved.
Track ◄ / ►58 / 59Cycle active engine mode in menu-bar order (FM → Harmonic → Timbral → Granular, wraps in both directions). Press edge only.
Marker ◄ / ►61 / 62Cycle the active engine’s sub-tabs (e.g. ALGO → RATIOS → LEVELS … on FM). Press edge only.
Marker ◎60Reserved.
Cycle46Reserved.
Transport (Play / Stop / Rec / FF / Rew)41–45Reserved.
Factory CC Mode required The nanoKONTROL2 must be in its factory CC Mode (the default preset) for the CC numbers above to match. If the unit has been edited with Korg Kontrol Editor into a different profile, the numbers will differ; the workaround is to reset the device to factory defaults rather than editing Brume’s binding.

The Novation Launch Control XL 3 is detected by the substring lcxl3 in the port name (or launch control xl on platforms that report the full product name). The Mk3 exposes four ALSA ports per device; only the surface MIDI port is bound, with the DAW (HUI/Mackie) and DIN passthrough siblings ignored.

Full factory custom-mode mapping: CC numbers and per-control action
ControlCCAction
Encoder row 1 (top, 1–8)13–20First eight parameters of the currently-visible sub-tab. Same screen-follows path as the nanoKONTROL2 top knob row, so a turn moves the active parameter on the audio thread without waiting for a UI tick. Continuous value, no press edge.
Encoder rows 2 & 321–28, 29–36Reserved.
Faders 1–45–8Mixer level for FM / Harmonic / Timbral / Granular. Mirrors the MIX page faders per strip.
Faders 5–89–12Reserved.
DAW Control pads 1–4 (top row)37–40Direct engine select: pad 1 → FM, pad 2 → Harmonic, pad 3 → Timbral, pad 4 → Granular.
DAW Control pads 5–8 (top row)41–44Reserved.
DAW Mixer pads 1–6 (bottom row)45–50Direct sub-tab select within the active engine. Pad N selects sub-tab N−1; FM and Harmonic have six sub-tabs, Timbral and Granular have five (the unused pad on those engines no-ops).
DAW Mixer pads 7–8 (bottom row)51–52Reserved.
PAGE / TRACK / Record / Play / Shift / ModeNo MIDI emission in the factory custom mode. The Mk3 firmware reserves these for navigating between templates and pages on the device’s OLED, and Novation Components does not expose them as bindable in the Custom Mode editor. Not reachable from Brume.
Default factory custom mode The mapping above assumes a fresh-out-of-box LCXL3 on its default Custom 1 template. If a Custom slot has been edited in Novation Components into a different layout, the CC numbers will differ; the workaround is to reset that slot to factory defaults rather than editing Brume’s binding.

Bring your own controller

Any controller not in the recognised-surfaces list works through MIDI Learn on the MIDI page. Tap LEARN, turn a knob or press a button, then pick a destination from the binding card (see the CC Mapping: LEARN workflow section for the LISTENING and DETECTED states walked through). Each binding persists until removed. Because Learn runs at the Control Matrix layer, it is completely independent of the engine on screen and of the recognised-surface path.

Where LEARN bindings live Every binding is serialised to ~/.brume/cc-bindings.json on the device as part of the full Control Matrix. The file is written after each LEARN save, binding removal, or reset, and read at startup; a missing or malformed file is treated as “no bindings yet” (the defaults load and startup continues). The file is plain JSON, so it can be inspected or hand-edited for bulk operations like exporting a working set of bindings for backup or sharing between devices.

To add a new recognised surface at the code level, three small edits cover it:

FileChange
crates/midi-io/src/lib.rsIn start_with_script_tx, extend the port-name match block that sets controller_kind. Add a case matching the new surface’s ALSA port name (substring, case-insensitive) and set a unique kind string such as "LaunchControlXL3".
crates/ui-app/src/ui.jsIn window._onControllerCc / window._onControllerNote, add a branch keyed on the kind argument. The screen-follows pattern (knob index → _tabParams[i]) is reusable; any extra controls follow the same structure as the existing nanoKONTROL2 branches.
brume-web/docs.htmlAdd a mapping table under Supported surfaces for the new controller so users can see what every control does.

The protocol layer (crates/app-protocol/src/lib.rs) already carries EngineToUi::ControllerCc and EngineToUi::ControllerNote with a kind field, so no additional message variants are needed for the common case of routing a new surface through the existing screen-follows logic. Custom behaviour that escapes the screen-follows model (a pad grid triggering chords, for example) is easiest to implement directly in the UI branch that handles that surface’s kind.

Meridian: MIDI and Audio to your DAW

Meridian is Brume’s integrated audio-and-MIDI bridge to a host computer, comparable in role to Elektron’s Overbridge for the Elektron range but built on open USB class-compliant standards so it works on Mac, Windows, and Linux without proprietary drivers. A single USB cable carries 8-channel audio out, bidirectional MIDI, and MIDI clock simultaneously.

In a DAW, arm one or more audio tracks with Brume’s capture as the input, route MIDI out from a track to Brume’s MIDI port, and Brume behaves as a first-class external instrument just like a Prophet or Moog patched into a multi-channel audio interface, with the additional convenience that it’s all on a single cable.

Incoming notes, CC, and MIDI clock over Meridian are parsed identically to other MIDI sources: they flow through the channel map, respect CC bindings, and drive the Sync clock mode. Audio output is structured for multi-track DAW workflows by default.

AUDIO OUTPUT panel on the SYS page with Meridian (USB to DAW) selected as the active output. HDMI 0 (touchscreen) and HDMI 1 are listed below as alternative outputs. The CHANNELS section maps Meridian stem pairs to parts and the spatial labels macOS will show in a DAW: 1–2 FM (Front L / R), 3–4 HARMONIC (Front Center / LFE), 5–6 TIMBRAL (Back L / R), 7–8 GRANULAR (Front L / R of Center). Sample rate 48000 Hz, format f32 stereo.
AUDIO OUTPUT on the SYS page. Meridian active, with the per-part stem map visible.

Per-part stems (8 channels)

Each of Brume’s four parts writes its own dry mono signal to a dedicated stereo channel pair on the USB capture endpoint:

ChannelsSource
1 – 2FM (dry, pre-FX, mono duplicated to L/R)
3 – 4Harmonic (dry, pre-FX, mono duplicated to L/R)
5 – 6Timbral (dry, pre-FX, mono duplicated to L/R)
7 – 8Granular (dry, pre-FX, mono duplicated to L/R)

Stems are dry: no master saturation, chorus, delay, or reverb. The intent is that DAW users already have better plugin FX than anything Brume ships internally, and recording dry preserves total flexibility. Brume’s master FX chain still computes for the local monitoring path (HDMI / DAC) so your touchscreen monitoring still sounds finished, but the USB stems are clean. The SYS page includes a compact channel-mapping reference (Ch 1-2 • FM / 3-4 • Harmonic / 5-6 • Timbral / 7-8 • Granular) so you can cross-check your DAW’s input picker without leaving the device.

macOS channel labels Apple’s class-compliant USB audio driver labels Brume’s eight capture channels with spatial-position names (Front Left, Front Right, Front Center, LFE, Back Left, Back Right, Front L of Center, Front R of Center) instead of per-part names. This is a class-compliant limitation, not a Brume choice. The fix is a one-time channel rename in your DAW’s I/O panel (Bitwig, Logic, Ableton, Reaper all support it) which then persists across sessions.

The mapping between channel pair, Brume part, and the spatial label the DAW will display:

Channel pairBrume partDAW spatial label
1–2 FMFront L / R
3–4 HarmonicFront Center / LFE
5–6 TimbralBack L / R
7–8 GranularFront L / R of Center

Use this when wiring input tracks in the DAW, or as the source of truth when performing the one-time channel rename to “FM”, “Harmonic”, and so on. The same mapping is also available on the device itself in the SYS page, collapsed to save space.

macOS aggregate setup Apple’s driver splits bidirectional devices into separate input and output entries in Core Audio (you’ll see “Capture Inactive” and “Playback Inactive” in Audio MIDI Setup until something opens them). If you have another audio interface and want Brume’s channels alongside your existing I/O, create an Aggregate Device that combines Brume’s capture half with your main interface (e.g. MOTU, RME) and point your DAW at the aggregate. If Brume is your only interface, no aggregate is needed.

Meridian expands in capability over firmware releases. Already shipped: 8-channel per-part stems, bidirectional MIDI with clock, the channel-mapping SYS reference. Active follow-ons: a USB-NCM virtual network interface for the brumectl companion CLI, optional stripping of the UAC2 Feature Unit so the macOS volume slider disappears for bit-perfect passthrough.

Library

LIBRARY page on the HARMONIC tab: five mode sub-tabs at the top (FM, HARMONIC, TIMBRAL, GRANULAR, PERF) and a SAVE button on the right. A single saved patch row shows the patch name (HARMONIC-9298) with LOAD and DELETE buttons.
LIBRARY page. Patch and perf browser; SAVE captures current state for the active tab.

The LIBRARY page holds two kinds of recallable state: patches (a single engine's parameter state, or a single FX chain snapshot) and perfs (a whole-instrument snapshot containing all four engines' patches plus the FX chain plus mixer state). The mode tabs at the top switch between the FM, HARMONIC, TIMBRAL, GRANULAR, and FX patch browsers, plus a PERF tab for the whole-instrument snapshots.

Tapping SAVE captures current state for the active tab. On a patch tab (FM / HARMONIC / TIMBRAL / GRANULAR / FX) this writes just that engine's or the FX chain's parameters. On the PERF tab it writes the full instrument: every part's patch, the FX chain, the mixer levels and sends. Each row in the list has explicit LOAD and DELETE buttons; LOAD applies the saved state to the engine, DELETE removes the file from disk. Loading a patch switches the display to that engine's synth page so the slider positions visibly snap to the loaded values; loading a perf applies every part + FX + mixer in one batch, shows a centered LOADED PERF confirmation, then drops you on the first populated engine's page.

Storage layout ~/.brume/library/{fm,harmonic,timbral,granular,fx,perf}/*.json: one directory per mode for patches, plus perf/ for whole-instrument snapshots. Atomic write-then-rename on every save survives unexpected power loss.

Every patch and perf file carries a small metadata envelope alongside its parameters: name, tags (the engine mode is auto-inserted on save), created_at and modified_at timestamps (ISO 8601 UTC), the Brume version that wrote the file, and optional author / description / notes fields. Unknown JSON fields are preserved on save-reload round-trips, so files written by a newer Brume don't lose data when read by an older binary. Both patch and perf schemas are versioned; new fields arrive as optional additions rather than breaking rewrites.

A perf embeds copies of each part's patch state (not references) so rename or delete of a source patch can't silently break a perf. Each embedded slot carries a non-authoritative source_patch breadcrumb for UI context, but that name is never consulted at load time; the embedded params are the source of truth.

System

SYS page: AUDIO OUTPUT section with the active output (Meridian) plus alternative options (HDMI 0, HDMI 1) and a per-pair Meridian stem mapping (1–2 FM Front L/R, 3–4 HARMONIC, 5–6 TIMBRAL, 7–8 GRANULAR), sample rate, and format. MIDI section listing connected device and ports. SYSTEM section with version, engine config, active voice count, tempo, clock source, and SoC temperature.
SYS page. Audio output selector, Meridian channel mapping, MIDI ports, and live system diagnostics.

The SYS page is Brume’s diagnostic and configuration surface. Every value on the page is read live from the running system; nothing is hardcoded. Plug in a different display, swap controllers, change sample rate, switch audio outputs, and SYS reflects it immediately. Sections are accent-colored: green = audio, cyan = MIDI, orange = system, magenta = display.

Audio Output

The audio-output section picks where Brume’s master mix lands. Brume enumerates every ALSA card on the device (the USB Meridian gadget, the HDMI output through the touchscreen speakers, any DAC hat, and any USB audio interface plugged into a USB-A port) and renders one row per detected output. The active device shows in the section accent color with a filled dot and an “ACTIVE” label; alternate devices render below as tappable “OPTION” rows. Tapping an option tears down the current audio stream and reopens on the chosen device with a brief (~100–200 ms) silence gap. The choice persists to ~/.brume/settings.json and is restored at startup.

Default vs. fallback First-boot default is Meridian (the USB gadget). If the persisted device is missing on a later boot (e.g. you persisted an HDMI panel that’s not currently connected), Brume falls back to the first available output and logs a warning. The choice stays pointed at the missing device so reconnecting it picks back up where you left off.
CHANNELS: Meridian stem to DAW spatial label

On-device recap of the mapping between the eight Meridian stems, their Brume part, and the spatial-position label Apple’s class-compliant UAC2 driver shows in the DAW. The full treatment lives in Meridian.

Channel pairBrume partDAW spatial label
1–2 FMFront L / R
3–4 HarmonicFront Center / LFE
5–6 TimbralBack L / R
7–8 GranularFront L / R of Center

SAMPLE RATE shows the actual rate the audio backend opened the device at, typically 48 000 Hz on Meridian, HDMI, and any modern audio interface. FORMAT shows the engine’s internal sample format.

MIDI

DEVICE shows the connected MIDI input by its OS-reported name (e.g. nanoKONTROL2). PORTS lists every MIDI port currently feeding the engine, joined with “ + ” when multiple sources are attached; a USB control surface and Meridian’s f_midi endpoint commonly run side by side. With no MIDI device connected, both rows show a placeholder dash.

Hardware

Hardware diagnostics for the CM5 reference platform. TEMPERATURE reads from the CM5 thermal sysfs and updates once per second. MEMORY shows the in-use resident memory for the Brume process. UPTIME is system uptime since boot. ENGINE reports the configured polyphony layout (4 parts × 6 voices = 24 total).

Display

RESOLUTION is detected from the connected monitor at startup via GDK and used to compute the auto-fit zoom level. Brume is canvas-designed against a 1024×600 logical resolution and auto-scales to whatever panel you plug in (the reference 1920×1200 touchscreen runs at scale 1.875). FPS shows the animation frame-rate cap. TOUCH reads the connected touch input device’s OS-reported name, useful when troubleshooting input issues or confirming the touchscreen probed correctly at boot.

BRUME_UI_SCALE override If the auto-fit scale isn’t what you want (e.g. you want pixel-doubled GEM aesthetic on a 1080p panel), set BRUME_UI_SCALE=2.0 in the environment before launching Brume. SYS’s RESOLUTION row still shows the panel’s native size; the override only affects the UI zoom multiplier.

Extending Brume with Lua

Brume SCRIPT page: list of available Lua scripts under ~/brume/scripts/, rendered as path-prefixed entries (controllers/, instruments/, studies/). A green RUNNING banner at the top shows the currently-loaded script (instruments/granular-pad.lua) with an UNLOAD button; other entries have LOAD buttons.
SCRIPT page. Available scripts listed by relative path, with the active script's RUNNING banner at the top.

Brume embeds a Lua 5.4 scripting engine. Scripts are loaded from ~/brume/scripts/ and managed through the SCRIPT page.

API reference

-- Part constants. Targets for every part-addressed call.
brume.FM        -- part 0
brume.HARMONIC  -- part 1
brume.TIMBRAL   -- part 2
brume.GRANULAR  -- part 3

-- Any parameter on any part (name is the ParameterId string)
brume.set_param(part, name, value)

-- Trigger notes; velocity is 0.0–1.0
brume.note_on(part, note, velocity)
brume.note_off(part, note)

-- Chord and scale helpers
local notes = brume.chord(note.C4, "maj7")

-- FM algorithm constants: normalized 0..1 tap values accepted by
-- the engine's Algorithm parameter, so they slot into set_param directly.
brume.set_param(brume.FM, "Algorithm", brume.ALG.FAN_IN)
-- Also: STACK DOUBLE TWIN TRIO FAN_IN BRANCH HYBRID ADDITIVE
--       PAIRS TOWER FUNNEL CHAIN

-- Declarative FM patch. Sets algorithm, per-op ratios + levels,
-- feedback, and FM index in a single call. Any field is optional.
brume.set_fm_patch(brume.FM, {
  algorithm = brume.ALG.HYBRID,
  ratios    = {1.0, 2.0, 3.01, 4.0, 5.03, 6.0},
  levels    = {0.6, 0.35, 0.22, 0.14, 0.1, 0.07},
  feedback  = 0.2,
  index     = 0.7,
})

Coroutine clock

clock.run(function()
  while true do
    brume.note_on(brume.TIMBRAL, note.C3, 0.4)
    clock.sync(1/4)  -- wait a quarter note
    brume.note_off(brume.TIMBRAL, note.C3)
    clock.sync(1/4)
  end
end)
Hot-reload If a loaded script file is modified on disk, Brume detects the change within 2 seconds and automatically reloads, calling cleanup() on the old version and init() on the new one.

Brumectl: companion CLI

brumectl is the host-side companion command-line tool for Brume: a single Rust binary you run on your workstation (Mac, Linux, or WSL) to install Brume onto a CM5, push binary updates, open a maintenance shell, and probe device vitals. It is scoped to Brume devices specifically; every subcommand assumes the device on the other end is running Brume.

A bare brumectl invocation prints help. Every action is explicit.

Commands

CommandStatusDescription
installshippedPrimary onboarding path. Takes a reachable CM5 running Pi OS Lite and turns it into a Brume appliance over SSH: probes the target, apt-installs runtime packages, fetches the matching brume aarch64 binary (auto-downloaded from GitHub Releases by default, with SHA-256 verification against the published sidecar; override with --binary PATH or $BRUME_BINARY for a local build), copies it to /usr/bin/brume, writes appliance configs (labwc autostart, brume.service, ALSA, tty1 autologin, transparent cursor theme), and verifies. Flags: --update (binary-only refresh, ~5 s), --dry-run (preview without touching the target), --binary PATH (use a local binary instead of fetching), --no-download (refuse to fetch; fail fast if no local build), --force-download (re-fetch even if cached).
flashshippedAlternate onboarding path for users who prefer a pre-baked image. Interactive wizard that writes brume-cm5-X.Y.Z.img.gz straight to the eMMC over rpiboot, gathering WiFi credentials, hostname, and SSH public key, seeding the boot partition, and verifying post-boot. Requires the CM5 in rpiboot mode (BOOT jumper shorted, USB-C to your Mac) and sudo. macOS only today (shells out to diskutil and ioreg).
statusshippedOne-shot SSH probe that reports firmware version, kernel, uptime, memory and temperature, the Brume process state, and network interfaces. Falls back to ARP-scan discovery when mDNS resolution fails.
shellshippedPass-through SSH shell to the device. Honours $BRUME_HOST and $BRUME_SSH_KEY as well as the global --host and -i flags.
watchpartialLive three-panel ratatui dashboard: device vitals (working), console stream (stub), script watcher (stub). The console and watch panels light up once the device-side logging socket lands.
updateplannedPush a signed image bundle or app tarball to the device with A/B slot management and rollback on boot failure. Channels: stable and beta.
logsplannedTail Brume’s journal or /var/log/brume.jsonl over SSH; will also feed the watch dashboard’s console panel.
config get / setplannedRead and write user-facing config (WiFi, hostname, MIDI channels, audio routing) without a re-flash.
recoverplannedForce boot into the read-only recovery partition.
channelplannedSwitch update channel (stable / beta); each channel is gated by a separate signing key.
doctorplannedDiagnostic mode: checks Audio MIDI Setup, Meridian UAC2 endpoint visibility, and common bring-up failures.

Global flags and environment

Two flags and two env vars apply to every subcommand that talks to a device:

The install subcommand resolves the brume aarch64 binary in this order: --binary PATH (CLI flag), $BRUME_BINARY (env var), local workspace cross-build under target/aarch64-unknown-linux-gnu/release/, user cache (~/.cache/brumectl/binaries/ on Linux, ~/Library/Caches/brumectl/binaries/ on macOS), then download from GitHub Releases for the matching brumectl version with SHA-256 verification. Pass --no-download to refuse the network fetch, or --force-download to re-fetch a cached entry.

Typical install flow

# First-time install onto a fresh Pi OS Lite CM5
brumectl -i ~/.ssh/id_brume_cm5 install

# Binary-only refresh (edit source → cross-build → push)
brumectl -i ~/.ssh/id_brume_cm5 install --update

# Preview the install without running it
brumectl -i ~/.ssh/id_brume_cm5 install --dry-run

The install runs in six phases: probe (SSH + sudo + arch + OS checks), apt (runtime packages), binary (/usr/bin/brume), configs (labwc / systemd / ALSA / cursor theme), autologin (tty1 auto-login as the install user), verify. --update skips apt + configs + autologin and just refreshes the binary, with a round-trip under 30 seconds.

Build

# From a clone of the brume repo
cargo build --release -p brumectl

# Resulting binary
./target/release/brumectl --help

Pre-built binaries for macOS arm64 and Linux x86_64 are published on every tagged release at GitHub Releases. The cargo build above is also supported and is the natural path for contributors working on brumectl itself.

How it talks to the device

Every subcommand except flash is a thin layer over SSH. The CM5 lives on your LAN (WiFi or Ethernet) and announces itself as brume.local via mDNS; brumectl uses the system ssh and scp binaries to connect, honouring your existing ssh-agent and ~/.ssh/config. No bespoke protocol, no API tokens, no pairing flow.

The flash subcommand is the exception: it talks to a bare CM5 over USB mass-storage via rpiboot before any operating system is on the device, then hands off to SSH after first boot.

Trust model Authorization is the SSH key on your workstation, the same key you gave Raspberry Pi Imager or brumectl flash. brumectl never holds its own credentials, never uses an API token, and never phones home. If your SSH key can reach the CM5, you can manage it.

Hardware compatibility

The reference rig is a Compute Module 5 on a CM5 IO board. That’s the platform Brume is regression-tested on and the only one where Meridian (USB audio + MIDI bridge to your DAW) works, because Meridian needs a CM5 IO board wired for USB peripheral mode on its USB_OTG pin; the Pi 5’s Type-C is wired host-only.

That said, brumectl install is platform-agnostic. If you already own a Raspberry Pi 5 (or a Pi 4 with at least 8 GB of RAM, or a Pi 400), you can run Brume on it: synth engines, MIDI input, HDMI audio, and the touchscreen UI all work on stock Pi OS Lite 64-bit. You lose Meridian and you’re off the regression-test path, but the instrument itself plays.

End of manual · rev dev · Aftertone & Signal