Mixer tracks
The Mixer is the strip section of the right-side Master Control panel. One MixerTrack per channel — gain / mute / solo / sends + its own FX chain — just like a DAW mixer. The key idea: a MixerTrack is an audio-side entity decoupled from the source that feeds it (the Ableton / Logic / Bitwig pattern). Sources (a Builder, a Faust .dsp) route INTO a track; the track owns the fader, the inserts, the sends, and routes on to master.
Adding audio — the "+ ADD AUDIO" picker
Master Control starts with no tracks. You populate it explicitly:
- "+ ADD AUDIO" — lists the audio-shaped
.builderDSPs in your project (Documents → PROJECT /assets/). Pick one; the IDE opens/mounts it as a Source and attaches its output to a MixerTrack. (FX-shaped DSPs — those with anInputnode — appear under "+ ADD FX" instead and go to the Master-FX rack; see § 2.)
Attaching runs a 3-stage Auto-Create-mit-Reconnect resolver to decide which track the source lands on:
- Persisted edge — if this source was attached to a track before, that routing is restored.
- Name match — an existing track whose name equals the source's title.
- Auto-create — otherwise a fresh track is created (named after the source) and the source routes into it.
Anatomy of a track strip
Top-to-bottom:
- Label — the track name (defaults to the attached source's title; rename via
mixer.tracks.rename). - FX chain — per-track insert slots (see Per-track FX below). Distinct from the global Master-FX rack in § 2.
- Send sliders — one per Master-FX send slot, a level into that send bus (default 0).
- Mute / Solo — standard mixer semantics. Solo wins: when ANY track is soloed, only soloed tracks pass; un-soloed tracks are silenced regardless of their own mute. Multiple solos allowed.
- Gain fader — linear 0..1 (unity = 1.0), 5 ms ramp so live moves don't click. Display dB via
20 · log10(gain). Per-track L/R can be split (ganged: false) for balance. - Per-track meter — post-gain peak of this track's contribution to master.
- × delete — removes the track (its inbound sources become unrouted, audio keeps running but silent until re-attached).
Track state (gain / muted / soloed / fxSlots / sendLevels / routesTo) persists in the project's mixerTracks slice of project.json, so your mix comes back on reload.
Per-track FX
Each track has its own insert chain, independent of the global Master-FX rack. Append a Faust-DSP slot to a track via mixer.tracks.fx.add (compiled asynchronously — the slot appears immediately, wires in once compile succeeds), toggle bypass via enabled, set params via mixer.tracks.fx.set. Use per-track FX for channel-strip processing (EQ/comp on one source); use the Master-FX rack (§ 2) for bus-wide processing.
Driving the mixer from MCP
Precondition for the chain: at least one MixerTrack exists (add one via "+ ADD AUDIO" or mixer.tracks.input.set — a fresh project has none, and the template below targets track 0).
actions:
- action_id: surface.open
input: { surface: faustwave-bundled/mixer }
label: "▶ 0. Show Master Control (watch the faders move)"
- action_id: system.state
input: { sections: ["mixer_tracks"] }
save_as: m
label: "▶ 1. Inspect current tracks"
- action_id: mixer.tracks.set
input:
track_id: "{{m.mixer_tracks.tracks.0.id}}"
gain: 0.5
label: "▶ 2. Drop the first track to −6 dB"
- action_id: mixer.tracks.set
input:
track_id: "{{m.mixer_tracks.tracks.0.id}}"
muted: true
label: "▶ 3. Mute it"
- action_id: mixer.tracks.clear
input: { field: mutes }
label: "■ Clear all mutes"
The MCP actions
| Action | Purpose |
|---|---|
mixer.tracks.create { name?, routesTo? } | New track (name → Track N, routesTo → master:in). Returns its id. |
mixer.tracks.set { track_id, gain? / gain_l? / gain_r? / ganged? / muted? / soloed? / sends? } | Update fields. gain ramps 5 ms; sends REPLACES the whole send-set. Solo wins over mute. |
mixer.tracks.rename { track_id, name } | Rename (also used to keep track-name = source-title in sync). |
mixer.tracks.delete { track_id } | Remove a track; inbound sources become unrouted. |
mixer.tracks.reorder { ids } | Reorder the strip list to the given permutation. |
mixer.tracks.input.set { ... } | MCP mirror of "+ ADD AUDIO" — attach a Source output to a track via the 3-stage resolver. |
mixer.tracks.fx.add / remove / set | Per-track FX-chain slot CRUD. |
mixer.tracks.clear { field: mutes | solos } | Reset every track's mute or solo flag in one shot. |
system.state { sections: ["mixer_tracks"] } | Snapshot: array of { id, name, gainL, gainR, ganged, muted, soloed, fxSlots, sendLevels, routesTo }. |
For AI & automation · MCP
A legacy mixer.set { module_id, … } + system.state { sections: ["mixer"] } slice still exist for per-Source-module Faust-param persistence (slotParams), but the visible faders are MixerTracks — reach for mixer.tracks.*.
Sends — feeding a track into a Master-FX send slot
The Master-FX rack supports inserts (serial chain) and sends (parallel bus). Each track carries one send level per send slot — how much of THIS track to feed into that send bus:
1. master.fx.slots.list {} → slot ids (send slots included)
2. mixer.tracks.set {
track_id: "<track id from system.state>",
sends: { "<send slot id>": 0.4 }
}
(Not a click-chain — the track id and send-slot id are yours to pick from step 1 and system.state { sections: ["mixer_tracks"] }.)
The sends map is set as a whole — omitting a slot removes its send. To keep a send wired but silent (for a smooth ramp-back-up), pass 0 for that slot id rather than omitting it.
Common moves
- "Hear only one track, mute the rest" —
mixer.tracks.set { track_id, soloed: true }. Solo wins. - "Add my Hub snare to the mix" — install it (it lands in the project), then "+ ADD AUDIO" → pick it; a track auto-creates and the source routes in.
- "Disarm all solos and mutes" —
mixer.tracks.clear { field: mutes }then{ field: solos }. - "Audition just one source" — set it
soloed: true, listen, thenmixer.tracks.clear { field: solos }.
Next section: the Master-FX rack — inserts vs sends, slot management, per-param control.