use super::MAX_LPC_ORDER;
pub struct LpCoefficients {
coeff: Vec<f32>,
pub error: [f64; MAX_LPC_ORDER],
pub max_order: usize,
}
impl LpCoefficients {
pub fn row(&self, order: usize) -> &[f32] {
let base = (order - 1) * MAX_LPC_ORDER;
&self.coeff[base..base + order]
}
}
pub fn compute_lp_coefficients(autoc: &[f64], max_order: usize) -> LpCoefficients {
debug_assert!(max_order > 0 && max_order <= MAX_LPC_ORDER);
let mut coeff = vec![0f32; MAX_LPC_ORDER * MAX_LPC_ORDER];
let mut error = [0f64; MAX_LPC_ORDER];
let mut lpc = [0f64; MAX_LPC_ORDER];
let mut err = autoc[0];
let mut out_max_order = max_order;
let mut i = 0;
while i < max_order {
let mut r = -autoc[i + 1];
for j in 0..i {
r -= lpc[j] * autoc[i - j];
}
r /= err;
lpc[i] = r;
let mut j = 0;
while j < i >> 1 {
let tmp = lpc[j];
lpc[j] += r * lpc[i - 1 - j];
lpc[i - 1 - j] += r * tmp;
j += 1;
}
if i & 1 != 0 {
lpc[j] += lpc[j] * r;
}
err *= 1.0 - r * r;
for j in 0..=i {
coeff[i * MAX_LPC_ORDER + j] = (-lpc[j]) as f32;
}
error[i] = err;
if err == 0.0 {
out_max_order = i + 1;
break;
}
i += 1;
}
LpCoefficients {
coeff,
error,
max_order: out_max_order,
}
}
pub fn expected_bits_with_error_scale(lpc_error: f64, error_scale: f64) -> f64 {
if lpc_error > 0.0 {
let bps = 0.5 * (error_scale * lpc_error).ln() / std::f64::consts::LN_2;
if bps >= 0.0 { bps } else { 0.0 }
} else if lpc_error < 0.0 {
1e32
} else {
0.0
}
}
pub fn expected_bits(lpc_error: f64, total_samples: u32) -> f64 {
let error_scale = 0.5 / total_samples as f64;
expected_bits_with_error_scale(lpc_error, error_scale)
}
pub fn compute_best_order(
error: &[f64],
max_order: usize,
total_samples: u32,
overhead_bits_per_order: u32,
) -> usize {
let error_scale = 0.5 / total_samples as f64;
let mut best_index = 0usize;
let mut best_bits = u32::MAX as f64;
for (indx, &err) in error.iter().enumerate().take(max_order) {
let order = (indx + 1) as u32;
let bits = expected_bits_with_error_scale(err, error_scale)
* (total_samples - order) as f64
+ (order * overhead_bits_per_order) as f64;
if bits < best_bits {
best_index = indx;
best_bits = bits;
}
}
best_index + 1
}