use crate::sbr_envelope::{SbrEnvelopeData, SbrNoiseData};
use crate::sbr_freq_bands::HiLoTables;
use crate::sbr_grid::{SbrDtdf, SbrGrid};
use crate::{Error, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvelopeScalefactors {
pub eq: Vec<Vec<i32>>,
pub freq_res: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NoiseScalefactors {
pub q: Vec<Vec<i32>>,
}
#[inline]
fn inv_delta(coupling: bool, ch: bool) -> i32 {
if coupling && ch {
2
} else {
1
}
}
fn high_to_low(bands: &HiLoTables, k: usize) -> usize {
let target = bands.f_table_high[k];
let mut i = 0usize;
while i + 1 < bands.f_table_low.len() && bands.f_table_low[i + 1] <= target {
i += 1;
}
i
}
fn low_to_high(bands: &HiLoTables, k: usize) -> usize {
let target = bands.f_table_low[k];
bands
.f_table_high
.iter()
.position(|&v| v == target)
.unwrap_or(0)
}
pub(crate) fn ref_band(
bands: &HiLoTables,
prev: &[i32],
cur_high: bool,
prev_high: bool,
k: usize,
) -> i32 {
let idx = if cur_high == prev_high {
k
} else if cur_high {
high_to_low(bands, k)
} else {
low_to_high(bands, k)
};
prev.get(idx).copied().unwrap_or(0)
}
impl EnvelopeScalefactors {
pub fn reconstruct(
env: &SbrEnvelopeData,
grid: &SbrGrid,
dtdf: &SbrDtdf,
bands: &HiLoTables,
coupling: bool,
ch: bool,
prev: Option<&EnvelopeScalefactors>,
) -> Result<Self> {
let inv = inv_delta(coupling, ch);
let mut eq: Vec<Vec<i32>> = Vec::with_capacity(grid.num_env);
for l in 0..grid.num_env {
let cur_high = grid.freq_res[l];
let n = if cur_high {
bands.n_high()
} else {
bands.n_low()
};
let raw = &env.data[l];
if raw.len() != n {
return Err(Error::SbrGridInvalid);
}
let mut row = vec![0i32; n];
if !dtdf.df_env[l] {
row[0] = raw[0] * inv;
for k in 1..n {
row[k] = row[k - 1] + raw[k] * inv;
}
} else {
let (prev_row, prev_high): (Vec<i32>, bool) = if l >= 1 {
(eq[l - 1].clone(), grid.freq_res[l - 1])
} else if let Some(p) = prev {
let last = p.eq.len().saturating_sub(1);
(
p.eq.get(last).cloned().unwrap_or_default(),
*p.freq_res.get(last).unwrap_or(&cur_high),
)
} else {
(vec![0i32; n], cur_high)
};
for k in 0..n {
let g = ref_band(bands, &prev_row, cur_high, prev_high, k);
row[k] = g + raw[k] * inv;
}
}
eq.push(row);
}
Ok(EnvelopeScalefactors {
eq,
freq_res: grid.freq_res.clone(),
})
}
}
impl NoiseScalefactors {
pub fn reconstruct(
noise: &SbrNoiseData,
grid: &SbrGrid,
dtdf: &SbrDtdf,
num_noise_bands: usize,
coupling: bool,
ch: bool,
prev: Option<&NoiseScalefactors>,
) -> Result<Self> {
let inv = inv_delta(coupling, ch);
let mut q: Vec<Vec<i32>> = Vec::with_capacity(grid.num_noise);
for l in 0..grid.num_noise {
let raw = &noise.data[l];
if raw.len() != num_noise_bands {
return Err(Error::SbrGridInvalid);
}
let mut row = vec![0i32; num_noise_bands];
if !dtdf.df_noise[l] {
row[0] = raw[0] * inv;
for k in 1..num_noise_bands {
row[k] = row[k - 1] + raw[k] * inv;
}
} else {
let prev_row: Vec<i32> = if l >= 1 {
q[l - 1].clone()
} else if let Some(p) = prev {
p.q.last()
.cloned()
.unwrap_or_else(|| vec![0i32; num_noise_bands])
} else {
vec![0i32; num_noise_bands]
};
for k in 0..num_noise_bands {
let g = prev_row.get(k).copied().unwrap_or(0);
row[k] = g + raw[k] * inv;
}
}
q.push(row);
}
Ok(NoiseScalefactors { q })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sbr_freq_bands::{k0, k2, master_table, HiLoTables};
use crate::sbr_grid::FrameClass;
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 single_env_grid(high: bool) -> (SbrGrid, SbrDtdf) {
(
SbrGrid {
frame_class: FrameClass::FixFix,
num_env: 1,
num_noise: 1,
freq_res: vec![high],
var_bord_0: 0,
var_bord_1: 0,
rel_bord_0: vec![],
rel_bord_1: vec![],
pointer: 0,
amp_res_override: false,
},
SbrDtdf {
df_env: vec![false],
df_noise: vec![false],
},
)
}
#[test]
fn freq_direction_accumulates() {
let bands = bands_44100();
let (grid, dtdf) = single_env_grid(true);
let n = bands.n_high();
let mut raw = vec![10i32];
for k in 1..n {
raw.push(if k % 2 == 0 { 2 } else { -1 });
}
let env = SbrEnvelopeData {
data: vec![raw.clone()],
};
let rec = EnvelopeScalefactors::reconstruct(&env, &grid, &dtdf, &bands, false, false, None)
.unwrap();
let mut acc = 10;
assert_eq!(rec.eq[0][0], 10);
for (k, &delta) in raw.iter().enumerate().skip(1) {
acc += delta;
assert_eq!(rec.eq[0][k], acc);
}
}
#[test]
fn coupled_second_channel_doubles_delta() {
let bands = bands_44100();
let (grid, dtdf) = single_env_grid(true);
let n = bands.n_high();
let mut raw = vec![4i32];
raw.extend(std::iter::repeat_n(2, n - 1));
let env = SbrEnvelopeData { data: vec![raw] };
let rec = EnvelopeScalefactors::reconstruct(&env, &grid, &dtdf, &bands, true, true, None)
.unwrap();
assert_eq!(rec.eq[0][0], 8); assert_eq!(rec.eq[0][1], 12); }
#[test]
fn time_direction_uses_prev_envelope_in_frame() {
let bands = bands_44100();
let n = bands.n_high();
let grid = SbrGrid {
frame_class: FrameClass::FixVar,
num_env: 2,
num_noise: 2,
freq_res: vec![true, true],
var_bord_0: 0,
var_bord_1: 0,
rel_bord_0: vec![],
rel_bord_1: vec![],
pointer: 0,
amp_res_override: false,
};
let dtdf = SbrDtdf {
df_env: vec![false, true], df_noise: vec![false, false],
};
let mut raw0 = vec![20i32]; raw0.extend(std::iter::repeat_n(0, n - 1));
let raw1 = vec![1i32; n]; let env = SbrEnvelopeData {
data: vec![raw0, raw1],
};
let rec = EnvelopeScalefactors::reconstruct(&env, &grid, &dtdf, &bands, false, false, None)
.unwrap();
for k in 0..n {
assert_eq!(rec.eq[0][k], 20);
assert_eq!(rec.eq[1][k], 21); }
}
#[test]
fn time_direction_cross_frame() {
let bands = bands_44100();
let n = bands.n_high();
let (grid, _) = single_env_grid(true);
let prev = EnvelopeScalefactors {
eq: vec![vec![30i32; n]],
freq_res: vec![true],
};
let dtdf = SbrDtdf {
df_env: vec![true],
df_noise: vec![false],
};
let env = SbrEnvelopeData {
data: vec![vec![2i32; n]],
};
let rec = EnvelopeScalefactors::reconstruct(
&env,
&grid,
&dtdf,
&bands,
false,
false,
Some(&prev),
)
.unwrap();
for k in 0..n {
assert_eq!(rec.eq[0][k], 32); }
}
#[test]
fn resolution_remap_high_to_low_is_monotone() {
let bands = bands_44100();
let mut prev = 0usize;
for k in 0..=bands.n_high() {
let i = high_to_low(&bands, k);
assert!(i < bands.f_table_low.len());
assert!(i >= prev);
prev = i;
}
}
#[test]
fn noise_reconstruct_accumulates() {
let bands = bands_44100();
let nq = bands.n_q();
let (grid, dtdf) = single_env_grid(true);
let raw = (0..nq)
.map(|k| if k == 0 { 5 } else { 1 })
.collect::<Vec<_>>();
let noise = SbrNoiseData { data: vec![raw] };
let rec =
NoiseScalefactors::reconstruct(&noise, &grid, &dtdf, nq, false, false, None).unwrap();
let mut acc = 5;
assert_eq!(rec.q[0][0], 5);
for k in 1..nq {
acc += 1;
assert_eq!(rec.q[0][k], acc);
}
}
}