← back to Butlr
Fix µ-law decoder bias (33 → 0x84) — root cause of distorted call audio
b52ca5ef4bdec301774b6596c1318dc6eb94b9e7 · 2026-05-19 14:00:17 -0700 · SteveStudio2
lib/listen-bridge.js decoded Twilio's G.711 µ-law media frames with
MULAW_BIAS=33. The G.711 decode bias is 0x84 (132), added inside the
<< exponent shift. At 33 the bias was under-counted 4×: quiet samples
(exponent 0) stayed correct but every loud sample was nonlinearly
crushed (0x00 decoded to -19551 instead of -32124). That amplitude-
dependent distortion made both the recorded .mp3 and the live-listen
feed sound horrible. Verified: the decoder now matches canonical
G.711 on all 256 µ-law byte values.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit b52ca5ef4bdec301774b6596c1318dc6eb94b9e7
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Tue May 19 14:00:17 2026 -0700
Fix µ-law decoder bias (33 → 0x84) — root cause of distorted call audio
lib/listen-bridge.js decoded Twilio's G.711 µ-law media frames with
MULAW_BIAS=33. The G.711 decode bias is 0x84 (132), added inside the
<< exponent shift. At 33 the bias was under-counted 4×: quiet samples
(exponent 0) stayed correct but every loud sample was nonlinearly
crushed (0x00 decoded to -19551 instead of -32124). That amplitude-
dependent distortion made both the recorded .mp3 and the live-listen
feed sound horrible. Verified: the decoder now matches canonical
G.711 on all 256 µ-law byte values.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
lib/listen-bridge.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/lib/listen-bridge.js b/lib/listen-bridge.js
index d01920b..644e99a 100644
--- a/lib/listen-bridge.js
+++ b/lib/listen-bridge.js
@@ -106,7 +106,12 @@ function finalizeArchive(callId) {
// µ-law → linear PCM16 LE decoder (G.711 standard).
// Bit-fiddly but small. Adapted from RFC 5391.
-const MULAW_BIAS = 33;
+// G.711 decode bias is 0x84 (132) and is added INSIDE the << exponent shift.
+// This was 33 — under-counted by 4× — which left quiet samples (exponent 0)
+// correct but nonlinearly crushed every loud sample (e.g. 0x00 decoded to
+// -19551 instead of -32124). That amplitude-dependent distortion is what made
+// the recordings and the live-listen feed sound horrible.
+const MULAW_BIAS = 0x84;
const MULAW_CLIP = 32635;
function mulawDecodeOne(mulawByte) {
mulawByte = ~mulawByte & 0xff;
← f709144 Add external call-trigger API for first-party sites (NPH)
·
back to Butlr
·
gitignore + serve-time 404-guard for .bak/.pre- snapshot fil a5dc24d →