LC3 Encoding: Bitstream Encoding

 

LC3 Encoding: Bitstream Encoding
Chapter 3, Section 3.3.13 — Payload Structure, Side Information, Arithmetic Coding, Residual Packing
Chapter
3 — Section 3.3.13
Subsections
3.3.13.1 to 3.3.13.6
Level
Advanced

Bitstream encoding is the final encoder stage — it takes everything computed in the previous stages and packs it all into exactly nbytes bytes of output payload. The LC3 payload has a unique two-direction structure: side information is written backward from the end of the buffer, while arithmetic-coded spectral data is written forward from the start. They meet in the middle, and any leftover space between them holds residual data.

Keywords

Bitstream Structure Side Information Arithmetic Coder write_bit_backward ac_encode bp / bp_side Residual Data

3.3.13.1 Payload Structure Overview

The LC3 payload is organized into four parts, arranged as two streams that grow toward each other:

Part Location in Payload Direction Written Content
Side Information End of payload (byte nbytes−1 downward) Backward (LSB first) Pbw, lastnz, lsbMode, ggind, TNS flags, pitch_present, SNS VQ, LTPF data, FNF
Arithmetic Coded Data Start of payload (byte 0 upward) Forward (MSB first) TNS coefficient data, spectral MSBs (2-tuples)
Signs and LSBs Backward from end of side info Backward Sign bits and LSBs of large spectral values
Residual Data Between arithmetic data and signs/LSBs Backward Residual bits for non-zero coefficient refinement (or LSBs in lsbMode)

This bidirectional structure allows both forward (AC coder) and backward (side info) parts to grow as large as they need to, sharing the same payload buffer efficiently.

3.3.13.2 Initialization

bp      = 0;            /* forward pointer: start of payload  */
bp_side = nbytes − 1;  /* backward pointer: end of payload   */
mask_side = 1;          /* current bit mask for backward writing (LSB first) */
c = 0;                  /* arithmetic coder context state     */
nlsbs = 0;              /* count of LSBs stored               */

3.3.13.3 Side Information Writing Order

All side information is written backward using write_uint_backward and write_bit_backward. The exact write order is:

Field Bits Source
Bandwidth Pbw nbits_bw (0–3) BW detector (Section 3.3.5)
lastnz_trunc (last non-zero 2-tuple) ceil(log2(NE/2)) Truncation step (Section 3.3.10.5)
lsbMode 1 Section 3.3.10.5
Global gain index ggind 8 Section 3.3.10.2
TNS activation flag (per filter) 1 per filter Section 3.3.8.2
pitch_present 1 Section 3.3.9.6
SNS Stage 1: ind_LF 5 Section 3.3.7.3.2
SNS Stage 1: ind_HF 5 Section 3.3.7.3.2
SNS Stage 2: submodeMSB 1 shape_j >> 1
SNS Stage 2: gain MSBs 1–2 gain_i MSBs
SNS Stage 2: LS_indA 1 Leading sign of shape A
SNS Stage 2: joint shape index 24–25 indexjoint (Eqs. 58–61)
LTPF ltpf_active (if pitch_present=1) 1 Section 3.3.9.8
LTPF pitch_index (if pitch_present=1) 9 Section 3.3.9.7
Noise level FNF 3 Section 3.3.12.2

3.3.13.4 Arithmetic Encoding

The arithmetic coder is a range coder operating on 24-bit precision. It encodes TNS coefficient indices and spectral data. Spectral coefficients are encoded in 2-tuples {a, b} of adjacent coefficients, walking from k=0 to lastnz_trunc−1.

For each 2-tuple, the encoding proceeds in bitplane layers from MSB to LSB:

  • Escape symbols: if max(|a|, |b|) ≥ 4, an escape symbol is sent first and a, b are right-shifted. This repeats until max(|a|, |b|) < 4.
  • MSB symbol: the 2-tuple of remaining (a, b) values (each 0..3) is arithmetically coded as sym = |a| + 4×|b|.
  • Sign bits: for each non-zero coefficient, 1 sign bit is written backward.
  • LSB bits: in lsbMode=1, the first bitplane’s LSBs are written separately; in lsbMode=0, they are written backward inline.

The context variable c tracks the recent encoding history of coefficient magnitudes to select the correct probability table (ac_spec_lookup → ac_spec_cumfreq/freq from Section 3.7.7).

/* Simplified flow for each 2-tuple */
t = c + rateFlag + (k > NE/2 ? 256 : 0);
a = |Xq[k]|;  b = |Xq[k+1]|;  lev = 0;
while max(a,b) >= 4:
    pki = ac_spec_lookup[t + min(lev,3)*1024]
    ac_encode(escape_symbol)
    write LSB of a and b (backward or as lsb array)
    a >>= 1;  b >>= 1;  lev++
pki = ac_spec_lookup[t + min(lev,3)*1024]
sym = a + 4*b
ac_encode(sym)
write sign bits of original Xq[k] and Xq[k+1] (backward)
update context c

3.3.13.5 and 3.3.13.6 Residual, Finalization, and Helper Functions

After arithmetic coding, the remaining bits between the AC stream and the backward-written side info are used for residual data (or LSBs in lsbMode). Then ac_enc_finish flushes the arithmetic coder state into the forward bytes.

The key helper functions used throughout bitstream writing:

Function What It Does
write_bit_backward Writes 1 bit to bytes[bp_side] using mask_side (LSB first). Decrements bp_side when byte is full.
write_uint_backward Calls write_bit_backward for each of the numbits bits in val (LSB first).
write_uint_forward Writes numbits bits MSB-first into bytes[bp]. Used by ac_enc_finish for final flush bytes.
ac_enc_init Initializes the range coder state: low=0, range=0xFFFFFF, cache=−1, carry=0, carry_count=0.
ac_encode Encodes one symbol using cumulative frequency cum_freq and symbol frequency sym_freq. Calls ac_shift when range < 0x10000.
ac_shift Renormalization step: outputs carry bytes when the range falls below threshold. Handles carry propagation.
ac_enc_finish Flushes remaining arithmetic coder state. Emits final bits to close the range coder stream precisely within the allocated bytes.

Next in this Series

Section 3.4 Decoder — Bitstream Decoding: the exact reverse of encoding, including BEC detection

Next Tutorial → All Tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *