#![allow(dead_code, reason = "consumed incrementally as the SILK decoder stages land")]
use super::indices::MAX_NB_SUBFR;
use super::math::{lin2log, log2lin, smulwb};
const N_LEVELS_QGAIN: i32 = 64;
const MAX_DELTA_GAIN_QUANT: i32 = 36;
const MIN_DELTA_GAIN_QUANT: i32 = -4;
const OFFSET: i32 = (2 * 128) / 6 + 16 * 128;
const INV_SCALE_Q16: i32 = (65536 * (((88 - 2) * 128) / 6)) / (N_LEVELS_QGAIN - 1);
const SCALE_Q16: i32 = (65536 * (N_LEVELS_QGAIN - 1)) / (((88 - 2) * 128) / 6);
pub(crate) fn gains_quant(
ind: &mut [i8; MAX_NB_SUBFR],
gain_q16: &mut [i32; MAX_NB_SUBFR],
prev_ind: &mut i8,
conditional: bool,
nb_subfr: usize,
) {
for k in 0..nb_subfr {
ind[k] = smulwb(SCALE_Q16, lin2log(gain_q16[k]) - OFFSET) as i8;
if i32::from(ind[k]) < i32::from(*prev_ind) {
ind[k] = ind[k].wrapping_add(1);
}
ind[k] = i32::from(ind[k]).clamp(0, N_LEVELS_QGAIN - 1) as i8;
if k == 0 && !conditional {
ind[k] = i32::from(ind[k]).clamp(i32::from(*prev_ind) + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1) as i8;
*prev_ind = ind[k];
} else {
ind[k] = (i32::from(ind[k]) - i32::from(*prev_ind)) as i8;
let double_step = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + i32::from(*prev_ind);
if i32::from(ind[k]) > double_step {
ind[k] = (double_step + ((i32::from(ind[k]) - double_step + 1) >> 1)) as i8;
}
ind[k] = i32::from(ind[k]).clamp(MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT) as i8;
if i32::from(ind[k]) > double_step {
*prev_ind =
(i32::from(*prev_ind) + (i32::from(ind[k]) << 1) - double_step).min(N_LEVELS_QGAIN - 1) as i8;
} else {
*prev_ind = (i32::from(*prev_ind) + i32::from(ind[k])) as i8;
}
ind[k] = (i32::from(ind[k]) - MIN_DELTA_GAIN_QUANT) as i8;
}
gain_q16[k] = log2lin((smulwb(INV_SCALE_Q16, i32::from(*prev_ind)) + OFFSET).min(3967));
}
}
pub(crate) fn gains_dequant(
ind: &[i8; MAX_NB_SUBFR],
prev_ind: &mut i8,
conditional: bool,
nb_subfr: usize,
) -> [i32; MAX_NB_SUBFR] {
let mut gain_q16 = [0i32; MAX_NB_SUBFR];
for k in 0..nb_subfr {
if k == 0 && !conditional {
*prev_ind = i32::from(ind[k]).max(i32::from(*prev_ind) - 16) as i8;
} else {
let ind_tmp = i32::from(ind[k]) + MIN_DELTA_GAIN_QUANT;
let double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + i32::from(*prev_ind);
if ind_tmp > double_step_size_threshold {
*prev_ind = (i32::from(*prev_ind) + ((ind_tmp << 1) - double_step_size_threshold)) as i8;
} else {
*prev_ind = (i32::from(*prev_ind) + ind_tmp) as i8;
}
}
*prev_ind = i32::from(*prev_ind).clamp(0, N_LEVELS_QGAIN - 1) as i8;
gain_q16[k] = log2lin((smulwb(INV_SCALE_Q16, i32::from(*prev_ind)) + OFFSET).min(3967));
}
gain_q16
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dequant_matches_reference_pins() {
let mut prev = 10i8;
let gains = gains_dequant(&[32, 20, 20, 25], &mut prev, false, 4);
assert_eq!(gains, [12_713_984, 158_334_976, 1_686_110_208, 1_686_110_208]);
assert_eq!(prev, 63);
let gains = gains_dequant(&[4, 0, 5, 8], &mut prev, true, 4);
assert_eq!(gains, [1_686_110_208, 897_581_056, 1_048_576_000, 1_686_110_208]);
assert_eq!(prev, 63);
let mut prev = 0i8;
let gains = gains_dequant(&[40, 0, 0, 0], &mut prev, false, 4);
assert_eq!(gains, [44_826_624, 23_855_104, 12_713_984, 6_782_976]);
assert_eq!(prev, 28);
}
#[test]
fn quant_dequant_round_trip() {
for &conditional in &[false, true] {
for target in [
[12_000_000i32, 160_000_000, 1_600_000_000, 800_000_000],
[500_000, 50_000_000, 5_000_000, 900_000_000],
[1_000_000, 1_000_000, 1_000_000, 1_000_000],
] {
let mut prev_e = 20i8;
let mut ind = [0i8; MAX_NB_SUBFR];
let mut gain = target;
gains_quant(&mut ind, &mut gain, &mut prev_e, conditional, 4);
let mut prev_d = 20i8;
let dec = gains_dequant(&ind, &mut prev_d, conditional, 4);
assert_eq!(dec, gain, "gains differ (conditional={conditional})");
assert_eq!(prev_d, prev_e, "prev_ind differs (conditional={conditional})");
let start = usize::from(!conditional);
for &i in &ind[start..4] {
assert!(i >= 0, "negative coded index {i}");
}
}
}
}
}