3 — Section 3.3.13
3.3.13.1 to 3.3.13.6
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.
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
