use crate::range_decoder::RangeDecoder;
use crate::silk_lsf_stabilize::NlsfStabilized;
use crate::silk_lsf_stage2::D_LPC_MAX;
use crate::Error;
const LSF_INTERP_ICDF: &[u8] = &[243, 221, 192, 181, 0];
const W_Q2_RESET: u8 = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LsfInterpContext {
TwentyMs,
TwentyMsAfterResetOrUncoded,
TenMs,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LsfInterpolated {
w_q2: Option<u8>,
len: u8,
n1_q15: [i16; D_LPC_MAX],
has_first_half: bool,
}
impl LsfInterpolated {
pub fn decode(
rd: &mut RangeDecoder,
n2: &NlsfStabilized,
n0_q15: Option<&[i16]>,
context: LsfInterpContext,
) -> Result<Self, Error> {
let d_lpc = n2.len();
let n2_q15 = n2.nlsf_q15();
if let Some(n0) = n0_q15 {
if n0.len() != d_lpc {
return Err(Error::MalformedPacket);
}
}
if context == LsfInterpContext::TenMs {
return Ok(Self {
w_q2: None,
len: d_lpc as u8,
n1_q15: [0i16; D_LPC_MAX],
has_first_half: false,
});
}
let decoded_w_q2 = rd.dec_icdf(LSF_INTERP_ICDF, 8) as u8;
let use_reset =
matches!(context, LsfInterpContext::TwentyMsAfterResetOrUncoded) || n0_q15.is_none();
let effective_w_q2 = if use_reset { W_Q2_RESET } else { decoded_w_q2 };
let mut n1_q15 = [0i16; D_LPC_MAX];
match n0_q15 {
Some(n0) => {
for k in 0..d_lpc {
let n0k = n0[k] as i32;
let n2k = n2_q15[k] as i32;
let interp = n0k + ((effective_w_q2 as i32 * (n2k - n0k)) >> 2);
n1_q15[k] = interp as i16;
}
}
None => {
n1_q15[..d_lpc].copy_from_slice(&n2_q15[..d_lpc]);
}
}
Ok(Self {
w_q2: Some(decoded_w_q2),
len: d_lpc as u8,
n1_q15,
has_first_half: true,
})
}
pub fn w_q2(&self) -> Option<u8> {
self.w_q2
}
pub fn n1_q15(&self) -> Option<&[i16]> {
if self.has_first_half {
Some(&self.n1_q15[..self.len as usize])
} else {
None
}
}
pub fn len(&self) -> usize {
self.len as usize
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::silk_lsf_recon::NlsfReconstructed;
use crate::silk_lsf_stage2::LsfStage2;
use crate::toc::Bandwidth;
#[test]
fn table26_pdf_sums_to_256() {
let pdf = [13u32, 22, 29, 11, 181];
assert_eq!(pdf.iter().sum::<u32>(), 256);
let mut cum = 0u32;
let mut expected = Vec::new();
for &p in &pdf {
cum += p;
expected.push((256 - cum) as u8);
}
assert_eq!(LSF_INTERP_ICDF, expected.as_slice());
assert_eq!(*LSF_INTERP_ICDF.last().unwrap(), 0);
}
#[test]
fn table26_icdf_monotone_decreasing() {
for w in LSF_INTERP_ICDF.windows(2) {
assert!(
w[0] > w[1],
"icdf not strictly decreasing: {LSF_INTERP_ICDF:?}"
);
}
assert_eq!(LSF_INTERP_ICDF.len(), 5);
}
fn stabilized(bandwidth: Bandwidth, i1: u8, buf: &[u8]) -> NlsfStabilized {
let mut rd = RangeDecoder::new(buf);
let stage2 = LsfStage2::decode(&mut rd, bandwidth, i1).expect("stage-2");
let recon =
NlsfReconstructed::from_stage1_and_stage2(bandwidth, i1, &stage2).expect("recon");
NlsfStabilized::from_reconstructed(bandwidth, &recon).expect("stabilize")
}
fn interp_formula(n0: &[i16], n2: &[i16], w_q2: u8) -> Vec<i16> {
n0.iter()
.zip(n2.iter())
.map(|(&a, &b)| {
let a = a as i32;
let b = b as i32;
(a + ((w_q2 as i32 * (b - a)) >> 2)) as i16
})
.collect()
}
#[test]
fn ten_ms_reads_nothing_and_has_no_first_half() {
let buf = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2 = stabilized(Bandwidth::Nb, 3, &buf);
let mut rd = RangeDecoder::new(&buf);
let tell_before = rd.tell();
let interp = LsfInterpolated::decode(&mut rd, &n2, None, LsfInterpContext::TenMs).unwrap();
assert_eq!(rd.tell(), tell_before);
assert_eq!(interp.w_q2(), None);
assert!(interp.n1_q15().is_none());
assert_eq!(interp.len(), n2.len());
}
#[test]
fn twenty_ms_interpolates_between_n0_and_n2() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let buf0 = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2 = stabilized(Bandwidth::Nb, 5, &buf2);
let n0 = stabilized(Bandwidth::Nb, 5, &buf0);
let n0_vec: Vec<i16> = n0.nlsf_q15().to_vec();
let factor_buf = [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut rd = RangeDecoder::new(&factor_buf);
let interp =
LsfInterpolated::decode(&mut rd, &n2, Some(&n0_vec), LsfInterpContext::TwentyMs)
.unwrap();
let w = interp.w_q2().expect("20 ms has a factor");
assert!(w <= 4, "w_Q2 out of range: {w}");
let expected = interp_formula(&n0_vec, n2.nlsf_q15(), w);
assert_eq!(interp.n1_q15().unwrap(), expected.as_slice());
}
#[test]
fn twenty_ms_factor_zero_yields_n0() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let buf0 = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2 = stabilized(Bandwidth::Wb, 0, &buf2);
let n0 = stabilized(Bandwidth::Wb, 0, &buf0);
let n0_vec: Vec<i16> = n0.nlsf_q15().to_vec();
let zero = interp_formula(&n0_vec, n2.nlsf_q15(), 0);
assert_eq!(zero, n0_vec, "w_Q2 == 0 must reproduce n0 exactly");
}
#[test]
fn twenty_ms_factor_four_yields_n2() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let buf0 = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2 = stabilized(Bandwidth::Wb, 0, &buf2);
let n0 = stabilized(Bandwidth::Wb, 0, &buf0);
let n0_vec: Vec<i16> = n0.nlsf_q15().to_vec();
let four = interp_formula(&n0_vec, n2.nlsf_q15(), 4);
assert_eq!(four, n2.nlsf_q15(), "w_Q2 == 4 must reproduce n2 exactly");
}
#[test]
fn after_reset_decodes_factor_but_uses_four() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let buf0 = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2 = stabilized(Bandwidth::Nb, 7, &buf2);
let n0 = stabilized(Bandwidth::Nb, 7, &buf0);
let n0_vec: Vec<i16> = n0.nlsf_q15().to_vec();
let factor_buf = [0x80u8, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01];
let mut rd_reset = RangeDecoder::new(&factor_buf);
let tell_before = rd_reset.tell();
let interp = LsfInterpolated::decode(
&mut rd_reset,
&n2,
Some(&n0_vec),
LsfInterpContext::TwentyMsAfterResetOrUncoded,
)
.unwrap();
assert!(
rd_reset.tell() > tell_before,
"factor must still be decoded"
);
assert_eq!(
interp.n1_q15().unwrap(),
n2.nlsf_q15(),
"reset context must force w_Q2 = 4 → n1 == n2"
);
let mut rd_normal = RangeDecoder::new(&factor_buf);
let _ = LsfInterpolated::decode(
&mut rd_normal,
&n2,
Some(&n0_vec),
LsfInterpContext::TwentyMs,
)
.unwrap();
assert_eq!(rd_reset.tell(), rd_normal.tell());
}
#[test]
fn no_history_forces_n2_even_in_normal_context() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let n2 = stabilized(Bandwidth::Wb, 9, &buf2);
let factor_buf = [0x33u8, 0x66, 0x99, 0xCC, 0xFF, 0x00, 0x55, 0xAA];
let mut rd = RangeDecoder::new(&factor_buf);
let interp =
LsfInterpolated::decode(&mut rd, &n2, None, LsfInterpContext::TwentyMs).unwrap();
assert_eq!(interp.n1_q15().unwrap(), n2.nlsf_q15());
assert!(interp.w_q2().is_some());
}
#[test]
fn rejects_n0_length_mismatch() {
let buf = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
let n2_nb = stabilized(Bandwidth::Nb, 0, &buf); let wb_buf = [
0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6, 0x4C, 0x8E,
];
let n0_wb = stabilized(Bandwidth::Wb, 0, &wb_buf); let n0_vec: Vec<i16> = n0_wb.nlsf_q15().to_vec();
let mut rd = RangeDecoder::new(&buf);
assert!(LsfInterpolated::decode(
&mut rd,
&n2_nb,
Some(&n0_vec),
LsfInterpContext::TwentyMs
)
.is_err());
}
#[test]
fn interpolated_values_stay_in_q15_range() {
let buf2 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA];
let buf0 = [0x5A, 0xC3, 0x17, 0x9E, 0x42, 0xFB, 0x08, 0x71, 0x2D, 0xB6];
for bandwidth in [Bandwidth::Nb, Bandwidth::Mb, Bandwidth::Wb] {
let extra = [0x4C, 0x8E];
let mut b2 = buf2.to_vec();
let mut b0 = buf0.to_vec();
if bandwidth == Bandwidth::Wb {
b2.extend_from_slice(&extra);
b0.extend_from_slice(&extra);
}
for i1 in 0u8..32 {
let n2 = stabilized(bandwidth, i1, &b2);
let n0 = stabilized(bandwidth, i1, &b0);
let n0_vec: Vec<i16> = n0.nlsf_q15().to_vec();
for w in 0u8..=4 {
let res = interp_formula(&n0_vec, n2.nlsf_q15(), w);
for &v in &res {
assert!(
(0..=i16::MAX).contains(&v),
"n1 out of range: bw={bandwidth:?} i1={i1} w={w} v={v}"
);
}
}
}
}
}
}