Skip to content

Mastering Processors

This page is the registry for the named mastering API in libsonare. It answers "what can I call?", not "how does it work internally?"

The authoritative runtime source is the name-list API: masteringProcessorNames(), masteringPairProcessorNames(), masteringPairAnalysisNames(), masteringStereoAnalysisNames(), and masteringPresetNames(). This page mirrors those lists.

New to mastering? Don't start here

Calling individual processors one by one is the hard way. Start with a preset (masterAudio) or the Mastering Assistant, which profiles your audio and proposes a whole chain. Reach for solo processors only when you need surgical control over one stage.

For behavior, processing boundaries, and real-time notes by DSP family, see DSP Implementation Notes. For standards and paper citations, see Algorithm References. For test coverage, see Implementation Validation.

What You Will Learn

By the end of this page you should be able to:

  • distinguish presets, solo processors, pair processors, and JSON-returning analyses;
  • start from a goal such as "control dynamics" or "match a reference" rather than scanning IDs alphabetically;
  • know when a preset or assistant flow is more appropriate than directly calling a processor;
  • find the exact registry name to pass to JavaScript, Python, Node native, or the C ABI.

What the names mean

Name typeMeaningExample
PresetA named chain configuration for a style or delivery targetstreaming, podcast, jpop
Solo processorOne processor applied to a mono or stereo signaldynamics.compressor, eq.tilt
Pair processorA processor that uses a source and a reference signalmatch.applyMatchEq
AnalysisA measurement that returns JSON instead of audiomatch.referenceLoudness, stereo.monoCompatCheck

Sidechain and loudness processors

The dynamics family includes dynamics.duckingProcessor (sidechain ducking), maximizer.loudnessOptimize (maximizing toward a LUFS target — LUFS is Loudness Units relative to Full Scale, the broadcast loudness scale), and a de-esser bandpass Q control on dynamics.deesser with stereo preservation, alongside dynamics.transientShaper, dynamics.upwardCompressor, dynamics.upwardExpander, dynamics.vocalRider, and dynamics.sidechainRouter.

Presets

Presets are named chain configurations, not separate algorithms. Apply one with masterAudio(samples, sr, preset, overrides?).

pop, edm, acoustic, hipHop, aiMusic, speech, streaming, youtube, broadcast, podcast, audiobook, cinema, jpop, ambient, lofi, classical, drumAndBass, techno, metal, trap, rnb, jazz, kpop, trance, gameOst

See Choosing a Mastering Preset for how to pick one without treating a preset as a finished master.

Which processor for which job

A goal-first index into the registry below. This is a starting point, not a rule — read the linked guides before committing.

You want to…Reach forLearn the concept
Even out level / control dynamicsdynamics.compressor, dynamics.limiter, multiband.compressorDynamics
Add punch without squashingdynamics.transientShaper, dynamics.parallelCompDynamics
Tame harsh "ess" soundsdynamics.deesserDynamics
Duck a music bed under voicedynamics.duckingProcessor, dynamics.sidechainRouterMixing Engine
Shape overall tone / brightnesseq.tilt, eq.parametric, spectral.airBandTone and Air
Add warmth / harmonicssaturation.tape, saturation.tube, saturation.exciterTone and Air
Widen / narrow / check stereostereo.imager, stereo.monoMaker, stereo.monoCompatCheckStereo, Limiter, Loudness
Hit a loudness target safelyloudness stage, maximizer.loudnessOptimize, maximizer.truePeakLimiterDelivery Targets
Clean up noise / clicks / clippingrepair.denoiseClassical, repair.declick, repair.declipRepair and Input
Match a reference trackmatch.applyMatchEq, match.referenceLoudnessReference Match
What is sidechaining / ducking?

Sidechaining lets one signal control a processor applied to another. The most common use is ducking: a music bed is automatically turned down whenever a voice is present, then comes back up in the gaps — the way background music drops under a narrator.

What is parallel compression?

A normal compressor turns the loud parts down.

Parallel compression mixes the original signal with a heavily compressed copy. The compressed copy lifts quiet detail, while the original keeps the natural peaks.

Use it when you want density and "glue" without flattening transients. It is also called New York compression. dynamics.transientShaper is the related tool for the opposite goal: exaggerating or softening the attack of each hit.

Drag the threshold and ratio to watch the transfer curve bend and hear a dynamics.compressor work on a live signal:

DYNAMICS · COMPRESSORIDLE
Compression — threshold, ratio, knee, attack, release

