Master Limiter
Added in 5.8.0
When several sounds play at the same time their waveforms add up. Five samples at full volume sum to roughly five times full scale, and the Web Audio destination hard-clips everything above that ceiling. You hear it as crackle or distortion, most noticeably on sounds with a sharp attack such as piano notes, drum hits or gunfire.
The master limiter holds those peaks back instead of letting them clip. It sits last in the master chain, after volume and panning, so it catches everything on the way out:
sound → gain → pan → master gain → master pan → [limiter] → output
It is off by default, so upgrading to 5.8.0 never changes how an existing project sounds. Turn it on when you mix several sounds at once.
Try it
Play a stack of identical notes with the limiter off and then on. Identical samples add up coherently, so this reaches the clipping ceiling quickly.
Enabling it
Set it once when you create the manager:
const soundHub = new SoundHub({
createNewInstance: true,
masterLimiter: true, // prevents clipping when sounds overlap
});
Or toggle it at runtime. This only rewires the output chain, so playback is not interrupted:
soundHub.setMasterLimiter(true);
soundHub.isMasterLimiterEnabled(); // true
Tuning it
The defaults are tuned as a brick-wall limiter rather than a compressor:
| Parameter | Value | Why |
|---|---|---|
threshold | -3 dBFS | Leaves a little headroom below the ceiling |
knee | 0 | Hard knee, so it limits rather than compresses |
ratio | 20 | Effectively a brick wall |
attack | 0.003 s | Fast enough to catch note transients |
release | 0.25 s | Recovers without pumping |
Anything below the threshold passes through untouched, so quiet material is unaffected.
If you need different behaviour, the underlying
DynamicsCompressorNode
is exposed:
const limiter = soundHub.getMasterLimiterNode();
if (limiter) {
limiter.threshold.value = -6; // start limiting earlier
limiter.release.value = 0.4; // let it recover more slowly
console.log(limiter.reduction); // current gain reduction in dB
}
Reading reduction is the easiest way to check whether the limiter is actually doing
anything: it stays at 0 while you are under the threshold and goes negative as peaks are
held back.
Audio you generate yourself
The limiter only sees what passes through the master chain. Sound you create with an
oscillator, a MediaElementSource or an AudioWorklet and connect straight to
context.destination bypasses it completely, along with master volume, mute and panning.
Connect it to getMasterInput() instead:
const context = soundHub.getContext();
const osc = context.createOscillator();
const gain = context.createGain();
osc.connect(gain);
gain.connect(soundHub.getMasterInput()); // not context.destination
osc.start();
This matters more than it sounds. Synthesized sources are usually much hotter than recorded samples: a sawtooth at full amplitude peaks at 0 dBFS while a typical sample peaks around -20 dBFS, so an untamed oscillator can be ten times louder than everything else and clip on its own.
When to use it
| Situation | Recommendation |
|---|---|
| A single background track | Not needed |
| Playing a sound the user triggers repeatedly | Worth enabling |
| A playable instrument, several notes at once | Enable |
| A game scene with many overlapping effects | Enable |
| You already mix at low per-sound volumes | Optional, it will rarely engage |
A limiter is a safety net, not a substitute for a sensible mix. If you know you will play ten sounds at once, lowering the individual volumes still gives you the cleanest result; the limiter is there to catch what you did not plan for.