3 — Section 3.7
3.7.1 to 3.7.7
Reference
Section 3.7 contains all the pre-computed tables that the LC3 encoder and decoder reference during processing. These tables are not generated at runtime — they are fixed constants baked into every conformant implementation. This tutorial explains what each table is, how many entries it has, how it is indexed, and which algorithm steps use it. The actual numeric values are in the LC3 spec PDF (pages 89–221) and are too large to fully reproduce here, but all sizes, shapes, and usage references are covered completely.
3.7.1 Band Index Tables Ifs — 10 ms Frame Duration
These tables map band number b to the starting MDCT coefficient index for that band. Ifs(b) is the first coefficient in band b; Ifs(b+1)−1 is the last. Used by energy estimation (3.3.4.4), SNS analysis (3.3.7.2), bandwidth detector (3.3.5.2), and SNS spectral shaping (3.3.7.5 / 3.4.7.4).
| Table Name | Sampling Rate | Size (entries) | NF | Nb (bands) | Last entry (=NE) |
|---|---|---|---|---|---|
I_8000[65] |
8 kHz | 65 | 80 | 64 | 80 |
I_16000[65] |
16 kHz | 65 | 160 | 64 | 160 |
I_24000[65] |
24 kHz | 65 | 240 | 64 | 240 |
I_32000[65] |
32 kHz | 65 | 320 | 64 | 320 |
I_48000[65] |
44.1/48 kHz | 65 | 480 | 64 | 400 (NE, not NF) |
For 8 kHz (NF=80, NE=80): all 80 MDCT coefficients map 1:1 to bands at the low end, then progressively wider bands at high frequencies. For 48 kHz, only 400 of the 480 MDCT coefficients are encoded (NE=400), so the last entry of I_48000 is 400.
3.7.2 Band Index Tables Ifs — 7.5 ms Frame Duration
Same structure as the 10 ms tables but for 7.5 ms frame sizes. Notable exception: 8 kHz at 7.5 ms has NF=60 and Nb=60 (not 64) — the only configuration in the spec where Nb ≠ 64.
| Table Name | Sampling Rate | Size | NF | Nb |
|---|---|---|---|---|
I_8000_7.5ms[61] |
8 kHz | 61 | 60 | 60 |
I_16000_7.5ms[65] |
16 kHz | 65 | 120 | 64 |
I_24000_7.5ms[65] |
24 kHz | 65 | 180 | 64 |
I_32000_7.5ms[65] |
32 kHz | 65 | 240 | 64 |
I_48000_7.5ms[65] |
44.1/48 kHz | 65 | 360 | 64 |
3.7.3 LD-MDCT Windows
The LD-MDCT window coefficients are pre-computed from an offline optimization. They cannot be derived mathematically — you must use the exact values from the spec. Each window has length 2×NF (the MDCT operates on a 2×NF buffer). The last Z entries are exactly zero (the leading zeros that create the look-ahead delay).
| Window Name | Frame | NF | Window Size (2×NF) | Z (trailing zeros) | Section |
|---|---|---|---|---|---|
w_N80[160] |
10ms, 8kHz | 80 | 160 | 30 | 3.7.3.1.1 |
w_N160[320] |
10ms, 16kHz | 160 | 320 | 60 | 3.7.3.1.2 |
w_N240[480] |
10ms, 24kHz | 240 | 480 | 90 | 3.7.3.1.3 |
w_N320[640] |
10ms, 32kHz | 320 | 640 | 120 | 3.7.3.1.4 |
w_N480[960] |
10ms, 48kHz | 480 | 960 | 180 | 3.7.3.1.5 |
w_N60[120] |
7.5ms, 8kHz | 60 | 120 | 14 | 3.7.3.2.1 |
w_N120[240] |
7.5ms, 16kHz | 120 | 240 | 28 | 3.7.3.2.2 |
w_N180[360] |
7.5ms, 24kHz | 180 | 360 | 42 | 3.7.3.2.3 |
w_N240_7.5ms[480] |
7.5ms, 32kHz | 240 | 480 | 56 | 3.7.3.2.4 |
w_N360[720] |
7.5ms, 48kHz | 360 | 720 | 84 | 3.7.3.2.5 |
All window values are double precision (64-bit) floats. The window can have amplitude > 1.0 in some regions — fixed-point implementations must account for this carefully to avoid overflow. At the decoder, the same window is used flipped: w(2N−1−n) instead of w(n).
3.7.4 SNS Quantization Tables
The SNS section uses several pre-computed tables:
| Table | Size | Used By | Description |
|---|---|---|---|
LFCB[32][8] |
32 × 8 = 256 doubles | 3.3.7.3.2 Stage 1 | Low-frequency codebook. 32 entries of dimension 8, trained offline for lower 8 scale factors. Indexed by ind_LF (5 bits). |
HFCB[32][8] |
32 × 8 = 256 doubles | 3.3.7.3.2 Stage 1 | High-frequency codebook. Same structure. Indexed by ind_HF (5 bits). |
D[16][16] |
256 doubles | 3.3.7.3.3 Stage 2 | 16×16 orthogonal DCT rotation matrix used for Stage 2 shape analysis (DCT) and synthesis (IDCT). D^T × D = I. Stored column-wise. |
MPVQ_offsets[10][11] |
10 × 11 = 110 uint32 | 3.3.7.3.3.8 Enumeration 3.4.7.2.2.1 De-enum |
Offset table for MPVQ enumeration/de-enumeration. Entry (n, k) = number of PVQ vectors of dimension n+1 with L1-norm k. Defined recursively by Eq. 57. |
sns_vq_reg_adj_gains[2] |
2 values | 3.3.7.3.3.6 Gain sets | Adjustment gain values for shape_j=0 (regular). 2 levels indexed by gain_i = 0 or 1. |
sns_vq_reg_lf_adj_gains[4] |
4 values | 3.3.7.3.3.6 | Gain levels for shape_j=1 (regular_lf). 4 levels. |
sns_vq_near_adj_gains[4] |
4 values | 3.3.7.3.3.6 | Gain levels for shape_j=2 (outlier_near). 4 levels. |
sns_vq_far_adj_gains[8] |
8 values | 3.3.7.3.3.6 | Gain levels for shape_j=3 (outlier_far). 8 levels. |
3.7.5 TNS Tables
TNS uses two arithmetic coding tables for transmitting the reflection coefficient indices:
| Table | Size | Indexing | Used By |
|---|---|---|---|
ac_tns_order_bits[2][8] |
2 × 8 = 16 entries | [tns_lpc_weighting][rcorder−1] | 3.3.8.3 (Eq 76): fractional bit cost (×2048) for transmitting the filter order. |
ac_tns_coef_bits[8][17] |
8 × 17 = 136 entries | [k][rci(k,f)] | 3.3.8.3 (Eq 77): fractional bit cost for each quantized reflection coefficient index (0–16). Varies by coefficient position k (0–7). |
ac_tns_order_cumfreq[2][9]ac_tns_order_freq[2][9] |
2 × 9 each | [tns_lpc_weighting][rcorder] | 3.3.13.4 arithmetic encoder / 3.4.2.5 decoder: cumulative and symbol frequencies for the order symbol. |
ac_tns_coef_cumfreq[8][17]ac_tns_coef_freq[8][17] |
8 × 17 each | [k][rci] | Arithmetic encoder/decoder: cumulative and symbol frequencies for each reflection coefficient index per coefficient position k. |
3.7.6 LTPF Tables
| Table | Size | Used By | Description |
|---|---|---|---|
tab_resamp_filter[240] |
240 doubles | 3.3.9.3 (Eq 79) | FIR low-pass filter impulse response for polyphase resampling to 12.8 kHz. h12.8(n) = tab_resamp_filter[n+119], n = −119..120. |
tab_ltpf_interp_R[32] |
32 doubles | 3.3.9.7 (Eq 100) | FIR filter for 1/4-sample interpolation of the autocorrelation R12.8, used for fractional pitch-lag determination. h4(n) = tab_ltpf_interp_R[n+15], n = −15..16. |
tab_ltpf_interp_x12k8[16] |
16 doubles | 3.3.9.8 (Eq 105) | FIR filter for interpolating the 12.8 kHz signal at fractional pitch lag. hi(n) = tab_ltpf_interp_x12k8[n+7], n = −7..8. |
tab_ltpf_num_fs[4][Lnum+1] |
4 rows × variable column count | 3.4.9.4 (Eq 146) | Numerator FIR coefficients (before gain scaling) for the LTPF decoder IIR filter. Indexed by [gain_ind][k], k = 0..Lnum. There is one sub-table per sampling rate. |
tab_ltpf_den_fs[4][Lden+1] |
4 rows × variable column count | 3.4.9.4 (Eq 147) | Denominator FIR coefficients for the LTPF decoder filter. Indexed by [pfr][k], k = 0..Lden. pfr = 0..3 (fractional pitch lag quarter-sample). One sub-table per sampling rate. |
3.7.7 Spectral Data Tables (Arithmetic Coder)
The arithmetic coder uses context-dependent probability tables for encoding and decoding spectral 2-tuples. These are the largest tables in the spec (many kilobytes each).
| Table | Size | Used By | Description |
|---|---|---|---|
ac_spec_lookup[4096] |
4096 uint16 entries | 3.3.10.4, 3.3.13.4, 3.4.2.5 | Maps context index t (0–1023) + level (0–3) to a probability table index pki. Indexed as ac_spec_lookup[t + lev×1024]. Returns the index into the cumfreq/freq tables. |
ac_spec_bits[N_PKIS][17] |
N_PKIs × 17 uint16 | 3.3.10.4 bit estimation | Fractional bit costs (×2048) for each symbol (0–16) under each probability model pki. Entry [pki][16] is the escape symbol cost. |
ac_spec_cumfreq[N_PKIS][17] |
N_PKIs × 17 uint16 | 3.3.13.4 encoder, 3.4.2.5 decoder |
Cumulative frequency table for the range coder. cumfreq[sym] = sum of freq[0..sym−1]. Required by ac_encode and ac_decode. |
ac_spec_freq[N_PKIS][17] |
N_PKIs × 17 uint16 | 3.3.13.4 encoder, 3.4.2.5 decoder |
Individual symbol frequency for the range coder. All freq[pki][0..16] sum to 1024 (= 2^10) for each pki. The sum property ensures the range coder operates correctly. |
N_PKIs is the number of distinct probability models in the system. The context variable c in the encoder and decoder tracks which probability model to use for the current 2-tuple based on the previous encoding history.
Implementation Notes
When implementing LC3 from scratch (rather than using liblc3), these are the key points about table management:
- Band tables: Select the correct table for your (fs, Nms) combination at session init time. No computation needed per frame.
- MDCT windows: Select based on NF. The same window is used for both encoder analysis and decoder synthesis (flipped). Values are read-only constants.
- SNS codebooks (LFCB, HFCB, D matrix): Used in both encoder and decoder Stage 1/2 processing. Values are read-only; they are not modified per frame.
- MPVQ_offsets: Can be recomputed from the recursive formula in Eq. 57, but the pre-computed table is recommended for speed.
- TNS and spectral tables: Large lookup tables that should be compiled as static const arrays. The arithmetic coder tables are the most performance-critical — they are accessed inside the inner encoding loop for every 2-tuple.
- LTPF filter tables: Selected per-frame based on sampling rate and gain_ind/pfr. Small lookup — 4 × a few coefficients.
/* Session init: select tables once based on (fs, Nms) */
const int *Ifs; /* Band index table pointer */
const double *wN; /* MDCT window pointer */
int NF, NE, Nb, Z;
switch(fs) {
case 48000: Ifs = I_48000; wN = w_N480; NF=480; NE=400; Nb=64; Z=180; break;
case 32000: Ifs = I_32000; wN = w_N320; NF=320; NE=320; Nb=64; Z=120; break;
case 24000: Ifs = I_24000; wN = w_N240; NF=240; NE=240; Nb=64; Z=90; break;
case 16000: Ifs = I_16000; wN = w_N160; NF=160; NE=160; Nb=64; Z=60; break;
case 8000: Ifs = I_8000; wN = w_N80; NF=80; NE=80; Nb=64; Z=30; break;
/* 7.5ms variants: use corresponding _7.5ms tables */
}
/* Tables are now ready for all per-frame encode/decode calls */
LC3 Tutorial Series Complete!
You have completed all 17 tutorials covering every section of Chapter 2 and Chapter 3 of the LC3 Specification v1.0. You now have a complete understanding of how LC3 encodes and decodes audio for Bluetooth LE Audio.