The left panel is the transfer curve — input level in, output level out — with the threshold and the soft knee marked; raise the ratio and it bends harder past the threshold. The right panel runs a fixed program (a steady bed with transient hits) through the compressor: the shaded gap is the gain reduction, and attack and release decide how fast it clamps down and lets go. Press play to hear the same program — the pumping you see is the pumping you hear.

Threshold
-18 dB
Ratio
4 :1
Knee
6 dB
Attack
15 ms
Release
160 ms

Processor Families In Plain English

The exact IDs matter for code, but users usually choose by role:

FamilyUse it whenAvoid it when
DynamicsThe level envelope is the problem: peaks jump out, vocals are uneven, transients need shaping, or a bed must duck under speechThe problem is tonal balance; EQ or spectral processors are clearer
EQThe frequency balance is wrong: too dark, too harsh, too boomy, or needs a surgical cutYou are trying to increase loudness; use dynamics/maximizer stages
MultibandDifferent frequency ranges need different dynamics or width treatmentA broad single-band processor already solves it; multiband can overfit quickly
SaturationYou want harmonic density, edge, warmth, or controlled clipping characterYou need clean correction; saturation adds coloration by design
SpectralThe issue is perceptual tone shaping: air, presence, low-end focus, broad spectral contourYou need exact filter moves; use EQ
StereoWidth, mono compatibility, phase, or left/right balance is the problemThe mix is already phase-sensitive or mono delivery is primary
Maximizer / finalYou are at the delivery stage: loudness, ceiling, bit depth, or final output polishYou are still fixing balance or arrangement problems
RepairThe input has defects: clicks, crackle, hum, clipping, noise, excessive tailYou expect source separation or neural restoration

Most full chains use only a small subset: repair if needed, one tone stage, one dynamics stage, optional saturation/stereo, then maximizer/loudness. Stacking many processors from the registry is rarely better than starting from a preset and overriding one or two values.

Loudness, oversampling, and metering details

A few capabilities sit underneath the maximizer/final and analysis APIs:

  • Integrated LUFS measurement supports surround layouts up to 8 channels, applying the BS.1770 channel weights. BS.1770-4 itself normatively defines layouts only up to 5.1 (6 channels); the 7.1/8-channel weighting (treating the side-surround pair like the rear surrounds, +1.5 dB) is a non-normative extrapolation, not part of the standard.
  • The internal oversampler and true-peak stages accept power-of-two oversampling factors from 1 to 16 (1, 2, 4, 8, 16; the live meter accepts the same factors), trading CPU for inter-sample-peak accuracy.
  • For UI metering, pass maxPoints to meteringVectorscope(...) and meteringPhaseScope(...): they thin the point series down to at most maxPoints points, so a busy scope stays cheap to draw. (Without maxPoints they emit one point per input sample. The older meteringVectorscopeDecimated(...) / meteringPhaseScopeDecimated(...) aliases are deprecated and just delegate.) meteringSpectrumFrame(...) reads a single, non-time-averaged spectrum frame for spectrum-analyzer snapshots.
  • Every multiband.* solo processor — compressor, dynamicEq, expander, imager, limiter, and saturation — shares the same crossover mechanism and accepts a custom number of crossover cutoffs, so you can split into the band count your material needs instead of a fixed three. This entry point exposes up to 8 cutoffNHz slots (cutoff0Hzcutoff7Hz), so a single multiband.* call can address up to 9 bands.

What is a crossover?

A crossover splits the signal into frequency bands (e.g. lows / mids / highs) so each band can be processed separately. The "crossover cutoffs" are the frequencies where one band ends and the next begins; more cutoffs means more bands and finer control.

Solo processors

FamilyProcessor names
Dynamicsdynamics.brickwallLimiter, dynamics.compressor, dynamics.deesser, dynamics.expander, dynamics.gate, dynamics.limiter, dynamics.parallelComp, dynamics.sidechainRouter, dynamics.duckingProcessor, dynamics.transientShaper, dynamics.upwardCompressor, dynamics.upwardExpander, dynamics.vocalRider
EQeq.apiStyle, eq.bandPass, eq.cutFilter, eq.dynamic, eq.equalizer, eq.graphic, eq.linearPhase, eq.midSide, eq.minimumPhase, eq.parametric, eq.pultec, eq.shelving, eq.tilt
Finalfinal.bitDepth, final.dither, final.outputChain
Maximizermaximizer.adaptiveRelease, maximizer.loudnessOptimize, maximizer.maximizer, maximizer.softKneeMax, maximizer.truePeakLimiter
Multibandmultiband.compressor, multiband.dynamicEq, multiband.expander, multiband.imager, multiband.limiter, multiband.saturation
Repairrepair.declick, repair.declip, repair.decrackle, repair.dehum, repair.denoiseClassical, repair.dereverbClassical, repair.trimSilence
Saturationsaturation.ampSim, saturation.bitcrusher, saturation.exciter, saturation.hardClipper, saturation.multibandExciter, saturation.softClipper, saturation.tape, saturation.transformer, saturation.tube, saturation.waveshaper
Spectralspectral.airBand, spectral.lowEndFocus, spectral.presenceEnhancer, spectral.spectralShaper
Stereostereo.autoPan, stereo.haasEnhancer, stereo.imager, stereo.monoMaker, stereo.phaseAlign, stereo.stereoBalance

