feat: smooth noise gate for mic sensitivity

Replace the per-frame hard-cut noise gate with a stateful envelope gate
(src/audio/gate.rs):

- Hysteresis: opens at the slider threshold, closes only below 0.6x that,
  so speech near the threshold doesn't flap the gate.
- Attack/release: per-sample gain ramp (5ms open, 80ms close) instead of a
  click — the gate fades rather than dropping frames outright.
- Hangover: holds the gate open 200ms after the level drops, so word tails
  and brief pauses aren't chopped.

A fully-closed frame still reports don't-transmit, preserving the original
bandwidth win of not sending pure silence (receiver jitter buffer conceals
the gap). The live slider value is read per frame so changes apply
immediately. Settings slider gains a one-line hint. 6 unit tests cover
attack shape, hysteresis, hangover-then-release, disabled pass-through, and
the closed-gate no-transmit path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 16:35:41 -04:00
co-authored by Claude Opus 4.8
parent ead3031f3c
commit a7ad07d1f5
4 changed files with 243 additions and 12 deletions
+1
View File
@@ -51,5 +51,6 @@ pub trait AudioBackend: Send + Sync {
fn stop(&self) -> Result<(), AudioError>;
}
pub mod gate;
pub mod pipewire_impl;
pub mod pw_cli;