use crate::format::SUBFRAME_LPC_QLP_SHIFT_LEN;
pub struct Quantized {
pub qlp_coeff: Vec<i32>,
pub shift: i32,
}
fn frexp_exponent(x: f64) -> i32 {
debug_assert!(x > 0.0 && x.is_finite());
let raw = ((x.to_bits() >> 52) & 0x7ff) as i32;
if raw != 0 {
raw - 1022 } else {
let scaled = x * (2f64).powi(64);
(((scaled.to_bits() >> 52) & 0x7ff) as i32) - 1022 - 64
}
}
pub fn quantize_coefficients(
lp_coeff: &[f32],
order: usize,
precision: u32,
) -> Result<Quantized, i32> {
let precision = precision - 1;
let qmax0 = 1i32 << precision;
let qmin = -qmax0;
let qmax = qmax0 - 1;
let mut cmax = 0.0f64;
for &c in &lp_coeff[..order] {
let d = (c as f64).abs();
if d > cmax {
cmax = d;
}
}
if cmax <= 0.0 {
return Err(2);
}
let max_shiftlimit = (1i32 << (SUBFRAME_LPC_QLP_SHIFT_LEN - 1)) - 1; let min_shiftlimit = -max_shiftlimit - 1; let log2cmax = frexp_exponent(cmax) - 1;
let mut shift = precision as i32 - log2cmax - 1;
if shift > max_shiftlimit {
shift = max_shiftlimit;
} else if shift < min_shiftlimit {
return Err(1);
}
let mut qlp_coeff = vec![0i32; order];
if shift >= 0 {
let scale = (1i32 << shift) as f32;
let mut error = 0.0f64;
for i in 0..order {
error += (lp_coeff[i] * scale) as f64;
let mut q = error.round() as i32;
if q > qmax {
q = qmax;
} else if q < qmin {
q = qmin;
}
error -= q as f64;
qlp_coeff[i] = q;
}
} else {
let divisor = (1i32 << -shift) as f32;
let mut error = 0.0f64;
for i in 0..order {
error += (lp_coeff[i] / divisor) as f64;
let mut q = error.round() as i32;
if q > qmax {
q = qmax;
} else if q < qmin {
q = qmin;
}
error -= q as f64;
qlp_coeff[i] = q;
}
shift = 0;
}
Ok(Quantized { qlp_coeff, shift })
}