Audio Loudness

Different people master assets for different purposes, and they do not agree on how loud "loud" should be. When viewers play those assets back to back, they reach for the volume control. Loudness correction fixes this during encoding.

Bitmovin gives you three ways to control loudness, and which one applies depends on the codec you are encoding to.

  1. Dolby Loudness Filter. The newest option, and the subject of this page. It works on PCM audio before it reaches the encoder and runs in two passes, measuring the whole program first and then applying one gain change that lands it on target. Allowing special Dolby tweaks such as Dialogue Intelligence.
  2. EBU R128 Single Pass Filter. Also a PCM filter. It does the same job in a single pass, which means committing to a correction before it knows what comes later in the program.
  3. LoudnessControl parameter. For Dolby Digital, Dolby Digital Plus and Dolby Atmos, loudness belongs to the codec configuration rather than to a filter. It can correct the audio, write loudness metadata, or both.

The Dolby Loudness Filter

Supported codecs

Attach the filter to an audio stream. The stream's output codec determines whether the filter applies.

Output codecLoudness handling
AAC, HE_AAC_V1, Opus, PCMSupported by this filter
DD, DDPlus, DolbyAtmosNot supported by the filter. Use loudnessControl in the codec configuration
AC3, EAC3, HE_AAC_V2, Vorbis, MP3, MP2, DTS, DTS:XNot yet supported

Configuring the filter

Create the filter, set a target, and attach it to an audio stream.

import com.bitmovin.api.sdk.model.DolbyLoudnessContentForm;
import com.bitmovin.api.sdk.model.DolbyLoudnessDialogueIntelligence;
import com.bitmovin.api.sdk.model.DolbyLoudnessFilter;
import com.bitmovin.api.sdk.model.StreamFilter;
import java.util.Collections;
 
// 1. Create the filter.
DolbyLoudnessFilter filter = new DolbyLoudnessFilter();
filter.setName("Loudness correction -24 LKFS");
filter.setTargetLoudness(-24);
filter.setMaximumTruePeakLevel(-2.0);
filter.setDialogueIntelligence(DolbyLoudnessDialogueIntelligence.ENABLED);
filter.setSpeechDetectionThreshold(20);
filter.setContentForm(DolbyLoudnessContentForm.AUTO_DETECT);
 
DolbyLoudnessFilter createdFilter = bitmovinApi.encoding.filters.dolbyLoudness.create(filter);
 
// 2. Attach it to the audio stream you want corrected.
StreamFilter streamFilter = new StreamFilter();
streamFilter.setId(createdFilter.getId());
streamFilter.setPosition(0);
 
bitmovinApi.encoding.encodings.streams.filters.create(
    encodingId, audioStreamId, Collections.singletonList(streamFilter));
from bitmovin_api_sdk import (
    DolbyLoudnessContentForm,
    DolbyLoudnessDialogueIntelligence,
    DolbyLoudnessFilter,
    StreamFilter,
)
 
# 1. Create the filter.
dolby_loudness_filter = DolbyLoudnessFilter(
    name='Loudness correction -24 LKFS',
    target_loudness=-24,
    maximum_true_peak_level=-2.0,
    dialogue_intelligence=DolbyLoudnessDialogueIntelligence.ENABLED,
    speech_detection_threshold=20,
    content_form=DolbyLoudnessContentForm.AUTO_DETECT,
)
created_filter = bitmovin_api.encoding.filters.dolby_loudness.create(
    dolby_loudness_filter=dolby_loudness_filter)
 
# 2. Attach it to the audio stream you want corrected.
stream_filter = StreamFilter(id_=created_filter.id, position=0)
bitmovin_api.encoding.encodings.streams.filters.create(
    encoding_id=encoding_id,
    stream_id=audio_stream_id,
    stream_filter=[stream_filter])

position controls filter order when a stream has several filters attached, lowest first.

targetLoudness

How loud the output should be, in LUFS.

Loudness describes how loud audio sounds to a person, measured as energy across the whole program and weighted to match the frequencies human hearing is most sensitive to. The filter measures the incoming audio, works out the difference between that and your target, and applies it.

The value is negative because the reference point is a signal that fills the format completely. Zero means completely full, so everything real sits below it, and a target of -24 LUFS means 24 units quieter than full.

Choose a target based on the audio delivery destination:

DeliveryTarget
EBU R128, European broadcast-23 LUFS
ATSC A/85, North American broadcast-24 LKFS
Streaming platformsaround -14 to -16 LUFS

