use crate::fixed::{acc, hi, mul, mul32x16, sat, shift, trunc32};
pub use crate::LPC_ORDER as ORDER;
pub const MA_TAPS: usize = 3;
const LSF_MIN: i16 = 41;
const LSF_MAX: i16 = 25682;
const LSF_GAP: i16 = 321;
const REARRANGE_GAPS: [i16; 2] = [10, 5];
#[derive(Clone, Copy, Debug)]
pub struct LsfIndices {
pub mode: usize,
pub stage1: usize,
pub stage2_low: usize,
pub stage2_high: usize,
}
impl LsfIndices {
pub fn unpack(field0: i16, field1: i16) -> Self {
LsfIndices {
mode: ((field0 >> 7) & 1) as usize,
stage1: (field0 & 0x7f) as usize,
stage2_high: ((field1 >> 6) & 0x3f) as usize,
stage2_low: (field1 & 0x3f) as usize,
}
}
}
#[derive(Clone)]
pub struct LsfState {
pub history: [[i16; ORDER]; MA_TAPS],
pub prev_lsf: [i16; ORDER],
pub prev_mode: usize,
}
impl Default for LsfState {
fn default() -> Self {
let mean = &crate::tables::LSF_MEAN[..ORDER];
let mut init = [0i16; ORDER];
init.copy_from_slice(mean);
LsfState {
history: [init; MA_TAPS],
prev_lsf: init,
prev_mode: 0,
}
}
}
fn codebook_row(base: &'static [i16], index: usize) -> &'static [i16] {
&base[index * ORDER..][..ORDER]
}
pub fn decode(state: &mut LsfState, idx: LsfIndices) -> [i16; ORDER] {
let stage1 = codebook_row(&crate::tables::LSF_CB1, idx.stage1);
let low = codebook_row(&crate::tables::LSF_CB2, idx.stage2_high);
let high = codebook_row(&crate::tables::LSF_CB2, idx.stage2_low);
let mut residual = [0i16; ORDER];
for i in 0..ORDER / 2 {
residual[i] = hi(((stage1[i] as i64) + (low[i] as i64)) << 16);
residual[i + 5] = hi(((stage1[i + 5] as i64) + (high[i + 5] as i64)) << 16);
}
for gap in REARRANGE_GAPS {
rearrange(&mut residual, gap);
}
let lsf = ma_predict(&residual, &state.history, idx.mode);
push_history(&mut state.history, &residual);
let mut lsf = lsf;
stabilize(&mut lsf);
state.prev_mode = idx.mode;
lsf
}
pub fn residual(
lsf: &[i16; ORDER],
history: &[[i16; ORDER]; MA_TAPS],
mode: usize,
) -> [i16; ORDER] {
let pred = &crate::tables::LSF_MA_PRED
[mode * MA_TAPS * ORDER..mode * MA_TAPS * ORDER + MA_TAPS * ORDER];
let gain_inv = &crate::tables::LSF_MA_GAIN_INV[mode * ORDER..mode * ORDER + ORDER];
let mut out = [0i16; ORDER];
for i in 0..ORDER {
let mut a = (lsf[i] as i64) << 16;
for j in 0..MA_TAPS {
a = acc(a - mul(history[j][i], pred[j * ORDER + i]));
}
out[i] = hi(shift(mul32x16(acc(a), gain_inv[i]), 3));
}
out
}
pub fn decode_suppressed(state: &mut LsfState) -> [i16; ORDER] {
let lsf = state.prev_lsf;
let residual = residual(&lsf, &state.history, state.prev_mode);
push_history(&mut state.history, &residual);
lsf
}
pub fn rearrange(lsf: &mut [i16; ORDER], gap: i16) {
for k in 0..ORDER - 1 {
let cur = (lsf[k] as i64) << 16;
let excess = shift(cur - ((lsf[k + 1] as i64) << 16) + ((gap as i64) << 16), -1);
if excess > 0 {
lsf[k] = hi(cur - excess);
lsf[k + 1] = hi(excess + ((lsf[k + 1] as i64) << 16));
}
}
}
fn ma_predict(
residual: &[i16; ORDER],
history: &[[i16; ORDER]; MA_TAPS],
mode: usize,
) -> [i16; ORDER] {
let pred = &crate::tables::LSF_MA_PRED
[mode * MA_TAPS * ORDER..mode * MA_TAPS * ORDER + MA_TAPS * ORDER];
let gain = &crate::tables::LSF_MA_GAIN[mode * ORDER..mode * ORDER + ORDER];
let mut lsf = [0i16; ORDER];
for i in 0..ORDER {
let mut a = mul(residual[i], gain[i]);
for j in 0..MA_TAPS {
a = acc(a + mul(history[j][i], pred[j * ORDER + i]));
}
lsf[i] = hi(a);
}
lsf
}
fn push_history(history: &mut [[i16; ORDER]; MA_TAPS], residual: &[i16; ORDER]) {
for j in (1..MA_TAPS).rev() {
history[j] = history[j - 1];
}
history[0] = *residual;
}
pub fn stabilize(lsf: &mut [i16; ORDER]) {
for k in 0..ORDER - 1 {
if lsf[k + 1] < lsf[k] {
lsf.swap(k, k + 1);
}
}
if lsf[0] < LSF_MIN {
lsf[0] = LSF_MIN;
}
for k in 0..ORDER - 1 {
if (lsf[k + 1] as i64) - (lsf[k] as i64) < LSF_GAP as i64 {
lsf[k + 1] = hi(((lsf[k] as i64) << 16) + ((LSF_GAP as i64) << 16));
}
}
if lsf[ORDER - 1] > LSF_MAX {
lsf[ORDER - 1] = LSF_MAX;
}
}
pub fn lsf_to_lsp(lsf: &[i16; ORDER]) -> [i16; ORDER] {
let mut lsp = [0i16; ORDER];
for i in 0..ORDER {
let scaled = mul(lsf[i], 20861);
let index = hi(shift(scaled, -8).min(63 << 16)) as usize;
let frac = (hi(scaled) & 0xff) as i64;
let interp = acc(((crate::tables::COS[index] as i64) << 16)
+ (frac << 3) * (crate::tables::COS_SLOPE[index] as i64) * 2);
lsp[i] = hi(interp);
}
lsp
}
pub fn lsp_to_lsf(lsp: &[i16; ORDER]) -> [i16; ORDER] {
const TABLE_LAST: usize = 63;
let mut lsf = [0i16; ORDER];
let mut index = TABLE_LAST;
for i in (0..ORDER).rev() {
let mut diff;
loop {
diff = (lsp[i] as i64) - (crate::tables::COS[index] as i64);
if diff <= 0 || index == 0 {
break;
}
index -= 1;
}
let slope = crate::tables::ACOS[index] as i64;
let pos = acc(((index as i64) << 25) + ((diff * slope * 2) << 4));
let angle = acc((pos >> 16) * 25736 * 2 + 0x8000);
lsf[i] = hi(angle);
}
lsf
}
fn lsp_polynomial(lsp: &[i16], first: usize) -> [i64; 6] {
let mut f = [0i64; 6];
f[0] = 1 << 24;
f[1] = trunc32(-((lsp[first] as i64) << 10));
for i in 2..=5 {
let l = -lsp[first + 2 * (i - 1)];
f[i] = trunc32(acc(2 * f[i - 2] + (mul32x16(f[i - 1], l) << 1)));
for j in (2..i).rev() {
f[j] = trunc32(acc(f[j] + (mul32x16(f[j - 1], l) << 1) + f[j - 2]));
}
f[1] = trunc32(acc(f[1] + ((l as i64) << 10)));
}
f
}
pub fn lsp_to_lpc(lsp: &[i16; ORDER]) -> [i16; ORDER + 1] {
let mut f1 = lsp_polynomial(lsp, 0);
let mut f2 = lsp_polynomial(lsp, 1);
for i in (1..=5).rev() {
f1[i] = trunc32(acc(f1[i] + f1[i - 1]));
f2[i] = trunc32(acc(f2[i] - f2[i - 1]));
}
let mut a = [0i16; ORDER + 1];
a[0] = 4096;
for i in 1..=5 {
a[i] = hi(acc(shift(shift(acc(f1[i] + f2[i]), -1), 4) + (1 << 15)));
a[ORDER + 1 - i] = hi(acc(shift(shift(acc(f1[i] - f2[i]), -1), 4) + (1 << 15)));
}
a
}
pub fn interpolate_pair(
prev: &[i16; ORDER],
cur: &[i16; ORDER],
) -> (
[i16; ORDER],
[i16; ORDER],
[i16; ORDER + 1],
[i16; ORDER + 1],
) {
let mid = midpoint(prev, cur);
(mid, *cur, lsp_to_lpc(&mid), lsp_to_lpc(cur))
}
pub fn midpoint(first: &[i16; ORDER], second: &[i16; ORDER]) -> [i16; ORDER] {
let mut out = [0i16; ORDER];
for i in 0..ORDER {
out[i] = hi(acc(((first[i] as i64) + (second[i] as i64)) << 15));
}
out
}
pub fn reflection_coefficients(lpc: &[i16; ORDER + 1]) -> [i16; ORDER] {
let mut k = [0i16; ORDER];
k.copy_from_slice(&lpc[1..]);
for step in 0..ORDER - 1 {
let order = ORDER - step;
let top = order - 1;
let kv = k[top];
let residual = acc((16384i64 << 16) - shift(acc((kv as i64) * (kv as i64) * 2), 5));
let (quotient, exponent) = crate::fixed::normalised_reciprocal(residual);
let scale = (exponent << 27) >> 27; let inverse = hi(shift(quotient, -1));
let pairs = ((order - 2) >> 1) + 1;
for p in 0..pairs {
let (i, j) = (p, top - 1 - p);
let low = acc(((k[i] as i64) << 16) - shift(acc(mul(k[j], kv)), 3));
let updated_low = hi(shift(mul32x16(sat(low), inverse), scale));
let high = acc(((k[j] as i64) << 16) - shift(acc(mul(kv, k[i])), 3));
let updated_high = hi(shift(mul32x16(sat(high), inverse), scale));
k[i] = updated_low;
k[j] = updated_high;
}
}
k
}
pub fn interpolation_control(reflection: &[i16; ORDER], previous_flag: bool) -> (bool, bool) {
let term = |k: i16| acc((16384i64 << 16) - shift(acc((k as i64) * (k as i64) * 2), 5));
let mut product = sat(term(reflection[0]));
for &k in reflection[1..].iter() {
product = mul32x16(product, hi(term(k)));
}
let error = hi(shift(product, 9));
let peaky = acc(shift((reflection[0] as i64) << 16, 3) - (16384i64 << 16)) > 0
|| acc(shift((error as i64) << 16, 1) - (16384i64 << 16)) > 0;
if peaky {
(false, false)
} else {
(true, !previous_flag)
}
}
const CROSSING_GAIN: i16 = 26214;
const FIRST_HALF: usize = 40;
const QUIET: i64 = 10;
const NOISY: i64 = 20;
const SETTLED: i16 = 50;
struct Weights {
slow: [i16; 2],
fast: [i16; 2],
near: i64,
far: i64,
}
const STARTING: Weights = Weights {
slow: [5898, 26870],
fast: [13435, 19333],
near: 0x000d_4563,
far: 0x0018_9375,
};
const RUNNING: Weights = Weights {
slow: [27853, 4915],
fast: [30147, 2621],
near: 0x0000_29f1,
far: 0x0043_9581,
};
fn prediction_error(reflection: &[i16; ORDER]) -> i16 {
let term = |coefficient: i16| {
acc((16384i64 << 16) - shift(acc((coefficient as i64) * (coefficient as i64) * 2), 5))
};
let mut product = sat(term(reflection[0]));
for &coefficient in reflection[1..].iter() {
product = crate::fixed::mul32x16(product, hi(term(coefficient)));
}
hi(shift(product, 9))
}
fn adjust_noisy_reflection(reflection: &mut [i16; ORDER], target: &[i16]) {
let (first, second) = crossings(target);
if first <= QUIET || second <= QUIET {
return;
}
reflection[0] = if first > NOISY && second > NOISY {
hi(shift(
acc(shift((reflection[0] as i64) << 16, 3) + (16384i64 << 16)),
-3,
))
} else {
let excess = acc((first + second - NOISY) << 16);
let graded = shift(acc(crate::fixed::mul(hi(excess), CROSSING_GAIN)), 7);
hi(acc(graded + ((reflection[0] as i64) << 16)))
};
}
#[derive(Clone, Copy, Default)]
pub struct Quantiser {
age: i16,
near: [i16; ORDER],
far: [i16; ORDER],
}
impl Quantiser {
fn weights(&mut self) -> &'static Weights {
if self.age < SETTLED {
self.age += 1;
&STARTING
} else {
&RUNNING
}
}
fn update_history(&mut self, lsf: &[i16; ORDER], weights: &Weights) -> bool {
let previous = self.near;
for (index, current) in self.near.iter_mut().enumerate() {
*current = hi(acc(crate::fixed::mul(previous[index], weights.slow[0])
+ crate::fixed::mul(lsf[index], weights.slow[1])));
}
let moved = acc(distance(&self.near, &previous) - weights.near) >= 0
&& acc(distance(lsf, &self.far) - weights.far) >= 0;
if !moved {
for (far, ¤t) in self.far.iter_mut().zip(lsf.iter()) {
*far = hi(acc(crate::fixed::mul(*far, weights.fast[0])
+ crate::fixed::mul(current, weights.fast[1])));
}
}
moved
}
pub fn choose(&mut self, lpc: &[i16; ORDER + 1], target: &[i16], lsf: &[i16; ORDER]) -> i16 {
let mut reflection = reflection_coefficients(lpc);
let error = prediction_error(&reflection);
adjust_noisy_reflection(&mut reflection, target);
let weights = self.weights();
let moved = self.update_history(lsf, weights);
let mut mode = 1;
if moved && acc(shift((error as i64) << 16, 1) - (16384i64 << 16)) <= 0 {
mode = 2;
}
if acc(shift((reflection[0] as i64) << 16, 3) - (16384i64 << 16)) > 0 {
mode = 0;
}
mode
}
}
fn crossings(target: &[i16]) -> (i64, i64) {
let mut total = 0i64;
for &x in target.iter() {
total = acc(total + crate::fixed::mul(x, CROSSING_GAIN));
}
let level = hi(shift(total, -6));
let mut counts = [0i64; 2];
let mut previous = hi(acc(((target[0] as i64) - (level as i64)) << 16));
for (i, &x) in target.iter().enumerate().skip(1) {
let difference = hi(acc(((x as i64) - (level as i64)) << 16));
if acc(crate::fixed::mul(previous, difference)) < 0 {
counts[usize::from(i >= FIRST_HALF)] += 1;
}
previous = difference;
}
(counts[0], counts[1])
}
fn distance(x: &[i16], y: &[i16]) -> i64 {
let mut total = 0i64;
for i in 0..ORDER {
let difference = hi(acc(((x[i] as i64) - (y[i] as i64)) << 16));
total = acc(total + crate::fixed::mul(difference, difference));
}
total
}
impl Quantiser {
pub fn restore(&mut self, near: [i16; ORDER], far: [i16; ORDER], age: i16) {
self.near = near;
self.far = far;
self.age = age;
}
pub fn saved(&self) -> ([i16; ORDER], [i16; ORDER], i16) {
(self.near, self.far, self.age)
}
}