use oxideav_core::bits::BitReader;
use oxideav_core::{Error, Result};
use crate::acpl_huffman;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcplDataType {
Alpha,
Beta,
Beta3,
Gamma,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcplQuantMode {
Fine,
Coarse,
}
impl AcplQuantMode {
pub fn from_bit(b: bool) -> Self {
if b {
AcplQuantMode::Coarse
} else {
AcplQuantMode::Fine
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcplHcbType {
F0,
Df,
Dt,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcplInterpolationType {
Smooth,
Steep,
}
#[derive(Debug, Clone, Copy)]
pub struct AcplHcb {
pub name: &'static str,
pub len: &'static [u8],
pub cw: &'static [u32],
pub cb_off: i32,
}
impl AcplHcb {
pub fn decode_delta(&self, br: &mut BitReader<'_>) -> Result<i32> {
debug_assert_eq!(self.len.len(), self.cw.len());
let mut code: u32 = 0;
let mut width: u8 = 0;
while width < 24 {
let b = br.read_u32(1)?;
code = (code << 1) | b;
width += 1;
for (i, &l) in self.len.iter().enumerate() {
if l == width && self.cw[i] == code {
return Ok(i as i32 - self.cb_off);
}
}
}
Err(Error::invalid("ac4: no matching A-CPL Huffman codeword"))
}
}
pub fn get_acpl_hcb(dt: AcplDataType, qm: AcplQuantMode, ht: AcplHcbType) -> AcplHcb {
use acpl_huffman::*;
use AcplDataType::*;
use AcplHcbType::*;
use AcplQuantMode::*;
match (dt, qm, ht) {
(Alpha, Coarse, F0) => AcplHcb {
name: "ACPL_HCB_ALPHA_COARSE_F0",
len: ACPL_HCB_ALPHA_COARSE_F0_LEN,
cw: ACPL_HCB_ALPHA_COARSE_F0_CW,
cb_off: 8,
},
(Alpha, Fine, F0) => AcplHcb {
name: "ACPL_HCB_ALPHA_FINE_F0",
len: ACPL_HCB_ALPHA_FINE_F0_LEN,
cw: ACPL_HCB_ALPHA_FINE_F0_CW,
cb_off: 16,
},
(Alpha, Coarse, Df) => AcplHcb {
name: "ACPL_HCB_ALPHA_COARSE_DF",
len: ACPL_HCB_ALPHA_COARSE_DF_LEN,
cw: ACPL_HCB_ALPHA_COARSE_DF_CW,
cb_off: 16,
},
(Alpha, Fine, Df) => AcplHcb {
name: "ACPL_HCB_ALPHA_FINE_DF",
len: ACPL_HCB_ALPHA_FINE_DF_LEN,
cw: ACPL_HCB_ALPHA_FINE_DF_CW,
cb_off: 32,
},
(Alpha, Coarse, Dt) => AcplHcb {
name: "ACPL_HCB_ALPHA_COARSE_DT",
len: ACPL_HCB_ALPHA_COARSE_DT_LEN,
cw: ACPL_HCB_ALPHA_COARSE_DT_CW,
cb_off: 16,
},
(Alpha, Fine, Dt) => AcplHcb {
name: "ACPL_HCB_ALPHA_FINE_DT",
len: ACPL_HCB_ALPHA_FINE_DT_LEN,
cw: ACPL_HCB_ALPHA_FINE_DT_CW,
cb_off: 32,
},
(Beta, Coarse, F0) => AcplHcb {
name: "ACPL_HCB_BETA_COARSE_F0",
len: ACPL_HCB_BETA_COARSE_F0_LEN,
cw: ACPL_HCB_BETA_COARSE_F0_CW,
cb_off: 0,
},
(Beta, Fine, F0) => AcplHcb {
name: "ACPL_HCB_BETA_FINE_F0",
len: ACPL_HCB_BETA_FINE_F0_LEN,
cw: ACPL_HCB_BETA_FINE_F0_CW,
cb_off: 0,
},
(Beta, Coarse, Df) => AcplHcb {
name: "ACPL_HCB_BETA_COARSE_DF",
len: ACPL_HCB_BETA_COARSE_DF_LEN,
cw: ACPL_HCB_BETA_COARSE_DF_CW,
cb_off: 4,
},
(Beta, Fine, Df) => AcplHcb {
name: "ACPL_HCB_BETA_FINE_DF",
len: ACPL_HCB_BETA_FINE_DF_LEN,
cw: ACPL_HCB_BETA_FINE_DF_CW,
cb_off: 8,
},
(Beta, Coarse, Dt) => AcplHcb {
name: "ACPL_HCB_BETA_COARSE_DT",
len: ACPL_HCB_BETA_COARSE_DT_LEN,
cw: ACPL_HCB_BETA_COARSE_DT_CW,
cb_off: 4,
},
(Beta, Fine, Dt) => AcplHcb {
name: "ACPL_HCB_BETA_FINE_DT",
len: ACPL_HCB_BETA_FINE_DT_LEN,
cw: ACPL_HCB_BETA_FINE_DT_CW,
cb_off: 8,
},
(Beta3, Coarse, F0) => AcplHcb {
name: "ACPL_HCB_BETA3_COARSE_F0",
len: ACPL_HCB_BETA3_COARSE_F0_LEN,
cw: ACPL_HCB_BETA3_COARSE_F0_CW,
cb_off: 4,
},
(Beta3, Fine, F0) => AcplHcb {
name: "ACPL_HCB_BETA3_FINE_F0",
len: ACPL_HCB_BETA3_FINE_F0_LEN,
cw: ACPL_HCB_BETA3_FINE_F0_CW,
cb_off: 8,
},
(Beta3, Coarse, Df) => AcplHcb {
name: "ACPL_HCB_BETA3_COARSE_DF",
len: ACPL_HCB_BETA3_COARSE_DF_LEN,
cw: ACPL_HCB_BETA3_COARSE_DF_CW,
cb_off: 8,
},
(Beta3, Fine, Df) => AcplHcb {
name: "ACPL_HCB_BETA3_FINE_DF",
len: ACPL_HCB_BETA3_FINE_DF_LEN,
cw: ACPL_HCB_BETA3_FINE_DF_CW,
cb_off: 16,
},
(Beta3, Coarse, Dt) => AcplHcb {
name: "ACPL_HCB_BETA3_COARSE_DT",
len: ACPL_HCB_BETA3_COARSE_DT_LEN,
cw: ACPL_HCB_BETA3_COARSE_DT_CW,
cb_off: 8,
},
(Beta3, Fine, Dt) => AcplHcb {
name: "ACPL_HCB_BETA3_FINE_DT",
len: ACPL_HCB_BETA3_FINE_DT_LEN,
cw: ACPL_HCB_BETA3_FINE_DT_CW,
cb_off: 16,
},
(Gamma, Coarse, F0) => AcplHcb {
name: "ACPL_HCB_GAMMA_COARSE_F0",
len: ACPL_HCB_GAMMA_COARSE_F0_LEN,
cw: ACPL_HCB_GAMMA_COARSE_F0_CW,
cb_off: 10,
},
(Gamma, Fine, F0) => AcplHcb {
name: "ACPL_HCB_GAMMA_FINE_F0",
len: ACPL_HCB_GAMMA_FINE_F0_LEN,
cw: ACPL_HCB_GAMMA_FINE_F0_CW,
cb_off: 20,
},
(Gamma, Coarse, Df) => AcplHcb {
name: "ACPL_HCB_GAMMA_COARSE_DF",
len: ACPL_HCB_GAMMA_COARSE_DF_LEN,
cw: ACPL_HCB_GAMMA_COARSE_DF_CW,
cb_off: 20,
},
(Gamma, Fine, Df) => AcplHcb {
name: "ACPL_HCB_GAMMA_FINE_DF",
len: ACPL_HCB_GAMMA_FINE_DF_LEN,
cw: ACPL_HCB_GAMMA_FINE_DF_CW,
cb_off: 40,
},
(Gamma, Coarse, Dt) => AcplHcb {
name: "ACPL_HCB_GAMMA_COARSE_DT",
len: ACPL_HCB_GAMMA_COARSE_DT_LEN,
cw: ACPL_HCB_GAMMA_COARSE_DT_CW,
cb_off: 20,
},
(Gamma, Fine, Dt) => AcplHcb {
name: "ACPL_HCB_GAMMA_FINE_DT",
len: ACPL_HCB_GAMMA_FINE_DT_LEN,
cw: ACPL_HCB_GAMMA_FINE_DT_CW,
cb_off: 40,
},
}
}
pub fn num_param_bands_from_id(id: u32) -> u32 {
match id & 0b11 {
0 => 15,
1 => 12,
2 => 9,
_ => 7, }
}
pub fn sb_to_pb(sb: u32, num_param_bands: u32) -> u32 {
let row: u32 = match sb {
0..=8 => sb,
9..=10 => 9,
11..=13 => 10,
14..=17 => 11,
18..=22 => 12,
23..=34 => 13,
_ => 14, };
let table_row: [u32; 4] = match row {
0 => [0, 0, 0, 0],
1 => [1, 1, 1, 1],
2 => [2, 2, 2, 2],
3 => [3, 3, 3, 2],
4 => [4, 4, 3, 3],
5 => [5, 4, 4, 3],
6 => [6, 5, 4, 3],
7 => [7, 5, 5, 3],
8 => [8, 6, 5, 4],
9 => [9, 6, 6, 4],
10 => [10, 7, 6, 4],
11 => [11, 8, 7, 5],
12 => [12, 9, 7, 5],
13 => [13, 10, 8, 6],
_ => [14, 11, 8, 6],
};
let col: usize = match num_param_bands {
15 => 0,
12 => 1,
9 => 2,
7 => 3,
n if n >= 13 => 0,
n if n >= 10 => 1,
n if n >= 8 => 2,
_ => 3,
};
table_row[col]
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Acpl1chMode {
Partial,
Full,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AcplConfig1ch {
pub num_param_bands_id: u8,
pub num_param_bands: u32,
pub quant_mode: AcplQuantMode,
pub qmf_band: u8,
}
pub fn parse_acpl_config_1ch(br: &mut BitReader<'_>, mode: Acpl1chMode) -> Result<AcplConfig1ch> {
let id = br.read_u32(2)? as u8;
let qm = AcplQuantMode::from_bit(br.read_bit()?);
let mut qmf_band = 0u8;
if matches!(mode, Acpl1chMode::Partial) {
let m1 = br.read_u32(3)? as u8;
qmf_band = m1 + 1;
}
Ok(AcplConfig1ch {
num_param_bands_id: id,
num_param_bands: num_param_bands_from_id(id as u32),
quant_mode: qm,
qmf_band,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AcplConfig2ch {
pub num_param_bands_id: u8,
pub num_param_bands: u32,
pub quant_mode_0: AcplQuantMode,
pub quant_mode_1: AcplQuantMode,
}
pub fn parse_acpl_config_2ch(br: &mut BitReader<'_>) -> Result<AcplConfig2ch> {
let id = br.read_u32(2)? as u8;
let qm0 = AcplQuantMode::from_bit(br.read_bit()?);
let qm1 = AcplQuantMode::from_bit(br.read_bit()?);
Ok(AcplConfig2ch {
num_param_bands_id: id,
num_param_bands: num_param_bands_from_id(id as u32),
quant_mode_0: qm0,
quant_mode_1: qm1,
})
}
#[derive(Debug, Clone)]
pub struct AcplFramingData {
pub interpolation_type: AcplInterpolationType,
pub num_param_sets_cod: u8,
pub num_param_sets: u32,
pub param_timeslots: Vec<u8>,
}
pub fn parse_acpl_framing_data(br: &mut BitReader<'_>) -> Result<AcplFramingData> {
let interp_bit = br.read_bit()?;
let interp = if interp_bit {
AcplInterpolationType::Steep
} else {
AcplInterpolationType::Smooth
};
let nps_cod = br.read_bit()?;
let nps_cod_val = if nps_cod { 1u8 } else { 0u8 };
let num_param_sets = (nps_cod_val as u32) + 1;
let mut slots = Vec::new();
if matches!(interp, AcplInterpolationType::Steep) {
for _ in 0..num_param_sets {
slots.push(br.read_u32(5)? as u8);
}
}
Ok(AcplFramingData {
interpolation_type: interp,
num_param_sets_cod: nps_cod_val,
num_param_sets,
param_timeslots: slots,
})
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AcplHuffParam {
pub values: Vec<i32>,
pub direction_time: bool,
}
pub fn parse_acpl_huff_data(
br: &mut BitReader<'_>,
data_type: AcplDataType,
data_bands: u32,
start_band: u32,
quant_mode: AcplQuantMode,
) -> Result<AcplHuffParam> {
if start_band > data_bands {
return Err(Error::invalid(
"ac4: acpl_huff_data start_band > data_bands",
));
}
let diff_type = br.read_bit()?;
let mut values: Vec<i32> = vec![0; data_bands as usize];
if !diff_type {
if data_bands > start_band {
let hcb_f0 = get_acpl_hcb(data_type, quant_mode, AcplHcbType::F0);
values[start_band as usize] = hcb_f0.decode_delta(br)?;
}
if data_bands > start_band + 1 {
let hcb_df = get_acpl_hcb(data_type, quant_mode, AcplHcbType::Df);
for i in (start_band + 1)..data_bands {
values[i as usize] = hcb_df.decode_delta(br)?;
}
}
} else {
let hcb_dt = get_acpl_hcb(data_type, quant_mode, AcplHcbType::Dt);
for i in start_band..data_bands {
values[i as usize] = hcb_dt.decode_delta(br)?;
}
}
Ok(AcplHuffParam {
values,
direction_time: diff_type,
})
}
pub fn parse_acpl_ec_data(
br: &mut BitReader<'_>,
data_type: AcplDataType,
data_bands: u32,
start_band: u32,
quant_mode: AcplQuantMode,
num_param_sets: u32,
) -> Result<Vec<AcplHuffParam>> {
let mut out = Vec::with_capacity(num_param_sets as usize);
for _ in 0..num_param_sets {
out.push(parse_acpl_huff_data(
br, data_type, data_bands, start_band, quant_mode,
)?);
}
Ok(out)
}
#[derive(Debug, Clone)]
pub struct AcplData1ch {
pub framing: AcplFramingData,
pub alpha1: Vec<AcplHuffParam>,
pub beta1: Vec<AcplHuffParam>,
}
pub fn parse_acpl_data_1ch(
br: &mut BitReader<'_>,
num_bands: u32,
start_band: u32,
quant_mode: AcplQuantMode,
) -> Result<AcplData1ch> {
let framing = parse_acpl_framing_data(br)?;
let alpha1 = parse_acpl_ec_data(
br,
AcplDataType::Alpha,
num_bands,
start_band,
quant_mode,
framing.num_param_sets,
)?;
let beta1 = parse_acpl_ec_data(
br,
AcplDataType::Beta,
num_bands,
start_band,
quant_mode,
framing.num_param_sets,
)?;
Ok(AcplData1ch {
framing,
alpha1,
beta1,
})
}
#[derive(Debug, Clone)]
pub struct AcplData2ch {
pub framing: AcplFramingData,
pub alpha1: Vec<AcplHuffParam>,
pub alpha2: Vec<AcplHuffParam>,
pub beta1: Vec<AcplHuffParam>,
pub beta2: Vec<AcplHuffParam>,
pub beta3: Vec<AcplHuffParam>,
pub gamma1: Vec<AcplHuffParam>,
pub gamma2: Vec<AcplHuffParam>,
pub gamma3: Vec<AcplHuffParam>,
pub gamma4: Vec<AcplHuffParam>,
pub gamma5: Vec<AcplHuffParam>,
pub gamma6: Vec<AcplHuffParam>,
}
pub fn parse_acpl_data_2ch(
br: &mut BitReader<'_>,
num_bands: u32,
start_band: u32,
quant_mode_0: AcplQuantMode,
quant_mode_1: AcplQuantMode,
) -> Result<AcplData2ch> {
let framing = parse_acpl_framing_data(br)?;
let nps = framing.num_param_sets;
let ec_alpha = |br: &mut BitReader<'_>| -> Result<Vec<AcplHuffParam>> {
parse_acpl_ec_data(
br,
AcplDataType::Alpha,
num_bands,
start_band,
quant_mode_0,
nps,
)
};
let ec_beta = |br: &mut BitReader<'_>| -> Result<Vec<AcplHuffParam>> {
parse_acpl_ec_data(
br,
AcplDataType::Beta,
num_bands,
start_band,
quant_mode_0,
nps,
)
};
let ec_beta3 = |br: &mut BitReader<'_>| -> Result<Vec<AcplHuffParam>> {
parse_acpl_ec_data(
br,
AcplDataType::Beta3,
num_bands,
start_band,
quant_mode_0,
nps,
)
};
let ec_gamma = |br: &mut BitReader<'_>| -> Result<Vec<AcplHuffParam>> {
parse_acpl_ec_data(
br,
AcplDataType::Gamma,
num_bands,
start_band,
quant_mode_1,
nps,
)
};
let alpha1 = ec_alpha(br)?;
let alpha2 = ec_alpha(br)?;
let beta1 = ec_beta(br)?;
let beta2 = ec_beta(br)?;
let beta3 = ec_beta3(br)?;
let gamma1 = ec_gamma(br)?;
let gamma2 = ec_gamma(br)?;
let gamma3 = ec_gamma(br)?;
let gamma4 = ec_gamma(br)?;
let gamma5 = ec_gamma(br)?;
let gamma6 = ec_gamma(br)?;
Ok(AcplData2ch {
framing,
alpha1,
alpha2,
beta1,
beta2,
beta3,
gamma1,
gamma2,
gamma3,
gamma4,
gamma5,
gamma6,
})
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::bits::BitWriter;
#[test]
fn get_acpl_hcb_returns_named_codebook_per_combination() {
for &(dt, dt_name) in &[
(AcplDataType::Alpha, "ALPHA"),
(AcplDataType::Beta, "BETA"),
(AcplDataType::Beta3, "BETA3"),
(AcplDataType::Gamma, "GAMMA"),
] {
for &(qm, qm_name) in &[
(AcplQuantMode::Coarse, "COARSE"),
(AcplQuantMode::Fine, "FINE"),
] {
for &(ht, ht_name) in &[
(AcplHcbType::F0, "F0"),
(AcplHcbType::Df, "DF"),
(AcplHcbType::Dt, "DT"),
] {
let hcb = get_acpl_hcb(dt, qm, ht);
let want = format!("ACPL_HCB_{dt_name}_{qm_name}_{ht_name}");
assert_eq!(hcb.name, want, "dt={dt_name} qm={qm_name} ht={ht_name}");
assert_eq!(hcb.len.len(), hcb.cw.len());
}
}
}
}
#[test]
fn quant_mode_from_bit_matches_table_144() {
assert_eq!(AcplQuantMode::from_bit(false), AcplQuantMode::Fine);
assert_eq!(AcplQuantMode::from_bit(true), AcplQuantMode::Coarse);
}
#[test]
fn num_param_bands_from_id_matches_table_143() {
assert_eq!(num_param_bands_from_id(0), 15);
assert_eq!(num_param_bands_from_id(1), 12);
assert_eq!(num_param_bands_from_id(2), 9);
assert_eq!(num_param_bands_from_id(3), 7);
}
#[test]
fn alpha_coarse_f0_decodes_zero_delta() {
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::F0);
assert_eq!(hcb.cb_off, 8);
let mut bw = BitWriter::new();
bw.write_u32(0, 1);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
assert_eq!(hcb.decode_delta(&mut br).unwrap(), 0);
}
#[test]
fn alpha_coarse_df_decodes_zero_delta_at_cb_off() {
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::Df);
assert_eq!(hcb.cb_off, 16);
let mut bw = BitWriter::new();
bw.write_u32(0, 1);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
assert_eq!(hcb.decode_delta(&mut br).unwrap(), 0);
}
#[test]
fn alpha_f0_signed_lanes_round_trip_fine_and_coarse() {
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Fine, AcplHcbType::F0);
assert_eq!(hcb.cb_off, 16);
for alpha_q in -16i32..=16i32 {
let idx = (alpha_q + hcb.cb_off) as usize;
let mut bw = BitWriter::new();
bw.write_u32(hcb.cw[idx], hcb.len[idx] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let got = hcb.decode_delta(&mut br).unwrap();
assert_eq!(
got, alpha_q,
"ALPHA_FINE F0 alpha_q={alpha_q} did not round-trip (got {got})"
);
}
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::F0);
assert_eq!(hcb.cb_off, 8);
for alpha_q in -8i32..=8i32 {
let idx = (alpha_q + hcb.cb_off) as usize;
let mut bw = BitWriter::new();
bw.write_u32(hcb.cw[idx], hcb.len[idx] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let got = hcb.decode_delta(&mut br).unwrap();
assert_eq!(
got, alpha_q,
"ALPHA_COARSE F0 alpha_q={alpha_q} did not round-trip (got {got})"
);
}
}
#[test]
fn beta3_f0_signed_lanes_round_trip_fine_and_coarse() {
let hcb = get_acpl_hcb(AcplDataType::Beta3, AcplQuantMode::Fine, AcplHcbType::F0);
assert_eq!(hcb.cb_off, 8);
for beta3_q in -8i32..=8i32 {
let idx = (beta3_q + hcb.cb_off) as usize;
let mut bw = BitWriter::new();
bw.write_u32(hcb.cw[idx], hcb.len[idx] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let got = hcb.decode_delta(&mut br).unwrap();
assert_eq!(
got, beta3_q,
"BETA3_FINE F0 beta3_q={beta3_q} did not round-trip (got {got})"
);
}
let hcb = get_acpl_hcb(AcplDataType::Beta3, AcplQuantMode::Coarse, AcplHcbType::F0);
assert_eq!(hcb.cb_off, 4);
for beta3_q in -4i32..=4i32 {
let idx = (beta3_q + hcb.cb_off) as usize;
let mut bw = BitWriter::new();
bw.write_u32(hcb.cw[idx], hcb.len[idx] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let got = hcb.decode_delta(&mut br).unwrap();
assert_eq!(
got, beta3_q,
"BETA3_COARSE F0 beta3_q={beta3_q} did not round-trip (got {got})"
);
}
}
#[test]
fn alpha_f0_zero_alpha_picks_one_bit_peak() {
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::F0);
let idx = hcb.cb_off as usize;
assert_eq!(
hcb.len[idx], 1,
"alpha_q = 0 must address the 1-bit peak entry in COARSE F0"
);
let hcb = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Fine, AcplHcbType::F0);
let idx = hcb.cb_off as usize;
assert_eq!(
hcb.len[idx], 1,
"alpha_q = 0 must address the 1-bit peak entry in FINE F0"
);
}
#[test]
fn gamma_fine_dt_decodes_zero_delta_at_cb_off() {
let hcb = get_acpl_hcb(AcplDataType::Gamma, AcplQuantMode::Fine, AcplHcbType::Dt);
assert_eq!(hcb.cb_off, 40);
let mut bw = BitWriter::new();
bw.write_u32(0, 1);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
assert_eq!(hcb.decode_delta(&mut br).unwrap(), 0);
}
#[test]
fn config_1ch_full_reads_3_bits() {
let mut bw = BitWriter::new();
bw.write_u32(0b10, 2); bw.write_u32(0b1, 1); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let cfg = parse_acpl_config_1ch(&mut br, Acpl1chMode::Full).unwrap();
assert_eq!(cfg.num_param_bands_id, 2);
assert_eq!(cfg.num_param_bands, 9);
assert_eq!(cfg.quant_mode, AcplQuantMode::Coarse);
assert_eq!(cfg.qmf_band, 0);
}
#[test]
fn config_1ch_partial_reads_qmf_band() {
let mut bw = BitWriter::new();
bw.write_u32(0b00, 2); bw.write_u32(0b0, 1); bw.write_u32(0b101, 3); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let cfg = parse_acpl_config_1ch(&mut br, Acpl1chMode::Partial).unwrap();
assert_eq!(cfg.num_param_bands_id, 0);
assert_eq!(cfg.num_param_bands, 15);
assert_eq!(cfg.quant_mode, AcplQuantMode::Fine);
assert_eq!(cfg.qmf_band, 6);
}
#[test]
fn config_2ch_reads_both_quant_modes() {
let mut bw = BitWriter::new();
bw.write_u32(0b11, 2); bw.write_u32(0b1, 1); bw.write_u32(0b0, 1); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let cfg = parse_acpl_config_2ch(&mut br).unwrap();
assert_eq!(cfg.num_param_bands_id, 3);
assert_eq!(cfg.num_param_bands, 7);
assert_eq!(cfg.quant_mode_0, AcplQuantMode::Coarse);
assert_eq!(cfg.quant_mode_1, AcplQuantMode::Fine);
}
#[test]
fn framing_smooth_one_param_set() {
let mut bw = BitWriter::new();
bw.write_u32(0, 1); bw.write_u32(0, 1); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let framing = parse_acpl_framing_data(&mut br).unwrap();
assert_eq!(framing.interpolation_type, AcplInterpolationType::Smooth);
assert_eq!(framing.num_param_sets, 1);
assert!(framing.param_timeslots.is_empty());
}
#[test]
fn framing_steep_two_param_sets_reads_two_timeslots() {
let mut bw = BitWriter::new();
bw.write_u32(1, 1); bw.write_u32(1, 1); bw.write_u32(7, 5); bw.write_u32(23, 5); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let framing = parse_acpl_framing_data(&mut br).unwrap();
assert_eq!(framing.interpolation_type, AcplInterpolationType::Steep);
assert_eq!(framing.num_param_sets, 2);
assert_eq!(framing.param_timeslots, vec![7, 23]);
}
#[test]
fn huff_data_freq_alpha_round_trips() {
let hcb_f0 = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::F0);
let hcb_df = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::Df);
let mut bw = BitWriter::new();
bw.write_u32(0, 1); bw.write_u32(hcb_f0.cw[8], hcb_f0.len[8] as u32);
bw.write_u32(hcb_df.cw[16], hcb_df.len[16] as u32);
bw.write_u32(hcb_df.cw[17], hcb_df.len[17] as u32);
bw.write_u32(hcb_df.cw[15], hcb_df.len[15] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let p = parse_acpl_huff_data(&mut br, AcplDataType::Alpha, 4, 0, AcplQuantMode::Coarse)
.unwrap();
assert!(!p.direction_time);
assert_eq!(p.values, vec![0, 0, 1, -1]);
}
#[test]
fn huff_data_time_beta_round_trips() {
let hcb_dt = get_acpl_hcb(AcplDataType::Beta, AcplQuantMode::Fine, AcplHcbType::Dt);
let mut bw = BitWriter::new();
bw.write_u32(1, 1); bw.write_u32(hcb_dt.cw[8], hcb_dt.len[8] as u32);
bw.write_u32(hcb_dt.cw[9], hcb_dt.len[9] as u32);
bw.write_u32(hcb_dt.cw[7], hcb_dt.len[7] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let p =
parse_acpl_huff_data(&mut br, AcplDataType::Beta, 3, 0, AcplQuantMode::Fine).unwrap();
assert!(p.direction_time);
assert_eq!(p.values, vec![0, 1, -1]);
}
#[test]
fn ec_data_runs_once_per_param_set() {
let hcb_f0 = get_acpl_hcb(AcplDataType::Beta, AcplQuantMode::Coarse, AcplHcbType::F0);
let mut bw = BitWriter::new();
for _ in 0..2 {
bw.write_u32(0, 1); bw.write_u32(hcb_f0.cw[0], hcb_f0.len[0] as u32); }
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let sets = parse_acpl_ec_data(
&mut br,
AcplDataType::Beta,
1, 0,
AcplQuantMode::Coarse,
2, )
.unwrap();
assert_eq!(sets.len(), 2);
assert_eq!(sets[0].values, vec![0]);
assert_eq!(sets[1].values, vec![0]);
}
#[test]
fn data_1ch_smooth_one_set_two_bands() {
let alpha_dt = get_acpl_hcb(AcplDataType::Alpha, AcplQuantMode::Coarse, AcplHcbType::Dt);
let beta_dt = get_acpl_hcb(AcplDataType::Beta, AcplQuantMode::Coarse, AcplHcbType::Dt);
let mut bw = BitWriter::new();
bw.write_u32(0, 1);
bw.write_u32(0, 1);
bw.write_u32(1, 1); bw.write_u32(alpha_dt.cw[16], alpha_dt.len[16] as u32);
bw.write_u32(alpha_dt.cw[17], alpha_dt.len[17] as u32);
bw.write_u32(1, 1); bw.write_u32(beta_dt.cw[4], beta_dt.len[4] as u32);
bw.write_u32(beta_dt.cw[3], beta_dt.len[3] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let data = parse_acpl_data_1ch(&mut br, 2, 0, AcplQuantMode::Coarse).unwrap();
assert_eq!(data.framing.num_param_sets, 1);
assert_eq!(data.alpha1.len(), 1);
assert_eq!(data.alpha1[0].values, vec![0, 1]);
assert_eq!(data.beta1.len(), 1);
assert_eq!(data.beta1[0].values, vec![0, -1]);
}
#[test]
fn sb_to_pb_15_bands_first_nine_are_one_to_one() {
for sb in 0..=8u32 {
assert_eq!(sb_to_pb(sb, 15), sb, "sb={sb} 15-band should be identity");
}
}
#[test]
fn sb_to_pb_15_bands_grouped_rows() {
assert_eq!(sb_to_pb(9, 15), 9);
assert_eq!(sb_to_pb(10, 15), 9);
assert_eq!(sb_to_pb(11, 15), 10);
assert_eq!(sb_to_pb(13, 15), 10);
assert_eq!(sb_to_pb(14, 15), 11);
assert_eq!(sb_to_pb(17, 15), 11);
assert_eq!(sb_to_pb(18, 15), 12);
assert_eq!(sb_to_pb(22, 15), 12);
assert_eq!(sb_to_pb(23, 15), 13);
assert_eq!(sb_to_pb(34, 15), 13);
assert_eq!(sb_to_pb(35, 15), 14);
assert_eq!(sb_to_pb(63, 15), 14);
}
#[test]
fn sb_to_pb_12_bands_table_197() {
assert_eq!(sb_to_pb(0, 12), 0);
assert_eq!(sb_to_pb(3, 12), 3);
assert_eq!(sb_to_pb(4, 12), 4);
assert_eq!(sb_to_pb(5, 12), 4);
assert_eq!(sb_to_pb(6, 12), 5);
assert_eq!(sb_to_pb(7, 12), 5);
assert_eq!(sb_to_pb(8, 12), 6);
assert_eq!(sb_to_pb(10, 12), 6);
assert_eq!(sb_to_pb(11, 12), 7);
assert_eq!(sb_to_pb(13, 12), 7);
assert_eq!(sb_to_pb(17, 12), 8);
assert_eq!(sb_to_pb(22, 12), 9);
assert_eq!(sb_to_pb(34, 12), 10);
assert_eq!(sb_to_pb(63, 12), 11);
}
#[test]
fn sb_to_pb_9_bands_table_197() {
assert_eq!(sb_to_pb(0, 9), 0);
assert_eq!(sb_to_pb(3, 9), 3);
assert_eq!(sb_to_pb(4, 9), 3);
assert_eq!(sb_to_pb(5, 9), 4);
assert_eq!(sb_to_pb(7, 9), 5);
assert_eq!(sb_to_pb(10, 9), 6);
assert_eq!(sb_to_pb(13, 9), 6);
assert_eq!(sb_to_pb(17, 9), 7);
assert_eq!(sb_to_pb(22, 9), 7);
assert_eq!(sb_to_pb(34, 9), 8);
assert_eq!(sb_to_pb(63, 9), 8);
}
#[test]
fn sb_to_pb_7_bands_table_197() {
assert_eq!(sb_to_pb(0, 7), 0);
assert_eq!(sb_to_pb(2, 7), 2);
assert_eq!(sb_to_pb(3, 7), 2);
assert_eq!(sb_to_pb(4, 7), 3);
assert_eq!(sb_to_pb(7, 7), 3);
assert_eq!(sb_to_pb(8, 7), 4);
assert_eq!(sb_to_pb(10, 7), 4);
assert_eq!(sb_to_pb(13, 7), 4);
assert_eq!(sb_to_pb(17, 7), 5);
assert_eq!(sb_to_pb(22, 7), 5);
assert_eq!(sb_to_pb(34, 7), 6);
assert_eq!(sb_to_pb(63, 7), 6);
}
#[test]
fn sb_to_pb_image_below_num_param_bands() {
for &npb in &[15u32, 12, 9, 7] {
for sb in 0..=63u32 {
let pb = sb_to_pb(sb, npb);
assert!(pb < npb, "sb_to_pb({sb}, {npb}) = {pb} >= {npb}");
}
}
}
}