feat: serial low-level shaper (Low Slope + Low Curve) before the compressor

Add a per-channel below-threshold shaper composed in series ahead of the comp:
gain = low_shape(level) + comp(level + low_shape(level)). The compressor's
threshold now sees the shaped level, so a Low Slope boost lifts quiet material
up into compression (and a cut pulls it out). Anchored at the -60 dB silence
floor. Low Curve bends the shaper toward a bounded saturation so the serial
composition doesn't blow up (0 = straight line).

gain_computer split into comp_gain_db + low_gain_db and composed; shared with
the editor gain-curve display. Slider order rearranged to read in signal order
(pre-gain -> low shaper -> compressor -> output). Defaults (slope 1, curve 0)
reproduce the plain compressor; 17 tests pass.

Known: the bipolar behaviour isn't final yet (milestone commit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mikkeli Matlock
2026-06-26 00:53:40 +09:00
parent 123703d34d
commit a4c542b2d9
6 changed files with 120 additions and 15 deletions
+3 -1
View File
@@ -100,11 +100,13 @@ a first-class mode, not an afterthought.
### Per-Channel Compressor (× 4: low, mid, high, **all** — one `#[nested]` params struct reused)
- `pre_gain_db` — drive into the compressor (24…+36 dB, smoothed)
- `detection` — peak / RMS level detection
- `low_slope` — low-level shaper slope at the silence floor (1 = unity, >1 fans up/boost, <1 fans down/cut). **Serial**: reshapes the level *before* the threshold, so a boost can lift quiet material up into compression
- `low_curve` — bends the low shaper toward a bounded saturation (0% = straight line) so the serial composition doesn't run away
- `threshold_db`
- `ratio` — 1.0 (off) to ∞ (limiting)
- `knee_db` — soft knee width
- `attack_ms`
- `release_ms`
- `knee_db` — soft knee width
- `makeup_db` — makeup gain (24…+24 dB)
- `mix` — per-channel dry/wet mix (parallel compression); 0% = dry (a clean bypass), 100% = fully processed. Bands at 0% → simple full-band comp via the 'all' channel