PostProductionSDK - Features Guide¶
This guide covers every feature of the PostProductionSDK module in detail. For initial setup and a minimal working example, see the Getting Started guide. For complete runnable examples, see Post-Production Examples.
Dialogue Enhancement¶
The dialogue enhancement engine analyses each track for noise floor, frequency balance, clipping, and reverb characteristics before applying corrective and creative processing. It can be enabled per track, per session, or both.
Per-Track Control¶
tonn::PostProdTrackSettings settings(
tonn::PostProdGroupType::DIALOGUE_MAIN,
tonn::DialoguePriority::HIGH,
tonn::PostProdFormat::TV);
settings.setDialogueEnhancementEnabled(true);
settings.setDialogueEnhancementMode(tonn::DialogueEnhancementMode::ENHANCE);
Session-Wide Toggle¶
sdk.setDialogueEnhancementEnabled(true);
When both per-track and session-wide settings are active, the per-track setting takes precedence.
Enhancement Modes¶
| Mode | Enum | Description | Best for |
|---|---|---|---|
| Preserve | PRESERVE (1) |
Minimal processing, preserves natural sound | Documentaries, naturalistic content |
| Enhance | ENHANCE (2) |
Standard clarity boost | TV, streaming, interviews |
| AD Enhanced | AD_ENHANCED (3) |
Aggressive enhancement for maximum intelligibility | Commercials, announcements, voiceover |
settings.setDialogueEnhancementMode(tonn::DialogueEnhancementMode::PRESERVE);
settings.setDialogueEnhancementMode(tonn::DialogueEnhancementMode::ENHANCE);
settings.setDialogueEnhancementMode(tonn::DialogueEnhancementMode::AD_ENHANCED);
Sidechain Ducking¶
Sidechain ducking automatically reduces the level of background tracks when dialogue is present. One sidechain source can duck multiple background tracks simultaneously.
Setup¶
- Mark the dialogue track as the sidechain source:
tonn::PostProdTrackSettings dialogue(
tonn::PostProdGroupType::DIALOGUE_MAIN,
tonn::DialoguePriority::HIGH,
tonn::PostProdFormat::BROADCAST);
dialogue.setIsDuckingSidechain(true);
- Enable ducking on each background track:
tonn::PostProdTrackSettings music(
tonn::PostProdGroupType::MUSIC,
tonn::DialoguePriority::NORMAL,
tonn::PostProdFormat::BROADCAST);
music.setDuckingEnabled(true);
music.setDuckingPreset(tonn::DuckingPreset::MEDIUM);
- Optionally toggle ducking for the entire session:
sdk.setAutoDuckingEnabled(true);
Ducking Presets¶
| Preset | Enum | Attenuation | Attack | Release | Use case |
|---|---|---|---|---|---|
| None | NONE (0) |
0 dB | n/a | n/a | Disable ducking |
| Light | LIGHT (1) |
-6 dB | 50 ms | 500 ms | Subtle background music |
| Medium | MEDIUM (2) |
-12 dB | 30 ms | 400 ms | Standard dialogue scenes |
| Heavy | HEAVY (3) |
-20 dB | 20 ms | 600 ms | Important narration over music |
| AD Mix | AD_MIX (4) |
-22 dB | fast | fast | Commercials |
| Custom | CUSTOM (5) |
User-defined | User-defined | User-defined | See below |
Custom Ducking Parameters¶
When using DuckingPreset::CUSTOM, set individual parameters:
settings.setDuckingPreset(tonn::DuckingPreset::CUSTOM);
settings.setCustomDuckAmount(-15.0f); // dB of attenuation
settings.setCustomDuckThreshold(-30.0f); // dB threshold for detection
settings.setCustomDuckAttack(25.0f); // ms
settings.setCustomDuckRelease(450.0f); // ms
Multi-Track Ducking¶
One sidechain source can duck any number of background tracks. Each background track can use a different preset:
// Sidechain source
dialogue.setIsDuckingSidechain(true);
// Different ducking depths per track
music.setDuckingEnabled(true);
music.setDuckingPreset(tonn::DuckingPreset::MEDIUM);
sfx.setDuckingEnabled(true);
sfx.setDuckingPreset(tonn::DuckingPreset::LIGHT);
ambience.setDuckingEnabled(true);
ambience.setDuckingPreset(tonn::DuckingPreset::HEAVY);
Delivery Format Presets¶
Each format defines a loudness target, true peak limit, and compliance thresholds. Set the format at construction or at any time before processing:
tonn::PostProductionSDK sdk(48000.0f, tonn::PostProdFormat::TV);
// Change format later
sdk.setFormat(tonn::PostProdFormat::STREAMING);
Format Specifications¶
| Format | Enum | Target LUFS | Max True Peak | Standard |
|---|---|---|---|---|
| Film | FILM (0) |
-24 LUFS | -2 dBTP | Cinema / Dolby reference |
| TV | TV (1) |
-23 LUFS | -2 dBTP | EBU R128 |
| Streaming | STREAMING (2) |
-27 LUFS | -2.3 dBTP | Major streaming platforms |
| YouTube | YOUTUBE (3) |
-14 LUFS | -1 dBTP | YouTube |
| Broadcast | BROADCAST (4) |
-23 LUFS | -1 dBTP | Strict EBU R128 |
| ADMIX | ADMIX (5) |
-23 LUFS | -1 dBTP | EBU R128 for advertising |
| Podcast | PODCAST (6) |
-16 LUFS | -1 dBTP | Podcast platforms |
Querying the Active Format¶
float targetLufs = sdk.getTargetLoudness();
float maxPeak = sdk.getMaxTruePeak();
float tolerance = sdk.getLoudnessTolerance();
std::string desc = sdk.getFormatDescription();
std::cout << desc << ": " << targetLufs << " LUFS, "
<< maxPeak << " dBTP" << std::endl;
Compliance Reporting¶
After processing, PostProdResult contains five compliance flags and six measurements:
Compliance Flags¶
| Flag | Meaning |
|---|---|
meetsLoudnessSpec |
Programme loudness is within the target for the selected format |
meetsDialogueSpec |
Dialogue loudness meets the format specification |
meetsPeakSpec |
True peak is below the format limit |
meetsProgramLRASpec |
Programme Loudness Range (LRA) is within the acceptable range |
meetsDialogueLRASpec |
Dialogue LRA is within the acceptable range |
Measurements¶
| Field | Type | Description |
|---|---|---|
measuredLUFS |
float | Integrated programme loudness |
dialogueLUFS |
float | Integrated dialogue loudness |
dialogueLRA |
float | Dialogue loudness range in LU |
truePeakDb |
float | Maximum true peak in dBTP |
dynamicRangeLU |
float | Overall dynamic range in LU |
shortTermLoudnessMax |
float | Maximum short-term loudness |
Example¶
tonn::PostProdResult result = sdk.process();
if (result.success) {
std::cout << "Programme: " << result.measuredLUFS << " LUFS" << std::endl;
std::cout << "Dialogue: " << result.dialogueLUFS << " LUFS" << std::endl;
std::cout << "Dialogue LRA: " << result.dialogueLRA << " LU" << std::endl;
std::cout << "True peak: " << result.truePeakDb << " dBTP" << std::endl;
std::cout << "Dynamic range: " << result.dynamicRangeLU << " LU" << std::endl;
bool allPass = result.meetsLoudnessSpec
&& result.meetsDialogueSpec
&& result.meetsPeakSpec
&& result.meetsProgramLRASpec
&& result.meetsDialogueLRASpec;
std::cout << "Overall compliance: " << (allPass ? "PASS" : "FAIL") << std::endl;
}
Dialogue Priority¶
Each track is assigned a DialoguePriority that influences how the engine balances it relative to other elements:
| Level | Enum | Effect |
|---|---|---|
| Low | LOW (1) |
Reduced priority in the mix |
| Normal | NORMAL (2) |
Standard treatment |
| High | HIGH (3) |
Elevated presence, protected from ducking |
| Critical | CRITICAL (4) |
Maximum priority, highest protection |
tonn::PostProdTrackSettings narration(
tonn::PostProdGroupType::VOICEOVER_HP,
tonn::DialoguePriority::CRITICAL,
tonn::PostProdFormat::PODCAST);
Reverb and Room Settings¶
Control the spatial character of individual tracks with PostProdReverbSetting:
| Setting | Enum | Description |
|---|---|---|
| None | NONE (0) |
No reverb processing |
| Dry | DRY (1) |
Remove existing reverb |
| Small Room | SMALL_ROOM (2) |
Intimate room character |
| Medium Room | MEDIUM_ROOM (3) |
Standard room |
| Large Room | LARGE_ROOM (4) |
Hall or large space |
| Match | MATCH (5) |
Match reverb to a reference audio source |
settings.setReverbSetting(tonn::PostProdReverbSetting::SMALL_ROOM);
The MATCH setting uses convolution-based reverb matching. On macOS, FFT convolution is GPU-accelerated via Metal.
Processed Stems Output¶
Pass true to sdk.process() to receive individually processed stems alongside the final mix:
tonn::PostProdResult result = sdk.process(true);
if (result.success) {
for (size_t i = 0; i < result.stems.size(); ++i) {
auto& [left, right] = result.stems[i];
std::cout << result.trackNames[i] << ": "
<< left.size() << " samples per channel" << std::endl;
}
}
Each stem is a std::pair<std::vector<float>, std::vector<float>> containing the left and right channels.
GPU Acceleration¶
PostProductionSDK automatically uses GPU acceleration when available:
- macOS: Metal (includes FFT convolution for reverb matching)
- Linux: CUDA
- Fallback: CPU processing is used automatically when no compatible GPU is detected
No explicit API call is required to enable GPU processing. The SDK selects the optimal backend at initialization.
JSON Serialization¶
PostProdTrackSettings supports JSON serialization for integration with web services, DAW plugins, and headless pipelines:
// Serialize to JSON
tonn::PostProdTrackSettings settings(
tonn::PostProdGroupType::DIALOGUE_MAIN,
tonn::DialoguePriority::HIGH,
tonn::PostProdFormat::FILM);
settings.setDialogueEnhancementEnabled(true);
std::string json = settings.toJson();
// Deserialize from JSON
tonn::PostProdTrackSettings restored = tonn::PostProdTrackSettings::fromJson(json);
This enables workflows where track configurations are stored in config files, sent over a network, or loaded from a database.
Progress Callback and Cancellation¶
The process() method accepts an optional progress callback. The callback receives a progress value (0.0 to 1.0) and a stage description. Return false from the callback to cancel processing:
auto callback = [](float progress, const std::string& stage) -> bool {
std::cout << "[" << int(progress * 100) << "%] " << stage << std::endl;
// Return false to cancel, true to continue
return true;
};
tonn::PostProdResult result = sdk.process(false, callback);
If the callback returns false, processing stops and result.success will be false.
Mastering Toggle¶
By default, the final mastering stage (loudness normalization and true peak limiting) is applied. You can disable it to get a pre-master mix:
sdk.setMasteringEnabled(false);
tonn::PostProdResult preMaster = sdk.process();
// preMaster contains the mixed audio without loudness normalization
Re-enable with sdk.setMasteringEnabled(true).
Per-Track EQ and Compression¶
For fine-grained control, PostProdTrackSettings exposes manual EQ and compressor parameters:
EQ¶
settings.setFilterFreqSettings({100.0f, 500.0f, 2000.0f, 8000.0f});
settings.setEQGains({-3.0f, 0.0f, 2.0f, 1.5f});
settings.setEQQFactors({0.7f, 1.0f, 1.4f, 0.8f});
Compressor¶
settings.setCompressorThreshold(-18.0f);
settings.setCompressorRatio(3.0f);
settings.setCompressorAttack(10.0f); // ms
settings.setCompressorRelease(100.0f); // ms
Gain and Pan¶
settings.setPreGainDb(-3.0f);
settings.setPostGainDb(1.5f);
settings.setPanAngle(-30.0f); // -90 (left) to +90 (right)
Licensing¶
PostProductionSDK requires a license key with LicenseFeature::POST_PRODUCTION enabled. You can check license status at any time:
tonn::LicenseStatus status = sdk.getLicenseStatus();
bool valid = sdk.isLicenseValid();
std::string customer = sdk.getLicenseCustomerName();
int daysLeft = sdk.getLicenseRemainingDays();
The post-production license is separate from music mixing and mastering licenses. Contact info@roexaudio.com to add post-production to your existing license.