No description
Closes the last gap before Phase 5's monitor TUI: per-app meter events already publish on the meters topic via the registry watcher; bus-level DSP meters now also publish. 4g — Bus meters headroom_core::meters::BusMetrics is an Arc<parking_lot::Mutex<...>> snapshot owned by the playback callback (try_lock; skip on contention) and read by the AGC controller on each 50 ms tick. Carries: compressor GR, limiter total/soft/hard GR, true peak. The AGC controller combines these with its ebur128 readings (momentary, short-term, integrated) and the current smoothed AGC target, then publishes a headroom_ipc::MeterTick on Topic::Meters. Publish cadence honours profile.meters.publish_hz, capped at the AGC tick rate (20 Hz). Lower publish_hz throttles to every Nth tick. Mode::I added to the AGC's EbuR128 so loudness_global() is available without a second ebur128 instance. Bounded cost — a histogram walk per call, <=20 Hz. LUFS values are sanitised to a -200.0 dB floor via finite_or_floor() — ebur128 returns -inf (not Err) for "no usable measurement yet," and non-finite f32 can't survive JSON serialisation (serde_json renders as null). Housekeeping shipped alongside headroom-client moved from [dependencies] to [dev-dependencies] in headroom-core — it's only used inside ipc::server's tests. Verified by full clippy + test run; production builds no longer pull it in. Pre-existing clippy nits cleared (limiter.rs x5, app_level.rs, ipc/ops.rs, pw/filter.rs). All field_reassign_with_default or assign_op_pattern in test code; stage-6 commit ran clippy without --all-targets so these slipped through. Verified 178 tests passing (28 dsp + 48 dsp + 20 ipc + 106 core including +2 new meters tests + 4 client). Clippy clean at default level with -D warnings --all-targets. Smoke test: monitor meters subscription receives 20 Hz MeterTick events with the expected JSON shape (all fields finite). |
||
|---|---|---|
| crates | ||
| docs | ||
| profiles | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| IPC.md | ||
| PLAN.md | ||
| README.md | ||
| rust-toolchain.toml | ||
headroom
AGC + compressor + true-peak limiter daemon for PipeWire, in Rust.
Headroom puts a per-application audio safety net between noisy sources (browsers, voice chat, random video) and your speakers, while leaving the things you don't want compressed (music players, games, DAWs) untouched.
- Hard −0.1 dBTP ceiling on the processed route, with proper
inter-sample-peak handling, enforced inline so the contract holds
regardless of control-plane state. Streams routed
bypassride the real sink directly and are not in scope of the contract — that's the trade-off that makes the per-app exclusion useful. - Per-app exclusion with profile-driven rules.
- Single binary daemon + CLI, controlled over a Unix-domain socket
with a documented JSON wire protocol (see
IPC.md). - First-party Rust crate (
headroom-client) for programmatic use; third-party clients (Qt panels, status bars, …) target the wire protocol directly.
See PLAN.md for the full design and roadmap.
Status
Pre-alpha. Wire protocol and crate scaffolding are in; daemon and filter are under construction.
Building
nix develop # toolchain + pipewire dev libs + helpers
cargo build # iterate
nix build # final packaged headroom binary
License
GPL-3.0-or-later for the daemon and CLI. headroom-dsp and headroom-ipc
are MPL-2.0 so they can be reused by non-GPL plugin hosts and clients.