use super::bits::BitReader;
use super::error::{Error, Result};
use super::ics::IcsInfo;
const MAX_PREDICTORS: usize = 672;
const PRED_SFB_MAX: [u8; 13] = [33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34, 34];
const A: f32 = 0.953125; const ALPHA: f32 = 0.90625;
#[derive(Clone, Copy, Debug)]
struct Bin {
r0: f32,
r1: f32,
cor0: f32,
cor1: f32,
var0: f32,
var1: f32,
}
impl Bin {
fn reset() -> Self {
Self {
r0: 0.0,
r1: 0.0,
cor0: 0.0,
cor1: 0.0,
var0: 1.0,
var1: 1.0,
}
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct PredChan {
bins: Vec<Bin>,
}
impl PredChan {
fn ensure(&mut self) {
if self.bins.is_empty() {
self.bins.resize(MAX_PREDICTORS, Bin::reset());
}
}
pub(crate) fn apply(&mut self, spec: &mut [f32], ics: &IcsInfo, fs_index: u8) -> Result<()> {
let Some(limit) = pred_sfb_max(fs_index) else {
return Err(Error::UnsupportedSampleRateIndex(fs_index));
};
self.ensure();
if ics.window_sequence.is_eight_short() {
for bin in &mut self.bins {
*bin = Bin::reset();
}
return Ok(());
}
let offsets = ics.swb_offsets(fs_index)?;
let nsfb = limit.min(offsets.len().saturating_sub(1));
for sfb in 0..nsfb {
let lo = offsets[sfb] as usize;
let hi = offsets[sfb + 1] as usize;
let enable = ics.predictor_present && ((ics.pred_used >> sfb) & 1) == 1;
for k in lo..hi {
if k >= spec.len() || k >= self.bins.len() {
break;
}
predict(&mut self.bins[k], &mut spec[k], enable);
}
}
if ics.pred_reset_group > 0 {
let mut i = usize::from(ics.pred_reset_group) - 1;
while i < self.bins.len() {
self.bins[i] = Bin::reset();
i += 30;
}
}
Ok(())
}
}
pub(crate) fn read_main(br: &mut BitReader<'_>, max_sfb: u8, fs_index: u8) -> Result<(u8, u64)> {
let mut group = 0u8;
if br.read_bit()? {
group = br.read(5)? as u8;
if group == 0 || group > 30 {
return Err(Error::Format("predictor reset group"));
}
}
let Some(limit) = pred_sfb_max(fs_index) else {
return Err(Error::UnsupportedSampleRateIndex(fs_index));
};
let n = limit.min(usize::from(max_sfb));
let mut used = 0u64;
for sfb in 0..n {
if br.read_bit()? {
used |= 1u64 << sfb;
}
}
Ok((group, used))
}
pub(crate) fn pred_sfb_max(fs_index: u8) -> Option<usize> {
PRED_SFB_MAX
.get(usize::from(fs_index))
.map(|n| usize::from(*n))
}
fn flt16_round(pf: f32) -> f32 {
let bits = pf.to_bits().wrapping_add(0x0000_8000) & 0xFFFF_0000;
f32::from_bits(bits)
}
fn flt16_even(pf: f32) -> f32 {
let bits = pf.to_bits();
let tie = bits & (0x0001_0000 >> 16);
f32::from_bits(bits.wrapping_add(0x0000_7FFF).wrapping_add(tie) & 0xFFFF_0000)
}
fn flt16_trunc(pf: f32) -> f32 {
f32::from_bits(pf.to_bits() & 0xFFFF_0000)
}
fn predict(ps: &mut Bin, coef: &mut f32, output_enable: bool) {
let r0 = ps.r0;
let r1 = ps.r1;
let cor0 = ps.cor0;
let cor1 = ps.cor1;
let var0 = ps.var0;
let var1 = ps.var1;
let k1 = if var0 > 1.0 {
cor0 * flt16_even(A / var0)
} else {
0.0
};
let k2 = if var1 > 1.0 {
cor1 * flt16_even(A / var1)
} else {
0.0
};
let pv = flt16_round(k1 * r0 + k2 * r1);
if output_enable {
*coef += pv;
}
let e0 = *coef;
let e1 = e0 - k1 * r0;
ps.cor1 = flt16_trunc(ALPHA * cor1 + r1 * e1);
ps.var1 = flt16_trunc(ALPHA * var1 + 0.5 * (r1 * r1 + e1 * e1));
ps.cor0 = flt16_trunc(ALPHA * cor0 + r0 * e0);
ps.var0 = flt16_trunc(ALPHA * var0 + 0.5 * (r0 * r0 + e0 * e0));
ps.r1 = flt16_trunc(A * (r0 - k1 * e0));
ps.r0 = flt16_trunc(A * e0);
}