Field Guide · term

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.

Word16 aWord16 b op (Word32) saturate→ Word16 Word32 MUST be 32-bit: a 64-bit long never hits the ±2³¹ clamp
Every operator computes in a 32-bit Word32 accumulator and clamps back to Word16; if Word32 is silently widened to 64 bits the clamp never triggers and results diverge.

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

  1. Saturation arithmetic — Wikipedia, on the clamping arithmetic the G.191 operators implement. 

See also