Stereo-family processors use a different entry point

Most processors run through the single-array masteringProcess() (mono, or interleaved). The stereo-family processors (stereo.imager, stereo.monoMaker, stereo.autoPan, stereo.haasEnhancer, stereo.phaseAlign, stereo.stereoBalance) operate on true left/right channels, so call them through the separate stereo entry point masteringProcessStereo() / mastering_process_stereo(), which takes distinct left and right arrays. stereo.monoMaker uses frequencyHz as the crossover below which it collapses the signal toward mono; amount controls how strongly it does so. The same is true of eq.midSide and the multiband.* processors. Passing these to masteringProcess() cannot express independent channels — see How to call them for the exact signatures.

What is dither?

When you reduce bit depth (e.g. 24-bit down to 16-bit for CD/streaming), rounding creates a faint distortion on quiet tails. Dither adds a tiny, carefully shaped noise that masks that distortion so fades sound smooth instead of grainy. Apply it once, last, at the final bit-depth reduction.

Repair is classical DSP, by design

repair.denoiseClassical, repair.dereverbClassical, and related processors use spectral subtraction / MMSE-STSA / LogMMSE with explicit noise estimation.

They are not DNN source separation or neural spectral repair.

  • Good for: noise, hum, clicks, clipping, and mild room smear.
  • Not for: unmixing finished tracks or rebuilding missing sources.
  • Design reason: the repair path stays deterministic and dependency-free.
A/B PROCESS · DENOISEIDLE
Denoise repair — damaged vs repaired

The clean chord is given a layer of broadband hiss (Damaged); the repair stage removes it (Repaired). Both averaged spectra are drawn together — the raised high-frequency floor is the hiss, and it drops back onto the music once denoised. Flip Compare to audition each side — the gain is untouched, so the hiss is the only thing that moves — and switch the algorithm to see how much floor each one pulls down. FLOOR is the high-band reduction in dB.

Compare
Algorithm

Registry names and chain keys differ

The named processor registry exposes one-shot repair processors as repair.denoiseClassical and repair.dereverbClassical.

Full-chain configs use shorter stage keys: repair.denoise.* and repair.dereverb.*. Those keys address the repair slots inside MasteringChainConfig.

Both naming styles point to the same classical denoise/dereverb implementations.

What is spectral subtraction (MMSE-STSA / LogMMSE)?

These are classical denoising methods.

  1. The algorithm estimates a noise profile from quiet passages, such as steady hiss or hum.
  2. Spectral subtraction subtracts that estimated noise from each short-time spectrum frame.
  3. MMSE-STSA and LogMMSE are statistical versions that estimate how much of each frequency bin is signal versus noise before subtracting.

This reduces the warbly "musical noise" that naive subtraction can leave. These methods do not separate instruments; they only attenuate noise.

What is saturation.ampSim?

A guitar/bass-amp-style coloration stage in the form preamp drive → tone stack → power amp → cabinet. An oversampled 12AX7 triode drive stage sits behind a single [0, 1] drive knob, with a drive-scaled pre-emphasis shelf so the gain character shifts as you push it. After the drive comes a bass/mid/treble tone stack, then an optional power-amp section and a data-free cab voicing. Construction/param keys: drive (0-1), bassDb, midDb, trebleDb, presenceDb, levelDb, power, sag, transformer, and nfb are automatable through set_parameter on every binding. power adds a class-AB push-pull soft-saturation stage; sag models supply droop and bloom after hard hits; transformer adds low-frequency output-transformer saturation; nfb adds a negative-feedback loop around the active power stage. cab (boolean), cabModel (0 = guitar 4x12, 1 = bass 8x10), and ampModel (0 = classic crunch, 1 = Fender-style clean, 2 = modern high-gain, 3 = tweed, 4 = Vox-style chime, 5 = rectifier) are discrete topology choices, so set them at construction time rather than automating them.

Pair processors and analyses

