Commit Graph
4 Commits
Author SHA1 Message Date
molluskandClaude Opus 4.8 d0a16cb8b9 style: apply cargo fmt across the crate (A20)
The repo never enforced rustfmt, so formatting had drifted broadly. This is a
single mechanical `cargo fmt` pass over the whole crate (no behavioral change;
lib suite green, 493 passed). Going forward fmt should be enforced (planned CI
fmt --check step). Part of the 0.6.1 hygiene pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 02:11:44 -04:00
molluskandClaude Opus 4.8 9e5fd63291 feat(dsp): double-talk detection for the NLMS echo canceller (Stage C)
Add Geigel double-talk detection so the adaptive filter stops diverging when
the near-end talks over the far-end (the failure the Stage B demo exposed:
ERLE went negative as the filter mistook near-end voice for echo).

- src/dsp/aec.rs: DoubleTalkDetector — Geigel test (mic level vs a sliding-
  window peak of the far-end, via an O(1) monotonic-deque max) with a hangover
  latch. EchoCanceller — wraps Nlms + the detector, freezing adaptation while
  double-talk is declared; reports the double-talk rate; DTD can be toggled off
  for A/B. 5 aec tests (detector fires on near-end not echo; DTD protects a
  converged filter through double-talk, +15 dB over raw NLMS).
- specview aec: now uses EchoCanceller with tunable --dtd-threshold / --hangover
  / --near-onset / --no-dtd, and prints the double-talk %.

Tuning found with the harness (white far-end, -12 dB echo, near-end onset
mid-call): DTD threshold 0.5 is the sweet spot — late-call ERLE +29.6 dB with
DTD vs -4.0 dB without (a 33 dB swing); 0.35 over-triggers (never learns), 0.7
under-triggers (drifts). Default set to 0.5. Also documents the false-positive
/miss tradeoff and that correlated (pink/speech) far-ends converge slower.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 02:45:40 -04:00
molluskandClaude Opus 4.8 eeb725f996 feat(dsp): in-process NLMS echo canceller + headless AEC test loop
Stage A+B of the in-process AEC: a Normalized LMS adaptive-filter echo
canceller and a synthetic echo-path simulator, driven end-to-end by a new
`specview aec` command so cancellation can be measured fully headless on
conjured signals (no speakers/mic needed).

- src/dsp/echo_path.rs: EchoPath — synthetic acoustic echo (bulk delay +
  exponentially-decaying diffuse RIR, energy-normalized to a target
  attenuation) convolved over a far-end signal. Gives ground-truth echo.
- src/dsp/aec.rs: Nlms — sample-at-a-time NLMS adaptive FIR (ring-buffered
  reference history, energy-normalized update, freezable for double-talk).
  Cleaned output = mic minus the learned echo estimate.
- specview aec: far -> sim echo -> (+ optional near-end) -> cancel -> measure.
  ERLE via oracle residual (cleaned - near), broadband + early/late
  (convergence) + per voice band, optional before/after spectrograms.
- 6 new tests (path delay/attenuation, NLMS convergence >20 dB on a known
  path, frozen-filter no-op, near-end passthrough). 33 dsp tests total.

Verified: single-talk pink-noise echo cancels +14.5 -> +32.0 dB ERLE as the
filter converges; double-talk (no DTD yet) drives ERLE negative as the filter
diverges onto the near-end tone — the motivating result for Stage C (DTD).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 02:39:01 -04:00
molluskandClaude Opus 4.8 aa94e861b1 feat(dsp): spectrogram + AEC measurement toolkit (specview)
Add a dependency-free signal-analysis toolkit and a `specview` dev CLI to
evaluate audio (especially echo cancellation) with objective numbers and a
terminal spectrogram instead of ear alone.

- src/dsp/: hand-written radix-2 FFT, Hann window, STFT, seeded test-signal
  generators (sine/log-sweep/white/pink/impulse), metrics (RMS/dBFS/peak/ERLE/
  per-band energy), minimal WAV read+write, and a 24-bit-ANSI half-block
  spectrogram renderer (magma colormap, freq/time axes, dB legend, ASCII
  fallback). Pure layers have no I/O; only `wav` touches the filesystem.
- src/bin/specview.rs: `gen` (conjure a test signal -> WAV), `show` (spectrogram
  + per-band energy summary), `erle` (broadband + per-band echo-return-loss
  between a before/after pair).
- 27 unit tests (FFT correctness, ERLE landmarks, WAV round-trip, render shape).
  Verified end-to-end: log sweep renders as the expected exponential curve;
  a 20 dB-quieter copy reads +20.0 dB ERLE broadband and per band.

Measurement substrate for upcoming AEC refinement (no shipped-path changes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 02:25:58 -04:00