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
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.
ALGO tab: topology and feedback
| Parameter | Range | Default | Description |
|---|---|---|---|
| ALGO | 12 options | STACK | Algorithm 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). |
| FDBK | 0 – 1 | 0.3 | Global 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
| Parameter | Range | Default | Description |
|---|---|---|---|
| OP1–OP6 RATIO | 0.25 – 16 | 1.0 / 2.0 / 3.0 / 4.0 / 5.0 / 6.0 | Per-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
| Parameter | Range | Default | Description |
|---|---|---|---|
| OP1–OP6 LEVEL | 0 – 1 | tapered 0.8 → 0.1 | Per-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
| Parameter | Range | Default | Description |
|---|---|---|---|
| FM INDEX | 0 – 10 | 0.7 | Global 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 DEPTH | 0 – 10 | 0 | Depth 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 ATTACK | 0 – 5000 ms | 2 ms | Attack time of the FM-index envelope. |
| ENV DECAY | 0 – 5000 ms | 800 ms | Decay time from peak down to sustain. |
| ENV SUSTAIN | 0 – 1 | 0 | Sustain level of the FM-index envelope, relative to ENV DEPTH. |
| ENV RELEASE | 0 – 5000 ms | 400 ms | Release 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.
SCAN tab: spectral scanning and waveform morph
| Parameter | Range | Default | Description |
|---|---|---|---|
| CENTER | 0 – 1 | 0.5 | Position of the scanning window across the harmonic series. At 0 the window centers on the fundamental; at 1 it centers on the 8th harmonic. |
| WIDTH | 0 – 1 | 1.0 | Width of the scanning window. Intermediate values produce a Gaussian falloff from the center. |
| MORPH | 0 – 1 | 0 | Per-harmonic waveform morph. Coupled to the scan window, so harmonics near the center receive more morph. |
| SPREAD | 0 – 1 | 0 | Phase 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.
SHAPE tab: wave multiplier and feedback
| Parameter | Range | Default | Description |
|---|---|---|---|
| TIMBRE | 0 – 1 | 0 | Wave 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 – 1 | 0 | Triangle tilt and asymmetric bias. Positive values stretch the rising slope; negative values produce the inverse. |
| STAGES | 1 – 4 | 1 | Number of wavefolding stages. Each stage cascades another triangle-fold pass, densifying the harmonic spectrum. |
| FEEDBK | 0 – 1 | 0 | Self-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.
CLOUD tab: grain generation
| Parameter | Range | Default | Description |
|---|---|---|---|
| DENSITY | 0 – 1 | 0.3 | Grain spawn rate. Maps from 1 to 200 grains per second. Spawn timing includes a 30% jitter. |
| SIZE | 0 – 1 | 0.2 | Grain duration. Maps from 1 ms to 500 ms. Each grain's actual length varies by ±20%. |
| SCATTER | 0 – 1 | 0 | Pitch randomization per grain. At maximum, each grain's pitch is randomized within ±2 octaves of the fundamental. |
| SPREAD | 0 – 1 | 0 | Stereo pan randomization per grain. |
| DRIFT | 0 – 1 | 0 | Slow 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.
| Parameter | Range | Default | Description |
|---|---|---|---|
| CUTOFF | 20 – 20,000 Hz | varies | Filter cutoff. Smooth resonant rolloff above this frequency. |
| RESO | 0 – 1 | 0.1 | Resonance. Values near 1.0 produce self-oscillation. |
| ENV DEP | 0 – 1 | 0.3 | Envelope depth. Modulates cutoff above its static value. |
Modulation: LFOs and step sequencers
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.
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
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
| Parameter | Range | Default | Description |
|---|---|---|---|
| TYPE | Soft / Hard / Tape / Tube | Soft | Saturation algorithm. Soft uses tanh waveshaping; Hard clips at ±1; Tape applies asymmetric soft clipping; Tube adds even harmonics via polynomial distortion. |
| DRIVE | 0 – 1 | 0 | Pre-gain into the saturation circuit. At 0 the signal passes clean; at 1 the input is boosted 5× before shaping. |
| MIX | 0 – 1 | 1 | Dry/wet blend. |
Chorus
| Parameter | Range | Default | Description |
|---|---|---|---|
| RATE | 0.1 – 5 Hz | 0.5 | LFO speed controlling the modulation of the internal delay lines. Left and right voices run at slightly offset rates for stereo width. |
| DEPTH | 0 – 1 | 0.3 | Modulation depth. Higher values produce more pronounced pitch variation and wider stereo field. |
| MIX | 0 – 1 | 0 | Dry/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.
| Parameter | Range | Default | Description |
|---|---|---|---|
| SYNC | FREE / MIDI / 1/1 – 1/8t | FREE | Tempo 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. |
| TIME | 10 – 2000 ms | 300 | Delay time in free mode. Overridden when a sync division is active. |
| FEEDBACK | 0 – 0.95 | 0.3 | Amount of delayed signal fed back into the input. Values above 0.8 produce long, building repeats. |
| DAMPING | 0 – 1 | 0.3 | High-frequency rolloff in the feedback loop. At 0 the repeats stay bright; at 1 they darken rapidly, simulating tape degradation. |
| MIX | 0 – 1 | 0 | Dry/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.
| Parameter | Range | Default | Description |
|---|---|---|---|
| TYPE | Plate / Room / Hall / Spring | Plate | Plate (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. |
| PREDELAY | 0 – 200 ms | 20 | Delay before the reverb onset. Separates the dry signal from the reverb tail, preserving transient clarity at higher values. |
| DECAY | 0.1 – 8 | 2.0 | Reverb tail length. Controls the feedback coefficient in the comb filter network. Higher values produce longer, more sustained reverberation. |
| DAMPING | 0 – 1 | 0.4 | High-frequency absorption in the reverb tail. Low values produce bright, shimmering tails; high values simulate absorptive room surfaces. |
| MIX | 0 – 1 | 0 | Dry/wet blend. |
MIDI
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.
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:
~/.brume/cc-bindings.json.| Action | Behavior |
|---|---|
| Tap LEARN | Arms 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 / fader | Capture 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 destination | The 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 BINDING | Writes the binding and disarms capture. The new mapping takes effect immediately. |
| Tap CANCEL | Discards the in-progress capture without writing anything. |
| Tap RESET | Two-tap confirm. Wipes all CC bindings, FX bindings, and channel routing back to factory defaults. Use when an experiment goes sideways. |
~/.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:
| Mode | Behavior |
|---|---|
| Off | Internal clock at the configured BPM. No MIDI clock is sent or received. |
| Master | Internal clock at the configured BPM. Brume sends MIDI clock (24 PPQN) to connected devices. |
| Sync | Brume 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
| Control | CC | Action |
|---|---|---|
| Top-row knobs 1–8 | 16–23 | First 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–4 | 0–3 | Mixer 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–8 | 4–7 | Reserved. |
| S buttons 1–4 | 32–35 | Exclusive 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–4 | 48–51 | Per-part mute toggle. Press edge only. |
| S / M buttons 5–8, R 1–8 | 36–39, 52–55, 64–71 | Reserved. |
| Track ◄ / ► | 58 / 59 | Cycle active engine mode in menu-bar order (FM → Harmonic → Timbral → Granular, wraps in both directions). Press edge only. |
| Marker ◄ / ► | 61 / 62 | Cycle the active engine’s sub-tabs (e.g. ALGO → RATIOS → LEVELS … on FM). Press edge only. |
| Marker ◎ | 60 | Reserved. |
| Cycle | 46 | Reserved. |
| Transport (Play / Stop / Rec / FF / Rew) | 41–45 | Reserved. |
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
| Control | CC | Action |
|---|---|---|
| Encoder row 1 (top, 1–8) | 13–20 | First 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 & 3 | 21–28, 29–36 | Reserved. |
| Faders 1–4 | 5–8 | Mixer level for FM / Harmonic / Timbral / Granular. Mirrors the MIX page faders per strip. |
| Faders 5–8 | 9–12 | Reserved. |
| DAW Control pads 1–4 (top row) | 37–40 | Direct engine select: pad 1 → FM, pad 2 → Harmonic, pad 3 → Timbral, pad 4 → Granular. |
| DAW Control pads 5–8 (top row) | 41–44 | Reserved. |
| DAW Mixer pads 1–6 (bottom row) | 45–50 | Direct 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–52 | Reserved. |
| PAGE / TRACK / Record / Play / Shift / Mode | — | No 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. |
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.
~/.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:
| File | Change |
|---|---|
crates/midi-io/src/lib.rs | In 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.js | In 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.html | Add 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.
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:
| Channels | Source |
|---|---|
| 1 – 2 | FM (dry, pre-FX, mono duplicated to L/R) |
| 3 – 4 | Harmonic (dry, pre-FX, mono duplicated to L/R) |
| 5 – 6 | Timbral (dry, pre-FX, mono duplicated to L/R) |
| 7 – 8 | Granular (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.
The mapping between channel pair, Brume part, and the spatial label the DAW will display:
| Channel pair | Brume part | DAW spatial label |
|---|---|---|
| 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 |
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.
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
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.
~/.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
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.
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 pair | Brume part | DAW spatial label |
|---|---|---|
| 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 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=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 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)
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
| Command | Status | Description |
|---|---|---|
| install | shipped | Primary 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). |
| flash | shipped | Alternate 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). |
| status | shipped | One-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. |
| shell | shipped | Pass-through SSH shell to the device. Honours $BRUME_HOST and $BRUME_SSH_KEY as well as the global --host and -i flags. |
| watch | partial | Live 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. |
| update | planned | Push a signed image bundle or app tarball to the device with A/B slot management and rollback on boot failure. Channels: stable and beta. |
| logs | planned | Tail Brume’s journal or /var/log/brume.jsonl over SSH; will also feed the watch dashboard’s console panel. |
| config get / set | planned | Read and write user-facing config (WiFi, hostname, MIDI channels, audio routing) without a re-flash. |
| recover | planned | Force boot into the read-only recovery partition. |
| channel | planned | Switch update channel (stable / beta); each channel is gated by a separate signing key. |
| doctor | planned | Diagnostic 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:
--host USER@HOSTor$BRUME_HOST: SSH target. Defaults tobrume@brume.local.-i PATH/--key PATHor$BRUME_SSH_KEY: SSH identity file. Falls back tossh-agent/~/.ssh/config.
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.
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