Voice Coding is a 12-part deep dive into how GopherTrunk turns a few kilobits per second of digital voice frames back into audio — in pure Go, with no DSP libraries and no CGO. Digital voice isn’t recorded sound; it’s a model of a voice. This series walks the two vocoders GopherTrunk implements — IMBE (P25 Phase 1) and AMBE+2 (P25 Phase 2, DMR, NXDN) — their shared MBE synthesis core, the per-mode composer that wires frames to the right decoder, and everything after: enhancement, loudness, recording, encoding, and calibration.
SDR Internals gave the vocoders one episode; here each gets the full treatment, including a “problem we hit” post on the v0.7.1 call-startup acquisition squelch — why fresh P25 recordings opened with a full-scale burst of noise, and the speech-signature heuristic that fixed it.
Every post reads three ways: a TL;DR + cheat-sheet for skimmers, bold headers, tables, and diagrams for the medium read, and full prose with real code for the deep read.
New to digital voice first? See the digital voice lesson, then come back for the implementation.<ol class="post-list series-list"><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 1: What a Vocoder Is & the Pluggable Registry</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk turns 2400-bit-per-second radio data back into speech — what a vocoder actually models, and the Go Vocoder interface + registry that lets IMBE and AMBE+2 plug in behind one seam.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 2: The MBE Model — Pitch, Voicing & Spectral Envelope</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">The Multi-Band Excitation parameter set at the heart of IMBE and AMBE+2 — fundamental frequency, per-band voiced/unvoiced decisions, and spectral amplitudes, as the Go structs both codecs synthesize from.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 3: MBE Synthesis — Voiced Sinusoids + Unvoiced Noise</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk grows 160 samples of speech from an MBE parameter set — summed sinusoids for the voiced bands, FFT-shaped noise for the unvoiced bands, and the cross-frame phase and overlap-add smoothing that kills clicks.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 4: IMBE — Decoding P25 Phase 1 Voice</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk turns 88 IMBE information bits into MBE parameters — the b_0 pitch codeword, the PRBS scrambler that whitens the spectrum, and the table-driven PRBA and DCT quantization that reconstruct the spectral envelope.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 5: IMBE FEC & De-Interleave — Recovering the Bit Soup</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk turns 144 noisy on-air IMBE channel bits into 88 clean information bits — the Golay and Hamming FEC on the eight u-vectors, the channel layout, and why de-interleave must run before descramble.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 6: The Call-Startup Acquisition Squelch</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">A real bug in GopherTrunk — fresh P25 recordings opened with a full-scale noise burst while the receiver acquired lock, because the FEC resolved marginal dibits to valid-but-wrong IMBE frames. Here’s the heuristic that mutes it.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 7: AMBE+2 — One Decoder, Two Rates</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk’s pure-Go AMBE+2 decoder unpacks 49 information bits into shared MBE parameters, and why P25 Phase 2, DMR, and NXDN all run through one Go decoder with two rate tables.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 8: AMBE+2 FEC & the Knox Path</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">Where AMBE+2 error correction actually lives, how GopherTrunk conceals bad frames with replay and adaptive smoothing, and what the vendor-specific knox tone path really is — and isn’t.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 9: The Composer — Wiring Frames to the Right Vocoder</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk’s composer turns a CallStart event into PCM — per-protocol demod chains, front-end decimation, boundary handling, and how the recorder maps each protocol to its vocoder.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 10: Enhancement & Loudness — Making It Sound Right</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">The post-synthesis audio chain in GopherTrunk’s MBE decoders — spectral enhancement, DC blocking, AGC, tone tilt, an opt-in voice enhancer, and per-call EBU R128 loudness normalization.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 11: Recording & Encoding — WAV, MP3, Tone-Out & Hardware</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk writes crash-safe WAVs, encodes MP3 in pure Go with a Xing/LAME header, detects paging tones with Goertzel, and offers an optional DVSI hardware vocoder behind a build tag.</p></li><li class="post-card"> <h2 class="post-card__title">Voice Coding, Part 12: Calibrating & Testing Vocoders Against References</h2> <p class="post-card__meta"> Deep dives </p><p class="post-card__desc">How GopherTrunk proves its pure-Go IMBE and AMBE+2 decoders are correct — the voice-calibrate harness, golden-frame regression, streaming decode, and cross-correlation against DSD-FME and OP25.</p></li></ol><p class="blog-feed-link"> See all deep dives or subscribe via RSS. </p>