use crate::engine::bits::BitReader;
use crate::engine::sbr_envelope::{SbrEnvelopeData, SbrNoiseData};
use crate::engine::sbr_freq_bands::HiLoTables;
use crate::engine::sbr_grid::{SbrDtdf, SbrGrid, SbrInvf};
use crate::engine::{Error, Result};
pub const EXTENSION_ID_PS: u8 = 2;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SbrChannel {
pub grid: SbrGrid,
pub dtdf: SbrDtdf,
pub invf: SbrInvf,
pub envelope: SbrEnvelopeData,
pub noise: SbrNoiseData,
pub add_harmonic: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SbrElement {
pub coupling: bool,
pub channels: Vec<SbrChannel>,
pub extension: Option<SbrExtension>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SbrExtension {
pub id: u8,
pub data: Vec<u8>,
}
fn parse_sinusoidal(reader: &mut BitReader<'_>, n_high: usize) -> Result<Vec<bool>> {
let mut v = Vec::with_capacity(n_high);
for _ in 0..n_high {
v.push(read_flag(reader)?);
}
Ok(v)
}
fn parse_grid_dtdf_invf(
reader: &mut BitReader<'_>,
n_q: usize,
) -> Result<(SbrGrid, SbrDtdf, SbrInvf)> {
let grid = SbrGrid::parse(reader)?;
let dtdf = SbrDtdf::parse(reader, grid.num_env, grid.num_noise)?;
let invf = SbrInvf::parse(reader, n_q)?;
Ok((grid, dtdf, invf))
}
impl SbrElement {
pub fn parse_single(
reader: &mut BitReader<'_>,
bands: &HiLoTables,
amp_res: bool,
) -> Result<Self> {
let n_q = bands.n_q();
if read_flag(reader)? {
read(reader, 4)?;
}
let (grid, dtdf, invf) = parse_grid_dtdf_invf(reader, n_q)?;
let eff_amp = amp_res && !grid.amp_res_override;
let envelope = SbrEnvelopeData::parse(reader, &grid, &dtdf, bands, false, false, eff_amp)?;
let noise = SbrNoiseData::parse(reader, &grid, &dtdf, n_q, false, false, eff_amp)?;
let add_harmonic = if read_flag(reader)? {
parse_sinusoidal(reader, bands.n_high())?
} else {
Vec::new()
};
let extension = parse_extended_data(reader)?;
Ok(SbrElement {
coupling: false,
channels: vec![SbrChannel {
grid,
dtdf,
invf,
envelope,
noise,
add_harmonic,
}],
extension,
})
}
pub fn parse_pair(
reader: &mut BitReader<'_>,
bands: &HiLoTables,
amp_res: bool,
) -> Result<Self> {
let n_q = bands.n_q();
if read_flag(reader)? {
read(reader, 4)?;
read(reader, 4)?;
}
let coupling = read_flag(reader)?;
let channels = if coupling {
let grid = SbrGrid::parse(reader)?;
let dtdf0 = SbrDtdf::parse(reader, grid.num_env, grid.num_noise)?;
let dtdf1 = SbrDtdf::parse(reader, grid.num_env, grid.num_noise)?;
let invf0 = SbrInvf::parse(reader, n_q)?;
let eff_amp = amp_res && !grid.amp_res_override;
let env0 = SbrEnvelopeData::parse(reader, &grid, &dtdf0, bands, true, false, eff_amp)?;
let noise0 = SbrNoiseData::parse(reader, &grid, &dtdf0, n_q, true, false, eff_amp)?;
let env1 = SbrEnvelopeData::parse(reader, &grid, &dtdf1, bands, true, true, eff_amp)?;
let noise1 = SbrNoiseData::parse(reader, &grid, &dtdf1, n_q, true, true, eff_amp)?;
let (h0, h1) = parse_pair_harmonics(reader, bands)?;
vec![
SbrChannel {
grid: grid.clone(),
dtdf: dtdf0,
invf: invf0,
envelope: env0,
noise: noise0,
add_harmonic: h0,
},
SbrChannel {
grid,
dtdf: dtdf1,
invf: SbrInvf {
invf_mode: Vec::new(),
},
envelope: env1,
noise: noise1,
add_harmonic: h1,
},
]
} else {
let grid0 = SbrGrid::parse(reader)?;
let grid1 = SbrGrid::parse(reader)?;
let dtdf0 = SbrDtdf::parse(reader, grid0.num_env, grid0.num_noise)?;
let dtdf1 = SbrDtdf::parse(reader, grid1.num_env, grid1.num_noise)?;
let invf0 = SbrInvf::parse(reader, n_q)?;
let invf1 = SbrInvf::parse(reader, n_q)?;
let eff0 = amp_res && !grid0.amp_res_override;
let eff1 = amp_res && !grid1.amp_res_override;
let env0 = SbrEnvelopeData::parse(reader, &grid0, &dtdf0, bands, false, false, eff0)?;
let env1 = SbrEnvelopeData::parse(reader, &grid1, &dtdf1, bands, false, true, eff1)?;
let noise0 = SbrNoiseData::parse(reader, &grid0, &dtdf0, n_q, false, false, eff0)?;
let noise1 = SbrNoiseData::parse(reader, &grid1, &dtdf1, n_q, false, true, eff1)?;
let (h0, h1) = parse_pair_harmonics(reader, bands)?;
vec![
SbrChannel {
grid: grid0,
dtdf: dtdf0,
invf: invf0,
envelope: env0,
noise: noise0,
add_harmonic: h0,
},
SbrChannel {
grid: grid1,
dtdf: dtdf1,
invf: invf1,
envelope: env1,
noise: noise1,
add_harmonic: h1,
},
]
};
let extension = parse_extended_data(reader)?;
Ok(SbrElement {
coupling,
channels,
extension,
})
}
}
fn parse_pair_harmonics(
reader: &mut BitReader<'_>,
bands: &HiLoTables,
) -> Result<(Vec<bool>, Vec<bool>)> {
let h0 = if read_flag(reader)? {
parse_sinusoidal(reader, bands.n_high())?
} else {
Vec::new()
};
let h1 = if read_flag(reader)? {
parse_sinusoidal(reader, bands.n_high())?
} else {
Vec::new()
};
Ok((h0, h1))
}
fn parse_extended_data(reader: &mut BitReader<'_>) -> Result<Option<SbrExtension>> {
if !read_flag(reader)? {
return Ok(None);
}
let mut cnt = read(reader, 4)?;
if cnt == 15 {
cnt += read(reader, 8)?;
}
let mut num_bits_left = (8 * cnt) as i64;
let mut id = 0u8;
let mut data: Vec<u8> = Vec::new();
if num_bits_left > 7 {
id = read(reader, 2)? as u8;
num_bits_left -= 2;
let mut w = crate::engine::bits::BitWriter::new();
while num_bits_left >= 8 {
w.write_u32(read(reader, 8)?, 8);
num_bits_left -= 8;
}
if num_bits_left > 0 {
let n = num_bits_left as u32;
w.write_u32(read(reader, n)?, n);
num_bits_left = 0;
}
data = w.finish();
}
if num_bits_left > 0 {
read(reader, num_bits_left as u32)?;
}
Ok(Some(SbrExtension { id, data }))
}
#[inline]
fn read(reader: &mut BitReader<'_>, n: u32) -> Result<u32> {
reader.read_u32(n).map_err(|_| Error::SbrGridInvalid)
}
#[inline]
fn read_flag(reader: &mut BitReader<'_>) -> Result<bool> {
reader.read_bit().map_err(|_| Error::SbrGridInvalid)
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
use crate::engine::bits::{BitReader, BitWriter};
use crate::engine::sbr_freq_bands::{HiLoTables, k0, k2, master_table};
use crate::engine::sbr_grid::FrameClass;
use crate::engine::sbr_huffman::{SbrHuffContext, env_tables, noise_tables};
fn bands_44100() -> HiLoTables {
let k0v = k0(88_200, 5).unwrap();
let k2v = k2(88_200, 5, k0v).unwrap();
let fm = master_table(k0v, k2v, 0, false).unwrap();
HiLoTables::derive(&fm, 1, 2).unwrap()
}
fn push_code(w: &mut BitWriter, table: &[(u8, u32)], idx: usize) {
let (len, code) = table[idx];
w.write_u32(code, len as u32);
}
fn write_minimal_sce(bands: &HiLoTables) -> Vec<u8> {
let n_high = bands.n_high();
let n_q = bands.n_q();
let mut w = BitWriter::new();
w.write_bit(false); w.write_u32(FrameClass::FixFix.to_bits(), 2);
w.write_u32(0, 2); w.write_bit(true); w.write_bit(false); w.write_bit(false); for _ in 0..n_q {
w.write_u32(1, 2);
}
let ((_t, _tl), (f_huff, f_lav)) = env_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(33, 7); for i in 1..n_high {
push_code(&mut w, f_huff, (i + f_lav as usize) % f_huff.len());
}
let ((_nt, _ntl), (nf, nfl)) = noise_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(10, 5);
for i in 1..n_q {
push_code(&mut w, nf, (i + nfl as usize) % nf.len());
}
w.write_bit(false); w.write_bit(false); w.finish()
}
#[test]
fn single_channel_element_round_trips_structure() {
let bands = bands_44100();
let bytes = write_minimal_sce(&bands);
let mut r = BitReader::new(&bytes);
let el = SbrElement::parse_single(&mut r, &bands, true).unwrap();
assert!(!el.coupling);
assert_eq!(el.channels.len(), 1);
let ch = &el.channels[0];
assert_eq!(ch.grid.frame_class, FrameClass::FixFix);
assert_eq!(ch.grid.num_env, 1);
assert!(ch.grid.amp_res_override);
assert_eq!(ch.envelope.data[0].len(), bands.n_high());
assert_eq!(ch.envelope.data[0][0], 33);
assert_eq!(ch.noise.data[0].len(), bands.n_q());
assert_eq!(ch.noise.data[0][0], 10);
assert!(ch.add_harmonic.is_empty());
assert!(el.extension.is_none());
assert_eq!(ch.invf.invf_mode.len(), bands.n_q());
}
#[test]
fn single_channel_with_sinusoidal_and_extension() {
let bands = bands_44100();
let n_high = bands.n_high();
let n_q = bands.n_q();
let mut w = BitWriter::new();
w.write_bit(false); w.write_u32(FrameClass::FixFix.to_bits(), 2);
w.write_u32(0, 2);
w.write_bit(true);
w.write_bit(false); w.write_bit(false); for _ in 0..n_q {
w.write_u32(0, 2);
}
let ((_t, _tl), (f_huff, f_lav)) = env_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(20, 7);
for i in 1..n_high {
push_code(&mut w, f_huff, (i + f_lav as usize) % f_huff.len());
}
let ((_nt, _ntl), (nf, nfl)) = noise_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(5, 5);
for i in 1..n_q {
push_code(&mut w, nf, (i + nfl as usize) % nf.len());
}
w.write_bit(true);
for n in 0..n_high {
w.write_bit(n % 2 == 0);
}
w.write_bit(true); w.write_u32(1, 4); w.write_u32(EXTENSION_ID_PS as u32, 2);
w.write_u32(0, 6); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let el = SbrElement::parse_single(&mut r, &bands, false).unwrap();
let ch = &el.channels[0];
assert_eq!(ch.add_harmonic.len(), n_high);
assert!(ch.add_harmonic[0]);
assert!(!ch.add_harmonic[1]);
let ext = el.extension.unwrap();
assert_eq!(ext.id, EXTENSION_ID_PS);
}
#[test]
fn channel_pair_independent_grids() {
let bands = bands_44100();
let n_high = bands.n_high();
let n_q = bands.n_q();
let mut w = BitWriter::new();
w.write_bit(false); w.write_bit(false); w.write_u32(FrameClass::FixFix.to_bits(), 2);
w.write_u32(0, 2);
w.write_bit(true);
w.write_u32(FrameClass::FixFix.to_bits(), 2);
w.write_u32(0, 2);
w.write_bit(true);
w.write_bit(false);
w.write_bit(false);
w.write_bit(false);
w.write_bit(false);
for _ in 0..n_q {
w.write_u32(2, 2);
}
for _ in 0..n_q {
w.write_u32(3, 2);
}
let ((_t, _tl), (f_huff, f_lav)) = env_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
let ((_nt, _ntl), (nf, nfl)) = noise_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
for &start in &[30u32, 40] {
w.write_u32(start, 7);
for i in 1..n_high {
push_code(&mut w, f_huff, (i + f_lav as usize) % f_huff.len());
}
}
for &start in &[8u32, 9] {
w.write_u32(start, 5);
for i in 1..n_q {
push_code(&mut w, nf, (i + nfl as usize) % nf.len());
}
}
w.write_bit(false); w.write_bit(false); w.write_bit(false); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let el = SbrElement::parse_pair(&mut r, &bands, false).unwrap();
assert!(!el.coupling);
assert_eq!(el.channels.len(), 2);
assert_eq!(el.channels[0].envelope.data[0][0], 30);
assert_eq!(el.channels[1].envelope.data[0][0], 40);
assert_eq!(el.channels[0].noise.data[0][0], 8);
assert_eq!(el.channels[1].noise.data[0][0], 9);
assert_eq!(el.channels[0].invf.invf_mode, vec![2u8; n_q]);
assert_eq!(el.channels[1].invf.invf_mode, vec![3u8; n_q]);
}
#[test]
fn truncated_element_errors() {
let bands = bands_44100();
let bytes = [0u8; 0];
let mut r = BitReader::new(&bytes);
assert!(matches!(
SbrElement::parse_single(&mut r, &bands, true),
Err(Error::SbrGridInvalid)
));
}
}