Loudness and mastering

Measure loudness the EBU R128 way and deliver to streaming, podcast or broadcast targets with a true-peak limiter.

On this page

Peak level tells you how close a file is to clipping. It does not tell you how loud it sounds. Streaming services, podcasts and broadcasters measure loudness instead, in LUFS (loudness units relative to full scale), and turn loud tracks down to a target. Deliver at the target and nothing is changed for you.

Measure

mix = audioGain( audioNoise( seconds=8, color="pink" ), -14 );
r = audioLoudness( mix );
println( "integrated " & r.integrated & " LUFS, range " & r.range & " LU, true peak " & r.truePeak & " dBFS" );

audioLoudness follows ITU-R BS.1770 and EBU R128 (K-weighting, gated 400 ms blocks, true peak from a 4 times oversampled signal) and returns:

KeyMeaning
integratedLoudness of the whole program in LUFS, with silence and very quiet passages gated out. The number services use
rangeLoudness range (LRA) in LU: how much the loudness moves
truePeakHighest peak between samples, dBFS
samplePeakHighest sample, dBFS
momentaryMax / shortTermMaxLoudest 400 ms and loudest 3 s, LUFS

Silence, or audio shorter than 400 ms, reads -120. This implementation agrees with FFmpeg's ebur128 filter to within 0.1 LU on rendered music, and with the EBU reference tones (a stereo sine at -23 dBFS reads -23 LUFS).

Master to a target

mix = audioGain( audioNoise( seconds=8, color="pink" ), -22 );
final = audioMaster( audio=mix, target="streaming", truePeak=-1 );
println( audioLoudness( final ).integrated );   // -14

audioMaster sets the gain to reach the target, then a look-ahead limiter holds the peaks under the true-peak ceiling. The limiter lowers the loudness a little, so the gain is corrected and the pass repeated until the target is hit within 0.05 LU.

TargetLUFSUsed for
streaming-14Spotify, YouTube, Apple Music and most video platforms
podcast-16Podcasts
game-16Game audio
broadcast-23EBU R128 television and radio
cinema-24Film trailers and cinema

Pass a number for any other level. glue=true compresses lightly first (2:1, slow) so a busy mix sounds more even. audioNormalizeLoudness does the same with a plain number of LUFS.

The tools it is built from

You can use them directly:

voice = audioNoise( seconds=4, color="pink", seed=3 );

voice = audioEq( voice, [
    { type: "highpass", freq: 90 },                       // no rumble
    { type: "peak", freq: 3000, gain: 3, q: 1 },          // presence
    { type: "highshelf", freq: 9000, gain: -2 }           // tame the hiss
] );
voice = audioCompress( audio=voice, thresholdDb=-20, ratio=3, attack=8, release=120 );
voice = audioLimit( audio=voice, ceilingDb=-1 );
FunctionDoes
audioCompressTurns loud parts down by ratio above thresholdDb, with attack, release and a soft knee. makeupDb="auto" matches the loudness of the input
audioLimitA look-ahead limiter: no sample ends above ceilingDb, and the gain recovers over release
audioEqParametric bands: peak, lowshelf, highshelf, lowpass, highpass, notch

From the command line

bx-audio loudness mix.wav
bx-audio master mix.wav final.wav --target=podcast
bx-audio master mix.wav final.wav --target=-18 --truePeak=-2 --glue
Edit this page Download Markdown Last updated Oct 16, 2026, 11:59:46 AM Report an issue