LKFS is the name ATSC uses for the same measurement as LUFS, so -24 LKFS and -24 LUFS mean the same thing.

maximumTruePeakLevel

The highest peak the output is allowed to reach, in dBTP. This is a limit rather than a goal: it does nothing unless correcting the loudness would push peaks above it, at which point a limiter holds them down.

True peak is a different measurement from loudness. Where loudness averages energy over the whole program, true peak is the single loudest instant in it, and the two are close to independent.

Both files above have identical peaks. One is dense from beginning to end, the other is quiet apart from a single door slam. Peak tells you nothing about which is which, and loudness tells you nothing about whether either is close to clipping, so both numbers have to be set.

True peak differs from the loudest stored sample because the measurement uses the waveform reconstructed between samples. That reconstructed curve can rise higher than either sample, and a playback device reproduces the curve, including the overshoot.

Ceilings therefore sit below zero, leaving room for what happens after the filter has finished. Lossy encoding and sample rate conversion both move peaks around, and a file that measured safely can come out over the limit. EBU R128 uses -1 dBTP and ATSC A/85 uses -2 dBTP.

Most of the time this setting never engages. Correcting a loud source downward moves its peaks away from the ceiling anyway. It matters for quiet sources needing a large upward correction: raising a program from -35 LUFS to -24 LUFS adds 11 dB to every peak as well, and if that would cross the ceiling the limiter clamps the peaks and the loudness target may be missed slightly. The ceiling wins, because audio that clips is worse than audio slightly below target.

dialogueIntelligence

Selects which parts of the timeline the loudness measurement covers.

MeasuresSuits
DISABLEDThe whole programMusic, and anything without speech
ENABLEDEverything inside the ranges where speech is detectedFilm, drama, news, anything dialogue-led

For example, the same program encoded both ways, measured over its whole duration:

DI DisabledDI Enabled
Integrated loudness-24.1 LUFS-23.1 LUFS
Loudness range16.1 LU16.0 LU

Its speech-bearing segments are about 1 LU quieter than the program as a whole, so ENABLED called for 1 dB less correction. Loudness range is identical, because the correction is one constant gain either way.

To verify a DI Enabled encode, measure a speech section. A whole-program measurement will not return the target because the filter does not apply the target to the whole program.

speechDetectionThreshold

The minimum share of the program that must be speech, as a percentage, for speech-based measurement to be used. Below it, the whole program is measured. The examples above use 20, meaning one fifth.

Raise it so that brief speech in a music-led program does not set the level. Lower it for sparse dialogue that should, such as a documentary with long stretches of atmosphere between lines.

The default value is 20%.

contentForm

LONG, SHORT, or AUTO_DETECT, default AUTO_DETECT. Sets whether relative gating is used when measuring loudness.

Relative gating excludes the quietest parts of a program from the measurement, so pauses and near-silence do not pull the result down. LONG applies it and SHORT does not, which is why the same audio can measure slightly differently under the two settings.

ValueContentGating
LONGLonger than 180 seconds, such as films and episodesRelative gating
SHORT180 seconds or shorter, such as adverts and promosNo relative gating
AUTO_DETECTThe filter detects the content formMatches the detected form

Set it explicitly when duration and form disagree, such as a five-minute promo reel that should be measured as short-form.

customData

Add arbitrary key-value data to the filter. The API returns that data unchanged, and it does not affect encoding. Use it to tag configurations in your own systems.

Checking the result

Measure the encoded output with any tool implementing ITU-R BS.1770. With ffmpeg:

ffmpeg -nostats -i output.mp4 -af ebur128=peak=true -f null - 2>&1 | tail -14

Integrated loudness should match the target you set. Because the filter measures the program before correcting it, and then applies a single calculated gain, there is no reason for it to land anywhere else. Expect a tenth of a LU or so of difference and nothing more.

That small residue comes from measuring the encoded file rather than the PCM the filter produced. Lossy encoding alters the signal slightly and the measurement follows. If the gap is larger than a few tenths of a LU, the likely explanation is the peak limiter engaging, which happens when the correction was upward and large.

Notes

This filter modifies the audio itself. If your delivery specification asks for loudness metadata rather than corrected audio, use a Dolby codec and its loudnessControl object instead.

Correction cannot repair clipping that already exists in a source. A master limited hard into the ceiling before it reached you stays clipped afterwards, though pulling the level down does stop anything downstream from clipping again.


Did this page help you?