31 KiB
Patina: resonance-compressor research and design
Research date: 2026-11-05. This document preserves the research and design proposal. The first implementation is now in the repository; see the implementation and setup guide.
1. What we want to build
A Rust audio effect for FL Studio that reduces objectionable spectral peaks while retaining the source's intended tone, movement, and punch. The conventional name for this category is dynamic resonance suppressor. “Resonance compressor” is a useful working name: gain reduction varies with both frequency and time.
The main application here is aggressive, harmonically rich riddim sound design, with melodic parts and full mixes as additional evaluation material. A useful result is a bass that keeps its vowel, metallic edge, and rhythm while a painful ring becomes less distracting. Making every spectrum smooth is not the goal.
The recommendation is an independently designed STFT spectral attenuation engine, first delivered as a separate CLAP effect. Start with explicit controls, conservative reduction, linked stereo, delta monitoring, and correct host latency. Add transient protection after validating the basic detector. Defer automatic harmonic protection, multiple resolution engines, and zero-latency processing.
Throughout this document:
- Documented behavior means a manufacturer, paper, or source code describes it.
- Proposed design means our engineering choice, not a disclosed commercial algorithm or a claim of equivalent sound quality.
- Listening hypothesis means something to test with producers.
No commercial binaries were reverse engineered or benchmarked. Product claims below were researched from public primary sources; they are not listening results.
2. What the reference tools actually offer
Quance — CodWaves
This is the product referred to as “quance.” At the research date its official page lists €49.99 launch pricing, a crossed-out €79.99 price, and a sale ending November 30, 2026. These are temporary advertised prices, not a guaranteed future checkout price. Formats listed are VST3, AU, and AAX for Windows/macOS.
Its useful workflow references include editable tame/protect regions, learn, tone/transient protection, delta monitoring, and multiple processing grades. The developer describes both multi-resolution studio processing and a separate causal filter-bank audio path for zero added sample latency. Official product page.
The manual describes a detector based on neighboring spectral content and an adaptive longer-term reference. Reduction uses a soft knee and temporal smoothing. Its zero-latency audio path still uses an STFT for detection: detection therefore reacts late even though audio is not delayed. This distinction is important for our design. The manual also documents stereo linking, dry alignment, and an optional reduction ceiling. These descriptions do not disclose all tuning or implementation details. Quance manual, especially §§9 and 13.
Soothe2 — oeksound
Soothe2 documents adaptive resonance reduction with frequency-dependent attack and release. Sharpness controls the shape of cuts; selectivity controls which resonances qualify. A frequency curve steers sensitivity rather than applying ordinary static EQ. Delta, external sidechain detection, stereo options, and quality controls support contextual audition. The manual warns that extreme settings can damage the sound.
Design lesson: keep where to work, what qualifies, how deeply to cut, and how quickly to react understandable as separate decisions. This is an interpretation of the workflow, not a reconstruction of Soothe2's DSP. Official Soothe2 manual.
Soothe3 — the current oeksound reference
Research should include Soothe3 rather than treating Soothe2 as the newest version. Its manual describes a level-adaptive soft mode and an absolute-level hard mode, a Detail control, maximum-cut limiting, and minimum-phase processing by default with a linear-phase option. It also documents frequency-dependent timing adjustments. These are useful references for control design and phase tradeoffs; our first STFT processor would not reproduce these modes. Official Soothe3 manual.
Oeksound's product listing currently advertises $259 for Soothe3. Price alone does not establish comparative value or sound quality. Official product listing.
Useful lower-cost comparison points
| Tool | Why compare it | What the comparison does not establish |
|---|---|---|
| TDR Nova | Free parallel dynamic EQ with four dynamic bands: a practical manual corrective baseline | It is not the same workflow as automatic dense resonance suppression |
| NIH-plug Spectral Compressor | Public Rust example of FFT-domain dynamics and sidechain spectral processing | Many-band compression is not automatically a resonance detector |
| Static parametric EQ | Tests whether a simple fixed cut solves the problem adequately | A changing resonance may need different treatment over time |
Sources: Tokyo Dawn's Nova page, Spectral Compressor's author README.
We should compare output against bypass and a sensible manual correction before claiming an advantage over either commercial reference.
3. The perceptual problem
A peak is observable; an unwanted peak is a judgment
A spectral peak can be a fundamental, a formant, an instrument resonance, a room mode, deliberate filter emphasis, or an analysis artifact. Height alone cannot classify it as a defect. A stable peak may be the exact feature that makes a bass recognizable. Noise-like sibilance can be objectionable without a narrow peak.
For this project, use excess relative to a local spectral reference as an operational detection rule, and expose decisions to the producer. It is not a physical measurement of the source's resonator and not an emotion detector.
Frequency neighborhoods should reflect listening, not just FFT indices
Human auditory filtering provides a reason to explore perceptual frequency coordinates. Glasberg and Moore's research derives auditory-filter shapes from notched-noise experiments; its scope is hearing, not a universal rule for desirable EQ. An ERB-spaced or logarithmic neighborhood is a useful engineering hypothesis. It should not be marketed as a complete model of perception. Glasberg and Moore, 1990.
Relevant research on automatic resonance equalization
Grachten, Deruty, and Tanguy describe a spectral resonance attenuator separately from a neural network that predicts attenuation strength. Their detector compares a smoothed spectral reference with a perceptually weighted spectrum on a log-frequency representation. Their listening experiment involved 15 professional participants and 150 excerpts, with substantial variation in preferred treatment.
This supports trying a transparent, non-neural detector first and evaluating preferred strength through listening. It does not demonstrate equivalence to Soothe, success on riddim stems, or that their long analysis windows suit live monitoring. Use the explicitly linked 2018 v1 when reproducing this account; the unversioned arXiv record has subsequently changed. Paper, v1, §§2–3.
Corbach and colleagues study automated room-resonance suppression using measured room behavior and parametric filtering. It is relevant to targeted filters, but room-response identification is a different problem from deciding which peaks to remove from an arbitrary musical recording. DAFx-09 paper.
Consequences for riddim and melodic bass
The following are project-specific listening hypotheses, not findings established by the cited papers:
- A resonant vowel sweep may be the musical gesture. Protect its body and reduce only a distracting upper whistle instead of flattening the entire sweep.
- Distortion and multiband dynamics can change which partial dominates from note to note. Evaluate after the intended processing chain as well as before it.
- A repeated metallic resonance can function as a hook. Persistence alone is insufficient evidence that it should be removed.
- A snare's initial crack and its later ring need different treatment. Preserving the attack while controlling the tail may retain impact.
- Cleaning a soloed bass can reduce its ability to cut through the mix. Make final decisions against the drums and melodic context, at comparable listening level.
The Devath reference work in this repository measured broad signal changes. It did not establish which resonances were intentional or identify an ideal correction. Use original stems and controlled synthetic examples for development; full mastered references cannot isolate cause or provide a clean target.
4. Architecture choices
| Approach | Advantages | Main difficulties | Recommendation |
|---|---|---|---|
| STFT → gain surface → inverse STFT | Dense frequency control; straightforward delta and analysis; testable reconstruction | Window latency, time/frequency tradeoff, ringing and modulation artifacts | First implementation |
| Detector → a few tracked dynamic notches | Economical audio path; can target persistent rings | Peak tracking, filter stability, crossing peaks, phase movement | Later experiment |
| Dense causal filter bank | Audio path can have no added buffering delay | Finite band selectivity, detector lag, interacting filters, moving phase | Separate live-mode project |
| Multi-resolution spectral processing | Longer low-frequency observation and shorter high-frequency observation | Crossovers, alignment, phase, extra CPU and more validation | After single-resolution baseline |
| Learned detector or parameter estimator | Could model preferences or source categories | Dataset, labels, domain shift, inference cost, explainability | Defer |
These are engineering tradeoffs. Zero audio delay does not imply instantaneous detection. Minimum phase does not imply no phase change. Retaining FFT phase does not make a time-varying processor equivalent to one fixed linear-phase filter.
5. Proposed first DSP pipeline
main audio ── analysis window / FFT ──────────────── complex-bin gains
│ │
└─ detector spectrum inverse FFT
local reference synthesis window
prominence overlap-add
sensitivity mask │
knee + strength + cap wet audio
frequency/time smoothing │
└───────────────────────────────┘
main audio ── matching delay ── dry ── mix / delta / bypass ── output trim
This is our proposed baseline, not either manufacturer's internal block diagram. An external sidechain can later replace the detector input without replacing the main audio being filtered. Spectral ducking needs its own detection semantics; simply feeding a resonance-only detector with a sidechain will not duck all its musically relevant energy.
5.1 Reconstruction before suppression
Implement weighted overlap-add (WOLA), then demonstrate a unity-gain null against
the delayed input before adding detection. With analysis window wa, synthesis
window ws, and hop H, reconstruction requires a constant window-product sum:
sum_m wa[n - mH] * ws[n - mH] = C
Normalize by C, or use a corresponding reconstruction-normalization buffer.
Use a compatible periodic window/hop pair and explicitly test stream startup,
tail flushing, and arbitrary host block boundaries. The analysis window alone
is not sufficient when a synthesis window is also applied.
Julius O. Smith, Weighted Overlap Add.
For the prototype, try a periodic square-root Hann pair with H = N/4 and
the appropriate product-sum normalization. Use the FFT library's required
round-trip normalization separately. RealFFT does not normalize either transform;
a forward/inverse pair needs a total 1/N factor.
RealFFT scaling documentation.
5.2 Detector and local reference
The following equations define an original experimental detector. They are starting points to measure and tune, not validated optimal settings.
For channel c, frame t, bin k:
P[c,t,k] = calibrated_power(|X[c,t,k]|²)
L[c,t,k] = 10 * log10(max(P[c,t,k], epsilon))
B[c,t,k] = robust_local_reference(L[c,t,*], frequency[k], neighborhood_width)
E[c,t,k] = max(0, L[c,t,k] - B[c,t,k])
calibrated_power must define its units. Correct for FFT size, window gain, and
one-sided spectrum conventions before introducing any absolute-level threshold.
Do not interchange per-bin power, band energy, and power spectral density.
Start with a log-frequency neighborhood and a bounded weighted mean baseline; compare a median/percentile baseline offline. Excluding a small central region can keep a strong peak from raising its own reference too much, but can also make leakage look like multiple resonances. Define edge behavior near DC/Nyquist. Precompute interpolation maps and neighbor lists outside the audio callback.
Adding a constant gain to the signal shifts both L and B; their difference is
approximately level-invariant above the numerical floor. That is useful for a
relative mode. An absolute gate, saturation, and noise-floor handling break this
invariance and must be documented and tested.
A smooth spectrum can still sound harsh, while harmonics can have large E.
Keep detection range and manual protection available from the first usable build.
Do not promise automatic separation of tone from unwanted resonance.
5.3 Independent controls and reduction law
Use these meanings consistently:
- Sensitivity: local-prominence threshold
Tin dB. - Amount: slope
aof attenuation above that threshold. - Max cut: explicit upper bound
Dmaxon the applied attenuation surface. - Detail: neighborhood/reduction width, with the actual mapping documented.
- Focus/protect curve: steers sensitivity or reduction; label which it does.
A simple continuous knee function for positive excess u = E - T, width W > 0:
K(u,W) = 0 if u <= -W/2
(u + W/2)² / (2W) if -W/2 < u < W/2
u if u >= W/2
Dtarget = clamp(a * K(E - T,W), 0, Dmax)
For W = 0, use max(0,u) explicitly. This is a knee on relative prominence,
not the complete static transfer curve of an ordinary broadband compressor.
Apply smooth frequency limits and protection weights. Smooth reduction across frequency to avoid isolated, rapidly appearing holes. Reapply the mask and cap after operations that could spread or overshoot reduction into excluded regions. Transition mask edits smoothly rather than abruptly changing gains.
5.4 Temporal behavior
Smooth attenuation in dB at the frame rate, with separate attack and release:
alpha = exp(-H / (sample_rate * tau_seconds))
D[t,k] = alpha * D[t-1,k] + (1-alpha) * Dtarget[t,k]
Choose attack when the target attenuation increases and release when it decreases. Handle zero time explicitly. The time constants describe this smoother, not total response latency: windows, hop, and detector averaging also contribute.
Compare frequency-scaled timing against uniform timing; do not assume one wins. Very fast changing narrow cuts can produce audible movement and sidebands. Very slow cuts can miss a short whistle or remain after it disappears. Inspect step response and note transitions as well as steady-state attenuation.
5.5 Apply the gain surface
G[t,k] = 10^(-D[t,k]/20)
Y[t,k] = G[t,k] * X[t,k]
Use amplitude gains on complex bins, not power ratios directly. Preserve the real-spectrum constraints at DC and Nyquist and keep reconstruction scaling consistent. Initially retain each bin's phase; evaluate ringing and transient smear honestly. This is not a claimed minimum-phase implementation.
G <= 1 is a spectral attenuation constraint. It does not guarantee that
every output sample peak is lower than the input peak: changing frequency
components can change their time-domain cancellation. This is not a limiter.
5.6 Stereo and monitoring
Default to a shared attenuation surface for left and right. One proposed rule is to compute both channels' target reductions and use their per-bin maximum before smoothing. This avoids oppositely panned tones canceling in a summed detector. Identical gains preserve per-bin L/R relationships, though tonal balance changes.
Add dual-mono and mid/side only after linked stereo passes image and mono checks. Use an explicit reversible M/S normalization and test it with no attenuation.
For monitoring, define the signal taps precisely:
delta = delayed_dry - wet_before_output_trim
mixed = (1-mix) * delayed_dry + mix * wet
Use a linear dry/wet law so identical dry/wet signals remain unity at all mix positions. Bypass keeps the same delay and crossfades to dry. Delta bypasses makeup gain and loudness matching so the subtraction remains interpretable. It reveals changed material, including phase/time changes; it is not proof that everything heard there was unwanted. Restore normal monitoring when loading a preset.
6. Resolution, latency, and phase
For a length-N transform, nominal bin spacing is sample_rate/N. This is not
the full practical ability to distinguish neighboring tones: the window matters.
Zero-padding adds interpolated spectral samples, not more observation time.
Calculated examples at 48 kHz, with H=N/4:
| FFT length | Observation length | Bin spacing | Hop duration |
|---|---|---|---|
| 1024 | 21.33 ms | 46.875 Hz | 5.33 ms |
| 2048 | 42.67 ms | 23.438 Hz | 10.67 ms |
| 4096 | 85.33 ms | 11.719 Hz | 21.33 ms |
| 8192 | 170.67 ms | 5.859 Hz | 42.67 ms |
These are calculations, not measured plugin latencies. A causal implementation's
actual buffering schedule determines its reported delay. In the repository's
pinned NIH-plug revision, StftHelper::latency_samples() returns its active
window length. With that helper, N=2048 reports 2048 samples, not N/2 or H.
Report the actual helper delay to the host and verify it with an impulse.
Pinned STFT helper source.
Start with one fixed configuration: N=2048, H=512 at 44.1/48 kHz. Consider
doubling both at 88.2/96 kHz to retain similar time/frequency behavior. This choice
is primarily for mid/high resonance work; it is not precise sub-bass surgery.
Increasing FFT length while retaining 75% overlap also increases time between
updates. Greater overlap can improve update rate at extra CPU cost.
Do not advertise zero latency for this first engine. Keep quality changes out of ordinary automation initially. Later mode switches need state transitions, host latency updates, and aligned crossfades or a controlled processing restart. Offline rendering should initially use the same DSP configuration as playback.
Linear-phase-style spectral shaping can ring before transients. Minimum-phase shaping changes phase and can complicate parallel blending. Neither removes the time/frequency tradeoff. A future minimum-phase option needs its own validated filter construction, not just a label on the existing gain surface.
7. Protection features worth researching next
| Feature | Candidate approach | Failure to evaluate |
|---|---|---|
| Transient protection | Positive spectral flux or fast/slow energy comparison reduces suppression briefly; separate onset and tail | Missing a short painful peak, or ducking protection too often on distorted bass |
| Harmonic protection | Confidence-weighted fundamental/harmonic evidence relaxes reduction | Polyphonic, inharmonic, noisy, or rapidly changing tones; a harmful ring may itself be pitched |
| Learn | Aggregate prominence statistics over a representative passage and propose editable focus points | Learning the hook as a defect or treating one passage as the entire song |
| Fixed protect regions | User draws a smooth exclusion around the bass body or snare | Protecting a problem along with the desired tone |
| External spectral ducking | Derive a smooth masking/priority curve from a routed reference | Removing too much accompaniment, noisy sidechains, missing input routing |
For a first protection feature, prefer an optional transient guard with a visible effect and an off switch. Explicit protect regions are a more dependable initial interface than promising perfect automatic harmonic preservation.
If Learn is added, keep the result editable and undoable; show exactly which parameters changed. It should suggest where to investigate rather than declare that detected peaks are mistakes.
8. Professional workflow
- Insert on the problem source or bus and loop the offending passage in context.
- Restrict the processing range; protect the source's body or deliberate vowel.
- Raise Amount until the problem is clearly affected, then back off. Use an explicit modest Max cut as an initial experiment, not a universal preset.
- Listen to delta briefly. If it carries the melody, vowel, or whole snare attack, reassess what is being removed. This is a diagnostic, not an automatic verdict.
- Adjust sensitivity/detail and timing. Check the quieter phrase and the next note as well as the loudest part.
- Compare bypass and processed sound at similar loudness in the whole mix.
- Save A/B states and automation only when the choice improves the musical role.
Useful starting tasks: upper-mid whistle on a growl, a moving metallic partial, snare-tail ring, a bright melodic layer masking another part, and harsh buildup on a bass bus. Evaluate these separately: one universal setting is unlikely.
The first interface should expose Amount, Sensitivity, Detail, Max cut, Attack, Release, frequency limits, linked stereo, Mix, output trim, Delta, and Bypass. Show input spectrum and actual reduction as distinct traces, with a fixed logarithmic frequency axis and readable reduction units. The UI should distinguish frequency sensitivity from static EQ gain.
Loudness matching can initially be a manual output-trim workflow. A later automatic comparison feature should use bounded, slow compensation with silence handling; avoid makeup gain that disguises excessive removal or boosts between phrases.
9. Rust integration in this repository
Current components, kept separate from Rivet’s musical generator:
plugins/patina/core/ detector, gain law, smoothing, fixed DSP state
plugins/patina/render/ offline WAV processing and measurement harness
plugins/patina/ui/ shared native editor and font assets
plugins/patina/plugin/ independent NIH-plug CLAP effect wrapper
Reuse the existing pinned NIH-plug wrapper strategy and packaging conventions, but register a new plugin identifier and an audio effect layout with mono and stereo input/output. Do not inherit the generator's instrument classification, MIDI scheduling, or sound-generation path. External audio sidechain is a later optional port with explicit host-routing tests.
Candidate FFT implementation: realfft backed by rustfft. Plan transforms and
allocate all ring buffers, spectra, smoothing state, neighbor maps, and scratch
storage during initialization. RustFFT's convenient process() allocates scratch;
use the supplied-scratch methods in the processing path and query their required
sizes during setup.
RustFFT API.
Additional engineering requirements:
- No heap allocation/deallocation, blocking locks, file I/O, or FFT planning in the audio callback; prevent an overwritten shared buffer from freeing there.
- Bound detector work. A naive all-bin neighborhood scan is quadratic; use precomputed bounded neighborhoods, running sums, or a coarser detector grid.
- Process arbitrary host buffer lengths through the ring-buffer scheduler.
- Smooth automatable parameters; keep latency-changing parameters nonautomatable until the transition contract is implemented.
- Decimate analyzer data into preallocated UI buffers; rendering must not drive processing or stall the callback.
- Reset histories and delay buffers consistently on reinitialization. Bound and version state; default to normal monitoring, never unexpected delta playback.
- Sanitize invalid numerical state and handle silence/denormals without noise bursts. Flush the delayed tail correctly in offline rendering.
Existing source-code reference and licensing distinction
NIH-plug itself has an ISC license, but its Spectral Compressor example is GPL-3.0-or-later, including in the locally cached revision used by this project. The example's manifest and source header were checked. Treat it as a reference; do not assume the framework license applies to every bundled plugin or copy that implementation into an ISC-labeled plugin without resolving the differing terms. Framework license, example manifest.
10. Validation before calling it useful
Deterministic DSP checks
| Check | Required observation |
|---|---|
| Unity reconstruction | With attenuation disabled, null against delayed input within a declared floating-point tolerance, including startup/tail |
| Reported latency | Impulse delay agrees with host-reported samples at each supported sample rate |
| Dry/mix/bypass | Unity response at every Mix position when wet equals dry; crossfades and delta use aligned taps |
| Synthetic narrow ring | A gated tone over a shaped noise bed triggers localized reduction with predictable timing |
| Sweeping tone | No unstable hopping, clicks, or unexpectedly wide removal as a peak crosses bins |
| Harmonic stack | Fundamentals and intentional harmonics reveal the detector's false-positive behavior |
| Silence and fades | No gain bursts, NaNs, denormal CPU spikes, or stale reduction after silence |
| Gain scaling | Relative mode behaves similarly above its gate/floor after input-level changes |
| Stereo | In-phase, opposite-polarity, hard-panned, and decorrelated inputs retain expected linking behavior |
| Parameter motion | Extreme valid automation does not click, allocate, or exceed the defined attenuation cap |
| Block invariance | Equivalent stream output for fixed, tiny, irregular, and changing host buffer sizes |
| Real-time performance | Allocation counter stays zero during processing; worst-frame CPU tested with many instances |
Measure the gain-surface bound separately from output sample/true-peak behavior. Use swept and stepped resonances to measure attack, release, and detector lag; steady-state plots alone are insufficient. Benchmark on named hardware with stereo, sample rate, FFT size, overlap, host buffer size, and instance count stated.
Listening evaluation
Use producer-owned dry stems, synthetic controls, and several source categories. For each, compare bypass, a manual EQ/dynamic-EQ correction, our output, and commercial references only when legitimately available. Randomize labels and match listening level before judging. Include cases where bypass is preferred.
Ask concrete questions: Is the whistle less distracting? Does the vowel still move? Does the snare retain impact? Does the melodic layer retain its identity? Can a producer achieve the result faster? Repeat on the complete arrangement.
Record dulling, loss of body, pre-ringing, warbling, transient smear, image changes, and the amount of useful adjustment. A visually flatter spectrum and a larger reduction number are not success metrics.
FL Studio acceptance
Verify discovery as an effect, insert routing, latency compensation, parallel mixing, automation, save/reopen, sample-rate changes, render tails, and repeated instance loading. Test mono/stereo channel layouts and multiple buffer sizes. When sidechain support arrives, test absent/connected/changed routes explicitly. Do not infer host compatibility solely from a successful Rust build.
11. Implementation sequence and unresolved decisions
- Reconstruction milestone: offline identity processor, impulse/latency tests, ring-buffer scheduling, and allocation checks. No suppression UI yet.
- Detector milestone: relative prominence, explicit range/protection, knee, separate Amount/Max cut, linked stereo, gain smoothing, and offline comparisons.
- Usable effect milestone: CLAP audio wrapper, stable parameters and state, analyzer/reduction display, delta, aligned bypass/mix, and FL Studio validation.
- Musical evaluation milestone: transient guard, producer A/B sessions, tuned defaults, CPU measurements, and a documented set of failures.
- Only then: learn, harmonic evidence, sidechain ducking, additional quality modes, minimum-phase filtering, or a separate low-latency engine.
Open decisions require prototypes: the local baseline statistic and bandwidth, detector grid, detail mapping, smoothing order, frequency-scaled timing, and the acceptable CPU/latency envelope. No claim of matching Quance or Soothe is justified until repeatable comparisons establish which tasks the new plugin handles well.
The most valuable first outcome is a reliable, understandable suppressor that helps the producer keep a sound's character while making a specific annoyance easier to control.
12. First implementation
Version 0.1 uses a complex RustFFT engine with preallocated scratch storage. The initial mixing configuration is 4096 samples with a 512-sample hop at 44.1/48 kHz, scaling both for higher supported rates. This supersedes the smaller experimental configuration proposed above. It implements linked stereo, relative prominence, soft-knee bounded reduction, explicit focus/protect controls, transient guard, aligned monitoring, and the full visible engineer panel. The original research scope and unverified listening hypotheses still apply.
The effect is independently implemented. The commercial references were not reverse engineered. Tests establish reconstruction and scheduling behavior; FL Studio acceptance and producer listening remain separate requirements.