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

  1. Mark the dialogue track as the sidechain source:
tonn::PostProdTrackSettings dialogue(
    tonn::PostProdGroupType::DIALOGUE_MAIN,
    tonn::DialoguePriority::HIGH,
    tonn::PostProdFormat::BROADCAST);
dialogue.setIsDuckingSidechain(true);
  1. 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);
  1. 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.