use oxideav_celt::range_decoder::RangeDecoder;
use oxideav_core::Result;
use crate::silk::tables;
pub const MAG_NIBBLE_ICDF: [u8; 16] = [
240, 224, 208, 192, 176, 160, 144, 128, 112, 96, 80, 64, 48, 32, 16, 0,
];
pub fn decode_excitation(
rc: &mut RangeDecoder<'_>,
frame_len: usize,
_subframe_len: usize,
signal_type: u8,
_quant_offset_type: u8,
_seed: u32,
) -> Result<Vec<f32>> {
let rate_icdf: &[u8] = if signal_type == 2 {
&tables::RATE_LEVEL_VOICED_ICDF
} else {
&tables::RATE_LEVEL_INACTIVE_ICDF
};
let rate_level = rc.decode_icdf(rate_icdf, 8).min(10);
let n_shells = frame_len.div_ceil(16);
let pulse_icdf = &tables::PULSE_COUNT_ICDF[rate_level];
let mut _pulse_counts = vec![0i32; n_shells];
for pc in _pulse_counts.iter_mut() {
*pc = rc.decode_icdf(pulse_icdf, 8) as i32;
}
let mut excitation = vec![0f32; frame_len];
for e in excitation.iter_mut() {
let hi = rc.decode_icdf(&MAG_NIBBLE_ICDF, 8) as i32;
let lo = rc.decode_icdf(&MAG_NIBBLE_ICDF, 8) as i32;
let mag = (hi << 4) | lo; let signed = if mag != 0 {
let neg = rc.decode_bit_logp(1);
if neg {
-(mag as f32)
} else {
mag as f32
}
} else {
0.0
};
*e = signed / 128.0;
}
Ok(excitation)
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_celt::range_encoder::RangeEncoder;
#[test]
fn magnitude_nibble_roundtrip() {
for v in 0..16 {
let mut enc = RangeEncoder::new(8);
enc.encode_icdf(v, &MAG_NIBBLE_ICDF, 8);
let buf = enc.done().unwrap();
let mut dec = RangeDecoder::new(&buf);
let got = dec.decode_icdf(&MAG_NIBBLE_ICDF, 8);
assert_eq!(got, v);
}
}
}