use super::det_math;
use super::spectrum::SF_OFFSET;
use super::swb::{LONG_WINDOW_LEN, SHORT_WINDOW_LEN};
pub const QUANT_MAX: i32 = 8191;
pub const BOOKS: usize = 12;
pub const MAX_BANDS: usize = 51;
pub const UNREPRESENTABLE: u32 = u32::MAX;
pub const QUANT_ROUND: f32 = 0.4054;
pub const QUANT_SAFE: f32 = 7600.0;
#[inline]
fn quant_mag(pow34: f32, gain: f32) -> i32 {
let v = pow34 * gain + QUANT_ROUND;
if v >= 0.0 {
(v as i32).min(QUANT_MAX)
} else {
(v.floor() as i32).min(QUANT_MAX)
}
}
pub fn cache_mags(spec: &[f32; 1024], mag: &mut [f32; 1024]) {
for (m, &x) in mag.iter_mut().zip(spec.iter()) {
*m = det_math::pow_three_quarter(x);
}
}
#[derive(Clone)]
pub struct QuantChannel {
pub quant: [i32; 1024],
pub mag: [f32; 1024],
pub bits: [[u32; BOOKS]; MAX_BANDS],
pub sf: [i32; MAX_BANDS],
pub coded: [bool; MAX_BANDS],
pub zero: [bool; MAX_BANDS],
pub pns: [bool; MAX_BANDS],
pub noise_nrg: [i32; MAX_BANDS],
pub intensity: [bool; MAX_BANDS],
pub is_pos: [i32; MAX_BANDS],
pub is_hcb: [u8; MAX_BANDS],
pub n_bands: usize,
}
impl QuantChannel {
pub fn new(n_bands: usize) -> Self {
Self {
quant: [0; 1024],
mag: [0.0; 1024],
bits: [[UNREPRESENTABLE; BOOKS]; MAX_BANDS],
sf: [0; MAX_BANDS],
coded: [false; MAX_BANDS],
zero: [false; MAX_BANDS],
pns: [false; MAX_BANDS],
noise_nrg: [0; MAX_BANDS],
intensity: [false; MAX_BANDS],
is_pos: [0; MAX_BANDS],
is_hcb: [0; MAX_BANDS],
n_bands,
}
}
}
pub const MAX_SFB_SHORT: usize = 15;
pub const MAX_GROUPS: usize = 8;
pub const MAX_FLAT_SHORT: usize = MAX_GROUPS * MAX_SFB_SHORT;
#[derive(Clone)]
pub struct QuantShort {
pub quant: [i32; LONG_WINDOW_LEN],
pub mag: [f32; LONG_WINDOW_LEN],
pub bits: [[u32; BOOKS]; MAX_FLAT_SHORT],
pub sf: [i32; MAX_FLAT_SHORT],
pub coded: [bool; MAX_FLAT_SHORT],
pub zero: [bool; MAX_FLAT_SHORT],
pub n_sfb: usize,
pub n_groups: usize,
pub group_len: [u8; 8],
}
impl QuantShort {
pub fn new(n_sfb: usize) -> Self {
Self {
quant: [0; LONG_WINDOW_LEN],
mag: [0.0; LONG_WINDOW_LEN],
bits: [[UNREPRESENTABLE; BOOKS]; MAX_FLAT_SHORT],
sf: [0; MAX_FLAT_SHORT],
coded: [false; MAX_FLAT_SHORT],
zero: [false; MAX_FLAT_SHORT],
n_sfb,
n_groups: MAX_GROUPS,
group_len: [1; 8],
}
}
pub fn set_grouping(&mut self, g: super::enc_group::Grouping) {
self.n_groups = g.n_groups as usize;
self.group_len = g.group_len;
}
#[must_use]
pub fn grouping_bits(&self) -> u8 {
super::enc_group::Grouping {
n_groups: self.n_groups as u8,
group_len: self.group_len,
}
.bits()
}
}
pub fn band_peaks(spec: &[f32; 1024], offsets: &[u16], out: &mut [f32; MAX_BANDS]) {
let n_bands = offsets.len() - 1;
for b in 0..n_bands {
let lo = usize::from(offsets[b]);
let hi = usize::from(offsets[b + 1]);
out[b] = spec[lo..hi].iter().map(|x| x.abs()).fold(0.0f32, f32::max);
}
}
pub fn sf_for_peak(peak: f32, target_q: f32) -> i32 {
if peak <= 0.0 || target_q <= 0.0 {
return 0;
}
let sf =
SF_OFFSET as f32 + 4.0 * det_math::log2(peak) - (16.0 / 3.0) * det_math::log2(target_q);
sf.round() as i32
}
pub fn raw_scalefactors(
peaks: &[f32; MAX_BANDS],
target_q: &[f32; MAX_BANDS],
global_offset: i32,
out: &mut QuantChannel,
) {
let bands = peaks
.iter()
.zip(target_q.iter())
.zip(out.coded.iter())
.zip(out.sf.iter_mut())
.take(out.n_bands);
for (((&peak, &tq), &coded), sf) in bands {
*sf = if coded && tq >= 1.0 {
(sf_for_peak(peak, tq) + global_offset).max(sf_for_peak(peak, QUANT_SAFE))
} else {
0
};
}
}
pub fn normalize_sf(out: &mut QuantChannel) -> u8 {
let mut global_gain = 100u8;
let mut prev: Option<i32> = None;
let bands = out.coded.iter().zip(out.sf.iter_mut()).take(out.n_bands);
for (&coded, sf) in bands {
if !coded {
continue;
}
let want = (*sf).clamp(0, 255);
let v = match prev {
None => {
global_gain = want as u8;
want
}
Some(p) => (p + (want - p).clamp(-60, 60)).clamp(0, 255),
};
*sf = v;
prev = Some(v);
}
global_gain
}
#[cfg(test)]
pub fn quantize(spec: &[f32; 1024], offsets: &[u16], out: &mut QuantChannel) {
cache_mags(spec, &mut out.mag);
quantize_cached(spec, offsets, out);
}
pub fn quantize_cached(spec: &[f32; 1024], offsets: &[u16], out: &mut QuantChannel) {
out.quant = [0; 1024];
let n_bands = out.n_bands.min(offsets.len() - 1);
let bands = out
.coded
.iter()
.zip(out.sf.iter())
.zip(out.bits.iter_mut().zip(out.zero.iter_mut()))
.zip(offsets.windows(2))
.take(n_bands);
for (((&coded, &sf), (bits, zero)), w) in bands {
let (lo, hi) = (usize::from(w[0]), usize::from(w[1]));
*zero = false;
if !coded {
*bits = [UNREPRESENTABLE; BOOKS];
continue;
}
let gain = quant_gain(sf);
bits::write_quants(
&mut out.quant[lo..hi],
&spec[lo..hi],
&out.mag[lo..hi],
gain,
);
*zero = out.quant[lo..hi].iter().all(|&v| v == 0);
fill_bits(bits, &out.quant[lo..hi]);
}
}
pub fn requant_band(spec: &[f32; 1024], offsets: &[u16], out: &mut QuantChannel, b: usize) {
if b >= out.n_bands || !out.coded[b] {
return;
}
let lo = usize::from(offsets[b]);
let hi = usize::from(offsets[b + 1]);
let gain = quant_gain(out.sf[b]);
for (q, &x) in out.quant[lo..hi].iter_mut().zip(spec[lo..hi].iter()) {
let mag = quant_mag(det_math::pow_three_quarter(x), gain);
*q = if x < 0.0 { -mag } else { mag };
}
out.zero[b] = out.quant[lo..hi].iter().all(|&v| v == 0);
fill_bits(&mut out.bits[b], &out.quant[lo..hi]);
}
pub fn band_peaks_short(
spec: &[f32; LONG_WINDOW_LEN],
offsets: &[u16],
n_sfb: usize,
out: &mut [f32; MAX_FLAT_SHORT],
) {
for w in 0..MAX_GROUPS {
for b in 0..n_sfb {
let lo = w * SHORT_WINDOW_LEN + usize::from(offsets[b]);
let hi = w * SHORT_WINDOW_LEN + usize::from(offsets[b + 1]);
out[w * n_sfb + b] = spec[lo..hi].iter().map(|x| x.abs()).fold(0.0f32, f32::max);
}
}
}
pub fn raw_scalefactors_short(
peaks: &[f32; MAX_FLAT_SHORT],
target_q: &[f32; MAX_FLAT_SHORT],
global_offset: i32,
out: &mut QuantShort,
) {
let n = out.n_groups * out.n_sfb;
let bands = peaks
.iter()
.zip(target_q.iter())
.zip(out.coded.iter())
.zip(out.sf.iter_mut())
.take(n);
for (((&peak, &tq), &coded), sf) in bands {
*sf = if coded && tq >= 1.0 {
(sf_for_peak(peak, tq) + global_offset).max(sf_for_peak(peak, QUANT_SAFE))
} else {
0
};
}
}
pub fn normalize_sf_short(out: &mut QuantShort) -> u8 {
let mut global_gain = 100u8;
let mut prev: Option<i32> = None;
let n = out.n_groups * out.n_sfb;
let bands = out.coded.iter().zip(out.sf.iter_mut()).take(n);
for (&coded, sf) in bands {
if !coded {
continue;
}
let want = (*sf).clamp(0, 255);
let v = match prev {
None => {
global_gain = want as u8;
want
}
Some(p) => (p + (want - p).clamp(-60, 60)).clamp(0, 255),
};
*sf = v;
prev = Some(v);
}
global_gain
}
#[cfg(test)]
pub fn quantize_short(spec: &[f32; LONG_WINDOW_LEN], offsets: &[u16], out: &mut QuantShort) {
cache_mags(spec, &mut out.mag);
quantize_short_cached(spec, offsets, out);
}
pub fn quantize_short_cached(spec: &[f32; LONG_WINDOW_LEN], offsets: &[u16], out: &mut QuantShort) {
out.quant = [0; LONG_WINDOW_LEN];
let mut wbase = 0usize;
for g in 0..out.n_groups {
let glen = out.group_len[g] as usize;
for b in 0..out.n_sfb {
let idx = g * out.n_sfb + b;
let start = usize::from(offsets[b]);
let end = usize::from(offsets[b + 1]);
out.zero[idx] = false;
if !out.coded[idx] {
out.bits[idx] = [UNREPRESENTABLE; BOOKS];
continue;
}
let gain = quant_gain(out.sf[idx]);
let mut tmp = [0i32; LONG_WINDOW_LEN];
let mut n = 0usize;
for k in 0..glen {
let w = wbase + k;
let lo = w * SHORT_WINDOW_LEN + start;
let hi = w * SHORT_WINDOW_LEN + end;
let src = spec[lo..hi].iter().zip(out.mag[lo..hi].iter());
for (q, (&x, &m)) in out.quant[lo..hi].iter_mut().zip(src) {
let mag = quant_mag(m, gain);
*q = if x < 0.0 { -mag } else { mag };
}
tmp[n..n + (hi - lo)].copy_from_slice(&out.quant[lo..hi]);
n += hi - lo;
}
out.zero[idx] = tmp[..n].iter().all(|&v| v == 0);
fill_bits(&mut out.bits[idx], &tmp[..n]);
}
wbase += glen;
}
}
#[path = "enc_quant_bits.rs"]
mod bits;
pub use bits::dpcm_ok;
use bits::{fill_bits, quant_gain};
#[cfg(test)]
#[path = "enc_quant_tests.rs"]
mod enc_quant_tests;