Also known as: STL basic operators, G.191 STL, basic operators
The G.191 basic operators are the small set of bit-exact fixed-point primitives — saturating
add, sub, mult, the multiply-accumulate L_mac, the shifts shr/L_shl, L_extract, and
the log2/pow2 table kernels — that the ETSI and ITU-T reference speech codecs are defined
in.1 A standards-body speech codec is not published as a formula but as C source built
entirely from these operators, so their exact overflow, rounding, and saturation behaviour is
the specification. Re-implement them faithfully and a decoder is bit-exact with the reference;
get one detail wrong and the whole codec drifts. GopherTrunk’s TETRA
ACELP decoder ports the ETSI reference operator library into
internal/voice/acelp/ops.go and mathfp.go.
What the operators guarantee
Each operator models a specific piece of DSP-chip arithmetic. sature clamps a 32-bit value into
the Q15 16-bit range; add/sub do 16-bit
saturating arithmetic; mult and L_mult are the fractional multiplies; L_mac/L_msu are the
multiply-accumulate and multiply-subtract that dominate filter loops; the shifts saturate on
overflow; and L_extract splits a 32-bit value into a high/low pair for double-precision work.
On top of these, mathfp.go provides the log2fp/pow2fp table kernels the
gain dequantizer needs. Because every operation clamps
rather than wraps, intermediate overflow degrades gracefully instead of flipping sign — the same
saturation discipline the reference chips enforced in hardware.
A representative clamp — GopherTrunk’s sature, the primitive every 16-bit result funnels
through — shows the shape of the whole library:
// sature clamps a 32-bit value into the 16-bit Word16 range,
// setting the reference codec's global overflow flag on clamp.
func sature(l int32) int16 {
switch {
case l > int32(maxWord16): // +32767
overflow = true
return maxWord16
case l < int32(minWord16): // -32768
overflow = true
return minWord16
default:
overflow = false
return int16(l)
}
}
The Word32 trap
The single most expensive detail is the width of Word32. The ETSI/ITU reference sources declare
it as typedef long Word32. On the ILP32 platforms the codecs were written for, long is 32
bits, and every saturating operator relies on that width — the accumulator is meant to reach
±2³¹ and clamp there. Build the same C on a modern LP64 system, where long is 64 bits,
and Word32 silently becomes 64-bit: the intermediate values that should overflow and saturate no
longer reach the 32-bit clamp, so L_mac, the shifts, and everything built on them return wrong
results, and the codec produces garbage. The fix is to define Word32 as a 32-bit int
explicitly. GopherTrunk sidesteps the problem entirely by using Go’s fixed-width int32, so the
operators saturate at exactly the reference boundaries regardless of host platform. This lesson —
build Word32 as 32-bit or every saturating op is garbage on LP64 — is recorded in the project’s
TETRA voice notes precisely because it silently defeats an otherwise-correct port.
Why a faithful port matters
Speech-codec bugs are notoriously self-consistent: a synthetic encode→decode round-trip inside one codebase can pass while the decoder still fails on real off-air frames, because both ends share the same wrong arithmetic. Anchoring the basic operators to the reference is what lets GopherTrunk test the decoder alone against the ETSI reference C codec — feed both the same bitstream and demand bit-identical PCM — rather than trusting a closed self-check.
Relevance to SDR
For a software scanner with no vendor DSP dongle, these operators are the foundation that makes a pure-Go ACELP (and, in the same spirit, MBE) decoder trustworthy. They are not glamorous, but they are load-bearing: the correctness of every higher-level codec block — LSP reconstruction, excitation, gain, and the output scaling — rests on this arithmetic behaving exactly as the standard prescribes.
Sources
-
Saturation arithmetic — Wikipedia, on the clamping arithmetic the G.191 operators implement. ↩