headroom/crates/headroom-dsp
atagen 03edb17180 F6: honour compressor.enabled in the DSP
The profile schema accepted `[compressor] enabled = false` (and the
`transparent` and `bypass-all` profiles set it) but the flag was
parsed and dropped — `build_compressor_config()` never threaded
it through to `CompressorConfig`, and `Compressor::process_frame`
had no enable branch. Result: the "compressor and AGC bypassed"
claim in `transparent.toml`'s description was a lie; the
compressor ran on every sample regardless of the profile knob.

Surfaced by Codex's review of the project.

Changes

  - `headroom_dsp::CompressorConfig` gains `pub enabled: bool`
    (default true). `Compressor::process_frame` early-returns
    `(left, right)` and resets `last_gr_db = 0.0` when disabled,
    so bus meters / `gain_reduction_db()` report the truthful
    "compressor off" state instead of the stale last value.
  - `headroom_core::profile::Profile::build_compressor_config`
    threads `self.compressor.enabled` into the materialised
    `CompressorConfig`. Live profile reload picks this up
    automatically — the next `set_config` push from
    `setting.set` / `profile.use` flips the audio thread.
  - Regression unit test `disabled_compressor_passes_signal_through_unchanged`:
    drive a -6 dBFS sine that would compress hard with enabled +
    aggressive thresholds, assert output equals input exactly and
    GR is zero.

What this does NOT change

  - **Limiter has no `enabled` flag** and intentionally remains
    always-on. It is the daemon's hard contract (the -0.1 dBTP
    ceiling on the processed route, advertised in the README and
    in PLAN §3). Users who don't want limiting should route
    bypass; the `bypass-all.toml` profile's own comment confirms
    the limiter is "still configured as a fail-safe in case a
    stream lands on the processed sink anyway."

Verified

  186 tests pass (+1 for the disable path); clippy clean at
  -D warnings --all-targets.

  Live A/B against `pw-cat /tmp/sine` (-6 dBFS sine into
  processed): default profile compresses at -4.5 dB GR;
  `headroom profile use transparent` flips to 0.00 dB GR
  exactly on the next meter tick.
2026-05-21 18:19:32 +10:00
..
benches stage 6: per-app 2026-05-20 23:49:58 +10:00
src F6: honour compressor.enabled in the DSP 2026-05-21 18:19:32 +10:00
Cargo.toml stage 6: per-app 2026-05-20 23:49:58 +10:00
README.md stage 2 2026-05-19 16:33:09 +10:00

headroom-dsp

DSP kernels for Headroom. Pure Rust, no dependencies.

  • Limiter — feed-forward true-peak brickwall with configurable oversampling (1/2/4/8×), lookahead, hold, and release.
  • Compressor — log-domain feed-forward with peak or RMS detector, soft knee, attack/release, and optional auto-makeup.
  • AttackRelease — exponential envelope follower (peak / inverse-gain modes).
  • DelayLine, SlidingMaxBuffer, PolyphaseUpsampler, PolyphaseDownsampler — supporting building blocks.

All processors are allocation-free in their process_* methods. Construction allocates; do not construct in the audio thread.

License

MPL-2.0.