zebra-report/web
Russell Ballestrini 1c52e09b37
zebra-spaces: anti-alias + compressor on self-transcribe (host accuracy fix)
Fox 2026-06-05: "the remote phones are transcribing more accurate than
the host version. figure out why and make host version better."

Two causes diagnosed:

1. Aliasing. The whisper-capture worklet decimates 48 kHz → 16 kHz by
   taking every 3rd sample with NO anti-alias filter. Listener path
   feeds Opus-decoded peer audio which is already band-limited
   (~12 kHz max). Host path feeds RAW mic — all 48 kHz of it —
   which means anything above 8 kHz folds back into the audible band
   as garbage when decimated. Whisper sees noisier input on host.

2. Amplitude / dynamic range. Music-mode mic has NO AGC/NS/EC
   (raw broadcast for music). Quiet passages are too low for
   Whisper to confidently transcribe; loud passages can clip. The
   listener path's audio has been through Opus encode/decode which
   normalizes implicitly.

Both addressed via Web Audio nodes inserted between the
MediaStreamSource and the whisper-capture worklet:

Self-capture chain:
  micStream → DynamicsCompressorNode → BiquadFilter (lowpass 7 kHz)
            → AudioWorkletNode (whisper-capture)

DynamicsCompressor: voice-friendly settings (threshold -30 dB,
knee 30, ratio 4:1, attack 3 ms, release 250 ms). Flattens
amplitude so Whisper sees a normalized waveform regardless of how
the user has the mic gain set or whether music mode is on.

BiquadFilter lowpass at 7 kHz (below Nyquist of 16 kHz = 8 kHz):
removes content that would alias when the worklet decimates.

Remote captures: just the lowpass (no compressor — Opus has already
normalized the peer audio adequately). Mostly a no-op on voice-mode
peers (Opus already cuts <12 kHz) but helps music-mode peers where
the encode preserves more high-frequency content.

stopCaptureForUuid / stopSelfCapture cleanly disconnect the new
nodes so re-toggle doesn't leak audio graph references.

Expected: host self-transcribe accuracy now comparable to (or better
than) the phone listener transcribes. Telemetry `emt=` should
increase per tick on host once the user is talking.
2026-06-05 13:42:14 -04:00
..
blog phase 1: unfirehose reconstruction from session JSONL ingest 2026-05-27 13:51:14 -04:00
fonts phase 2: gap analysis — cat>> append + binary asset recovery 2026-05-27 13:54:19 -04:00
chat.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
host-your-own.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
how-it-works.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
index.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
kernel.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
stamp.js web: stamp each zebra-report page with build date + md5/sha256 2026-05-28 17:50:12 -04:00
zebra-audio.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
zebra-spaces.html zebra-spaces: anti-alias + compressor on self-transcribe (host accuracy fix) 2026-06-05 13:42:14 -04:00