Mixer
The named bus graph that routes every voice from source to speakers.
TL;DR
The Mixer is your declarative routing model. You name your buses
(music, sfx, voice, etc.), give each
one a level and behavior, and the engine builds the audio graph for you.
The mixer is what separates "I called .play()" from
"I shipped a mix."
Mental model
Sources fan in through their default bus. Each bus has its own level, optional FX inserts, optional concurrency cap, and an optional sidechain key. Bus outputs sum at the master, which applies headroom and sends to the destination.
API surface
const engine = createEngine({
buses: {
music: { level: 0.8, concurrency: { max: 4 } },
sfx: { level: 1.0, concurrency: { max: 32, steal: 'oldest' } },
voice: { level: 1.0, sidechain: { from: 'music', amount: 0.5, attack: 0.08, release: 0.4 } },
},
master: {
headroom: -3,
// Fast-attack soft limiter on master out — best-effort peak control for
// when FX stack on busy mixes. Disable by omitting the field.
limiter: { threshold: -1, ratio: 20, attack: 0.001, release: 0.05 },
},
}); engine.bus('music').level = 0.5;
engine.bus('sfx').fadeTo(0, 0.8);
engine.bus('voice').muted = true; Live demo
Sliders, mute, real voice counter — live engine, real samples.
Recipes
Insert an FX chain on a bus
import { Compressor, Reverb } from '@schmooky/zvuk';
const comp = new Compressor(engine.context, { threshold: -18, ratio: 4 });
const reverb = new Reverb(engine.context, { wet: 0.3, decay: { seconds: 1.4 } });
engine.bus('music').addFx(reverb);
engine.bus('sfx').addFx(comp); // FX run between bus.input and bus.output Master limiter
Headroom is a static gain offset. The optional limiter is a fast-attack
DynamicsCompressor (ratio 20, ~1 ms attack) used as a soft
limiter on the master output — it catches most transients headroom alone
can't tame, but with a finite attack and no lookahead it does not guarantee
a hard 0 dBFS ceiling.
// The master limiter is configured at construction (see above). There is
// no public runtime accessor yet — to change or disable it, recreate the
// engine with a different master.limiter (or omit the field).
createEngine({ master: { limiter: { threshold: -0.5, ratio: 20 } } }); Pitfalls
Related
- Bus — single-bus details and the FX chain.
- Snapshot — capture & crossfade the whole mix.
- Building your mix — practical guide.