Skip to content

Mastering Processors

This page is the registry for the named mastering surface 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 (LUFS-target maximizing), 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.

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 surfaces:

  • Integrated LUFS measurement supports surround layouts up to 8 channels, applying the BS.1770 channel weights.
  • 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 there are display-decimated variants: meteringVectorscopeDecimated(...) and meteringPhaseScopeDecimated(...) thin the point series down to at most maxPoints points, so a busy scope stays cheap to draw. meteringSpectrumFrame(...) reads a single, non-time-averaged spectrum frame for spectrum-analyzer snapshots.
  • A stereo imager (widens or narrows the stereo field per band) and a dynamic EQ (an EQ whose boost/cut reacts to level, like a frequency-targeted compressor) are available in multiband form: multiband.imager and multiband.dynamicEq expose per-band parameters and accept a custom number of crossover cutoffs, so you can split into the band count your material needs instead of a fixed three.

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
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 at the same loudness, 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-amp-style coloration stage in the form drive → tone stack → cab. 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 a fixed, data-free cab voicing (low cut, body bump, presence peak, and a steep roll-off around 4.8 kHz) that can be bypassed for a clean DI tone. The drive, tone, presence, and level controls are automatable through set_parameter on every binding. Construction/param keys: drive (0–1, overdrives the 12AX7 triode stage), bassDb, midDb, trebleDb (tone-stack gains in dB at 120 Hz / 550 Hz / 3 kHz), presenceDb (presence-peak gain in dB on the cab voicing, ~3.8 kHz), and levelDb (output trim in dB) — these six are also the set_parameter automation lanes. The cab boolean (default true) is a discrete topology switch: set it false to bypass the cabinet voicing for a clean DI tone; unlike the others it is not exposed to set_parameter.

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
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 Insert Names

Mixer scene inserts use the same processor factory as mastering inserts, but the valid insert set is slightly broader than masteringProcessorNames(). Four runtime APIs describe what is available and how to configure it:

APIReturns
masteringInsertNames()The full list of valid insert ids
masteringInsertParamNames(name)The construction keys one insert accepts (band/sub-band processors list their indexed band{i}.* keys; an unknown name returns an empty array)
masteringInsertParamInfo(name)The realtime-automatable subset: each parameter's JSON key, numeric automation id, and realtime-safety flag
masteringProcessorCatalog()Machine-readable entries (kind, realtimeInsertable, stereoOnly, channelPolicy) for picker/filter UIs, so hosts can filter offline-only, pair, stereo-only, and surround-wrapping behavior without hard-coding processor IDs

The Python equivalents are mastering_insert_param_names(name), mastering_insert_param_info(name), and mastering_processor_catalog().

Keys outside an insert's list are ignored by the processor and reported through Mixer.sceneWarnings() when a scene carrying them loads. In addition to the solo processors above, builds with creative FX enabled expose reverb and modulation insert IDs:

Insert IDMeaning
effects.reverb.plateAlias for the Dattorro plate-style reverb
effects.reverb.dattorroDattorro reverb
effects.reverb.fdnFeedback delay network reverb
effects.reverb.velvetVelvet-noise style reverb
effects.reverb.convolutionConvolution reverb; can use an impulse response in native insert creation paths
effects.reverb.roomGeometric room reverb synthesized from room parameters
effects.acoustic.roomMorphRoom-character morph toward a target geometric room
effects.modulation.ensembleSolina-style BBD string-machine ensemble
effects.modulation.chorusStereo chorus
effects.modulation.flangerFlanger
effects.modulation.phaserPhaser
effects.delay.stereoStereo delay

These insert IDs are available only in builds with SONARE_HAVE_FX. The geometric room inserts also require BUILD_ACOUSTIC_SIM.

There are a few practical details to know:

DetailMeaning
effects.reverb.plate and effects.reverb.dattorroTwo names for the same Dattorro processor
Reverb paramsdecaySec, decay, damping / hfDamping, dryWet, preDelayMs, reverbTimeS, densityHz, enableShelf (which apply depend on the algorithm). The Dattorro/plate insert also accepts modRateHz (figure-8 tank LFO rate in Hz, default 0.5) and modDepthSamples (modulation depth in samples at the reverb's reference rate, default 6.0) for its chorused tail.
effects.modulation.chorus paramsrateHz, depthMs, centerDelayMs, dryWet
effects.modulation.flanger paramsrateHz, depthMs, centerDelayMs, feedback, dryWet
effects.modulation.phaser paramsrateHz, minHz, maxHz, stages, dryWet
effects.modulation.ensemble paramsrateSlowHz, rateFastHz, depthSlowMs, depthFastMs, centerDelayMs, toneHz, dryWet
effects.delay.stereo paramsdelayTimeLMs, delayTimeRMs, feedback, pingPong, dryWet
effects.reverb.convolutionNeeds an impulse response supplied through native insert construction
Convolution insert without an IREffectively behaves as a passthrough
What are these reverb algorithms?

They are different ways to synthesize a reverb tail. Pick by the character you want, not by correctness — all are valid.

  • Plate / Dattorro — a smooth, dense, classic-studio sound. The Dattorro topology is a widely used plate-style design; plate is an alias for it.
  • FDN (feedback delay network) — a flexible algorithmic reverb built from interconnected delay lines, easy to tune from small rooms to large halls.
  • Velvet-noise — uses sparse random impulses to build an efficient, natural-sounding tail at low CPU cost.
  • Convolution — reproduces a real space by convolving the signal with a measured impulse response of that room.
What is effects.modulation.ensemble?

A Solina-style BBD string-machine ensemble — the lush, chorused tone of vintage string synths. It runs three delay taps per channel, swept simultaneously by a slow and a fast 3-phase LFO bank, so the modulation is dense rather than a single chorus wobble. A BBD bucket-bandwidth lowpass darkens the wet path, emulating the analog bucket-brigade delay lines. The right-channel LFO polarity is inverted, which spreads a mono source into a wide stereo image. It is exposed through the insert factory and its parameters are automatable through set_parameter on every binding.

Use these in Mixing Scene JSON insert.processor fields. In the shipped FX-enabled WASM build, most of them are also one-shot mastering processors: effects.reverb.plate, effects.reverb.dattorro, effects.reverb.fdn, effects.reverb.velvet, effects.reverb.convolution, effects.modulation.chorus, effects.modulation.flanger, effects.modulation.phaser, and effects.delay.stereo are returned by masteringProcessorNames() and run through the one-shot apply path. The geometry-driven inserts and the ensemble — effects.reverb.room, effects.acoustic.roomMorph, and effects.modulation.ensemble — are insert-only and do not appear in masteringProcessorNames(); reach them through masteringInsertNames() and scene inserts.

How to call them

typescript
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));
python
import json
import libsonare as sonare

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
# 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

# stereo processors (stereo.imager) have no Python CLI subcommand.
# Source-built C++ CLI builds also expose mastering-stereo-analyze / analyses.
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
masterAudio(...) and Python/Node equivalentsFlat dot-notation overrides such as 'loudness.targetLufs'
Mastering Assistant chainConfig.paramsFlat form, ready for masterAudio

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(...).