lc3_codec/decoder/
spectral_noise_shaping.rs

1use super::side_info::SnsVq;
2use crate::tables::{
3    band_index_tables::*,
4    spec_noise_shape_quant_tables::{
5        D, HFCB, LFCB, SNS_VQ_FAR_ADJ_GAINS, SNS_VQ_NEAR_ADJ_GAINS, SNS_VQ_REG_ADJ_GAINS, SNS_VQ_REG_LF_ADJ_GAINS,
6    },
7};
8use crate::{
9    common::{
10        complex::Scaler,
11        config::{FrameDuration, Lc3Config},
12    },
13    tables::spec_noise_shape_quant_tables::MPVQ_OFFSETS,
14};
15
16// checked against spec
17
18#[allow(unused_imports)]
19use num_traits::real::Real;
20
21pub fn decode(config: &Lc3Config, sns: &SnsVq, spec_lines: &mut [Scaler]) {
22    let mut quant_1st_stage_vec = [0.0; 16];
23    quant_1st_stage_vec[..8].copy_from_slice(&LFCB[sns.ind_lf]);
24    quant_1st_stage_vec[8..].copy_from_slice(&HFCB[sns.ind_hf]);
25
26    let shape_j = (sns.submode_msb << 1) + sns.submode_lsb;
27    let gain_i = sns.g_ind;
28
29    let mut y = [0; 16];
30    let mut z = [0; 16];
31
32    // mpvq de-enumeration calls made for the demultiplexed shape_j
33    match shape_j {
34        0 => {
35            mpvq_deenum(10, 10, sns.ls_inda, sns.idx_a, &mut y);
36            mpvq_deenum(6, 1, sns.ls_indb, sns.idx_b, &mut z);
37            y[10..16].copy_from_slice(&z[..6]);
38        }
39        1 => {
40            mpvq_deenum(10, 10, sns.ls_inda, sns.idx_a, &mut y);
41            for y_n in &mut y[10..16] {
42                *y_n = 0;
43            }
44        }
45        2 => mpvq_deenum(16, 8, sns.ls_inda, sns.idx_a, &mut y),
46        3 => mpvq_deenum(16, 6, sns.ls_inda, sns.idx_a, &mut y),
47        _ => panic!("invalid shape_j when making mpvq denum calls: {}", shape_j),
48    };
49
50    // unit energy normalization of the received shape
51    let y_norm = y[..16]
52        .iter()
53        .map(|x| *x as Scaler * *x as Scaler)
54        .sum::<Scaler>()
55        .sqrt();
56
57    // reconstruction of the quantized sns scale factors - lookup adjustment gain candidates
58    let mut quant_adj_gain = match shape_j {
59        0 => SNS_VQ_REG_ADJ_GAINS[gain_i],
60        1 => SNS_VQ_REG_LF_ADJ_GAINS[gain_i],
61        2 => SNS_VQ_NEAR_ADJ_GAINS[gain_i],
62        3 => SNS_VQ_FAR_ADJ_GAINS[gain_i],
63        _ => panic!(
64            "invalid shape_j when loopking up adjustment gain candidates: {}",
65            shape_j
66        ),
67    };
68
69    if y_norm != 0.0 {
70        quant_adj_gain /= y_norm;
71    }
72
73    // synthesis of the quantized scale factors
74    let mut quant_scale_factor = [0.0; 16];
75    for n in 0..16 {
76        let mut factor = 0.0;
77        for (col, y_col) in y[..16].iter().enumerate() {
78            factor += *y_col as Scaler * D[n][col];
79        }
80
81        quant_scale_factor[n] = quant_1st_stage_vec[n] + quant_adj_gain * factor;
82    }
83
84    // sns scale factors interpolation
85    let mut scale_factor_interp = [0.0; 64];
86    scale_factor_interp[0] = quant_scale_factor[0];
87    scale_factor_interp[1] = quant_scale_factor[0];
88
89    for n in 0..=14 {
90        let factor_n = quant_scale_factor[n];
91        let diff_next = quant_scale_factor[n + 1] - factor_n;
92        scale_factor_interp[4 * n + 2] = factor_n + (1.0 / 8.0 * diff_next);
93        scale_factor_interp[4 * n + 3] = factor_n + (3.0 / 8.0 * diff_next);
94        scale_factor_interp[4 * n + 4] = factor_n + (5.0 / 8.0 * diff_next);
95        scale_factor_interp[4 * n + 5] = factor_n + (7.0 / 8.0 * diff_next);
96    }
97    scale_factor_interp[62] = quant_scale_factor[15] + 1.0 / 8.0 * (quant_scale_factor[15] - quant_scale_factor[14]);
98    scale_factor_interp[63] = quant_scale_factor[15] + 3.0 / 8.0 * (quant_scale_factor[15] - quant_scale_factor[14]);
99
100    // if nb < 64 then we need to reduce the number of scale factors
101    // TODO: check this again
102    let nb = config.nb;
103    let n2 = 64 - nb;
104    if n2 != 0 {
105        for i in 0..n2 {
106            scale_factor_interp[i] = (scale_factor_interp[2 * i] + scale_factor_interp[2 * i + 1]) / 2.0;
107        }
108        for i in n2..nb {
109            scale_factor_interp[i] = scale_factor_interp[i + n2];
110        }
111    }
112
113    let mut g_sns = [0.0; 64];
114
115    // transform scale factors back into the linear domain
116    for b in 0..nb {
117        // this is very slow (2.43 ms - but probably more accurate than the fast_math version below)
118        // g_sns[b] = (scf_quint[b]).exp2();
119
120        // use an approxmation function rater than slow libm exp2 (2.43 ms -> 0.12 ms)
121        // TODO: check that we can use the raw version (range criteria)
122        g_sns[b] = fast_math::exp2_raw(scale_factor_interp[b]);
123    }
124
125    let i_fs: &[usize] = match config.n_ms {
126        FrameDuration::SevenPointFiveMs => match config.fs_ind {
127            0 => &I_8000_7P5MS,
128            1 => &I_16000_7P5MS,
129            2 => &I_24000_7P5MS,
130            3 => &I_32000_7P5MS,
131            4 => &I_48000_7P5MS,
132            _ => panic!("invalid fs_ind"),
133        },
134        FrameDuration::TenMs => match config.fs_ind {
135            0 => &I_8000_10MS,
136            1 => &I_16000_10MS,
137            2 => &I_24000_10MS,
138            3 => &I_32000_10MS,
139            4 => &I_48000_10MS,
140            _ => panic!("invalid fs_ind"),
141        },
142    };
143
144    // Spectral Shaping
145    for (b, g_sns_b) in g_sns[..nb].iter().enumerate() {
146        // since i_fs has no overlapping indices it is safe to mutate x_hat in place
147        for spec_line in spec_lines[i_fs[b]..i_fs[b + 1]].iter_mut() {
148            *spec_line *= *g_sns_b;
149        }
150    }
151}
152
153// The logic in the spec is so mysterious that I decided to keep variable and function names as well as the business
154// logic is close as possible to the spec rather than to make sense of it.
155fn mpvq_deenum(dim_in: usize, k_val_in: usize, ls_ind: usize, mpvq_ind: usize, vec_out: &mut [i32]) {
156    for x in vec_out.iter_mut().take(dim_in) {
157        *x = 0;
158    }
159
160    let mut leading_sign = if ls_ind == 0 { 1 } else { -1 };
161    let mut k_max_local = k_val_in;
162    let mut ind = mpvq_ind;
163
164    // init
165    let mut k_acc;
166
167    // loop over positions
168    for pos in 0..dim_in {
169        let h_row_ptr = &MPVQ_OFFSETS[dim_in - 1 - pos];
170        let k_delta;
171        if ind != 0 {
172            k_acc = k_max_local;
173            let ul_tmp_offset = h_row_ptr[k_acc];
174            let mut wrap_flag = ind < ul_tmp_offset;
175            let mut ul_diff = 0;
176            if !wrap_flag {
177                // TODO: check this, looks unnecessary
178                ul_diff = ind - ul_tmp_offset;
179            }
180
181            while wrap_flag {
182                k_acc -= 1;
183                wrap_flag = ind < h_row_ptr[k_acc];
184                if !wrap_flag {
185                    // TODO: check this, looks unnecessary
186                    ul_diff = ind - h_row_ptr[k_acc];
187                }
188            }
189
190            ind = ul_diff;
191            k_delta = k_max_local - k_acc;
192        } else {
193            vec_out[pos] = mind2vec_one(k_max_local, leading_sign);
194            break;
195        }
196
197        k_max_local = setval_update_sign(k_delta, k_max_local, &mut leading_sign, &mut ind, &mut vec_out[pos])
198    }
199}
200
201fn setval_update_sign(
202    k_delta: usize,
203    k_max_local_in: usize,
204    leading_sign: &mut i32,
205    ind_in: &mut usize,
206    vec_out_item: &mut i32,
207) -> usize {
208    let mut k_max_local_out = k_max_local_in;
209    if k_delta != 0 {
210        *vec_out_item = mind2vec_one(k_delta, *leading_sign);
211        *leading_sign = get_lead_sign(ind_in);
212        k_max_local_out -= k_delta;
213    }
214
215    k_max_local_out
216}
217
218fn get_lead_sign(ind_in: &mut usize) -> i32 {
219    let mut leading_sign = 1;
220
221    if *ind_in & 0x1 != 0 {
222        leading_sign = -1;
223    }
224
225    *ind_in >>= 1;
226    leading_sign
227}
228
229fn mind2vec_one(k_val_in: usize, leading_sign: i32) -> i32 {
230    if leading_sign < 0 {
231        -(k_val_in as i32)
232    } else {
233        k_val_in as i32
234    }
235}
236
237#[cfg(test)]
238mod tests {
239    extern crate std;
240    use super::*;
241    use crate::common::config::FrameDuration;
242
243    #[test]
244    fn spectral_noise_shaping_decode() {
245        let config = Lc3Config {
246            fs_ind: 4,
247            n_ms: FrameDuration::TenMs,
248            nb: 64,
249            // not used below here
250            fs: 0,
251            ne: 0,
252            nf: 0,
253            z: 0,
254        };
255        let sns = SnsVq {
256            ind_lf: 13,
257            ind_hf: 4,
258            ls_inda: 1,
259            ls_indb: 0,
260            idx_a: 1718290,
261            idx_b: 2,
262            submode_lsb: 0,
263            submode_msb: 0,
264            g_ind: 0,
265        };
266        #[rustfmt::skip]
267        let mut spec_lines = [
268            -568.56555, 1972.808, 3987.5906, 2461.2402, -263.29547, -2949.6724, -2217.0242, 141.18742, 1270.6868,
269            -385.4035, 1667.538, 568.56555, -538.0386, -1924.9376, -330.6227, 358.01404, -103.25958, 640.72064,
270            -380.6663, -565.7268, 1425.4789, -1620.2815, -2171.777, 65.41626, -630.4777, -241.61359, 70.17501,
271            648.6986, 913.1724, 377.05695, 1248.8955, 447.55414, 122.224335, 387.0873, 670.9608, 202.11314, 470.52597,
272            9.777176, 250.14848, -869.4124, 705.27844, 764.594, -196.6836, 162.10555, 32.383907, 212.68384, -200.68219,
273            -385.05658, 74.749176, 244.4491, 75.39133, 71.7427, -370.58853, -284.1499, -221.86317, -378.81683,
274            -78.224205, 120.7565, 49.39573, -431.70422, -639.2284, -863.50916, -762.39795, -557.4247, -210.2326,
275            207.37712, 667.06, 268.28708, 266.76526, 180.27934, 266.1345, 18.510933, -71.35217, -18.678001, 61.719135,
276            78.072945, 41.07525, 31.682747, 65.34431, 39.83117, 50.713173, 265.0006, 87.029144, -105.01486, -92.9501,
277            109.07149, 213.51758, 237.69977, 244.04578, 169.18098, -60.653255, -202.20692, -5.709038, 418.32336,
278            390.42206, -52.63867, -409.54736, -371.99884, -123.08209, 15.460239, -13.179712, 10.579021, 10.312677,
279            49.179047, -104.04299, -108.42853, 45.232265, 106.2404, -18.412956, -252.0934, -189.36148, 85.68147,
280            260.1948, 66.20917, -89.14935, 37.372047, 196.89316, 4.2800827, -186.45068, -10.664055, 251.7307,
281            283.97842, 87.595795, 65.05641, 91.597, -64.72161, -260.67474, -120.33, 275.7829, 360.36444, 76.64067,
282            -85.21214, -19.708641, 59.083878, 71.03325, 37.62242, 41.2656, 33.881153, 25.94694, -3.6607666, -15.336594,
283            -46.333282, -68.63583, 51.637062, 181.11745, 75.242294, -25.19682, -26.834858, 23.40418, 38.82212,
284            -11.055281, -14.305193, -22.998611, 129.22333, 87.56438, -91.969635, -113.919846, -21.006641, 165.25201,
285            93.82325, 70.90962, 56.982315, 15.586489, -109.50122, -156.43475, -32.77449, 127.61873, 86.515625,
286            -71.82623, -60.272907, 74.61493, 174.22997, 35.206467, -130.87024, -37.255043, 125.10912, 72.04756,
287            28.948765, 1.5288572, 89.77242, 28.662163, -122.471275, -64.80139, 35.938797, 56.74036, 19.603413,
288            -92.18097, -95.45599, 4.2908516, 4.6752024, 39.53695, 19.507534, -69.66742, -24.112461, -4.6465445,
289            -19.89853, -2.2964888, 51.27441, 41.12713, 64.92945, 0.0, 0.0, 0.0, 61.05402, 0.0, 61.05402, 0.0, 61.05402,
290            0.0, 0.0, 0.0, -61.05402, 61.05402, 122.10804, -61.05402, 0.0, 122.10804, 0.0, 61.05402, -61.05402, 0.0,
291            0.0, -61.05402, 0.0, 0.0, 122.10804, -61.05402, -61.05402, 0.0, 0.0, 0.0, 0.0, -61.05402, 61.05402,
292            -61.05402, 61.05402, 61.05402, 61.05402, 0.0, 0.0, 61.05402, 0.0, 0.0, 0.0, 61.05402, 61.05402, 61.05402,
293            0.0, 0.0, 61.05402, 0.0, 0.0, 61.05402, 122.10804, -122.10804, 0.0, -61.05402, -61.05402, 0.0, 0.0, 0.0,
294            0.0, -61.05402, 0.0, 0.0, -61.05402, 61.05402, 61.05402, 61.05402, -122.10804, -61.05402, -61.05402, 0.0,
295            61.05402, -61.05402, 0.0, 0.0, 61.05402, 0.0, 0.0, 0.0, -61.05402, 61.05402, -61.05402, 0.0, 0.0,
296            -61.05402, 61.05402, 0.0, 0.0, 0.0, 61.05402, 61.05402, 0.0, -61.05402, -61.05402, 0.0, -61.05402, 0.0,
297            -61.05402, -61.05402, 0.0, 61.05402, 0.0, 0.0, 0.0, 0.0, -61.05402, 0.0, 61.05402, 61.05402, 0.0, 0.0, 0.0,
298            0.0, -61.05402, -61.05402, -61.05402, 0.0, 0.0, 0.0, -61.05402, 0.0, 0.0, 61.05402, 0.0, -61.05402, 0.0,
299            61.05402, 0.0, 0.0, 0.0, -61.05402, 0.0, 0.0, 0.0, -61.05402, 0.0, 0.0, -61.05402, 0.0, 0.0, 0.0, 0.0,
300            -61.05402, 61.05402, 0.0, 0.0, 0.0, 0.0, 61.05402, 0.0, 0.0, 0.0, 0.0, -61.05402, -61.05402, 61.05402, 0.0,
301            0.0, 0.0, -19.079382, -19.079382, -19.079382, -19.079382, 19.079382, -19.079382, 19.079382, 0.0, 0.0, 0.0,
302            -61.05402, -61.05402, 0.0, 0.0, 61.05402, -61.05402, -61.05402, 0.0, 0.0, 61.05402, 0.0, 0.0, 0.0, 0.0,
303            -61.05402, 0.0, 61.05402, 0.0, 61.05402, 0.0, 0.0, 0.0, 0.0, 0.0, -61.05402, 0.0, 0.0, 61.05402, 61.05402,
304        ];
305
306        decode(&config, &sns, &mut spec_lines);
307
308        #[rustfmt::skip]
309        let spec_lines_expected = [
310            -2268.137, 7869.9785, 15884.984, 9776.979, -1042.96, -11651.202, -8543.342, 519.08997, 4455.2827, -1288.14,
311            5093.401, 1520.3356, -1260.0343, -3961.906, -641.0432, 703.6705, -205.72899, 1298.229, -831.222,
312            -1235.3197, 3581.536, -4070.9802, -6290.9507, 189.4902, -2103.3403, -806.0485, 248.62497, 2298.2922,
313            3174.625, 1310.8307, 4260.057, 1526.6339, 409.04425, 1295.4526, 2116.6775, 637.6055, 1343.3187, 27.913153,
314            714.1564, -2245.3208, 1821.4329, 1974.6196, -459.77234, 378.94186, 75.70141, 449.14334, -423.7984,
315            -813.15814, 141.91173, 464.08798, 143.13086, 122.60409, -633.3142, -485.5956, -379.15125, -581.63947,
316            -120.10629, 185.41084, 75.84274, -589.5617, -872.96936, -1179.2609, -1041.1772, -671.12726, -253.11552,
317            249.67758, 803.12585, 285.46893, 283.84964, 191.82494, 283.1785, 17.406265, -67.094124, -17.563364,
318            58.03595, 73.413826, 35.959316, 27.736652, 57.205654, 34.870186, 44.39683, 227.21794, 74.620895, -90.04228,
319            -79.69767, 93.52053, 179.29234, 199.59831, 204.92711, 142.06258, -50.931004, -169.79471, -4.6945424,
320            343.98734, 321.0441, -43.284782, -336.7708, -305.89468, -90.73599, 11.397272, -9.71607, 7.7988434,
321            7.6024947, 36.25474, -76.700386, -65.53449, 27.338501, 64.21198, -11.1288395, -152.36592, -114.450584,
322            51.78611, 129.27042, 32.89415, -44.291332, 18.567244, 97.82079, 2.126438, -92.632744, -4.3691993,
323            103.137276, 116.34959, 35.889114, 26.654442, 37.52846, -26.51727, -106.801765, -40.06586, 91.82647,
324            119.98929, 25.518776, -28.37279, -6.5623174, 19.672953, 23.651693, 10.104294, 11.0827465, 9.099498,
325            6.9685974, -0.98317605, -4.1189656, -12.44378, -18.4336, 13.868221, 39.34896, 16.346886, -5.4741755,
326            -5.83005, 5.084713, 8.434362, -2.4018328, -3.1078978, -4.9966, 28.074621, 15.33394, -16.105371, -19.94921,
327            -3.678603, 28.938301, 16.42997, 12.417422, 9.978525, 2.7294464, -19.175436, -23.296207, -4.8807654,
328            19.004936, 12.883876, -10.696337, -8.97582, 11.111629, 25.946264, 5.242934, -19.48915, -5.5480075,
329            16.77535, 9.660551, 3.8816166, 0.20499796, 12.037202, 3.8431873, -16.421652, -8.688943, 4.8188806,
330            7.608073, 2.6285381, -11.124037, -11.519255, 0.51780313, 0.564185, 4.7711635, 2.3540926, -8.40719,
331            -2.909797, -0.5607267, -2.4012764, -0.27713123, 6.1875944, 4.4743004, 7.0638013, 0.0, 0.0, 0.0, 6.6421857,
332            0.0, 6.6421857, 0.0, 6.6421857, 0.0, 0.0, 0.0, -6.4278693, 6.4278693, 12.855739, -6.4278693, 0.0,
333            12.855739, 0.0, 6.4278693, -6.4278693, 0.0, 0.0, -6.4278693, 0.0, 0.0, 13.372511, -6.6862555, -6.6862555,
334            0.0, 0.0, 0.0, 0.0, -6.6862555, 6.6862555, -6.6862555, 6.6862555, 6.6862555, 6.6862555, 0.0, 0.0,
335            6.9530754, 0.0, 0.0, 0.0, 6.9530754, 6.9530754, 6.9530754, 0.0, 0.0, 6.9530754, 0.0, 0.0, 6.9530754,
336            13.906151, -13.906151, 0.0, -7.2283335, -7.2283335, 0.0, 0.0, 0.0, 0.0, -7.2283335, 0.0, 0.0, -7.2283335,
337            7.2283335, 7.2283335, 7.2283335, -14.456667, -7.2283335, -7.2283335, 0.0, 8.2442, -8.2442, 0.0, 0.0,
338            8.2442, 0.0, 0.0, 0.0, -8.2442, 8.2442, -8.2442, 0.0, 0.0, -8.2442, 8.2442, 0.0, 0.0, 0.0, 10.337095,
339            10.337095, 0.0, -10.337095, -10.337095, 0.0, -10.337095, 0.0, -10.337095, -10.337095, 0.0, 10.337095, 0.0,
340            0.0, 0.0, 0.0, -10.337095, 0.0, 10.337095, 12.974136, 0.0, 0.0, 0.0, 0.0, -12.974136, -12.974136,
341            -12.974136, 0.0, 0.0, 0.0, -12.974136, 0.0, 0.0, 12.974136, 0.0, -12.974136, 0.0, 12.974136, 0.0, 0.0, 0.0,
342            -16.216764, 0.0, 0.0, 0.0, -16.216764, 0.0, 0.0, -16.216764, 0.0, 0.0, 0.0, 0.0, -16.216764, 16.216764,
343            0.0, 0.0, 0.0, 0.0, 16.216764, 0.0, 0.0, 0.0, 0.0, -20.320456, -20.320456, 20.320456, 0.0, 0.0, 0.0,
344            -6.3501425, -6.3501425, -6.3501425, -6.3501425, 6.3501425, -6.3501425, 6.3501425, 0.0, 0.0, 0.0,
345            -20.320456, -20.320456, 0.0, 0.0, 25.512432, -25.512432, -25.512432, 0.0, 0.0, 25.512432, 0.0, 0.0, 0.0,
346            0.0, -25.512432, 0.0, 25.512432, 0.0, 25.512432, 0.0, 0.0, 0.0, 0.0, 0.0, -25.512432, 0.0, 0.0, 25.512432,
347            25.512432,
348        ];
349        assert_eq!(spec_lines, spec_lines_expected);
350    }
351
352    #[test]
353    fn mpvq_deenum_test1() {
354        let mut vec_out = [0; 16];
355
356        mpvq_deenum(10, 10, 1, 1718290, &mut vec_out);
357
358        assert_eq!(vec_out, [0, -2, 0, 0, 1, 1, 3, -2, 1, 0, 0, 0, 0, 0, 0, 0]);
359    }
360
361    #[test]
362    fn mpvq_deenum_test2() {
363        let mut vec_out = [0; 16];
364
365        mpvq_deenum(6, 1, 0, 2, &mut vec_out);
366
367        assert_eq!(vec_out, [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
368    }
369}