Pair processors consume a source and a reference. Pair/stereo analyses return measurement JSON and do not render audio by themselves.

TypeNames
Pair processorsmatch.applyMatchEq, match.alignReferenceToSource, match.abSwitch, match.abCrossfade
Pair analysesmatch.referenceLoudness, match.tonalBalance, match.tonalBalanceLogBands, match.matchEqCurve, match.estimateReferenceDelaySamples
Stereo analysesstereo.monoCompatCheck, stereo.monoCompatCheckLogBands

These are registry names you pass to masteringPairAnalyze(...) / masteringStereoAnalyze(...). Separately from the registry, the assistant helpers have their own stereo entry points that take a left/right pair directly — masteringAudioProfileStereo, masteringAssistantSuggestStereo, and masteringStreamingPreviewStereo. Use them instead of profiling a downmix, which under-reports integrated loudness by about 6 dB on decorrelated material; see Stereo sources.

What do "tonal balance" and "mono compatibility" measure?
  • Tonal balance (match.tonalBalance) describes how a track's energy is spread across frequency bands — how much sub, bass, mid, presence, and air it has. Comparing your tonal balance to a reference track shows where you are darker or brighter, which is what match.applyMatchEq then corrects.
  • Mono compatibility (stereo.monoCompatCheck) predicts what happens when your stereo mix is summed to mono (phone speakers, club PAs, some broadcast paths). If the left and right channels are out of phase, parts can cancel out and lose level when folded down. The check flags that risk before it surprises a listener. See Mono Compatibility for a deeper walk-through.

Mixer and engine inserts

The creative-FX insert catalog — reverb, modulation, and delay insert IDs, their parameter tables, the masteringInsertNames() discovery APIs, and SONARE_HAVE_FX / BUILD_ACOUSTIC_SIM build gating — lives on its own page: Effects Inserts.

How to call them

Use capabilityCatalog() / capability_catalog() when a host needs one build-aware picker across solo, pair, and creative-insert processors. It lists each processor's parameter descriptors — name, id, type, unit and realtime-safety — plus the built-in preset lists. Its min / max / default fields are always null, so it can populate a picker but not size a control; take value ranges from the per-processor tables on this page. masteringProcessorCatalog() is the narrower mastering registry classification used for mastering-specific pickers.

typescript
const build = capabilityCatalog();
console.log(build.processors.length, build.presets.mastering);

masteringProcessorNames();   // discover solo processor ids at runtime
masteringProcessorCatalog(); // classify processors for picker/filter UIs
masteringInsertParamInfo('eq.parametric'); // realtime automation metadata

const out = masteringProcess('dynamics.compressor', samples, sampleRate, {
  thresholdDb: -24,
  ratio: 1.5,
});

const stereo = masteringProcessStereo('stereo.imager', left, right, sampleRate, { width: 1.1 });

// Analyses return JSON strings — parse them
const report = JSON.parse(masteringPairAnalyze('match.referenceLoudness', source, reference, sampleRate));
const mono   = JSON.parse(masteringStereoAnalyze('stereo.monoCompatCheck', left, right, sampleRate));
typescript
import {
  capabilityCatalog,
  masteringInsertParamInfo,
  masteringPairAnalyze,
  masteringProcess,
  masteringProcessStereo,
  masteringProcessorCatalog,
  masteringProcessorNames,
  masteringStereoAnalyze,
} from '@libraz/libsonare-native';

const build = capabilityCatalog();
console.log(build.processors.length, build.presets.mastering);

masteringProcessorNames();
masteringProcessorCatalog();
masteringInsertParamInfo('eq.parametric');

const out = masteringProcess('dynamics.compressor', samples, sampleRate, {
  thresholdDb: -24,
  ratio: 1.5,
});
const stereo = masteringProcessStereo('stereo.imager', left, right, sampleRate, { width: 1.1 });
const report = JSON.parse(masteringPairAnalyze('match.referenceLoudness', source, reference, sampleRate));
const mono = JSON.parse(masteringStereoAnalyze('stereo.monoCompatCheck', left, right, sampleRate));
python
import json
import libsonare as sonare

build = sonare.capability_catalog()
print(len(build["processors"]), build["presets"]["mastering"])

sonare.mastering_processor_names()   # discover solo processor ids at runtime

out = sonare.mastering_process('dynamics.compressor', samples, sample_rate=sr, params={
    'thresholdDb': -24,
    'ratio': 1.5,
})

stereo = sonare.mastering_process_stereo('stereo.imager', left, right, sample_rate=sr, params={'width': 1.1})

