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 type | Meaning | Example |
|---|---|---|
| Preset | A named chain configuration for a style or delivery target | streaming, podcast, jpop |
| Solo processor | One processor applied to a mono or stereo signal | dynamics.compressor, eq.tilt |
| Pair processor | A processor that uses a source and a reference signal | match.applyMatchEq |
| Analysis | A measurement that returns JSON instead of audio | match.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 for | Learn the concept |
|---|---|---|
| Even out level / control dynamics | dynamics.compressor, dynamics.limiter, multiband.compressor | Dynamics |
| Add punch without squashing | dynamics.transientShaper, dynamics.parallelComp | Dynamics |
| Tame harsh "ess" sounds | dynamics.deesser | Dynamics |
| Duck a music bed under voice | dynamics.duckingProcessor, dynamics.sidechainRouter | Mixing Engine |
| Shape overall tone / brightness | eq.tilt, eq.parametric, spectral.airBand | Tone and Air |
| Add warmth / harmonics | saturation.tape, saturation.tube, saturation.exciter | Tone and Air |
| Widen / narrow / check stereo | stereo.imager, stereo.monoMaker, stereo.monoCompatCheck | Stereo, Limiter, Loudness |
| Hit a loudness target safely | loudness stage, maximizer.loudnessOptimize, maximizer.truePeakLimiter | Delivery Targets |
| Clean up noise / clicks / clipping | repair.denoiseClassical, repair.declick, repair.declip | Repair and Input |
| Match a reference track | match.applyMatchEq, match.referenceLoudness | Reference 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:
| Family | Use it when | Avoid it when |
|---|---|---|
| Dynamics | The level envelope is the problem: peaks jump out, vocals are uneven, transients need shaping, or a bed must duck under speech | The problem is tonal balance; EQ or spectral processors are clearer |
| EQ | The frequency balance is wrong: too dark, too harsh, too boomy, or needs a surgical cut | You are trying to increase loudness; use dynamics/maximizer stages |
| Multiband | Different frequency ranges need different dynamics or width treatment | A broad single-band processor already solves it; multiband can overfit quickly |
| Saturation | You want harmonic density, edge, warmth, or controlled clipping character | You need clean correction; saturation adds coloration by design |
| Spectral | The issue is perceptual tone shaping: air, presence, low-end focus, broad spectral contour | You need exact filter moves; use EQ |
| Stereo | Width, mono compatibility, phase, or left/right balance is the problem | The mix is already phase-sensitive or mono delivery is primary |
| Maximizer / final | You are at the delivery stage: loudness, ceiling, bit depth, or final output polish | You are still fixing balance or arrangement problems |
| Repair | The input has defects: clicks, crackle, hum, clipping, noise, excessive tail | You 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(...)andmeteringPhaseScopeDecimated(...)thin the point series down to at mostmaxPointspoints, 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.imagerandmultiband.dynamicEqexpose 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
| Family | Processor names |
|---|---|
| Dynamics | dynamics.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 |
| EQ | eq.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 |
| Final | final.bitDepth, final.dither, final.outputChain |
| Maximizer | maximizer.adaptiveRelease, maximizer.loudnessOptimize, maximizer.maximizer, maximizer.softKneeMax, maximizer.truePeakLimiter |
| Multiband | multiband.compressor, multiband.dynamicEq, multiband.expander, multiband.imager, multiband.limiter, multiband.saturation |
| Repair | repair.declick, repair.declip, repair.decrackle, repair.dehum, repair.denoiseClassical, repair.dereverbClassical, repair.trimSilence |
| Saturation | saturation.ampSim, saturation.bitcrusher, saturation.exciter, saturation.hardClipper, saturation.multibandExciter, saturation.softClipper, saturation.tape, saturation.transformer, saturation.tube, saturation.waveshaper |
| Spectral | spectral.airBand, spectral.lowEndFocus, spectral.presenceEnhancer, spectral.spectralShaper |
| Stereo | stereo.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.
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.
- The algorithm estimates a noise profile from quiet passages, such as steady hiss or hum.
- Spectral subtraction subtracts that estimated noise from each short-time spectrum frame.
- 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.
| Type | Names |
|---|---|
| Pair processors | match.applyMatchEq, match.alignReferenceToSource, match.abSwitch, match.abCrossfade |
| Pair analyses | match.referenceLoudness, match.tonalBalance, match.tonalBalanceLogBands, match.matchEqCurve, match.estimateReferenceDelaySamples |
| Stereo analyses | stereo.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 whatmatch.applyMatchEqthen 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:
| API | Returns |
|---|---|
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 ID | Meaning |
|---|---|
effects.reverb.plate | Alias for the Dattorro plate-style reverb |
effects.reverb.dattorro | Dattorro reverb |
effects.reverb.fdn | Feedback delay network reverb |
effects.reverb.velvet | Velvet-noise style reverb |
effects.reverb.convolution | Convolution reverb; can use an impulse response in native insert creation paths |
effects.reverb.room | Geometric room reverb synthesized from room parameters |
effects.acoustic.roomMorph | Room-character morph toward a target geometric room |
effects.modulation.ensemble | Solina-style BBD string-machine ensemble |
effects.modulation.chorus | Stereo chorus |
effects.modulation.flanger | Flanger |
effects.modulation.phaser | Phaser |
effects.delay.stereo | Stereo 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:
| Detail | Meaning |
|---|---|
effects.reverb.plate and effects.reverb.dattorro | Two names for the same Dattorro processor |
| Reverb params | decaySec, 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 params | rateHz, depthMs, centerDelayMs, dryWet |
effects.modulation.flanger params | rateHz, depthMs, centerDelayMs, feedback, dryWet |
effects.modulation.phaser params | rateHz, minHz, maxHz, stages, dryWet |
effects.modulation.ensemble params | rateSlowHz, rateFastHz, depthSlowMs, depthFastMs, centerDelayMs, toneHz, dryWet |
effects.delay.stereo params | delayTimeLMs, delayTimeRMs, feedback, pingPong, dryWet |
effects.reverb.convolution | Needs an impulse response supplied through native insert construction |
| Convolution insert without an IR | Effectively 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;
plateis 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
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));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))# 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 point | Config style |
|---|---|
WASM masteringChain(...) | Nested config objects |
masterAudio(...) and Python/Node equivalents | Flat dot-notation overrides such as 'loudness.targetLufs' |
Mastering Assistant chainConfig.params | Flat 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(...).
Related
- Mastering Assistant — profile/suggest/preview JSON and the suggestion→render path
- Mastering Implementation — the chain that renders in the browser demo
- DSP Implementation Notes — how each family behaves
- Mixing Engine — load these processors as channel-strip/bus inserts