use crate::vorbis_simd::{self, Imdct};
use super::window::Windows;
pub struct LappingState {
pub prev_block_flag: bool,
}
pub struct Dsp {
pub channels: Vec<DspChannel>,
pub imdct_short: Imdct,
pub imdct_long: Imdct,
pub windows: Windows,
pub lapping_state: Option<LappingState>,
}
impl Dsp {
pub fn reset(&mut self) {
for channel in &mut self.channels {
channel.reset();
}
self.lapping_state = None;
}
}
pub struct DspChannel {
pub floor: Vec<f32>,
pub residue: Vec<f32>,
pub do_not_decode: bool,
imdct: Vec<f32>,
overlap: Vec<f32>,
bs0: usize,
bs1: usize,
}
impl DspChannel {
pub fn new(bs0_exp: u8, bs1_exp: u8) -> Self {
let bs0 = 1 << bs0_exp;
let bs1 = 1 << bs1_exp;
DspChannel {
floor: vec![0.0; bs1 >> 1],
residue: vec![0.0; bs1 >> 1],
imdct: vec![0.0; bs1],
overlap: vec![0.0; bs1 >> 1],
do_not_decode: false,
bs0,
bs1,
}
}
pub fn synth(
&mut self,
block_flag: bool,
lap_state: &Option<LappingState>,
windows: &Windows,
imdct: &mut Imdct,
buf: &mut [f32],
) {
let bs = if block_flag { self.bs1 } else { self.bs0 };
imdct.imdct(&self.floor[..bs / 2], &mut self.imdct[..bs]);
if let Some(lap_state) = &lap_state {
let (win, win_rev) = if block_flag && lap_state.prev_block_flag {
(&windows.long, &windows.long_rev)
} else {
(&windows.short, &windows.short_rev)
};
if lap_state.prev_block_flag == block_flag {
vorbis_simd::overlap_add(
buf,
&self.overlap[..bs / 2],
&self.imdct[..bs / 2],
win,
win_rev,
);
} else if lap_state.prev_block_flag && !block_flag {
let start = (self.bs1 - self.bs0) / 4;
let end = start + self.bs0 / 2;
buf[..start].copy_from_slice(&self.overlap[..start]);
vorbis_simd::overlap_add(
&mut buf[start..],
&self.overlap[start..end],
&self.imdct[..self.bs0 / 2],
win,
win_rev,
);
} else {
let start = (self.bs1 - self.bs0) / 4;
let end = start + self.bs0 / 2;
vorbis_simd::overlap_add(
&mut buf[..self.bs0 / 2],
&self.overlap[..self.bs0 / 2],
&self.imdct[start..end],
win,
win_rev,
);
buf[self.bs0 / 2..].copy_from_slice(&self.imdct[end..self.bs1 / 2]);
}
vorbis_simd::clamp_unit(buf);
}
self.overlap[..bs / 2].copy_from_slice(&self.imdct[bs / 2..bs]);
}
pub fn reset(&mut self) {
self.overlap.fill(0.0);
}
}