# Analyses return JSON strings — parse them
report = json.loads(sonare.mastering_pair_analyze('match.referenceLoudness', source, reference, sample_rate=sr))
mono   = json.loads(sonare.mastering_stereo_analyze('stereo.monoCompatCheck', left, right, sample_rate=sr))
bash
# inspect this build and its capability-catalog summary
sonare doctor --json

# discover solo processor ids
sonare mastering-processors

# apply one solo processor (--params are floats: k=v,k=v)
sonare mastering-processor song.wav --processor dynamics.compressor \
  --params "thresholdDb=-24,ratio=1.5" -o out.wav

# two-input (pair) analysis prints JSON
sonare mastering-pair-analyze song.wav --reference ref.wav --analysis match.referenceLoudness

# The Python CLI has no dedicated mastering-stereo-analyze subcommand; only
# source-built C++ CLI builds expose the two-channel stereo analyses.
# (The Python `mastering-processor` command does run stereo-only processors,
#  but previews them by duplicating the mono input across left/right.)
Config style differs between chain entry points

The registry is string-based so C, Python, Node, WASM, and CLI callers share processor identifiers.

When you assemble a chain rather than a single processor, the config style depends on the entry point:

Entry pointConfig style
WASM masteringChain(...)Nested config objects; dot-notation leaf keys are also accepted in the same object
masterAudio(...) and Python/Node equivalentsFlat dot-notation overrides such as 'loudness.targetLufs'
Mastering Assistant chainConfig.paramsFlat form, ready for masterAudio. params["dynamics.multibandComp"] can also carry the nested, arbitrary-band v2 object described below — see The chain-config JSON schema

MasteringChainConfig accepts both spellings. A dot-notation leaf such as 'loudness.targetLufs': -20 can sit beside — or replace — the nested loudness: { targetLufs: -20 }, and the core validates the key and rejects an unknown one. Dot notation is the form the C ABI carries parameters in, which is what makes it the convenient shape when you are assembling overrides dynamically rather than writing them out.

The nested spelling is the canonical one, so prefer it in hand-written code: TypeScript checks a nested config field by field, while a dotted key is only checked at run time.

Repair chain keys follow the chain slots, not the one-shot registry names: use repair.denoise.* / repair.dereverb.* in flat overrides or the nested repair: { denoise: ..., dereverb: ... } shape in masteringChain(...).

The chain-config JSON schema

The flat chainConfig.params map (the shape chainConfig.params uses in the table above, and the shape masterAudio overrides accept) has a JSON-document serialization used by the CLI and the Mastering Assistant: sonare mastering --config <file> reads it, and masteringAssistantSuggest's chainConfig is expressed in it. That serialization auto-selects one of two schema versions.

Version 1 vs. version 2
  • Version 1 — the flat, fixed 3-band low/mid/high multiband compressor shape: dynamics.multibandComp.lowCutoffHz, .highCutoffHz, and per-band lowThresholdDb/midThresholdDb/highThresholdDb and their ratio/attack/release siblings. This is what every flat-override entry point sends, and what the Mastering Assistant always emits in practice — it never customizes the multiband compressor beyond the default 3-band shape, so its chainConfig stays version 1.

  • Version 2 — selected automatically once the multiband compressor configuration can no longer be represented as the fixed 3-band shape (a different cutoff count, non-default crossover slope/mode, or a non-default FIR kernel size). In that case params["dynamics.multibandComp"] becomes a structured object instead of the flat low/mid/high keys:

    • crossover.cutoffsHz[], crossover.slope, crossover.mode, crossover.firKernelSize
    • bands[] — up to 64 bands, each with thresholdDb, ratio, attackMs, releaseMs, kneeDb, makeupGainDb, autoMakeup, detector, sidechainHpfEnabled, sidechainHpfHz, pdrTimeMs, pdrReleaseScale

    Field validation is strict: unknown keys anywhere in the version-2 dynamics.multibandComp object are rejected, and the band count must equal the cutoff count plus one.

Reachability: JSON-document feature, not a JS-object feature

The version-2 structured form is reachable through the JSON document — the CLI's sonare mastering --config <file>, or any code that reads/writes chain config as JSON. The WASM masteringChain() TypeScript MasteringChainConfig.dynamics.multibandComp interface still only exposes the fixed low/mid/high shorthand, so the arbitrary-band form cannot be reached by building a MasteringChainConfig object directly in JavaScript — only by writing the JSON document yourself or generating one with the wider crossover count (for example through the named processor multiband.compressor and its up-to-9-band cutoffNHz slots) and passing it through the JSON path.