use oxideav_core::bits::BitReader;
use oxideav_core::{Error, Result};
use crate::huffman::{
asf_hcb, ext_decode, huff_decode, split_qspec, CB_DIM, HCB_SCALEFAC_CW, HCB_SCALEFAC_LEN,
HCB_SNF_CW, HCB_SNF_LEN, UNSIGNED_CB,
};
use crate::tables::num_sfb_48;
#[derive(Debug, Default, Clone)]
pub struct AsfSections {
pub sect_cb: Vec<u8>,
pub sect_start: Vec<u16>,
pub sect_end: Vec<u16>,
pub sfb_cb: Vec<u8>,
pub num_sec: u32,
pub num_sec_lsf: u32,
}
pub fn parse_asf_section_data(
br: &mut BitReader<'_>,
transf_length_idx: u32,
transform_length: u32,
max_sfb: u32,
) -> Result<AsfSections> {
let (n_sect_bits, sect_esc_val) = if transf_length_idx <= 2 {
(3u32, 7u32)
} else {
(5u32, 31u32)
};
let num_sfb = num_sfb_48(transform_length)
.ok_or_else(|| Error::invalid("ac4: asf_section_data: unsupported transform_length"))?;
let mut out = AsfSections {
sfb_cb: vec![0u8; max_sfb as usize],
..Default::default()
};
let mut k: u32 = 0;
while k < max_sfb {
let sect_cb = br.read_u32(4)? as u8;
let mut sect_len: u32 = 0;
loop {
let incr = br.read_u32(n_sect_bits)?;
sect_len += incr;
if incr != sect_esc_val {
break;
}
}
sect_len += 1;
let sect_start = k;
let mut sect_end = k + sect_len;
if sect_start < num_sfb && sect_end > num_sfb {
out.sect_cb.push(sect_cb);
out.sect_start.push(sect_start as u16);
out.sect_end.push(num_sfb as u16);
out.num_sec_lsf = out.sect_cb.len() as u32;
out.sect_cb.push(sect_cb);
out.sect_start.push(num_sfb as u16);
out.sect_end.push(sect_end as u16);
for sfb in sect_start..sect_end {
if (sfb as usize) < out.sfb_cb.len() {
out.sfb_cb[sfb as usize] = sect_cb;
}
}
k += sect_len;
continue;
}
if sect_end > max_sfb {
sect_end = max_sfb;
}
out.sect_cb.push(sect_cb);
out.sect_start.push(sect_start as u16);
out.sect_end.push(sect_end as u16);
for sfb in sect_start..sect_end {
if (sfb as usize) < out.sfb_cb.len() {
out.sfb_cb[sfb as usize] = sect_cb;
}
}
k += sect_len;
}
out.num_sec = out.sect_cb.len() as u32;
if out.num_sec_lsf == 0 {
out.num_sec_lsf = out.num_sec;
}
Ok(out)
}
pub fn parse_asf_spectral_data(
br: &mut BitReader<'_>,
sections: &AsfSections,
sfb_offset: &[u16],
max_sfb: u32,
) -> Result<(Vec<i32>, Vec<u32>)> {
let end_bin = sfb_offset[max_sfb as usize] as usize;
let mut quant_spec = vec![0i32; end_bin];
let mut max_quant_idx = vec![0u32; max_sfb as usize];
for i in 0..sections.num_sec_lsf as usize {
let cb = sections.sect_cb[i] as u32;
if cb == 0 || cb > 11 {
continue;
}
let hcb =
asf_hcb(cb).ok_or_else(|| Error::invalid("ac4: asf_spectral_data: bad codebook"))?;
let dim = CB_DIM[cb as usize];
let unsig = UNSIGNED_CB[cb as usize];
let sect_start_line = sfb_offset[sections.sect_start[i] as usize] as usize;
let sect_end_line = sfb_offset[sections.sect_end[i] as usize] as usize;
let mut k = sect_start_line;
let mut tmp = [0i32; 4];
while k < sect_end_line {
let cb_idx = huff_decode(br, hcb.len, hcb.cw)?;
split_qspec(hcb, cb_idx, &mut tmp);
let step = dim as usize;
for t in 0..step {
let mut q = tmp[t];
if unsig && q != 0 {
let s = br.read_u32(1)?;
if s == 1 {
q = -q;
}
}
if cb == 11 && q.unsigned_abs() == 16 {
let ext = ext_decode(br)?;
q = if q.is_negative() {
-(ext as i32)
} else {
ext as i32
};
}
if k + t < quant_spec.len() {
quant_spec[k + t] = q;
}
}
k += step;
}
}
for sfb in 0..max_sfb as usize {
let a = sfb_offset[sfb] as usize;
let b = sfb_offset[sfb + 1] as usize;
let mut m: u32 = 0;
for &q in &quant_spec[a..b.min(quant_spec.len())] {
m = m.max(q.unsigned_abs());
}
max_quant_idx[sfb] = m;
}
Ok((quant_spec, max_quant_idx))
}
pub fn parse_asf_scalefac_data(
br: &mut BitReader<'_>,
sections: &AsfSections,
max_quant_idx: &[u32],
max_sfb: u32,
transform_length: u32,
) -> Result<Vec<f32>> {
let num_sfb_lsf =
num_sfb_48(transform_length).ok_or_else(|| Error::invalid("ac4: scalefac: bad tl"))?;
let reference_scale_factor = br.read_u32(8)?;
let mut sf_gain = vec![0.0_f32; max_sfb as usize];
let mut scale_factor: i32 = reference_scale_factor as i32;
let mut first_scf_found = false;
let max_sfb_eff = max_sfb.min(num_sfb_lsf);
for sfb in 0..max_sfb_eff as usize {
let cb = sections.sfb_cb[sfb];
if cb == 0 || max_quant_idx[sfb] == 0 {
continue;
}
if first_scf_found {
let cw_idx = huff_decode(br, HCB_SCALEFAC_LEN, HCB_SCALEFAC_CW)?;
scale_factor += cw_idx as i32 - 60;
} else {
first_scf_found = true;
}
let sf = scale_factor;
let exp = (sf as f32 - 100.0) * 0.25;
sf_gain[sfb] = 2.0_f32.powf(exp);
}
Ok(sf_gain)
}
pub fn parse_asf_snf_data(
br: &mut BitReader<'_>,
sections: &AsfSections,
max_quant_idx: &[u32],
max_sfb: u32,
transform_length: u32,
) -> Result<Option<Vec<i32>>> {
let b_snf_data_exists = br.read_bit()?;
if !b_snf_data_exists {
return Ok(None);
}
let num_sfb_lsf =
num_sfb_48(transform_length).ok_or_else(|| Error::invalid("ac4: snf: bad tl"))?;
let mut dpcm_snf = vec![0i32; max_sfb as usize];
let max_sfb_eff = max_sfb.min(num_sfb_lsf);
for sfb in 0..max_sfb_eff as usize {
let cb = sections.sfb_cb[sfb];
if cb == 0 || max_quant_idx[sfb] == 0 {
let idx = huff_decode(br, HCB_SNF_LEN, HCB_SNF_CW)?;
dpcm_snf[sfb] = idx as i32;
}
}
Ok(Some(dpcm_snf))
}
pub fn dequantise_and_scale(
quant_spec: &[i32],
sf_gain: &[f32],
sfb_offset: &[u16],
max_sfb: u32,
) -> Vec<f32> {
let end_bin = sfb_offset[max_sfb as usize] as usize;
let mut scaled = vec![0.0_f32; end_bin];
for sfb in 0..max_sfb as usize {
let gain = sf_gain[sfb];
if gain == 0.0 {
continue;
}
let a = sfb_offset[sfb] as usize;
let b = sfb_offset[sfb + 1] as usize;
for k in a..b.min(end_bin) {
let q = quant_spec[k];
let rec = (q.unsigned_abs() as f32).powf(4.0 / 3.0);
let rec_signed = if q < 0 { -rec } else { rec };
scaled[k] = gain * rec_signed;
}
}
scaled
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::bits::BitWriter;
fn encode_scalefac_idx(bw: &mut BitWriter, idx: usize) {
bw.write_u32(
crate::huffman::HCB_SCALEFAC_CW[idx],
crate::huffman::HCB_SCALEFAC_LEN[idx] as u32,
);
}
#[test]
fn section_parser_single_cb_zero_covers_all_bands() {
let mut bw = BitWriter::new();
bw.write_u32(0, 4); bw.write_u32(4, 3); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let s = parse_asf_section_data(&mut br, 0, 256, 5).unwrap();
assert_eq!(s.num_sec, 1);
assert_eq!(s.sect_cb, vec![0u8]);
assert_eq!(s.sect_start, vec![0u16]);
assert_eq!(s.sect_end, vec![5u16]);
assert_eq!(s.sfb_cb, vec![0u8; 5]);
}
#[test]
fn section_parser_two_sections_escape() {
let mut bw = BitWriter::new();
bw.write_u32(3, 4);
bw.write_u32(2, 3);
bw.write_u32(5, 4);
bw.write_u32(6, 3);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let s = parse_asf_section_data(&mut br, 0, 256, 10).unwrap();
assert_eq!(s.num_sec, 2);
assert_eq!(s.sect_cb, vec![3u8, 5u8]);
assert_eq!(s.sect_start, vec![0u16, 3u16]);
assert_eq!(s.sect_end, vec![3u16, 10u16]);
}
#[test]
fn spectral_parser_all_zero_section() {
let sections = AsfSections {
sect_cb: vec![0u8],
sect_start: vec![0u16],
sect_end: vec![2u16],
sfb_cb: vec![0u8; 2],
num_sec: 1,
num_sec_lsf: 1,
};
let mut bw = BitWriter::new();
bw.write_u32(0, 8); let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let sfb_offset = crate::sfb_offset::sfb_offset_48(256).unwrap();
let (qspec, mqi) = parse_asf_spectral_data(&mut br, §ions, sfb_offset, 2).unwrap();
let end_bin = sfb_offset[2] as usize;
assert_eq!(qspec.len(), end_bin);
assert!(qspec.iter().all(|&v| v == 0));
assert_eq!(mqi, vec![0u32, 0u32]);
}
#[test]
fn scalefac_parser_yields_gain_when_mqi_nonzero() {
let sections = AsfSections {
sfb_cb: vec![5u8, 5u8, 5u8],
..AsfSections::default()
};
let mqi = vec![0u32, 3u32, 0u32];
let mut bw = BitWriter::new();
bw.write_u32(120, 8); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let gains = parse_asf_scalefac_data(&mut br, §ions, &mqi, 3, 256).unwrap();
assert_eq!(gains[0], 0.0);
assert!((gains[1] - 32.0).abs() < 1e-3);
assert_eq!(gains[2], 0.0);
}
#[test]
fn scalefac_parser_reads_dpcm_for_subsequent_bands() {
let sections = AsfSections {
sfb_cb: vec![5u8, 5u8, 5u8],
..AsfSections::default()
};
let mqi = vec![3u32, 3u32, 3u32];
let mut bw = BitWriter::new();
bw.write_u32(120, 8);
encode_scalefac_idx(&mut bw, 60);
encode_scalefac_idx(&mut bw, 63);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let gains = parse_asf_scalefac_data(&mut br, §ions, &mqi, 3, 256).unwrap();
assert!((gains[0] - 32.0).abs() < 1e-2);
assert!((gains[1] - 32.0).abs() < 1e-2);
assert!((gains[2] - 2.0_f32.powf((123.0 - 100.0) / 4.0)).abs() < 1e-2);
}
#[test]
fn dequantise_scales_correctly() {
let qspec = vec![0i32, 0, 2, -2, 0, 0, 0, 0];
let sfb_offset = [0u16, 2, 4, 8];
let sf_gain = vec![0.0_f32, 1.0, 0.5];
let out = dequantise_and_scale(&qspec, &sf_gain, &sfb_offset, 3);
assert_eq!(out[0], 0.0);
assert_eq!(out[1], 0.0);
let exp_mag = 2.0_f32.powf(4.0 / 3.0);
assert!((out[2] - exp_mag).abs() < 1e-4);
assert!((out[3] + exp_mag).abs() < 1e-4);
assert!(out[4..].iter().all(|&v| v == 0.0));
}
}