0008 — DCA/VCA is control-domain gain coupling, not an audio sub-bus

Status: Accepted (built — 2026-07-29 note below) Date: 2026-06-29

Context

A DCA (or VCA) group gives one master fader control over a set of member channels — pull the DCA down and every member comes down with it — without changing where any member's audio is routed. The naive implementation is to route the members into a real sub-bus and put the master on that bus. That is wrong for a live console: it changes the signal path, collapses the members into a summed stereo pair, and breaks per-member direct-outs and sends.

Decision

A DCA carries no audio. It is a control-domain coupling: a member channel's effective gain is its own fader plus the sum of the dB trims of every DCA it belongs to, pushed to that channel's own gain node.

effective_gain(ch) = fader_dB(ch) + Σ DCA_dB(groups containing ch)

This supports many-masters-per-member and VCA nesting, and mute/solo propagate through the masters. With faders implemented as node gains (0002), the coupling is cheap and exact. The canonical model already carries the dca channel kind; this ADR fixes how it is realised.

Consequences

  • Member audio paths, direct-outs, and sends are untouched — a DCA only trims gains.
  • "Spill" (show a DCA's members on a surface) is a navigation operation over the membership set, not a routing change.
  • Solo/mute on a DCA master propagate to members as control-domain operations.
  • The trap to avoid, recorded as an explicit anti-pattern: never implement a DCA as a real audio sub-bus.

Note — 2026-07-29: built

DCA-as-gain-coupling is implemented as specified. packages/audio-engine/src/software-mixer.ts holds the dcaRuntimes map (DcaRuntime) and exposes dcas(); the server side is setDcaFader in packages/server/src/structural-dsp.ts, with the dca.members / dca.fader / dca.name / dca.remove behaviour exercised by name in structural-dsp.test.ts. No audio sub-bus was introduced — the decision held.