How Steady evens out movie volume with the Web Audio API
Steady is a Chrome extension that keeps a tab's volume in a comfort range. This is how it works and what we measured.
The constraint: DRM and iframes
The obvious approach is to adjust the page's video element. That fails on protected players such as Netflix, whose audio is not accessible to page scripts, and on players embedded from other domains. So Steady works on the whole tab's audio instead, using chrome.tabCapture. Capturing a tab mutes it, so the audio is processed and played back from a hidden offscreen document.
The chain
`` tab → automatic gain → compressor → limiter → speakers ``
The slow, musical part is the automatic gain control. About ten times a second it:
- reads the last 4096 samples from an
AnalyserNode, - computes the root-mean-square level and smooths it,
- moves the gain toward
target − level, limited to +18 dB boost and −24 dB cut.
The smoothing is deliberately asymmetric. When it gets louder, the gain moves halfway to its target each tick, so a loud scene is turned down within about 0.15 seconds. When it gets quieter, it moves 8% per tick, so quiet dialog comes back over about a second without pumping. Below −55 dBFS the gain holds, so room tone and silence between scenes aren't boosted into hiss.
The gain changes go through setTargetAtTime, which avoids clicks. After it, a DynamicsCompressorNode (threshold −20 dB, ratio 4) evens out what the slow gain can't, and a second one acting as a limiter (threshold −2 dB, ratio 20, 1 ms attack) catches sudden bangs.
What we measured
We rendered a test scene offline with the same chain: six seconds of whispered dialog at about −40 dBFS, four seconds of an explosion at −6 dBFS, then dialog again.
| Dialog | Explosion | Spread | |
|---|---|---|---|
| Input | −39.9 dB | −5.9 dB | 34 dB |
| Output | −18.1 dB | −16.2 dB | about 2 dB |
The first 100 milliseconds of the explosion still reach −4.3 dB before the gain catches up, which is exactly what the limiter is for. Peaks stay below full scale.
Things we'd do differently
The level measurement is a plain RMS, so bass-heavy scenes can be turned down more than they deserve. A K-weighted loudness measure (as used for LUFS) would match human hearing better, and is the next improvement.
The code is small enough to read in one sitting. The gain logic is a pure function with its own tests, which made it easy to tune without listening to a hundred explosions.
Steady is one of the five free Ease extensions. No accounts, no tracking.
Learn about Steady