lc3_codec/decoder/
side_info_reader.rs

1use super::{
2    buffer_reader::{BufferReader, BufferReaderError},
3    side_info::{Bandwidth, LongTermPostFilterInfo, SideInfo, SnsVq},
4};
5
6#[allow(unused_imports)]
7use num_traits::real::Real;
8
9// checked against spec. The only function to double check is read_sns_vq
10
11const NBITS_BW_TABLE: [usize; 5] = [0, 1, 2, 2, 3];
12
13#[derive(Debug)]
14pub enum SideInfoError {
15    BandwidthIdxOutOfRange(usize),
16    LastNonZeroTupleGreaterThanYLen(usize, usize),
17    NotImplemented,
18    PlcTriggerSns1OutOfRange(usize),
19    PlcTriggerSns2OutOfRange(usize),
20    BufferReaderError(BufferReaderError),
21}
22
23impl From<BufferReaderError> for SideInfoError {
24    fn from(err: BufferReaderError) -> Self {
25        Self::BufferReaderError(err)
26    }
27}
28
29pub fn read(
30    buf: &[u8],
31    reader: &mut BufferReader,
32    fs_ind: usize, // sampling rate index (fs_ind)
33    ne: usize,     // number of encoded spectral lines (y_len)
34) -> Result<SideInfo, SideInfoError> {
35    let nbits_bw = NBITS_BW_TABLE[fs_ind];
36
37    // bandwidth
38    let p_bw = if nbits_bw > 0 {
39        let idx = reader.read_tail_usize(buf, nbits_bw)?;
40        if fs_ind < idx {
41            return Err(SideInfoError::BandwidthIdxOutOfRange(idx));
42        } else {
43            idx
44        }
45    } else {
46        0
47    };
48
49    // last non-zero tuple
50    let lastnz_num_bits = ((ne / 2) as f32).log2().ceil() as usize;
51    let lastnz = reader.read_tail_usize(buf, lastnz_num_bits)?;
52    let lastnz = (lastnz + 1) << 1;
53    if lastnz > ne {
54        return Err(SideInfoError::LastNonZeroTupleGreaterThanYLen(lastnz, ne));
55    }
56
57    // lsb mode bit
58    let lsb_mode = reader.read_tail_bool(buf)?;
59
60    // global gain
61    let gg_ind = reader.read_tail_usize(buf, 8)?;
62
63    // number of TNS filters
64    let num_tns_filters = if p_bw < 3 { 1 } else { 2 };
65
66    // TNS order of quantized reflection coefficients
67    let mut rc_order: [usize; 2] = [0; 2];
68    for item in rc_order.iter_mut().take(num_tns_filters) {
69        *item = reader.read_tail_bool(buf)? as usize;
70    }
71
72    // pitch present flag
73    let pitch_present = reader.read_tail_bool(buf)?;
74
75    // read sns-vq
76    let sns_vq = read_sns_vq(buf, reader)?;
77
78    // long term post filter
79    let long_term_post_filter_info = read_long_term_post_filter_info(buf, reader, pitch_present)?;
80
81    let f_nf = reader.read_tail_usize(buf, 3)?;
82
83    let bandwidth = match p_bw {
84        0 => Bandwidth::NarrowBand,
85        1 => Bandwidth::WideBand,
86        2 => Bandwidth::SemiSuperWideBand,
87        3 => Bandwidth::SuperWideBand,
88        4 => Bandwidth::FullBand,
89        _ => return Err(SideInfoError::BandwidthIdxOutOfRange(p_bw)),
90    };
91
92    Ok(SideInfo {
93        bandwidth,
94        lastnz,
95        lsb_mode,
96        global_gain_index: gg_ind,
97        num_tns_filters,
98        reflect_coef_order_ari_input: rc_order,
99        sns_vq,
100        long_term_post_filter_info,
101        noise_factor: f_nf,
102    })
103}
104
105fn read_long_term_post_filter_info(
106    buf: &[u8],
107    reader: &mut BufferReader,
108    pitch_present: bool,
109) -> Result<LongTermPostFilterInfo, SideInfoError> {
110    let ltpf_active;
111    let pitch_index;
112    if pitch_present {
113        ltpf_active = reader.read_tail_bool(buf)?;
114        pitch_index = reader.read_tail_usize(buf, 9)?;
115    } else {
116        ltpf_active = false;
117        pitch_index = 0;
118    }
119
120    Ok(LongTermPostFilterInfo {
121        pitch_present,
122        is_active: ltpf_active,
123        pitch_index,
124    })
125}
126
127fn read_sns_vq(buf: &[u8], reader: &mut BufferReader) -> Result<SnsVq, SideInfoError> {
128    // stage 1 decoding
129    let ind_lf = reader.read_tail_usize(buf, 5)?;
130    let ind_hf = reader.read_tail_usize(buf, 5)?;
131
132    // stage 2 decoding
133    let submode_msb = reader.read_tail_bool(buf)? as u8;
134    let mut g_ind = if submode_msb == 0 {
135        reader.read_tail_usize(buf, 1)?
136    } else {
137        reader.read_tail_usize(buf, 2)?
138    };
139
140    let ls_inda = reader.read_tail_bool(buf)? as usize;
141    let ls_indb;
142    let idx_a;
143    let idx_b;
144    let mut submode_lsb;
145
146    if submode_msb == 0 {
147        let tmp = reader.read_tail_usize(buf, 25)?;
148        if tmp >= 33460056 {
149            return Err(SideInfoError::PlcTriggerSns1OutOfRange(tmp));
150        }
151
152        let idx_bor_gain_lsb = tmp / 2390004;
153        idx_a = tmp - idx_bor_gain_lsb * 2390004;
154        submode_lsb = 0;
155        let idx_bor_gain_lsb: i32 = idx_bor_gain_lsb as i32 - 2_i32;
156        if idx_bor_gain_lsb < 0 {
157            submode_lsb = 1;
158        }
159
160        let idx_bor_gain_lsb = (idx_bor_gain_lsb + submode_lsb as i32 * 2) as usize;
161        if submode_lsb != 0 {
162            g_ind = (g_ind << 1) + idx_bor_gain_lsb;
163            idx_b = 0;
164            ls_indb = 0;
165        } else {
166            idx_b = idx_bor_gain_lsb >> 1;
167            ls_indb = idx_bor_gain_lsb & 1;
168        }
169    } else {
170        ls_indb = 0;
171        idx_b = 0;
172        submode_lsb = 0;
173        let tmp = reader.read_tail_usize(buf, 24)?;
174
175        if tmp >= 16708096 {
176            return Err(SideInfoError::PlcTriggerSns2OutOfRange(tmp));
177        }
178
179        if tmp >= 15158272 {
180            let tmp = tmp - 15158272;
181            submode_lsb = 1;
182            g_ind = (g_ind << 1) + (tmp & 1);
183            idx_a = tmp >> 1;
184        } else {
185            idx_a = tmp;
186        }
187    }
188
189    Ok(SnsVq {
190        ind_lf,
191        ind_hf,
192        ls_inda,
193        ls_indb,
194        idx_a,
195        idx_b,
196        submode_lsb,
197        submode_msb,
198        g_ind,
199    })
200}
201
202#[cfg(test)]
203mod tests {
204    extern crate std;
205    use super::*;
206
207    #[test]
208    fn read_side_info_test() {
209        // the last 8 bytes from a typical lc3 encoded frame
210        // side info is read from the end of the frame towards the front
211        let buf = [192, 74, 255, 80, 28, 187, 134, 52];
212        let mut reader = BufferReader::new();
213
214        let side_info = read(&buf, &mut reader, 4, 400).unwrap();
215
216        assert_eq!(side_info.bandwidth, Bandwidth::FullBand);
217        assert_eq!(side_info.lastnz, 398);
218        assert_eq!(side_info.lsb_mode, false);
219        assert_eq!(side_info.global_gain_index, 184);
220        assert_eq!(side_info.num_tns_filters, 2);
221        assert_eq!(side_info.reflect_coef_order_ari_input, [1, 1]);
222        let sns_vq = side_info.sns_vq;
223        assert_eq!(sns_vq.ind_lf, 25);
224        assert_eq!(sns_vq.ind_hf, 1);
225        assert_eq!(sns_vq.ls_inda, 0);
226        assert_eq!(sns_vq.ls_indb, 0);
227        assert_eq!(sns_vq.idx_a, 307189);
228        assert_eq!(sns_vq.idx_b, 0);
229        assert_eq!(sns_vq.submode_lsb, 1);
230        assert_eq!(sns_vq.submode_msb, 0);
231        assert_eq!(sns_vq.g_ind, 0);
232        let post_filter = side_info.long_term_post_filter_info;
233        assert_eq!(post_filter.pitch_present, false);
234        assert_eq!(post_filter.is_active, false);
235        assert_eq!(post_filter.pitch_index, 0);
236        assert_eq!(side_info.noise_factor, 6);
237    }
238}