Files
bass-foundry/docs/patina/README.md
T
nvrl 9ca4e4f9dd feat(patina): per-band compressor gain stage with Threshold, Ratio and Knee
Tester feedback asked for a threshold and a ratio. Each band now cuts like a
small compressor: Threshold (dB above the local floor) replaces Selectivity,
Ratio scales the cut per dB above it (inf:1 is the old behaviour), and a
Soft/Hard knee switch sets the curve. A small graph shows bump height in, cut
out. Mix and Output move to the slider panel so the detection panel fits.
common-ui gains rotary_text for knobs with custom value text.
2026-11-06 17:29:54 +01:00

166 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Patina
Patina smooths a sound’s rough surface without erasing its character. Formerly
**Resonance Compressor**; current version **0.4.0** (0.5.0 unreleased).
A mixing effect that finds harsh, ringing regions as they happen and pulls them
down, while plain harmonic tone passes. Independently designed in Rust; no claim
of matching Soothe or Quance.
![Patina](assets/editor.png)
## Install on Windows
Download the Windows artifact from the Gitea plugin's Gitea release, or the branch pipeline's **windows** job and
extract the ZIP. Copy `Patina.clap` into
`C:\Program Files\Common Files\CLAP\`. In FL Studio 2024.1 or newer, open
Options → Manage plugins, enable Verify plugins, and Find installed plugins.
Load Patina in a mixer effect slot. Keep the font license with
redistributed packages.
## Work with it
Each band works like a small compressor. It compares its level with the local floor
around it and cuts only the part that sticks out:
- **Depth** is the largest cut per band, in dB. 0 dB does nothing.
- **Sharpness** sets what counts as a resonance. Low values follow broad,
smooth bumps (honk, boxiness). High values target narrow rings and whistles.
- **Threshold** is how far (dB) a band must rise above its neighbours before it
is cut. Low values treat any bump; high values treat only the worst.
- **Ratio** is how hard a bump above the threshold is cut. At n:1 a bump ends
1/n as far above the threshold as it started. Low ratios leave small bumps
nearly alone and still cut big ones; ∞:1 flattens every bump to the
threshold (this is how Patina worked before 0.5).
- **Knee**: Soft fades cuts in around the threshold. Hard starts them right at
the threshold and uses half the Attack time.
The small graph under the knobs shows the result: bump height above the floor
in, cut out, with the threshold and the Depth limit.
Start with Depth around 6 dB. Raise Threshold until only the harsh parts show
cuts, then use Delta to hear what is removed. To hit big resonances hard and
leave small ones alone, raise Depth to 12–20 dB and set Ratio to 2:1–4:1.
Restrict Low/High frequency to keep the source’s body out of reach. Attack and
Release set how quickly cuts grow and recover; Transient guard briefly relaxes
cuts on attacks to keep punch.
### Tone guard for bass lines
On a bass line, a bump can mean two things. A resonance fixed in Hz (a formant,
a comb or filter ring) stays at the same frequency on every note: that is what
Patina should cut. A bump that follows the note (a harmonic the patch is built
on, or a Lathe boost) moves with every note: cutting it changes the patch
differently on each note.
**Tone guard** tells them apart. Patina detects the played note (30–500 Hz)
and remembers, over about four seconds, how high each bump was in Hz and how
high it was relative to the note. A bump that has stayed with the note more
than in Hz gets less cut; at 100 % none. A resonance fixed in Hz is cut as
before. It needs a few different notes before it can decide: on one held note
both look the same and Patina cuts as normal. The **NOTE** readout shows what
Patina follows, and a blue strip on top of the plot shows where cuts are held
back. Start from the **Bass line** preset. At 0 % Tone guard is off.
Measured on a saw line F1–F2 with Low at 150 Hz: a +12 dB boost on harmonic 6
is cut by 5.8 dB without Tone guard and by 0.4 dB at 100 %; a formant at 1.5 kHz
is cut by 5.8 dB either way.
Double-click the plot to add one of four focus points. Drag a point up to cut
more in that region, down to protect it. Wheel changes its width. Range handles
on the plot drag the processing limits.
On the plot, the grey fill is the measured input. The bright line is what the
detector hears (its smoothed spectral envelope); the dim line is what it expects
there. Accent-coloured cuts appear where the bright line rises above the dim one
by more than Threshold allows. The blue curve is the focus/protect shape.
Delta plays delayed dry minus wet before output trim. Use it to inspect changes,
then return to normal monitoring to decide whether the music improved.
Mix is a linear blend of aligned signals. Bypass keeps the same latency.
Use Output for matched-level comparison. Spectral attenuation is not a limiter:
sample peaks can increase even when frequency gains never exceed unity.
Four presets and A/B comparison help explore alternatives. Host parameters and
window size persist; Delta does not.
## How detection works
1. Each analysis frame is grouped into 512 log-spaced bands. Each band holds the
mean power of the FFT bins it covers, smoothed over time (about 5 ms rise,
40 ms fall) so cuts hold on a stable ring instead of flickering.
2. Neighbouring peaks are joined in dB, so the gaps between harmonics do not count
as the expected level. A plain harmonic tone reads as a smooth envelope.
3. The envelope is smoothed across frequency by the Sharpness width.
4. The reference is a robust local straight-line fit over 2–3 octaves: spectral
tilt is expected, bumps cannot raise their own reference, and empty regions
(below a fundamental, beyond a filter cutoff) are ignored.
5. Envelope minus reference is the band's height above its floor. Above
Threshold it becomes a cut through the Knee and Ratio curve, limited by
Depth, smoothed with Attack/Release, and linked across stereo.
## Timing and limits
Mixing only: 2048-sample analysis windows at 44.1/48 kHz, 4096 at 88.2/96 kHz,
8192 at 176.4/192 kHz, with eight overlaps. Delay is one window, about 43–46 ms.
The plugin reports it for host compensation. Supported layouts are mono and
linked stereo; supported rates are those six standard rates.
The engine uses complex RustFFT with supplied scratch buffers, WOLA reconstruction,
the envelope/reference detector above, bounded soft-knee cuts, and temporal
smoothing. Original bin phases are retained. This is not a minimum-phase filter
bank, a live monitoring effect, a limiter, or an automatic separation of tone and
unwanted resonance. No external sidechain, Learn or M/S. The pitch detector
serves Tone guard only.
## Build and offline evaluation
```sh
cargo test --workspace --locked
cargo run --release -p patina-render -- input.wav processed.wav
cargo run --release -p patina-render -- input.wav delta.wav --delta
cargo run --release -p patina-render -- --demo /tmp/patina-demo.wav
cargo run --release -p patina-render -- --benchmark
python scripts/build-plugin.py --plugin patina --target x86_64-pc-windows-gnu
```
The renderer accepts mono/stereo PCM16/24/32 and float32 RIFF/WAVE, capped at
256 MiB; WAV extensible/RF64 are not accepted. It writes float32 WAV, compensates
the processing delay, retains original duration, and refuses existing output.
An optional settings JSON uses the core's Settings structure.
## CI and acceptance
Gitea Actions cross-builds Windows binaries with MinGW on a Docker-capable
runner labelled `ubuntu-latest`. Branch/PR workflows build a combined preview
bundle; `patina-v<version>` tags check, build, and publish Patina independently.
See [release workflow](../releases.md) for runner setup and release attachments.
Actual runner execution remains to be verified on the Gitea instance.
Before calling host support complete, test FL Studio discovery as an effect,
automation, plugin delay compensation, parallel dry/wet alignment, repeated loading,
project restoration, mono/stereo, all supported sample rates, and render tails.
Judge through real patches with matched listening levels: preserve vowel motion,
snare punch, bass body, and stereo placement. Synthetic tests do not establish
artistic usefulness.
Local benchmark, optimized build, stereo 48 kHz, FFT 2048/hop 256: five seconds
processed in about 0.35–0.45 seconds (7–9% of one core on a laptop CPU). This is
not a worst-case multi-instance guarantee.
## Existing projects and source layout
The CLAP ID is now `io.narl.bass-foundry.patina` (earlier builds used
`io.storyboard.resonance-compressor`). Hosts treat Patina as a new plugin, so
add it again in projects saved with an earlier build. Version 0.2 replaced
Amount, Sensitivity, Max cut, Neighborhood, Cut width, and Knee with Depth,
Sharpness, and Selectivity; version 0.5 replaced Selectivity with Threshold
(dB), Ratio and Knee, so projects saved earlier load Threshold at its default.
Delete the old plugin file, place `Patina.clap`, and
rescan FL Studio.
Source is grouped into `plugins/patina/{core,ui,render,plugin}`. See
[research](research.md), [development](../development.md), and the
[independent release workflow](../releases.md).