use super::bits::BitWriter;
use super::enc_group::{self, Grouping};
use super::enc_huff::{sf_delta_bits, sf_emit_delta};
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::enc_tns::EncTns;
use super::ics::WindowSequence;
use super::section::has_spectral;
use super::swb::{LONG_WINDOW_LEN, SHORT_WINDOW_LEN};
#[path = "enc_short_win.rs"]
mod win;
pub use win::{ShortWindows, spectra};
#[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,
tns: &EncTns,
grouping: Grouping,
) -> usize {
let n_sfb = q.n_sfb;
let mut win_coded = [false; MAX_FLAT_SHORT];
let mut win_tq = [0.0f32; MAX_FLAT_SHORT];
let mut win_forced = [false; MAX_FLAT_SHORT];
let mut win_e = [0.0f32; MAX_FLAT_SHORT];
let mut win_n = [0.0f32; MAX_FLAT_SHORT];
let mut win_s = [0.0f32; MAX_FLAT_SHORT];
for w in 0..MAX_GROUPS {
let (lo, hi) = (w * n_sfb, (w + 1) * n_sfb);
psy.analyze(
&spec[w * SHORT_WINDOW_LEN..(w + 1) * SHORT_WINDOW_LEN],
offsets,
crate::engine::enc_frame::TARGET_Q,
&mut win_coded[lo..hi],
&mut win_tq[lo..hi],
);
let (e, n, s) = psy.bands();
win_e[lo..hi].copy_from_slice(&e[..n_sfb]);
win_n[lo..hi].copy_from_slice(&n[..n_sfb]);
win_s[lo..hi].copy_from_slice(&s[..n_sfb]);
if tns.short().window_on(w) {
for b in 0..n_sfb.min(14) {
win_forced[lo + b] = !win_coded[lo + b];
win_coded[lo + b] = true;
win_tq[lo + b] = crate::engine::enc_frame::TARGET_Q;
}
}
}
let mut peaks = [0.0f32; MAX_FLAT_SHORT];
enc_quant::band_peaks_short(spec, offsets, n_sfb, &mut peaks);
q.set_grouping(grouping);
let mut gpeaks = [0.0f32; MAX_FLAT_SHORT];
enc_group::fold_windows(
grouping,
n_sfb,
&win_coded,
&win_tq,
&peaks,
&mut q.coded,
tq,
&mut gpeaks,
);
let n = q.n_groups * n_sfb;
let (mut ge, mut gn, mut gs) = (
[0.0f32; MAX_FLAT_SHORT],
[0.0f32; MAX_FLAT_SHORT],
[0.0f32; MAX_FLAT_SHORT],
);
let mut gw = [0.0f32; MAX_FLAT_SHORT];
let mut gforced = [false; MAX_FLAT_SHORT];
let mut wbase = 0usize;
for g in 0..q.n_groups {
for k in 0..q.group_len[g] as usize {
for b in 0..n_sfb {
let (o, i) = (g * n_sfb + b, (wbase + k) * n_sfb + b);
ge[o] += win_e[i];
gn[o] += win_n[i];
gs[o] += win_s[i];
gw[o] += f32::from(offsets[b + 1] - offsets[b]);
gforced[o] |= win_forced[i];
}
}
wbase += q.group_len[g] as usize;
}
let cap = *tq;
crate::engine::enc_alloc::noise_targets(
&gpeaks,
&ge,
&gs,
&gn,
&gw,
&cap,
offset,
n,
&mut q.coded,
tq,
);
for o in 0..n {
if gforced[o] && !q.coded[o] && gpeaks[o] > 0.0 {
q.coded[o] = true;
tq[o] = 1.0;
}
}
enc_quant::raw_scalefactors_short(&gpeaks, tq, 0, q);
*gain = enc_quant::normalize_sf_short(q);
enc_quant::quantize_short_cached(spec, offsets, q);
*books = plan_books_short(q);
channel_body_bits_short(books, q, *gain, standalone, tns)
}
#[allow(clippy::too_many_arguments)]
pub fn emit_frame(
offsets: &[u16],
chans: &[QuantShort],
books: &[[u8; MAX_FLAT_SHORT]],
gains: &[u8],
ms: &MsBands,
tns: &[EncTns],
channels: usize,
fill: &[u8],
pad_fill: usize,
out: &mut Vec<u8>,
) -> usize {
let mut w = BitWriter::from_vec(std::mem::take(out));
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, &tns[0],
);
} 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,
chans[0].grouping_bits(),
);
ms.emit(&mut w); for ch in 0..channels {
emit_channel_body_short(
&mut w, offsets, &books[ch], &chans[ch], gains[ch], false, &tns[ch],
);
}
}
if !fill.is_empty() {
let _ = super::enc_sbr_bits::write_fill_element(&mut w, fill); }
super::enc_pad::write_pad_fill(&mut w, pad_fill); let end_at = w.bit_len() as usize;
w.write(7, 3); *out = w.finish();
end_at
}
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];
let n = q.n_groups * q.n_sfb;
let mut eff = q.coded;
for (e, &z) in eff.iter_mut().zip(q.zero.iter()).take(n) {
*e &= !z;
}
let coded = if super::enc_quant::dpcm_ok(&q.sf, &eff, n) {
eff
} else {
q.coded
};
for g in 0..q.n_groups {
let lo = g * q.n_sfb;
plan_books_into(
&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,
n_groups: usize,
) {
for g in 0..n_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 = q.n_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 channel_body_bits_short(
sfb_cb: &[u8; MAX_FLAT_SHORT],
q: &QuantShort,
global_gain: u8,
standalone: bool,
tns: &EncTns,
) -> usize {
let mut bits = 8; if standalone {
bits += 15; }
for g in 0..q.n_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 = q.n_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 += 2 + tns.bits(); 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,
tns: &EncTns,
) {
w.write(u32::from(global_gain), 8);
if standalone {
emit_ics_info(
w,
WindowSequence::EightShort,
q.n_sfb as u8,
q.grouping_bits(),
);
}
emit_section_data_short(w, sfb_cb, q.n_sfb, q.n_groups);
emit_scale_factors_short(w, sfb_cb, q, global_gain);
w.write_bit(false); tns.emit(w);
w.write_bit(false); enc_group::emit_spectral_short(w, offsets, sfb_cb, q);
}
#[cfg(test)]
#[path = "enc_short_tests.rs"]
mod enc_short_tests;