use super::bits::BitWriter;
use super::sf_tab::{SF_CODE, SF_LEN};
use super::{huff_esc, huff_pair, huff_quad};
fn tables(cb: u8) -> Option<(&'static [u8], &'static [u16])> {
match cb {
1 => Some((&huff_quad::H1_LEN, &huff_quad::H1_CODE)),
2 => Some((&huff_quad::H2_LEN, &huff_quad::H2_CODE)),
3 => Some((&huff_quad::H3_LEN, &huff_quad::H3_CODE)),
4 => Some((&huff_quad::H4_LEN, &huff_quad::H4_CODE)),
5 => Some((&huff_pair::H5_LEN, &huff_pair::H5_CODE)),
6 => Some((&huff_pair::H6_LEN, &huff_pair::H6_CODE)),
7 => Some((&huff_pair::H7_LEN, &huff_pair::H7_CODE)),
8 => Some((&huff_pair::H8_LEN, &huff_pair::H8_CODE)),
9 => Some((&huff_pair::H9_LEN, &huff_pair::H9_CODE)),
10 => Some((&huff_pair::H10_LEN, &huff_pair::H10_CODE)),
11 => Some((&huff_esc::H11_LEN, &huff_esc::H11_CODE)),
_ => None,
}
}
fn unsigned_book(cb: u8) -> bool {
matches!(cb, 3 | 4 | 7 | 8 | 9 | 10 | 11)
}
pub fn tuple_index(cb: u8, v: &[i32]) -> Option<usize> {
let in_range = |limit: i32| v.iter().all(|&x| x.abs() <= limit);
match cb {
1 | 2 if v.len() == 4 && in_range(1) => {
Some(((v[0] + 1) * 27 + (v[1] + 1) * 9 + (v[2] + 1) * 3 + (v[3] + 1)) as usize)
}
3 | 4 if v.len() == 4 && in_range(2) => {
Some((v[0].abs() * 27 + v[1].abs() * 9 + v[2].abs() * 3 + v[3].abs()) as usize)
}
5 | 6 if v.len() == 2 && in_range(4) => Some(((v[0] + 4) * 9 + (v[1] + 4)) as usize),
7 | 8 if v.len() == 2 && in_range(7) => Some((v[0].abs() * 8 + v[1].abs()) as usize),
9 | 10 if v.len() == 2 && in_range(12) => Some((v[0].abs() * 13 + v[1].abs()) as usize),
11 if v.len() == 2 => {
let a = v[0].abs().min(16);
let b = v[1].abs().min(16);
Some((a * 17 + b) as usize)
}
_ => None,
}
}
pub(crate) fn esc_bits(mag: u32) -> usize {
let n = 31 - mag.leading_zeros() as usize; (n - 4) + 1 + n
}
#[cfg_attr(not(test), allow(dead_code))] pub fn spectral_bits(cb: u8, v: &[i32]) -> Option<usize> {
let idx = tuple_index(cb, v)?;
let (len, _) = tables(cb)?;
let mut bits = usize::from(*len.get(idx)?);
if unsigned_book(cb) {
bits += v.iter().filter(|&&x| x != 0).count();
}
if cb == 11 {
for &x in v {
let mag = x.unsigned_abs();
if mag >= 16 {
bits += esc_bits(mag);
}
}
}
Some(bits)
}
pub fn spectral_emit(cb: u8, v: &[i32], w: &mut BitWriter) {
let Some(idx) = tuple_index(cb, v) else {
return;
};
let Some((len, code)) = tables(cb) else {
return;
};
let Some((&l, &c)) = len.get(idx).zip(code.get(idx)) else {
return;
};
w.write(u32::from(c), u32::from(l));
if unsigned_book(cb) {
for &x in v {
if x != 0 {
w.write_bit(x < 0);
}
}
}
if cb == 11 {
for &x in v {
let mag = x.unsigned_abs();
if mag >= 16 {
let n = 31 - mag.leading_zeros(); for _ in 4..n {
w.write_bit(true);
}
w.write_bit(false);
w.write(mag - (1 << n), n);
}
}
}
}
pub fn sf_delta_bits(delta: i32) -> usize {
usize::from(SF_LEN[(delta.clamp(-60, 60) + 60) as usize])
}
pub fn sf_emit_delta(w: &mut BitWriter, delta: i32) {
let idx = (delta.clamp(-60, 60) + 60) as usize;
w.write(SF_CODE[idx], u32::from(SF_LEN[idx]));
}
#[cfg(test)]
#[path = "enc_huff_tests.rs"]
mod enc_huff_tests;