use super::bits::BitWriter;
use super::enc_huff::{sf_delta_bits, sf_emit_delta, spectral_emit};
use super::enc_ms::MsBands;
use super::enc_psy::Psy;
use super::enc_quant::{self, MAX_FLAT_SHORT, MAX_GROUPS, QuantShort};
use super::enc_section::{emit_ics_info, plan_books_into};
use super::filterbank::window_left;
use super::ics::WindowSequence;
use super::mdct::mdct_into_f32;
use super::section::has_spectral;
use super::swb::{LONG_WINDOW_LEN, SHORT_WINDOW_LEN};
const SHORT_START: usize = (2 * LONG_WINDOW_LEN - 2 * SHORT_WINDOW_LEN) / 4;
const SHORT_HOP: usize = SHORT_WINDOW_LEN;
pub struct ShortWindows {
pub start: Box<[f32; 2 * LONG_WINDOW_LEN]>,
pub stop: Box<[f32; 2 * LONG_WINDOW_LEN]>,
pub short: Box<[f32; 2 * SHORT_WINDOW_LEN]>,
}
impl ShortWindows {
pub fn new() -> Self {
let long = window_left(2 * LONG_WINDOW_LEN, super::ics::WindowShape::Kbd);
let short = window_left(2 * SHORT_WINDOW_LEN, super::ics::WindowShape::Kbd);
let mut start = Box::new([0.0f32; 2 * LONG_WINDOW_LEN]);
let mut stop = Box::new([0.0f32; 2 * LONG_WINDOW_LEN]);
for i in 0..LONG_WINDOW_LEN {
start[i] = long[i] * 32768.0;
stop[LONG_WINDOW_LEN + i] = long[LONG_WINDOW_LEN - 1 - i] * 32768.0;
}
let flat = SHORT_START; for i in 0..flat {
start[LONG_WINDOW_LEN + i] = 32768.0;
stop[SHORT_START + SHORT_WINDOW_LEN + i] = 32768.0;
}
for m in 0..SHORT_WINDOW_LEN {
start[LONG_WINDOW_LEN + flat + m] = short[SHORT_WINDOW_LEN - 1 - m] * 32768.0;
stop[SHORT_START + m] = short[m] * 32768.0;
}
let mut sw = Box::new([0.0f32; 2 * SHORT_WINDOW_LEN]);
for i in 0..SHORT_WINDOW_LEN {
sw[i] = short[i] * 32768.0;
sw[2 * SHORT_WINDOW_LEN - 1 - i] = short[i] * 32768.0;
}
Self {
start,
stop,
short: sw,
}
}
}
pub fn spectra(
block: &[f32; 2 * LONG_WINDOW_LEN],
windows: &ShortWindows,
spec: &mut [f32; LONG_WINDOW_LEN],
) {
let mut seg = [0.0f32; 2 * SHORT_WINDOW_LEN];
for w in 0..MAX_GROUPS {
let base = SHORT_START + w * SHORT_HOP;
for (s, (&x, &win)) in seg.iter_mut().zip(
block[base..base + 2 * SHORT_WINDOW_LEN]
.iter()
.zip(windows.short.iter()),
) {
*s = x * win;
}
mdct_into_f32(
&seg,
&mut spec[w * SHORT_WINDOW_LEN..(w + 1) * SHORT_WINDOW_LEN],
);
}
}
#[allow(clippy::too_many_arguments)]
pub fn channel_build(
psy: &mut Psy,
offsets: &[u16],
spec: &[f32; LONG_WINDOW_LEN],
offset: i32,
q: &mut QuantShort,
tq: &mut [f32; MAX_FLAT_SHORT],
books: &mut [u8; MAX_FLAT_SHORT],
gain: &mut u8,
standalone: bool,
) -> usize {
let n_sfb = q.n_sfb;
for w in 0..MAX_GROUPS {
psy.analyze(
&spec[w * SHORT_WINDOW_LEN..(w + 1) * SHORT_WINDOW_LEN],
offsets,
crate::engine::enc_frame::TARGET_Q,
&mut q.coded[w * n_sfb..(w + 1) * n_sfb],
&mut tq[w * n_sfb..(w + 1) * n_sfb],
);
}
let mut peaks = [0.0f32; MAX_FLAT_SHORT];
enc_quant::band_peaks_short(spec, offsets, n_sfb, &mut peaks);
enc_quant::raw_scalefactors_short(&peaks, tq, offset, q);
*gain = enc_quant::normalize_sf_short(q);
enc_quant::quantize_short(spec, offsets, q);
*books = plan_books_short(q);
channel_body_bits_short(books, q, *gain, standalone)
}
pub fn frame_bits(
chans: &[QuantShort],
books: &[[u8; MAX_FLAT_SHORT]],
gains: &[u8],
channels: usize,
ms_overhead: usize,
) -> usize {
let mut total = 3 + 4 + 3 + 7; if channels == 2 {
total += 1 + 15 + ms_overhead; }
for ch in 0..channels {
total += channel_body_bits_short(&books[ch], &chans[ch], gains[ch], channels == 1);
}
total
}
pub fn drop_bands_until(
chans: &mut [QuantShort],
books: &mut [[u8; MAX_FLAT_SHORT]],
gains: &[u8],
channels: usize,
cap: usize,
ms_overhead: usize,
) {
loop {
let total = frame_bits(chans, books, gains, channels, ms_overhead);
if total <= cap {
return;
}
let mut hit: Option<(usize, usize)> = None;
for (ch, q) in chans.iter().enumerate().take(channels) {
let n = MAX_GROUPS * q.n_sfb;
if let Some(b) = q.coded[..n].iter().rposition(|&c| c) {
hit = Some((ch, b));
break;
}
}
let Some((ch, b)) = hit else { return };
chans[ch].coded[b] = false;
books[ch] = plan_books_short(&chans[ch]);
}
}
pub fn emit_frame(
offsets: &[u16],
chans: &[QuantShort],
books: &[[u8; MAX_FLAT_SHORT]],
gains: &[u8],
ms: &MsBands,
channels: usize,
) -> Vec<u8> {
let mut w = BitWriter::new();
if channels == 1 {
w.write(0, 3); w.write(0, 4); emit_channel_body_short(&mut w, offsets, &books[0], &chans[0], gains[0], true);
} else {
w.write(1, 3); w.write(0, 4); w.write_bit(true); emit_ics_info(&mut w, WindowSequence::EightShort, chans[0].n_sfb as u8);
ms.emit(&mut w); for ch in 0..channels {
emit_channel_body_short(&mut w, offsets, &books[ch], &chans[ch], gains[ch], false);
}
}
w.write(7, 3); w.finish()
}
fn section_header_bits_short(len: usize) -> usize {
4 + 3 * (len / 7 + 1)
}
pub fn plan_books_short(q: &QuantShort) -> [u8; MAX_FLAT_SHORT] {
let mut sfb_cb = [0u8; MAX_FLAT_SHORT];
for g in 0..MAX_GROUPS {
let lo = g * q.n_sfb;
plan_books_into(
&q.coded[lo..lo + q.n_sfb],
&q.bits[lo..lo + q.n_sfb],
q.n_sfb,
&mut sfb_cb[lo..lo + q.n_sfb],
section_header_bits_short,
);
}
sfb_cb
}
pub fn emit_section_data_short(w: &mut BitWriter, sfb_cb: &[u8; MAX_FLAT_SHORT], n_sfb: usize) {
for g in 0..MAX_GROUPS {
let row = &sfb_cb[g * n_sfb..(g + 1) * n_sfb];
let mut k = 0usize;
while k < n_sfb {
let cb = row[k];
let mut len = 1usize;
while k + len < n_sfb && row[k + len] == cb {
len += 1;
}
w.write(u32::from(cb), 4);
let mut rem = len;
while rem >= 7 {
w.write(7, 3);
rem -= 7;
}
w.write(rem as u32, 3);
k += len;
}
}
}
pub fn emit_scale_factors_short(
w: &mut BitWriter,
sfb_cb: &[u8; MAX_FLAT_SHORT],
q: &QuantShort,
global_gain: u8,
) {
let mut prev = i32::from(global_gain);
let n = MAX_GROUPS * q.n_sfb;
let bands = sfb_cb.iter().zip(q.sf.iter()).take(n);
for (&cb, &sf) in bands {
if !has_spectral(cb) {
continue;
}
sf_emit_delta(w, sf - prev);
prev = sf;
}
}
pub fn emit_spectral_short(
w: &mut BitWriter,
offsets: &[u16],
sfb_cb: &[u8; MAX_FLAT_SHORT],
q: &QuantShort,
) {
for g in 0..MAX_GROUPS {
for b in 0..q.n_sfb {
let cb = sfb_cb[g * q.n_sfb + b];
if !has_spectral(cb) {
continue;
}
let lo = g * SHORT_WINDOW_LEN + usize::from(offsets[b]);
let hi = g * SHORT_WINDOW_LEN + usize::from(offsets[b + 1]);
let step = if cb <= 4 { 4 } else { 2 };
let mut i = lo;
while i < hi {
spectral_emit(cb, &q.quant[i..i + step], w);
i += step;
}
}
}
}
pub fn channel_body_bits_short(
sfb_cb: &[u8; MAX_FLAT_SHORT],
q: &QuantShort,
global_gain: u8,
standalone: bool,
) -> usize {
let mut bits = 8; if standalone {
bits += 15; }
for g in 0..MAX_GROUPS {
let row = &sfb_cb[g * q.n_sfb..(g + 1) * q.n_sfb];
let mut k = 0usize;
while k < q.n_sfb {
let mut len = 1usize;
while k + len < q.n_sfb && row[k + len] == row[k] {
len += 1;
}
bits += section_header_bits_short(len);
k += len;
}
}
let n = MAX_GROUPS * q.n_sfb;
let mut prev = i32::from(global_gain);
let bands = sfb_cb.iter().zip(q.sf.iter()).zip(q.bits.iter()).take(n);
for ((&cb, &sf), row) in bands {
if !has_spectral(cb) {
continue;
}
bits += sf_delta_bits(sf - prev);
prev = sf;
bits += row[usize::from(cb)] as usize;
}
bits += 3; bits
}
pub fn emit_channel_body_short(
w: &mut BitWriter,
offsets: &[u16],
sfb_cb: &[u8; MAX_FLAT_SHORT],
q: &QuantShort,
global_gain: u8,
standalone: bool,
) {
w.write(u32::from(global_gain), 8);
if standalone {
emit_ics_info(w, WindowSequence::EightShort, q.n_sfb as u8);
}
emit_section_data_short(w, sfb_cb, q.n_sfb);
emit_scale_factors_short(w, sfb_cb, q, global_gain);
w.write_bit(false); w.write_bit(false); w.write_bit(false); emit_spectral_short(w, offsets, sfb_cb, q);
}
#[cfg(test)]
#[path = "enc_short_tests.rs"]
mod enc_short_tests;