Stage 2: full-band compressor with constant-latency look-ahead

Implements the single full-band feed-forward compressor (the engine that will be
reused per band + for the 'All' channel). Design follows Giannoulis et al. 2012:
log-domain gain computer with a quadratic soft knee feeding a smooth decoupled
peak detector for attack/release ballistics. Stereo-linked peak detection.

Look-ahead uses a fixed audio delay with a constant reported latency (set once in
initialize); the knob only moves the detector tap within that delay. This avoids
renegotiating latency from process(), which crashed FL Studio when the look-ahead
was adjusted during playback.

- src/dsp/compressor.rs: Compressor + CompressorSettings, RT-safe (no alloc in
  process; buffers sized in prepare; envelope denormals flushed in-code)
- src/lib.rs: nested CompressorParams (threshold/ratio/knee/attack/release/makeup/
  bypass) + global look-ahead; egui ParamSlider grid; latency reported once
- 5 unit tests (static curve, knee continuity, steady-state convergence, constant
  latency); Cargo.toml lib crate-type added so tests link
- README: 'All' channel architecture already documented; look-ahead spec updated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mikkeli Matlock
2026-06-15 19:33:31 +09:00
parent d9dc61cf90
commit 8d9eaeaffc
5 changed files with 503 additions and 35 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ a first-class mode, not an afterthought.
### Global
- `input_gain` — pre-gain before filterbank (dB)
- `output_ceiling` — brickwall ceiling (dBFS, default 0.0)
- `look_ahead_ms` — look-ahead time (010 ms)
- `look_ahead_ms` — look-ahead time (05 ms). Reported latency is **constant** (the max look-ahead); the knob only moves the detector tap within that fixed delay, so it is safe to adjust during playback (changing reported latency mid-stream crashes some hosts, FL included)
- `crossover_low_hz` — low/mid crossover frequency
- `crossover_high_hz` — mid/high crossover frequency
### Per-Channel Compressor (× 4: low, mid, high, **all** — one `#[nested]` params struct reused)