#![allow(dead_code)]
use alloc::vec;
use alloc::vec::Vec;
#[cfg(test)]
extern crate std;
use core::f32::consts::SQRT_2;
use crate::celt::entcode::ec_tell_frac;
#[cfg(feature = "fixed_point")]
use crate::celt::fixed_arch::{
DB_SHIFT, EPSILON as FIXED_EPSILON, NORM_SCALING as FIXED_NORM_SCALING, Q31_ONE,
};
#[cfg(feature = "fixed_point")]
use crate::celt::fixed_ops::{
abs32, add32, extract16, mult16_16, mult16_16_q15, mult16_32_q15, mult32_32_q31, pshr32,
qconst16, qconst32, shl32, shr32, sub32, vshr32,
};
#[cfg(feature = "fixed_point")]
use crate::celt::float_cast::{float2int, float2int16};
#[cfg(feature = "fixed_point")]
use crate::celt::math::{celt_ilog2, celt_zlog2};
#[cfg(feature = "fixed_point")]
use crate::celt::math_fixed::{
celt_rcp as celt_rcp_fixed, celt_rsqrt_norm as celt_rsqrt_norm_fixed,
celt_sqrt as celt_sqrt_fixed,
};
#[cfg(feature = "fixed_point")]
use crate::celt::pitch::dual_inner_prod_fixed;
#[cfg(not(feature = "fixed_point"))]
use crate::celt::renormalise_vector;
#[cfg(feature = "fixed_point")]
use crate::celt::types::{
FixedCeltEner, FixedCeltGlog, FixedCeltNorm, FixedCeltSig, FixedOpusVal32,
};
#[cfg(not(feature = "fixed_point"))]
use crate::celt::vq::{alg_quant, alg_unquant};
#[cfg(feature = "fixed_point")]
use crate::celt::vq::{alg_quant_fixed, alg_unquant_fixed, renormalise_vector_fixed};
use crate::celt::{
BITRES, EcDec, EcEnc, EcEncSnapshot, SPREAD_AGGRESSIVE, SPREAD_LIGHT, SPREAD_NONE,
SPREAD_NORMAL, celt_exp2, celt_inner_prod, celt_rsqrt, celt_rsqrt_norm, celt_sqrt, celt_sudiv,
celt_udiv, dual_inner_prod, ec_ilog,
math::{isqrt32, mul_add_f32},
quant_bands::E_MEANS,
rate::{QTHETA_OFFSET, QTHETA_OFFSET_TWOPHASE, bits2pulses, get_pulses, pulses2bits},
types::{CeltGlog, CeltSig, OpusCustomMode, OpusVal16, OpusVal32},
vq::stereo_itheta,
};
use core::convert::TryFrom;
const EPSILON: f32 = 1e-15;
const MAX_CELT_BAND_SIZE: usize = 208;
const NORM_SCALING: OpusVal16 = 1.0;
#[derive(Debug, Clone)]
pub(crate) struct BandCtx<'mode, 'band> {
pub encode: bool,
pub resynth: bool,
pub mode: &'mode OpusCustomMode<'mode>,
pub band: usize,
pub intensity: usize,
pub spread: i32,
pub tf_change: i32,
pub remaining_bits: i32,
pub band_e: &'band [CeltGlog],
pub seed: u32,
pub arch: i32,
pub theta_round: i32,
pub disable_inv: bool,
pub avoid_split_noise: bool,
}
pub(crate) enum BandCodingState<'a, 'b> {
Encoder(&'b mut EcEnc<'a>),
Decoder(&'b mut EcDec<'a>),
}
impl<'a, 'b> BandCodingState<'a, 'b> {
#[inline]
fn is_encoder(&self) -> bool {
matches!(self, Self::Encoder(_))
}
#[inline]
fn encode_bits(&mut self, value: u32, bits: u32) {
match self {
Self::Encoder(enc) => enc.enc_bits(value, bits),
Self::Decoder(_) => unreachable!("encoding requested on a decoder"),
}
}
#[inline]
fn decode_bits(&mut self, bits: u32) -> u32 {
match self {
Self::Decoder(dec) => dec.dec_bits(bits),
Self::Encoder(_) => unreachable!("decoding requested on an encoder"),
}
}
#[inline]
fn tell_frac(&self) -> u32 {
match self {
Self::Encoder(enc) => ec_tell_frac(enc.ctx()),
Self::Decoder(dec) => ec_tell_frac(dec.ctx()),
}
}
#[inline]
fn encode_range(&mut self, fl: u32, fh: u32, ft: u32) {
match self {
Self::Encoder(enc) => enc.encode(fl, fh, ft),
Self::Decoder(_) => unreachable!("encoding requested on a decoder"),
}
}
#[inline]
fn decode_range(&mut self, ft: u32) -> u32 {
match self {
Self::Decoder(dec) => dec.decode(ft),
Self::Encoder(_) => unreachable!("decoding requested on an encoder"),
}
}
#[inline]
fn update_range(&mut self, fl: u32, fh: u32, ft: u32) {
match self {
Self::Decoder(dec) => dec.update(fl, fh, ft),
Self::Encoder(_) => unreachable!("decoder update invoked on an encoder"),
}
}
#[inline]
fn encode_uint(&mut self, value: u32, total: u32) {
match self {
Self::Encoder(enc) => enc.enc_uint(value, total),
Self::Decoder(_) => unreachable!("encoding requested on a decoder"),
}
}
#[inline]
fn decode_uint(&mut self, total: u32) -> u32 {
match self {
Self::Decoder(dec) => dec.dec_uint(total),
Self::Encoder(_) => unreachable!("decoding requested on an encoder"),
}
}
#[inline]
fn encode_bit_logp(&mut self, bit: i32, logp: u32) {
match self {
Self::Encoder(enc) => enc.enc_bit_logp(bit, logp),
Self::Decoder(_) => unreachable!("encoding requested on a decoder"),
}
}
#[inline]
fn decode_bit_logp(&mut self, logp: u32) -> i32 {
match self {
Self::Decoder(dec) => dec.dec_bit_logp(logp),
Self::Encoder(_) => unreachable!("decoding requested on an encoder"),
}
}
#[inline]
fn encoder_mut(&mut self) -> &mut EcEnc<'a> {
match self {
Self::Encoder(enc) => enc,
Self::Decoder(_) => unreachable!("encoder access requested on a decoder"),
}
}
#[inline]
fn decoder_mut(&mut self) -> &mut EcDec<'a> {
match self {
Self::Decoder(dec) => dec,
Self::Encoder(_) => unreachable!("decoder access requested on an encoder"),
}
}
#[inline]
fn encoder_snapshot(&self) -> EcEncSnapshot {
match self {
Self::Encoder(enc) => EcEncSnapshot::capture(enc),
Self::Decoder(_) => unreachable!("encoder snapshot requested on a decoder"),
}
}
#[inline]
fn restore_encoder_snapshot(&mut self, snapshot: &EcEncSnapshot) {
match self {
Self::Encoder(enc) => snapshot.restore(enc),
Self::Decoder(_) => unreachable!("encoder restore requested on a decoder"),
}
}
#[cfg(test)]
fn encoder_ctx(&self) -> Option<&crate::celt::entcode::EcCtx<'_>> {
match self {
Self::Encoder(enc) => Some(enc.ctx()),
Self::Decoder(_) => None,
}
}
#[cfg(test)]
fn decoder_ctx(&self) -> Option<&crate::celt::entcode::EcCtx<'_>> {
match self {
Self::Decoder(dec) => Some(dec.ctx()),
Self::Encoder(_) => None,
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct SplitCtx {
pub inv: bool,
pub imid: i32,
pub iside: i32,
pub delta: i32,
pub itheta: i32,
pub qalloc: i32,
}
fn mask_from_bits(bits: i32) -> u32 {
if bits <= 0 {
0
} else if bits >= 32 {
u32::MAX
} else {
(1u32 << bits) - 1
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_theta(
ctx: &mut BandCtx<'_, '_>,
sctx: &mut SplitCtx,
x: &mut [OpusVal16],
y: &mut [OpusVal16],
n: usize,
b: &mut i32,
b_current: i32,
b0: i32,
lm: i32,
stereo: bool,
fill: &mut u32,
coder: &mut BandCodingState<'_, '_>,
) {
debug_assert!(n > 0, "band size must be positive");
debug_assert!(x.len() >= n, "mid buffer shorter than band length");
debug_assert!(y.len() >= n, "side buffer shorter than band length");
let encode = ctx.encode;
let mode = ctx.mode;
let band = ctx.band;
let intensity = ctx.intensity;
let band_e = ctx.band_e;
let log_n = i32::from(mode.log_n[band]);
let pulse_cap = log_n + lm * (1_i32 << BITRES);
let offset = (pulse_cap >> 1)
- if stereo && n == 2 {
QTHETA_OFFSET_TWOPHASE
} else {
QTHETA_OFFSET
};
let mut qn = compute_qn(n as i32, *b, offset, pulse_cap, stereo);
if stereo && band >= intensity {
qn = 1;
}
let mut itheta = if encode {
stereo_itheta(x, y, stereo, n, ctx.arch)
} else {
0
};
let tell_before = coder.tell_frac() as i32;
let mut inv = false;
let imid;
let iside;
let mut delta;
if qn != 1 {
if encode {
if !stereo || ctx.theta_round == 0 {
itheta = ((itheta * qn) + 8192) >> 14;
if !stereo && ctx.avoid_split_noise && itheta > 0 && itheta < qn {
let unquantized = celt_udiv((itheta * 16_384) as u32, qn as u32) as i32;
let mid = i32::from(bitexact_cos(unquantized as i16));
let side = i32::from(bitexact_cos((16_384 - unquantized) as i16));
let log_ratio = bitexact_log2tan(side, mid);
let scale = ((n as i32 - 1) << 7).max(0);
delta = frac_mul16(scale, log_ratio);
if delta > *b {
itheta = qn;
} else if delta < -*b {
itheta = 0;
}
}
} else {
let bias = if itheta > 8192 {
32_767 / qn
} else {
-32_767 / qn
};
let mut down = ((itheta * qn) + bias) >> 14;
down = down.clamp(0, qn - 1);
itheta = if ctx.theta_round < 0 { down } else { down + 1 };
}
}
if stereo && n > 2 {
let p0 = 3;
let mut x_val = itheta;
let x0 = qn / 2;
let ft = p0 * (x0 + 1) + x0;
if encode {
let (fl, fh) = if x_val <= x0 {
(p0 * x_val, p0 * (x_val + 1))
} else {
let base = (x0 + 1) * p0;
(base + (x_val - 1 - x0), base + (x_val - x0))
};
coder.encode_range(fl as u32, fh as u32, ft as u32);
} else {
let fs = coder.decode_range(ft as u32) as i32;
x_val = if fs < (x0 + 1) * p0 {
fs / p0
} else {
x0 + 1 + (fs - (x0 + 1) * p0)
};
let (fl, fh) = if x_val <= x0 {
(p0 * x_val, p0 * (x_val + 1))
} else {
let base = (x0 + 1) * p0;
(base + (x_val - 1 - x0), base + (x_val - x0))
};
coder.update_range(fl as u32, fh as u32, ft as u32);
itheta = x_val;
}
} else if b0 > 1 || stereo {
if encode {
coder.encode_uint(itheta as u32, (qn + 1) as u32);
} else {
itheta = coder.decode_uint((qn + 1) as u32) as i32;
}
} else {
let half_qn = qn >> 1;
let ft = (half_qn + 1) * (half_qn + 1);
if encode {
let (fl, fs) = if itheta <= half_qn {
let fl = (itheta * (itheta + 1)) >> 1;
(fl, itheta + 1)
} else {
let fs = qn + 1 - itheta;
let fl = ft - (((qn + 1 - itheta) * (qn + 2 - itheta)) >> 1);
(fl, fs)
};
coder.encode_range(fl as u32, (fl + fs) as u32, ft as u32);
} else {
let fm = coder.decode_range(ft as u32) as i32;
let threshold = (half_qn * (half_qn + 1)) >> 1;
let (fl, fs);
if fm < threshold {
let root = isqrt32((8 * fm + 1) as u32) as i32;
itheta = (root - 1) >> 1;
fl = (itheta * (itheta + 1)) >> 1;
fs = itheta + 1;
} else {
let root = isqrt32((8 * (ft - fm - 1) + 1) as u32) as i32;
itheta = (2 * (qn + 1) - root) >> 1;
fl = ft - (((qn + 1 - itheta) * (qn + 2 - itheta)) >> 1);
fs = qn + 1 - itheta;
}
coder.update_range(fl as u32, (fl + fs) as u32, ft as u32);
}
}
debug_assert!(itheta >= 0);
if qn > 0 {
itheta = celt_udiv((itheta * 16_384) as u32, qn as u32) as i32;
}
if encode && stereo {
if itheta == 0 {
intensity_stereo(mode, x, y, band_e, band, n);
} else {
let x_band = &mut x[..n];
let y_band = &mut y[..n];
stereo_split(x_band, y_band);
}
}
} else if stereo {
if encode {
inv = itheta > 8_192 && !ctx.disable_inv;
if inv {
for sample in y.iter_mut().take(n) {
*sample = -*sample;
}
}
intensity_stereo(mode, x, y, band_e, band, n);
}
let threshold = 2 << BITRES;
if *b > threshold && ctx.remaining_bits > threshold {
if encode {
coder.encode_bit_logp(if inv { 1 } else { 0 }, 2);
} else {
inv = coder.decode_bit_logp(2) != 0;
}
} else {
inv = false;
}
if ctx.disable_inv {
inv = false;
}
itheta = 0;
}
let tell_after = coder.tell_frac() as i32;
let qalloc = tell_after - tell_before;
*b -= qalloc;
let b_mask = mask_from_bits(b_current);
let band_scale = ((n as i32 - 1) << 7).max(0);
if itheta == 0 {
imid = 32_767;
iside = 0;
*fill &= b_mask;
delta = -16_384;
} else if itheta == 16_384 {
imid = 0;
iside = 32_767;
let shifted = if b_current <= 0 {
0
} else if b_current >= 32 {
u32::MAX
} else {
b_mask << (b_current as u32)
};
*fill &= shifted;
delta = 16_384;
} else {
imid = i32::from(bitexact_cos(itheta as i16));
iside = i32::from(bitexact_cos((16_384 - itheta) as i16));
delta = frac_mul16(band_scale, bitexact_log2tan(iside, imid));
}
sctx.inv = inv;
sctx.imid = imid;
sctx.iside = iside;
sctx.delta = delta;
sctx.itheta = itheta;
sctx.qalloc = qalloc;
}
const ORDERY_TABLES: [&[usize]; 4] = [
&[1, 0],
&[3, 0, 2, 1],
&[7, 0, 4, 3, 6, 1, 5, 2],
&[15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5],
];
fn hadamard_ordery(stride: usize) -> Option<&'static [usize]> {
match stride {
2 => Some(ORDERY_TABLES[0]),
4 => Some(ORDERY_TABLES[1]),
8 => Some(ORDERY_TABLES[2]),
16 => Some(ORDERY_TABLES[3]),
_ => None,
}
}
#[inline]
fn frac_mul16(a: i32, b: i32) -> i32 {
let a = a as i16;
let b = b as i16;
(16_384 + i32::from(a) * i32::from(b)) >> 15
}
#[must_use]
pub(crate) fn bitexact_cos(x: i16) -> i16 {
let tmp = (4_096 + i32::from(x) * i32::from(x)) >> 13;
let mut x2 = tmp;
x2 = (32_767 - x2) + frac_mul16(x2, -7_651 + frac_mul16(x2, 8_277 + frac_mul16(-626, x2)));
(1 + x2) as i16
}
#[must_use]
pub(crate) fn bitexact_log2tan(isin: i32, icos: i32) -> i32 {
let lc = ec_ilog(icos as u32) as i32;
let ls = ec_ilog(isin as u32) as i32;
let shift_cos = 15 - lc;
debug_assert!(shift_cos >= 0);
let icos = icos << shift_cos;
let shift_sin = 15 - ls;
debug_assert!(shift_sin >= 0);
let isin = isin << shift_sin;
((ls - lc) << 11) + frac_mul16(isin, frac_mul16(isin, -2_597) + 7_932)
- frac_mul16(icos, frac_mul16(icos, -2_597) + 7_932)
}
#[must_use]
pub(crate) fn hysteresis_decision(
value: OpusVal16,
thresholds: &[OpusVal16],
hysteresis: &[OpusVal16],
prev: usize,
) -> usize {
debug_assert_eq!(thresholds.len(), hysteresis.len());
let count = thresholds.len();
debug_assert!(prev <= count, "prev index must be within the table bounds");
let mut index = 0;
while index < count {
if value < thresholds[index] {
break;
}
index += 1;
}
if prev < count && index > prev && value < thresholds[prev] + hysteresis[prev] {
index = prev;
}
if prev > 0 && index < prev && value > thresholds[prev - 1] - hysteresis[prev - 1] {
index = prev;
}
index
}
#[must_use]
#[inline]
pub(crate) fn celt_lcg_rand(seed: u32) -> u32 {
seed.wrapping_mul(1_664_525).wrapping_add(1_013_904_223)
}
pub(crate) fn compute_qn(n: i32, b: i32, offset: i32, pulse_cap: i32, stereo: bool) -> i32 {
const EXP2_TABLE8: [i32; 8] = [16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048];
let mut n2 = 2 * n - 1;
if stereo && n == 2 {
n2 -= 1;
}
let mut qb = celt_sudiv(b + n2 * offset, n2);
let pulse_guard = b - pulse_cap - (4 << BITRES);
qb = qb.min(pulse_guard);
qb = qb.min(8 << BITRES);
let threshold = (1 << BITRES) >> 1;
let qn = if qb < threshold {
1
} else {
let index = (qb & 0x7) as usize;
let shift = 14 - (qb >> BITRES);
let mut value = EXP2_TABLE8[index] >> shift;
value = (value + 1) >> 1;
value << 1
};
debug_assert!(qn <= 256);
qn
}
fn quant_band_n1_channel(
ctx: &mut BandCtx<'_, '_>,
samples: &mut [OpusVal16],
coder: &mut BandCodingState<'_, '_>,
) {
assert!(
!samples.is_empty(),
"quant_band_n1 expects non-empty coefficient slices",
);
let mut sign = 0;
let bit_budget = 1_i32 << BITRES;
if ctx.remaining_bits >= bit_budget {
if ctx.encode {
debug_assert!(coder.is_encoder());
sign = i32::from(samples[0] < 0.0);
coder.encode_bits(sign as u32, 1);
} else {
debug_assert!(!coder.is_encoder());
sign = coder.decode_bits(1) as i32;
}
ctx.remaining_bits -= bit_budget;
}
if ctx.resynth {
samples[0] = if sign != 0 {
-NORM_SCALING
} else {
NORM_SCALING
};
}
}
pub(crate) fn quant_band_n1(
ctx: &mut BandCtx<'_, '_>,
x: &mut [OpusVal16],
y: Option<&mut [OpusVal16]>,
lowband_out: Option<&mut [OpusVal16]>,
coder: &mut BandCodingState<'_, '_>,
) -> usize {
debug_assert_eq!(ctx.encode, coder.is_encoder());
quant_band_n1_channel(ctx, x, coder);
if let Some(y_samples) = y {
quant_band_n1_channel(ctx, y_samples, coder);
}
if let Some(lowband) = lowband_out.filter(|lowband| !lowband.is_empty()) {
lowband[0] = x[0];
}
1
}
#[cfg(feature = "fixed_point")]
#[inline]
fn gain_to_q31(gain: OpusVal32) -> i32 {
qconst32(f64::from(gain), 31)
}
#[cfg(feature = "fixed_point")]
#[inline]
fn fixed_norm_to_float(value: FixedCeltNorm) -> OpusVal16 {
f32::from(value) * (1.0 / 32_768.0)
}
#[allow(clippy::too_many_arguments)]
#[cfg(not(feature = "fixed_point"))]
fn pvq_alg_quant_runtime(
x: &mut [OpusVal16],
n: usize,
k: i32,
spread: i32,
block_count: usize,
enc: &mut EcEnc<'_>,
gain: OpusVal32,
resynth: bool,
arch: i32,
) -> u32 {
alg_quant(x, n, k, spread, block_count, enc, gain, resynth, arch)
}
#[allow(clippy::too_many_arguments)]
#[cfg(feature = "fixed_point")]
fn pvq_alg_quant_runtime(
x: &mut [OpusVal16],
n: usize,
k: i32,
spread: i32,
block_count: usize,
enc: &mut EcEnc<'_>,
gain: OpusVal32,
resynth: bool,
arch: i32,
) -> u32 {
assert!(x.len() >= n, "input vector shorter than band size");
let mut fixed_x: Vec<FixedCeltNorm> = x
.iter()
.take(n)
.map(|&sample| float2int16(sample))
.collect();
let mask = alg_quant_fixed(
&mut fixed_x,
n,
k,
spread,
block_count,
enc,
gain_to_q31(gain),
resynth,
arch,
);
for (dst, &sample) in x.iter_mut().take(n).zip(fixed_x.iter()) {
*dst = fixed_norm_to_float(sample);
}
mask
}
#[cfg(not(feature = "fixed_point"))]
fn pvq_alg_unquant_runtime(
x: &mut [OpusVal16],
n: usize,
k: i32,
spread: i32,
block_count: usize,
dec: &mut EcDec<'_>,
gain: OpusVal32,
) -> u32 {
alg_unquant(x, n, k, spread, block_count, dec, gain)
}
#[cfg(feature = "fixed_point")]
fn pvq_alg_unquant_runtime(
x: &mut [OpusVal16],
n: usize,
k: i32,
spread: i32,
block_count: usize,
dec: &mut EcDec<'_>,
gain: OpusVal32,
) -> u32 {
assert!(x.len() >= n, "input vector shorter than band size");
let mut fixed_x = vec![0i16; n];
let mask = alg_unquant_fixed(
&mut fixed_x,
n,
k,
spread,
block_count,
dec,
gain_to_q31(gain),
);
for (dst, &sample) in x.iter_mut().take(n).zip(fixed_x.iter()) {
*dst = fixed_norm_to_float(sample);
}
mask
}
#[cfg(not(feature = "fixed_point"))]
fn pvq_renormalise_runtime(x: &mut [OpusVal16], n: usize, gain: OpusVal32, arch: i32) {
renormalise_vector(x, n, gain, arch);
}
#[cfg(feature = "fixed_point")]
fn pvq_renormalise_runtime(x: &mut [OpusVal16], n: usize, gain: OpusVal32, arch: i32) {
assert!(x.len() >= n, "input vector shorter than band size");
let mut fixed_x: Vec<FixedCeltNorm> = x
.iter()
.take(n)
.map(|&sample| float2int16(sample))
.collect();
renormalise_vector_fixed(&mut fixed_x, n, gain_to_q31(gain), arch);
for (dst, &sample) in x.iter_mut().take(n).zip(fixed_x.iter()) {
*dst = fixed_norm_to_float(sample);
}
}
#[cfg(feature = "fixed_point")]
#[derive(Debug, Clone)]
struct FixedDecodeBandCtx<'a> {
mode: &'a OpusCustomMode<'a>,
band: usize,
intensity: usize,
spread: i32,
tf_change: i32,
remaining_bits: i32,
seed: u32,
arch: i32,
disable_inv: bool,
avoid_split_noise: bool,
resynth: bool,
}
#[cfg(feature = "fixed_point")]
fn special_hybrid_folding_fixed(
mode: &OpusCustomMode<'_>,
norm: &mut [FixedCeltNorm],
norm2: Option<&mut [FixedCeltNorm]>,
start: usize,
m: usize,
dual_stereo: bool,
) {
let e_bands = mode.e_bands;
let n1 = m * (e_bands[start + 1] - e_bands[start]) as usize;
let n2 = m * (e_bands[start + 2] - e_bands[start + 1]) as usize;
if n2 <= n1 {
return;
}
let copy_len = n2 - n1;
let src_start = 2 * n1 - n2;
let temp: Vec<FixedCeltNorm> = norm[src_start..src_start + copy_len].to_vec();
norm[n1..n1 + copy_len].copy_from_slice(&temp);
if let (true, Some(norm2)) = (dual_stereo, norm2) {
let temp2: Vec<FixedCeltNorm> = norm2[src_start..src_start + copy_len].to_vec();
norm2[n1..n1 + copy_len].copy_from_slice(&temp2);
}
}
#[cfg(feature = "fixed_point")]
fn deinterleave_hadamard_fixed(x: &mut [FixedCeltNorm], n0: usize, stride: usize, hadamard: bool) {
if stride == 0 {
return;
}
let n = n0.checked_mul(stride).expect("stride * n0 overflowed");
assert!(x.len() >= n, "input buffer too small for deinterleave");
if n == 0 {
return;
}
let mut tmp = vec![0i16; n];
if hadamard {
let ordery = hadamard_ordery(stride)
.expect("hadamard interleave only defined for strides of 2, 4, 8, or 16");
for (i, &ord) in ordery.iter().enumerate() {
for j in 0..n0 {
tmp[ord * n0 + j] = x[j * stride + i];
}
}
} else {
for i in 0..stride {
for j in 0..n0 {
tmp[i * n0 + j] = x[j * stride + i];
}
}
}
x[..n].copy_from_slice(&tmp);
}
#[cfg(feature = "fixed_point")]
fn interleave_hadamard_fixed(x: &mut [FixedCeltNorm], n0: usize, stride: usize, hadamard: bool) {
if stride == 0 {
return;
}
let n = n0.checked_mul(stride).expect("stride * n0 overflowed");
assert!(x.len() >= n, "input buffer too small for interleave");
if n == 0 {
return;
}
let mut tmp = vec![0i16; n];
if hadamard {
let ordery = hadamard_ordery(stride)
.expect("hadamard interleave only defined for strides of 2, 4, 8, or 16");
for (i, &ord) in ordery.iter().enumerate() {
for j in 0..n0 {
tmp[j * stride + i] = x[ord * n0 + j];
}
}
} else {
for i in 0..stride {
for j in 0..n0 {
tmp[j * stride + i] = x[i * n0 + j];
}
}
}
x[..n].copy_from_slice(&tmp);
}
#[cfg(feature = "fixed_point")]
fn haar1_fixed(x: &mut [FixedCeltNorm], n0: usize, stride: usize) {
if stride == 0 || n0 < 2 {
return;
}
let half = n0 / 2;
if half == 0 {
return;
}
let required = stride * n0;
assert!(
x.len() >= required,
"haar1 expects at least stride * n0 coefficients"
);
let scale = qconst16(core::f64::consts::FRAC_1_SQRT_2, 15);
for i in 0..stride {
for j in 0..half {
let idx0 = stride * (2 * j) + i;
let idx1 = idx0 + stride;
let tmp1 = mult16_16(scale, x[idx0]);
let tmp2 = mult16_16(scale, x[idx1]);
x[idx0] = extract16(pshr32(add32(tmp1, tmp2), 15));
x[idx1] = extract16(pshr32(sub32(tmp1, tmp2), 15));
}
}
}
#[cfg(feature = "fixed_point")]
fn stereo_merge_fixed(x: &mut [FixedCeltNorm], y: &mut [FixedCeltNorm], mid: FixedOpusVal32) {
assert_eq!(
x.len(),
y.len(),
"stereo_merge expects slices of equal length"
);
if x.is_empty() {
return;
}
let (mut cross, side_energy) = dual_inner_prod_fixed(y, x, y);
cross = mult32_32_q31(mid, cross);
let mid_energy = shr32(mult32_32_q31(mid, mid), 3);
let el = add32(add32(mid_energy, side_energy), -2 * cross);
let er = add32(add32(mid_energy, side_energy), 2 * cross);
if er < qconst32(6e-4, 28) || el < qconst32(6e-4, 28) {
y.copy_from_slice(x);
return;
}
let mut kl = celt_ilog2(el) >> 1;
let mut kr = celt_ilog2(er) >> 1;
let t_left = vshr32(el, ((kl - 7) << 1) as i32);
let lgain = celt_rsqrt_norm_fixed(t_left);
let t_right = vshr32(er, ((kr - 7) << 1) as i32);
let rgain = celt_rsqrt_norm_fixed(t_right);
if kl < 7 {
kl = 7;
}
if kr < 7 {
kr = 7;
}
for (left, right) in x.iter_mut().zip(y.iter_mut()) {
let l = extract16(mult32_32_q31(mid, i32::from(*left)));
let r = *right;
*left = extract16(pshr32(mult16_16(lgain, l.wrapping_sub(r)), (kl + 1) as u32));
*right = extract16(pshr32(mult16_16(rgain, l.wrapping_add(r)), (kr + 1) as u32));
}
}
#[cfg(feature = "fixed_point")]
fn compute_theta_decode_fixed(
ctx: &mut FixedDecodeBandCtx<'_>,
sctx: &mut SplitCtx,
n: usize,
b: &mut i32,
b_current: i32,
b0: i32,
lm: i32,
stereo: bool,
fill: &mut u32,
coder: &mut BandCodingState<'_, '_>,
) {
let band = ctx.band;
let pulse_cap = i32::from(ctx.mode.log_n[band]) + lm * (1_i32 << BITRES);
let offset = (pulse_cap >> 1)
- if stereo && n == 2 {
QTHETA_OFFSET_TWOPHASE
} else {
QTHETA_OFFSET
};
let mut qn = compute_qn(n as i32, *b, offset, pulse_cap, stereo);
if stereo && band >= ctx.intensity {
qn = 1;
}
let mut itheta = 0i32;
let tell_before = coder.tell_frac() as i32;
let mut inv = false;
if qn != 1 {
if stereo && n > 2 {
let p0 = 3;
let x0 = qn / 2;
let ft = p0 * (x0 + 1) + x0;
let fs = coder.decode_range(ft as u32) as i32;
let x_val = if fs < (x0 + 1) * p0 {
fs / p0
} else {
x0 + 1 + (fs - (x0 + 1) * p0)
};
let (fl, fh) = if x_val <= x0 {
(p0 * x_val, p0 * (x_val + 1))
} else {
let base = (x0 + 1) * p0;
(base + (x_val - 1 - x0), base + (x_val - x0))
};
coder.update_range(fl as u32, fh as u32, ft as u32);
itheta = x_val;
} else if b0 > 1 || stereo {
itheta = coder.decode_uint((qn + 1) as u32) as i32;
} else {
let half_qn = qn >> 1;
let ft = (half_qn + 1) * (half_qn + 1);
let fm = coder.decode_range(ft as u32) as i32;
let (fl, fs);
if fm < ((half_qn * (half_qn + 1)) >> 1) {
itheta = (isqrt32((8 * fm + 1) as u32) as i32 - 1) >> 1;
fs = itheta + 1;
fl = (itheta * (itheta + 1)) >> 1;
} else {
itheta = (2 * (qn + 1) - isqrt32((8 * (ft - fm - 1) + 1) as u32) as i32) >> 1;
fs = qn + 1 - itheta;
fl = ft - (((qn + 1 - itheta) * (qn + 2 - itheta)) >> 1);
}
coder.update_range(fl as u32, (fl + fs) as u32, ft as u32);
}
itheta = celt_udiv((itheta * 16_384) as u32, qn as u32) as i32;
} else if stereo {
let threshold = 2 << BITRES;
if *b > threshold && ctx.remaining_bits > threshold {
inv = coder.decode_bit_logp(2) != 0;
}
if ctx.disable_inv {
inv = false;
}
itheta = 0;
}
let tell_after = coder.tell_frac() as i32;
let qalloc = tell_after - tell_before;
*b -= qalloc;
let b_mask = mask_from_bits(b_current);
let band_scale = ((n as i32 - 1) << 7).max(0);
let (imid, iside, delta) = if itheta == 0 {
*fill &= b_mask;
(32_767, 0, -16_384)
} else if itheta == 16_384 {
let shifted = if b_current <= 0 {
0
} else if b_current >= 32 {
u32::MAX
} else {
b_mask << (b_current as u32)
};
*fill &= shifted;
(0, 32_767, 16_384)
} else {
let imid = i32::from(bitexact_cos(itheta as i16));
let iside = i32::from(bitexact_cos((16_384 - itheta) as i16));
let delta = frac_mul16(band_scale, bitexact_log2tan(iside, imid));
(imid, iside, delta)
};
sctx.inv = inv;
sctx.imid = imid;
sctx.iside = iside;
sctx.delta = delta;
sctx.itheta = itheta;
sctx.qalloc = qalloc;
}
#[cfg(feature = "fixed_point")]
fn quant_band_n1_fixed(
ctx: &mut FixedDecodeBandCtx<'_>,
x: &mut [FixedCeltNorm],
y: Option<&mut [FixedCeltNorm]>,
lowband_out: Option<&mut [FixedCeltNorm]>,
coder: &mut BandCodingState<'_, '_>,
) -> usize {
fn decode_single_channel(
ctx: &mut FixedDecodeBandCtx<'_>,
samples: &mut [FixedCeltNorm],
coder: &mut BandCodingState<'_, '_>,
) {
let mut sign = 0i32;
let bit_budget = 1 << BITRES;
if ctx.remaining_bits >= bit_budget {
sign = coder.decode_bits(1) as i32;
ctx.remaining_bits -= bit_budget;
}
if ctx.resynth {
samples[0] = if sign != 0 {
-FIXED_NORM_SCALING
} else {
FIXED_NORM_SCALING
};
}
}
decode_single_channel(ctx, x, coder);
if let Some(y_samples) = y {
decode_single_channel(ctx, y_samples, coder);
}
if let Some(lowband) = lowband_out.filter(|lowband| !lowband.is_empty()) {
lowband[0] = x[0] >> 4;
}
1
}
#[cfg(feature = "fixed_point")]
fn quant_partition_fixed_decode(
ctx: &mut FixedDecodeBandCtx<'_>,
x: &mut [FixedCeltNorm],
n: usize,
mut b: i32,
mut b_blocks: i32,
lowband: Option<&mut [FixedCeltNorm]>,
mut lm: i32,
gain: FixedOpusVal32,
mut fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
let mode = ctx.mode;
let band = ctx.band;
let spread = ctx.spread;
let cache_index = i32::from(mode.cache.index[((lm + 1) as usize) * mode.num_ebands + band]);
let cache_slice = if cache_index >= 0 {
&mode.cache.bits[cache_index as usize..]
} else {
&[]
};
let mut cm = 0u32;
let original_b = b_blocks;
if lm != -1 && n > 2 && !cache_slice.is_empty() {
let hi_index = cache_slice[0] as usize;
if hi_index < cache_slice.len() {
let threshold = i32::from(cache_slice[hi_index]) + 12;
if b > threshold {
let half = n >> 1;
let (x_left, x_right) = x.split_at_mut(half);
let (lowband_left, lowband_right) = match lowband {
Some(slice) => {
let (left, right) = slice.split_at_mut(half);
(Some(left), Some(right))
}
None => (None, None),
};
lm -= 1;
if b_blocks == 1 {
fill = (fill & 1) | (fill << 1);
}
b_blocks = (b_blocks + 1) >> 1;
let mut split = SplitCtx::default();
compute_theta_decode_fixed(
ctx, &mut split, half, &mut b, b_blocks, original_b, lm, false, &mut fill,
coder,
);
let mid = shl32(split.imid, 16);
let side = shl32(split.iside, 16);
let mut delta = split.delta;
if original_b > 1 && (split.itheta & 0x3fff) != 0 {
if split.itheta > 8192 {
delta -= delta >> (4 - lm);
} else {
delta = (delta + (((half as i32) << BITRES) >> (5 - lm))).min(0);
}
}
let mut mbits = (b - delta) / 2;
mbits = mbits.clamp(0, b);
let mut sbits = b - mbits;
ctx.remaining_bits -= split.qalloc;
let mut rebalance = ctx.remaining_bits;
if mbits >= sbits {
cm = quant_partition_fixed_decode(
ctx,
x_left,
half,
mbits,
b_blocks,
lowband_left,
lm,
mult32_32_q31(gain, mid),
fill,
coder,
);
rebalance = mbits - (rebalance - ctx.remaining_bits);
if rebalance > (3 << BITRES) && split.itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
cm |= quant_partition_fixed_decode(
ctx,
x_right,
half,
sbits,
b_blocks,
lowband_right,
lm,
mult32_32_q31(gain, side),
fill >> (b_blocks as u32),
coder,
) << ((original_b >> 1) as u32);
} else {
cm = quant_partition_fixed_decode(
ctx,
x_right,
half,
sbits,
b_blocks,
lowband_right,
lm,
mult32_32_q31(gain, side),
fill >> (b_blocks as u32),
coder,
) << ((original_b >> 1) as u32);
rebalance = sbits - (rebalance - ctx.remaining_bits);
if rebalance > (3 << BITRES) && split.itheta != 16_384 {
mbits += rebalance - (3 << BITRES);
}
cm |= quant_partition_fixed_decode(
ctx,
x_left,
half,
mbits,
b_blocks,
lowband_left,
lm,
mult32_32_q31(gain, mid),
fill,
coder,
);
}
return cm;
}
}
}
let mut q = bits2pulses(mode, band, lm, b);
let mut curr_bits = pulses2bits(mode, band, lm, q);
ctx.remaining_bits -= curr_bits;
while ctx.remaining_bits < 0 && q > 0 {
ctx.remaining_bits += curr_bits;
q -= 1;
curr_bits = pulses2bits(mode, band, lm, q);
ctx.remaining_bits -= curr_bits;
}
if q != 0 {
let k = get_pulses(q);
cm = alg_unquant_fixed(
x,
n,
k,
spread,
b_blocks.max(1) as usize,
coder.decoder_mut(),
gain,
);
} else if ctx.resynth {
let cm_mask = mask_from_bits(b_blocks);
fill &= cm_mask;
if fill == 0 {
x[..n].fill(0);
} else {
if let Some(lowband_slice) = lowband {
let tmp = qconst16(1.0 / 256.0, 10);
for (dst, src) in x.iter_mut().take(n).zip(lowband_slice.iter()) {
ctx.seed = celt_lcg_rand(ctx.seed);
let noise = if (ctx.seed & 0x8000) != 0 { tmp } else { -tmp };
*dst = src.wrapping_add(noise);
}
cm = fill;
} else {
for sample in &mut x[..n] {
ctx.seed = celt_lcg_rand(ctx.seed);
*sample = ((ctx.seed as i32) >> 20) as FixedCeltNorm;
}
cm = cm_mask;
}
renormalise_vector_fixed(&mut x[..n], n, gain, ctx.arch);
}
}
cm
}
#[cfg(feature = "fixed_point")]
fn quant_band_fixed_decode(
ctx: &mut FixedDecodeBandCtx<'_>,
x: &mut [FixedCeltNorm],
n: usize,
b: i32,
mut b_blocks: i32,
lowband_input: Option<&mut [FixedCeltNorm]>,
lm: i32,
mut lowband_out: Option<&mut [FixedCeltNorm]>,
gain: FixedOpusVal32,
mut lowband_scratch: Option<&mut [FixedCeltNorm]>,
mut fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
if n == 1 {
return quant_band_n1_fixed(ctx, &mut x[..1], None, lowband_out, coder) as u32;
}
let n0 = n;
let mut n_b = celt_udiv(n as u32, b_blocks as u32) as usize;
let mut b0 = b_blocks;
let mut time_divide = 0;
let recombine = ctx.tf_change.max(0);
let long_blocks = b0 == 1;
let mut lowband_stack_storage = [0i16; MAX_CELT_BAND_SIZE];
let copy_lowband = lowband_input.is_some()
&& (recombine > 0 || ((n_b & 1) == 0 && ctx.tf_change < 0) || b0 > 1);
let mut lowband_view: Option<&mut [FixedCeltNorm]> = None;
if let Some(slice) = lowband_input {
let len = n.min(slice.len());
if copy_lowband {
if let Some(scratch) = lowband_scratch.as_mut() {
assert!(
scratch.len() >= len,
"lowband scratch shorter than current band width"
);
scratch[..len].copy_from_slice(&slice[..len]);
let (head, _) = scratch.split_at_mut(len);
lowband_view = Some(head);
} else {
assert!(
len <= lowband_stack_storage.len(),
"band width exceeds fixed lowband stack workspace"
);
lowband_stack_storage[..len].copy_from_slice(&slice[..len]);
let (head, _) = lowband_stack_storage.split_at_mut(len);
lowband_view = Some(head);
}
} else {
let (head, _) = slice.split_at_mut(len);
lowband_view = Some(head);
}
}
for k in 0..recombine {
const BIT_INTERLEAVE_TABLE: [u8; 16] = [0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3];
if let Some(ref mut lowband_slice) = lowband_view {
haar1_fixed(lowband_slice, n >> k, 1usize << k);
}
let low = (fill & 0xF) as usize;
let high = ((fill >> 4) & 0xF) as usize;
fill = u32::from(BIT_INTERLEAVE_TABLE[low]) | (u32::from(BIT_INTERLEAVE_TABLE[high]) << 2);
}
b_blocks >>= recombine;
n_b <<= recombine;
while (n_b & 1) == 0 && ctx.tf_change + time_divide < 0 {
if let Some(ref mut lowband_slice) = lowband_view {
haar1_fixed(lowband_slice, n_b, b_blocks.max(1) as usize);
}
fill |= fill << (b_blocks.max(1) as u32);
b_blocks <<= 1;
n_b >>= 1;
time_divide += 1;
}
b0 = b_blocks;
let n_b0 = n_b;
if b0 > 1
&& let Some(ref mut lowband_slice) = lowband_view
{
deinterleave_hadamard_fixed(
lowband_slice,
n_b >> recombine,
(b0 << recombine) as usize,
long_blocks,
);
}
let mut cm =
quant_partition_fixed_decode(ctx, x, n, b, b_blocks, lowband_view, lm, gain, fill, coder);
if ctx.resynth {
if b0 > 1 {
interleave_hadamard_fixed(x, n_b >> recombine, (b0 << recombine) as usize, long_blocks);
}
n_b = n_b0;
b_blocks = b0;
for _ in 0..time_divide {
b_blocks >>= 1;
n_b <<= 1;
if b_blocks > 0 {
cm |= cm >> (b_blocks as u32);
}
haar1_fixed(x, n_b, b_blocks.max(1) as usize);
}
for k in 0..recombine {
const BIT_DEINTERLEAVE_TABLE: [u8; 16] = [
0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3,
0xFC, 0xFF,
];
cm = u32::from(BIT_DEINTERLEAVE_TABLE[(cm & 0xF) as usize]);
haar1_fixed(x, n0 >> k, 1usize << k);
}
b_blocks <<= recombine;
if let Some(ref mut out) = lowband_out {
let scale = extract16(celt_sqrt_fixed(shl32(n0 as i32, 22)));
for (dst, src) in out.iter_mut().zip(x.iter()) {
*dst = mult16_16_q15(scale, *src);
}
}
cm &= mask_from_bits(b_blocks);
}
cm
}
#[cfg(feature = "fixed_point")]
fn quant_band_stereo_fixed_decode(
ctx: &mut FixedDecodeBandCtx<'_>,
x: &mut [FixedCeltNorm],
y: &mut [FixedCeltNorm],
n: usize,
mut b: i32,
b_blocks: i32,
lowband_input: Option<&mut [FixedCeltNorm]>,
lm: i32,
lowband_out: Option<&mut [FixedCeltNorm]>,
mut lowband_scratch: Option<&mut [FixedCeltNorm]>,
fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
if n == 1 {
return quant_band_n1_fixed(ctx, x, Some(y), lowband_out, coder) as u32;
}
let orig_fill = fill;
let mut fill_local = fill;
let mut split = SplitCtx::default();
compute_theta_decode_fixed(
ctx,
&mut split,
n,
&mut b,
b_blocks,
b_blocks,
lm,
true,
&mut fill_local,
coder,
);
let mid = shl32(split.imid, 16);
let side = shl32(split.iside, 16);
let inv = split.inv;
let itheta = split.itheta;
let qalloc = split.qalloc;
let delta = split.delta;
let mut cm;
if n == 2 {
let mut mbits = b;
let mut sbits = 0;
if itheta != 0 && itheta != 16_384 {
sbits = 1 << BITRES;
}
mbits -= sbits;
let use_side = itheta > 8_192;
ctx.remaining_bits -= qalloc + sbits;
let (x2, y2): (&mut [FixedCeltNorm], &mut [FixedCeltNorm]) =
if use_side { (y, x) } else { (x, y) };
let mut sign = 0i32;
if sbits != 0 {
sign = coder.decode_bits(1) as i32;
}
let sign_val = 1 - 2 * sign;
cm = quant_band_fixed_decode(
ctx,
x2,
n,
mbits,
b_blocks,
lowband_input,
lm,
lowband_out,
Q31_ONE,
lowband_scratch,
orig_fill,
coder,
);
y2[0] = ((-sign_val) as i16).wrapping_mul(x2[1]);
y2[1] = (sign_val as i16).wrapping_mul(x2[0]);
if ctx.resynth {
x[0] = extract16(mult32_32_q31(mid, i32::from(x[0])));
x[1] = extract16(mult32_32_q31(mid, i32::from(x[1])));
y[0] = extract16(mult32_32_q31(side, i32::from(y[0])));
y[1] = extract16(mult32_32_q31(side, i32::from(y[1])));
let tmp0 = x[0];
x[0] = tmp0.wrapping_sub(y[0]);
y[0] = y[0].wrapping_add(tmp0);
let tmp1 = x[1];
x[1] = tmp1.wrapping_sub(y[1]);
y[1] = y[1].wrapping_add(tmp1);
}
} else {
let mut mbits = (b - delta) / 2;
mbits = mbits.clamp(0, b);
let mut sbits = b - mbits;
ctx.remaining_bits -= qalloc;
let mut rebalance = ctx.remaining_bits;
if mbits >= sbits {
cm = quant_band_fixed_decode(
ctx,
x,
n,
mbits,
b_blocks,
lowband_input,
lm,
lowband_out,
Q31_ONE,
lowband_scratch.as_deref_mut(),
fill_local,
coder,
);
rebalance = mbits - (rebalance - ctx.remaining_bits);
if rebalance > (3 << BITRES) && itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
cm |= quant_band_fixed_decode(
ctx,
y,
n,
sbits,
b_blocks,
None,
lm,
None,
side,
None,
fill_local >> (b_blocks as u32),
coder,
);
} else {
cm = quant_band_fixed_decode(
ctx,
y,
n,
sbits,
b_blocks,
None,
lm,
None,
side,
None,
fill_local >> (b_blocks as u32),
coder,
);
rebalance = sbits - (rebalance - ctx.remaining_bits);
if rebalance > (3 << BITRES) && itheta != 16_384 {
mbits += rebalance - (3 << BITRES);
}
cm |= quant_band_fixed_decode(
ctx,
x,
n,
mbits,
b_blocks,
lowband_input,
lm,
lowband_out,
Q31_ONE,
lowband_scratch,
fill_local,
coder,
);
}
}
if ctx.resynth {
if n != 2 {
#[cfg(test)]
if std::env::var("CELT_EXP_FLOAT_STEREO_MERGE").is_ok() {
let mut xf: Vec<OpusVal16> = x.iter().copied().map(fixed_norm_to_float).collect();
let mut yf: Vec<OpusVal16> = y.iter().copied().map(fixed_norm_to_float).collect();
stereo_merge(&mut xf, &mut yf, (mid as f32) * (1.0 / 2_147_483_648.0));
for (dst, &src) in x.iter_mut().zip(xf.iter()) {
*dst = float2int16(src);
}
for (dst, &src) in y.iter_mut().zip(yf.iter()) {
*dst = float2int16(src);
}
} else {
stereo_merge_fixed(x, y, mid);
}
#[cfg(not(test))]
stereo_merge_fixed(x, y, mid);
}
if inv {
for sample in y.iter_mut().take(n) {
*sample = -*sample;
}
}
}
cm
}
#[cfg(feature = "fixed_point")]
#[allow(clippy::too_many_arguments)]
pub(crate) fn quant_all_bands_decode_fixed(
mode: &OpusCustomMode<'_>,
start: usize,
end: usize,
x: &mut [FixedCeltNorm],
mut y: Option<&mut [FixedCeltNorm]>,
collapse_masks: &mut [u8],
pulses: &[i32],
short_blocks: bool,
spread: i32,
mut dual_stereo: bool,
intensity: usize,
tf_res: &[i32],
total_bits: i32,
mut balance: i32,
coder: &mut BandCodingState<'_, '_>,
lm: i32,
coded_bands: usize,
seed: &mut u32,
arch: i32,
disable_inv: bool,
) {
if start >= end || end > mode.num_ebands {
return;
}
let channels = if y.is_some() { 2 } else { 1 };
let m = 1usize << (lm as usize);
let b_blocks_base = if short_blocks { m as i32 } else { 1 };
let norm_offset = m * (mode.e_bands[start] as usize);
let last_band_start = m * (mode.e_bands[mode.num_ebands - 1] as usize);
let norm_len = last_band_start.saturating_sub(norm_offset);
let mut norm_storage = vec![0i16; channels * norm_len];
let (norm, norm2_slice) = norm_storage.split_at_mut(norm_len);
let mut norm2 = if channels == 2 {
Some(norm2_slice)
} else {
None
};
let last_band_end = m * (mode.e_bands[mode.num_ebands] as usize);
let resynth_alloc = last_band_end.saturating_sub(last_band_start);
let mut lowband_scratch_storage = if resynth_alloc > 0 {
Some(vec![0i16; resynth_alloc])
} else {
None
};
let mut ctx = FixedDecodeBandCtx {
mode,
band: start,
intensity,
spread,
tf_change: 0,
remaining_bits: total_bits,
seed: *seed,
arch,
disable_inv,
avoid_split_noise: b_blocks_base > 1,
resynth: true,
};
let first_band_start = norm_offset;
let mut lowband_offset: Option<usize> = None;
let mut update_lowband = true;
for band in start..end {
ctx.band = band;
let last = band + 1 == end;
let band_start = m * (mode.e_bands[band] as usize);
let band_end = m * (mode.e_bands[band + 1] as usize);
let n = band_end.saturating_sub(band_start);
if n == 0 {
continue;
}
let tell = coder.tell_frac() as i32;
if band != start {
balance -= tell;
}
ctx.remaining_bits = total_bits - tell - 1;
let mut b_allocation = 0i32;
if band < coded_bands {
let remaining_coded = (coded_bands - band).min(3) as i32;
let curr_balance = celt_sudiv(balance, remaining_coded);
let pulse_target = pulses.get(band).copied().unwrap_or(0) + curr_balance;
b_allocation = (ctx.remaining_bits + 1).min(pulse_target).clamp(0, 16_383);
}
if (band_start >= first_band_start.saturating_add(n) || band == start + 1)
&& (update_lowband || lowband_offset.is_none())
{
lowband_offset = Some(band);
}
if band == start + 1 {
special_hybrid_folding_fixed(mode, norm, norm2.as_deref_mut(), start, m, dual_stereo);
}
ctx.tf_change = tf_res.get(band).copied().unwrap_or(0);
if band >= mode.effective_ebands || last {
lowband_scratch_storage = None;
}
let x_band = &mut x[band_start..band_end];
let mut y_band = y.as_mut().map(|slice| &mut slice[band_start..band_end]);
let mut effective_lowband = None;
let mut x_cm = 0u32;
let mut y_cm = 0u32;
if let Some(lowband_idx) = lowband_offset
&& (spread != SPREAD_AGGRESSIVE || b_blocks_base > 1 || ctx.tf_change < 0)
{
let lowband_start = m * (mode.e_bands[lowband_idx] as usize);
let effective = lowband_start.saturating_sub(norm_offset).saturating_sub(n);
effective_lowband = Some(effective);
let fold_start_threshold = effective.saturating_add(norm_offset);
let fold_end_threshold = fold_start_threshold.saturating_add(n);
let mut fold_start = lowband_idx;
while fold_start > 0 {
fold_start -= 1;
if m * (mode.e_bands[fold_start] as usize) <= fold_start_threshold {
break;
}
}
let mut fold_end = lowband_idx.saturating_sub(1);
while {
fold_end = fold_end.saturating_add(1);
fold_end < band && m * (mode.e_bands[fold_end] as usize) < fold_end_threshold
} {}
for fold in fold_start..fold_end {
let base = fold * channels;
x_cm |= u32::from(collapse_masks.get(base).copied().unwrap_or(0));
let right_index = base + channels - 1;
y_cm |= u32::from(collapse_masks.get(right_index).copied().unwrap_or(0));
}
}
if effective_lowband.is_none() {
let mask = mask_from_bits(b_blocks_base);
x_cm = mask;
y_cm = mask;
}
if dual_stereo && band == intensity {
dual_stereo = false;
if let Some(norm2_slice) = norm2.as_mut() {
for (dst, src) in norm.iter_mut().zip(norm2_slice.iter()) {
*dst = ((i32::from(*dst) + i32::from(*src)) >> 1) as i16;
}
}
}
let lowband_out_offset = if !last {
Some(band_start.saturating_sub(norm_offset))
} else {
None
};
if dual_stereo {
let lowband_input_offset = effective_lowband;
{
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band_fixed_decode(
&mut ctx,
x_band,
n,
b_allocation / 2,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
Q31_ONE,
lowband_scratch_storage.as_deref_mut(),
x_cm,
coder,
);
}
if let Some(y_band_slice_ref) = y_band.as_mut()
&& let Some(norm2_buf) = norm2.as_mut()
{
let (y_lowband_input, y_lowband_out) =
lowband_in_out_mut(norm2_buf, lowband_input_offset, lowband_out_offset, n);
y_cm = quant_band_fixed_decode(
&mut ctx,
y_band_slice_ref,
n,
b_allocation / 2,
b_blocks_base,
y_lowband_input,
lm,
y_lowband_out,
Q31_ONE,
lowband_scratch_storage.as_deref_mut(),
y_cm,
coder,
);
}
} else if let Some(y_band_slice_ref) = y_band.as_mut() {
let lowband_input_offset = effective_lowband;
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band_stereo_fixed_decode(
&mut ctx,
x_band,
y_band_slice_ref,
n,
b_allocation,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
lowband_scratch_storage.as_deref_mut(),
x_cm | y_cm,
coder,
);
y_cm = x_cm;
} else {
let lowband_input_offset = effective_lowband;
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band_fixed_decode(
&mut ctx,
x_band,
n,
b_allocation,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
Q31_ONE,
lowband_scratch_storage.as_deref_mut(),
x_cm | y_cm,
coder,
);
y_cm = x_cm;
}
if let Some(mask) = collapse_masks.get_mut(band * channels) {
*mask = x_cm as u8;
}
if let Some(mask) = collapse_masks.get_mut(band * channels + channels - 1) {
*mask = y_cm as u8;
}
balance += pulses.get(band).copied().unwrap_or(0) + tell;
update_lowband = b_allocation > ((n as i32) << BITRES);
ctx.avoid_split_noise = false;
}
*seed = ctx.seed;
}
#[allow(clippy::too_many_arguments)]
fn quant_partition(
ctx: &mut BandCtx<'_, '_>,
x: &mut [OpusVal16],
n: usize,
mut b: i32,
mut b_blocks: i32,
lowband: Option<&mut [OpusVal16]>,
mut lm: i32,
gain: OpusVal32,
mut fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
debug_assert!(n > 0, "partition length must be positive");
debug_assert!(
x.len() >= n,
"partition slice shorter than requested length"
);
if let Some(ref slice) = lowband {
debug_assert!(slice.len() >= n, "lowband slice shorter than partition");
}
let mode = ctx.mode;
let band = ctx.band;
let encode = ctx.encode;
let spread = ctx.spread;
let cache_index = i32::from(mode.cache.index[((lm + 1) as usize) * mode.num_ebands + band]);
let cache_slice = if cache_index >= 0 {
&mode.cache.bits[cache_index as usize..]
} else {
&[]
};
let mut cm = 0u32;
let original_b = b_blocks;
if lm != -1 && n > 2 && !cache_slice.is_empty() {
let hi_index = cache_slice[0] as usize;
if hi_index < cache_slice.len() {
let threshold = i32::from(cache_slice[hi_index]) + 12;
if b > threshold {
let half = n >> 1;
let (x_left, x_right) = x.split_at_mut(half);
let (lowband_left, lowband_right) = match lowband {
Some(slice) => {
let (left, right) = slice.split_at_mut(half);
(Some(left), Some(right))
}
None => (None, None),
};
lm -= 1;
if b_blocks == 1 {
fill = (fill & 1) | (fill << 1);
}
b_blocks = (b_blocks + 1) >> 1;
let mut split = SplitCtx::default();
compute_theta(
ctx, &mut split, x_left, x_right, half, &mut b, b_blocks, original_b, lm,
false, &mut fill, coder,
);
let imid = split.imid as OpusVal32 / 32_768.0;
let iside = split.iside as OpusVal32 / 32_768.0;
let mut delta = split.delta;
let itheta = split.itheta;
let qalloc = split.qalloc;
if original_b > 1 && (itheta & 0x3fff) != 0 {
if itheta > 8192 {
let shift = (4 - lm) as u32;
delta -= delta >> shift;
} else {
let shift = (5 - lm) as u32;
let adjust = ((half as i32) << BITRES) >> shift;
delta = (delta + adjust).min(0);
}
}
ctx.remaining_bits -= qalloc;
let mut mbits = (b - delta) / 2;
mbits = mbits.clamp(0, b);
let mut sbits = b - mbits;
let mut rebalance = ctx.remaining_bits;
if mbits >= sbits {
cm = quant_partition(
ctx,
x_left,
half,
mbits,
b_blocks,
lowband_left,
lm,
gain * imid,
fill,
coder,
);
let used = rebalance - ctx.remaining_bits;
rebalance = mbits - used;
if rebalance > (3 << BITRES) && itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
let cm_right = quant_partition(
ctx,
x_right,
half,
sbits,
b_blocks,
lowband_right,
lm,
gain * iside,
fill >> (b_blocks as u32),
coder,
);
cm |= cm_right << ((original_b >> 1) as u32);
} else {
let cm_right = quant_partition(
ctx,
x_right,
half,
sbits,
b_blocks,
lowband_right,
lm,
gain * iside,
fill >> (b_blocks as u32),
coder,
);
cm = cm_right << ((original_b >> 1) as u32);
let used = rebalance - ctx.remaining_bits;
rebalance = sbits - used;
if rebalance > (3 << BITRES) && itheta != 16_384 {
mbits += rebalance - (3 << BITRES);
}
cm |= quant_partition(
ctx,
x_left,
half,
mbits,
b_blocks,
lowband_left,
lm,
gain * imid,
fill,
coder,
);
}
return cm;
}
}
}
let mut q = bits2pulses(mode, band, lm, b);
let mut curr_bits = pulses2bits(mode, band, lm, q);
ctx.remaining_bits -= curr_bits;
while ctx.remaining_bits < 0 && q > 0 {
ctx.remaining_bits += curr_bits;
q -= 1;
curr_bits = pulses2bits(mode, band, lm, q);
ctx.remaining_bits -= curr_bits;
}
if q != 0 {
let k = get_pulses(q);
let block_count = b_blocks.max(1) as usize;
if encode {
cm = pvq_alg_quant_runtime(
x,
n,
k,
spread,
block_count,
coder.encoder_mut(),
gain,
ctx.resynth,
ctx.arch,
);
} else {
cm = pvq_alg_unquant_runtime(x, n, k, spread, block_count, coder.decoder_mut(), gain);
}
} else if ctx.resynth {
let cm_mask = mask_from_bits(b_blocks);
fill &= cm_mask;
if fill == 0 {
x[..n].fill(0.0);
} else if let Some(lowband_slice) = lowband {
let tmp = 1.0 / 256.0;
for (dst, src) in x.iter_mut().zip(lowband_slice.iter()) {
ctx.seed = celt_lcg_rand(ctx.seed);
let noise = if (ctx.seed & 0x8000) != 0 { tmp } else { -tmp };
*dst = *src + noise;
}
cm = fill;
pvq_renormalise_runtime(x, n, gain, ctx.arch);
} else {
for sample in &mut x[..n] {
ctx.seed = celt_lcg_rand(ctx.seed);
let value = ((ctx.seed as i32) >> 20) as OpusVal16;
*sample = value;
}
cm = cm_mask;
pvq_renormalise_runtime(x, n, gain, ctx.arch);
}
}
cm
}
#[allow(clippy::too_many_arguments)]
fn quant_band(
ctx: &mut BandCtx<'_, '_>,
x: &mut [OpusVal16],
n: usize,
b: i32,
mut b_blocks: i32,
lowband_input: Option<&mut [OpusVal16]>,
lm: i32,
mut lowband_out: Option<&mut [OpusVal16]>,
gain: OpusVal32,
mut lowband_scratch: Option<&mut [OpusVal16]>,
mut fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
debug_assert!(x.len() >= n, "quant_band expects at least n coefficients");
if let Some(ref slice) = lowband_input {
debug_assert!(slice.len() >= n, "lowband slice shorter than partition");
}
if let Some(ref slice) = lowband_out {
debug_assert!(slice.len() >= n, "lowband_out slice shorter than partition");
}
let encode = ctx.encode;
let mut tf_change = ctx.tf_change;
let n0 = n;
let mut n_b = n;
let mut b0 = b_blocks;
let mut time_divide = 0;
let mut recombine = 0;
let long_blocks = b0 == 1;
if b_blocks > 0 {
n_b = celt_udiv(n_b as u32, b_blocks as u32) as usize;
}
if n == 1 {
return quant_band_n1(ctx, &mut x[..1], None, lowband_out, coder) as u32;
}
if tf_change > 0 {
recombine = tf_change;
}
let mut lowband_stack_storage = [0.0; MAX_CELT_BAND_SIZE];
let copy_lowband =
lowband_input.is_some() && (recombine > 0 || ((n_b & 1) == 0 && tf_change < 0) || b0 > 1);
let mut lowband_view: Option<&mut [OpusVal16]> = None;
if let Some(slice) = lowband_input {
let len = n.min(slice.len());
if copy_lowband {
if let Some(scratch) = lowband_scratch.as_mut() {
assert!(
scratch.len() >= len,
"lowband scratch shorter than current band width"
);
scratch[..len].copy_from_slice(&slice[..len]);
let (head, _) = scratch.split_at_mut(len);
lowband_view = Some(head);
} else {
assert!(
len <= lowband_stack_storage.len(),
"band width exceeds fixed lowband stack workspace"
);
lowband_stack_storage[..len].copy_from_slice(&slice[..len]);
let (head, _) = lowband_stack_storage.split_at_mut(len);
lowband_view = Some(head);
}
} else {
let (head, _) = slice.split_at_mut(len);
lowband_view = Some(head);
}
}
for k in 0..recombine {
const BIT_INTERLEAVE_TABLE: [u8; 16] = [0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3];
if encode {
haar1(x, n >> k, 1usize << k);
}
if let Some(ref mut lowband_slice) = lowband_view {
haar1(lowband_slice, n >> k, 1usize << k);
}
let low = (fill & 0xF) as usize;
let high = ((fill >> 4) & 0xF) as usize;
let mapped =
u32::from(BIT_INTERLEAVE_TABLE[low]) | (u32::from(BIT_INTERLEAVE_TABLE[high]) << 2);
fill = mapped;
}
b_blocks >>= recombine;
n_b <<= recombine;
while (n_b & 1) == 0 && tf_change < 0 {
if encode {
haar1(x, n_b, b_blocks.max(1) as usize);
}
if let Some(ref mut lowband_slice) = lowband_view {
haar1(lowband_slice, n_b, b_blocks.max(1) as usize);
}
let shift = b_blocks.max(1) as u32;
fill |= fill << shift;
b_blocks <<= 1;
n_b >>= 1;
time_divide += 1;
tf_change += 1;
}
b0 = b_blocks;
let n_b0 = n_b;
if b0 > 1 {
if encode {
deinterleave_hadamard(x, n_b >> recombine, (b0 << recombine) as usize, long_blocks);
}
if let Some(ref mut lowband_slice) = lowband_view {
deinterleave_hadamard(
lowband_slice,
n_b >> recombine,
(b0 << recombine) as usize,
long_blocks,
);
}
}
let mut cm = quant_partition(ctx, x, n, b, b_blocks, lowband_view, lm, gain, fill, coder);
if ctx.resynth {
if b0 > 1 {
interleave_hadamard(x, n_b >> recombine, (b0 << recombine) as usize, long_blocks);
}
n_b = n_b0;
b_blocks = b0;
for _ in 0..time_divide {
b_blocks >>= 1;
n_b <<= 1;
if b_blocks > 0 {
cm |= cm >> (b_blocks as u32);
}
haar1(x, n_b, b_blocks.max(1) as usize);
}
for k in 0..recombine {
const BIT_DEINTERLEAVE_TABLE: [u8; 16] = [
0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3,
0xFC, 0xFF,
];
cm = u32::from(BIT_DEINTERLEAVE_TABLE[cm as usize & 0xF]);
haar1(x, n0 >> k, 1usize << k);
}
b_blocks <<= recombine;
if let Some(ref mut out) = lowband_out {
let scale = celt_sqrt(n0 as OpusVal32);
for (dst, src) in out.iter_mut().zip(x.iter()) {
*dst = scale * *src;
}
}
cm &= mask_from_bits(b_blocks);
}
cm
}
const MIN_STEREO_ENERGY: OpusVal32 = 1e-10;
#[allow(clippy::too_many_arguments)]
fn quant_band_stereo(
ctx: &mut BandCtx<'_, '_>,
x: &mut [OpusVal16],
y: &mut [OpusVal16],
n: usize,
mut b: i32,
b_blocks: i32,
mut lowband_input: Option<&mut [OpusVal16]>,
lm: i32,
mut lowband_out: Option<&mut [OpusVal16]>,
mut lowband_scratch: Option<&mut [OpusVal16]>,
fill: u32,
coder: &mut BandCodingState<'_, '_>,
) -> u32 {
debug_assert!(
x.len() >= n && y.len() >= n,
"stereo bands require at least n samples"
);
let encode = ctx.encode;
if n == 1 {
return quant_band_n1(ctx, x, Some(y), lowband_out, coder) as u32;
}
let mut fill_local = fill;
let orig_fill = fill;
if encode {
let band = ctx.band;
let mode = ctx.mode;
let stride = mode.num_ebands;
let left = ctx.band_e[band];
let right = ctx.band_e[band + stride];
if left < MIN_STEREO_ENERGY || right < MIN_STEREO_ENERGY {
if left > right {
y[..n].copy_from_slice(&x[..n]);
} else {
x[..n].copy_from_slice(&y[..n]);
}
}
}
let mut split = SplitCtx::default();
compute_theta(
ctx,
&mut split,
x,
y,
n,
&mut b,
b_blocks,
b_blocks,
lm,
true,
&mut fill_local,
coder,
);
let mut cm;
let inv = split.inv;
let imid = split.imid;
let iside = split.iside;
let delta = split.delta;
let itheta = split.itheta;
let qalloc = split.qalloc;
let mid = (imid as OpusVal32) / 32_768.0;
let side = (iside as OpusVal32) / 32_768.0;
if n == 2 {
let mut mbits = b;
let mut sbits = 0;
if itheta != 0 && itheta != 16_384 {
sbits = 1 << BITRES;
}
mbits -= sbits;
let use_side = itheta > 8_192;
ctx.remaining_bits -= qalloc + sbits;
let mut sign = 0i32;
{
let (x2, y2): (&mut [OpusVal16], &mut [OpusVal16]) = if use_side {
(&mut y[..n], &mut x[..n])
} else {
(&mut x[..n], &mut y[..n])
};
if sbits != 0 {
if encode {
sign = if x2[0] * y2[1] - x2[1] * y2[0] < 0.0 {
1
} else {
0
};
coder.encode_bits(sign as u32, 1);
} else {
sign = coder.decode_bits(1) as i32;
}
}
let sign_val = 1 - 2 * sign;
cm = quant_band(
ctx,
x2,
n,
mbits,
b_blocks,
lowband_input.take(),
lm,
lowband_out.take(),
1.0,
lowband_scratch.as_deref_mut(),
orig_fill,
coder,
);
y2[0] = -(sign_val as OpusVal16) * x2[1];
y2[1] = (sign_val as OpusVal16) * x2[0];
}
if ctx.resynth {
x[0] *= mid;
x[1] *= mid;
y[0] *= side;
y[1] *= side;
let tmp0 = x[0];
x[0] = tmp0 - y[0];
y[0] += tmp0;
let tmp1 = x[1];
x[1] = tmp1 - y[1];
y[1] += tmp1;
}
} else {
let mut mbits = (b - delta) / 2;
mbits = mbits.clamp(0, b);
let mut sbits = b - mbits;
ctx.remaining_bits -= qalloc;
let mut rebalance = ctx.remaining_bits;
if mbits >= sbits {
cm = quant_band(
ctx,
x,
n,
mbits,
b_blocks,
lowband_input.take(),
lm,
lowband_out.take(),
1.0,
lowband_scratch.as_deref_mut(),
fill_local,
coder,
);
let used = rebalance - ctx.remaining_bits;
rebalance = mbits - used;
if rebalance > (3 << BITRES) && itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
cm |= quant_band(
ctx,
y,
n,
sbits,
b_blocks,
None,
lm,
None,
side,
None,
fill_local >> (b_blocks as u32),
coder,
);
} else {
cm = quant_band(
ctx,
y,
n,
sbits,
b_blocks,
None,
lm,
None,
side,
None,
fill_local >> (b_blocks as u32),
coder,
);
let used = rebalance - ctx.remaining_bits;
rebalance = sbits - used;
if rebalance > (3 << BITRES) && itheta != 16_384 {
mbits += rebalance - (3 << BITRES);
}
cm |= quant_band(
ctx,
x,
n,
mbits,
b_blocks,
lowband_input,
lm,
lowband_out,
1.0,
lowband_scratch,
fill_local,
coder,
);
}
}
if ctx.resynth {
if n != 2 {
stereo_merge(x, y, mid);
}
if inv {
for sample in &mut y[..n] {
*sample = -*sample;
}
}
}
cm
}
#[inline]
fn lowband_window_mut<T>(buffer: &mut [T], offset: Option<usize>, len: usize) -> Option<&mut [T]> {
let start = offset?;
let end = start.checked_add(len)?;
if end > buffer.len() {
return None;
}
Some(&mut buffer[start..end])
}
#[inline]
fn lowband_in_out_mut<T>(
buffer: &mut [T],
input_offset: Option<usize>,
output_offset: Option<usize>,
len: usize,
) -> (Option<&mut [T]>, Option<&mut [T]>) {
match (input_offset, output_offset) {
(None, None) => (None, None),
(Some(input_start), None) => (lowband_window_mut(buffer, Some(input_start), len), None),
(None, Some(output_start)) => (None, lowband_window_mut(buffer, Some(output_start), len)),
(Some(input_start), Some(output_start)) => {
let Some(input_end) = input_start.checked_add(len) else {
return (None, None);
};
let Some(output_end) = output_start.checked_add(len) else {
return (None, None);
};
if input_end > buffer.len() || output_end > buffer.len() {
return (None, None);
}
if input_end <= output_start {
let (left, right) = buffer.split_at_mut(output_start);
(
Some(&mut left[input_start..input_end]),
Some(&mut right[..len]),
)
} else if output_end <= input_start {
let (left, right) = buffer.split_at_mut(input_start);
(
Some(&mut right[..len]),
Some(&mut left[output_start..output_end]),
)
} else {
debug_assert!(
false,
"lowband input/output windows unexpectedly overlap: input={input_start}..{input_end}, output={output_start}..{output_end}"
);
(None, None)
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn quant_all_bands(
encode: bool,
mode: &OpusCustomMode<'_>,
start: usize,
end: usize,
x: &mut [OpusVal16],
mut y: Option<&mut [OpusVal16]>,
collapse_masks: &mut [u8],
band_e: &[CeltGlog],
pulses: &[i32],
short_blocks: bool,
spread: i32,
mut dual_stereo: bool,
intensity: usize,
tf_res: &[i32],
total_bits: i32,
mut balance: i32,
coder: &mut BandCodingState<'_, '_>,
lm: i32,
coded_bands: usize,
seed: &mut u32,
complexity: i32,
arch: i32,
disable_inv: bool,
) {
if start >= end || end > mode.num_ebands {
return;
}
let channels = if y.is_some() { 2 } else { 1 };
let m = 1usize << (lm as usize);
let b_blocks_base = if short_blocks { m as i32 } else { 1 };
if mode.num_ebands == 0 {
return;
}
let norm_offset = m * (mode.e_bands[start] as usize);
let last_band_start = if mode.num_ebands > 0 {
m * (mode.e_bands[mode.num_ebands - 1] as usize)
} else {
0
};
let norm_len = last_band_start.saturating_sub(norm_offset);
let mut norm_storage = vec![0.0; channels * norm_len];
let (norm_slice, norm2_slice) = norm_storage.split_at_mut(norm_len);
let norm = norm_slice;
let mut norm2 = if channels == 2 {
Some(norm2_slice)
} else {
None
};
let theta_rdo = encode && y.is_some() && !dual_stereo && complexity >= 8;
let resynth = !encode || theta_rdo;
let last_band_end = if mode.num_ebands > 0 {
m * (mode.e_bands[mode.num_ebands] as usize)
} else {
0
};
let resynth_alloc = if resynth {
last_band_end.saturating_sub(last_band_start)
} else {
0
};
let mut lowband_scratch_storage = if resynth_alloc > 0 {
Some(vec![0.0; resynth_alloc])
} else {
None
};
let mut ctx = BandCtx {
encode,
resynth,
mode,
band: start,
intensity,
spread,
tf_change: 0,
remaining_bits: total_bits,
band_e,
seed: *seed,
arch,
theta_round: 0,
disable_inv,
avoid_split_noise: b_blocks_base > 1,
};
let first_band_start = norm_offset;
let mut lowband_offset: Option<usize> = None;
let mut update_lowband = true;
for band in start..end {
ctx.band = band;
let last = band + 1 == end;
let band_start = m * (mode.e_bands[band] as usize);
let band_end = m * (mode.e_bands[band + 1] as usize);
let n = band_end.saturating_sub(band_start);
if n == 0 {
continue;
}
let tell = coder.tell_frac() as i32;
if band != start {
balance -= tell;
}
let remaining_bits = total_bits - tell - 1;
ctx.remaining_bits = remaining_bits;
let mut b_allocation = 0i32;
if band < coded_bands {
let remaining_coded = (coded_bands - band).min(3) as i32;
let curr_balance = celt_sudiv(balance, remaining_coded);
let pulse_target = pulses.get(band).copied().unwrap_or(0) + curr_balance;
let max_target = (remaining_bits + 1).min(pulse_target);
b_allocation = max_target.clamp(0, 16_383);
}
if resynth
&& (band_start >= first_band_start.saturating_add(n) || band == start + 1)
&& (update_lowband || lowband_offset.is_none())
{
lowband_offset = Some(band);
}
if band == start + 1 {
special_hybrid_folding(
mode,
&mut *norm,
norm2.as_deref_mut(),
start,
m,
dual_stereo,
);
}
let tf_change = tf_res.get(band).copied().unwrap_or(0);
ctx.tf_change = tf_change;
if band >= mode.effective_ebands {
lowband_scratch_storage = None;
}
if last {
lowband_scratch_storage = None;
}
let x_band = &mut x[band_start..band_end];
let mut y_band = y.as_mut().map(|slice| &mut slice[band_start..band_end]);
let mut effective_lowband = None;
let mut x_cm = 0u32;
let mut y_cm = 0u32;
if let Some(lowband_idx) = lowband_offset
&& (spread != SPREAD_AGGRESSIVE || b_blocks_base > 1 || tf_change < 0)
{
let lowband_start = m * (mode.e_bands[lowband_idx] as usize);
let effective = lowband_start.saturating_sub(norm_offset).saturating_sub(n);
effective_lowband = Some(effective);
let threshold = effective.saturating_add(norm_offset).saturating_add(n);
let mut fold_start = lowband_idx;
while fold_start > 0 {
fold_start -= 1;
if m * (mode.e_bands[fold_start] as usize) <= threshold {
break;
}
}
let mut fold_end = lowband_idx.saturating_sub(1);
while {
fold_end = fold_end.saturating_add(1);
fold_end < band && m * (mode.e_bands[fold_end] as usize) < threshold
} {}
for fold in fold_start..fold_end {
let base = fold * channels;
x_cm |= u32::from(collapse_masks.get(base).copied().unwrap_or(0));
let right_index = base + channels - 1;
y_cm |= u32::from(collapse_masks.get(right_index).copied().unwrap_or(0));
}
}
if effective_lowband.is_none() {
let mask = if b_blocks_base >= 32 {
u32::MAX
} else {
(1u32 << b_blocks_base) - 1
};
x_cm = mask;
y_cm = mask;
}
if dual_stereo && band == intensity {
dual_stereo = false;
if resynth && let Some(norm2_slice) = norm2.as_mut() {
for (dst, src) in norm.iter_mut().zip(norm2_slice.iter()) {
*dst = (*dst + *src) * 0.5;
}
}
}
let mut lowband_out_offset = None;
if !last {
lowband_out_offset = Some(band_start.saturating_sub(norm_offset));
}
if dual_stereo {
let lowband_input_offset = effective_lowband;
{
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band(
&mut ctx,
x_band,
n,
b_allocation / 2,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
1.0,
lowband_scratch_storage.as_deref_mut(),
x_cm,
coder,
);
}
if let Some(y_band_slice_ref) = y_band.as_mut()
&& let Some(norm2_buf) = norm2.as_mut()
{
let y_band_slice = &mut **y_band_slice_ref;
let (y_lowband_input, y_lowband_out) =
lowband_in_out_mut(norm2_buf, lowband_input_offset, lowband_out_offset, n);
y_cm = quant_band(
&mut ctx,
y_band_slice,
n,
b_allocation / 2,
b_blocks_base,
y_lowband_input,
lm,
y_lowband_out,
1.0,
lowband_scratch_storage.as_deref_mut(),
y_cm,
coder,
);
}
} else if let Some(y_band_slice_ref) = y_band.as_mut() {
let y_band_slice = &mut **y_band_slice_ref;
let lowband_input_offset = effective_lowband;
let initial_fill = x_cm | y_cm;
let rdo_active = theta_rdo && band < intensity && coder.is_encoder();
if rdo_active {
let weights = compute_channel_weights(band_e[band], band_e[band + mode.num_ebands]);
let ctx_initial = ctx.clone();
let coder_initial = coder.encoder_snapshot();
let mut x_before = vec![0.0; n];
x_before.copy_from_slice(&x_band[..n]);
let mut y_before = vec![0.0; n];
y_before.copy_from_slice(&y_band_slice[..n]);
let lowband_initial_left = lowband_out_offset.and_then(|offset| {
if offset + n <= norm.len() {
Some((offset, norm[offset..offset + n].to_vec()))
} else {
None
}
});
let lowband_initial_right = lowband_out_offset.and_then(|offset| {
norm2.as_ref().and_then(|norm2_buf| {
if offset + n <= norm2_buf.len() {
Some((offset, norm2_buf[offset..offset + n].to_vec()))
} else {
None
}
})
});
ctx.theta_round = -1;
let cm_first = {
let (x_lowband_input_slice, x_lowband_out_slice) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
quant_band_stereo(
&mut ctx,
x_band,
y_band_slice,
n,
b_allocation,
b_blocks_base,
x_lowband_input_slice,
lm,
x_lowband_out_slice,
lowband_scratch_storage.as_deref_mut(),
initial_fill,
coder,
)
};
let dist0 = weights[0] * celt_inner_prod(&x_before[..n], &x_band[..n])
+ weights[1] * celt_inner_prod(&y_before[..n], &y_band_slice[..n]);
let coder_after_first = coder.encoder_snapshot();
let ctx_after_first = ctx.clone();
let mut x_after_first = vec![0.0; n];
x_after_first.copy_from_slice(&x_band[..n]);
let mut y_after_first = vec![0.0; n];
y_after_first.copy_from_slice(&y_band_slice[..n]);
let lowband_after_first_left = lowband_out_offset.and_then(|offset| {
if offset + n <= norm.len() {
Some((offset, norm[offset..offset + n].to_vec()))
} else {
None
}
});
let lowband_after_first_right = lowband_out_offset.and_then(|offset| {
norm2.as_ref().and_then(|norm2_buf| {
if offset + n <= norm2_buf.len() {
Some((offset, norm2_buf[offset..offset + n].to_vec()))
} else {
None
}
})
});
coder.restore_encoder_snapshot(&coder_initial);
ctx = ctx_initial.clone();
x_band[..n].copy_from_slice(&x_before[..n]);
y_band_slice[..n].copy_from_slice(&y_before[..n]);
if let Some((offset, data)) = lowband_initial_left.as_ref() {
let len = data.len().min(norm.len().saturating_sub(*offset));
norm[*offset..*offset + len].copy_from_slice(&data[..len]);
}
if let Some((offset, data)) = lowband_initial_right.as_ref()
&& let Some(norm2_buf) = norm2.as_mut()
{
let len = data.len().min(norm2_buf.len().saturating_sub(*offset));
norm2_buf[*offset..*offset + len].copy_from_slice(&data[..len]);
}
ctx.theta_round = 1;
let cm_second = {
let (x_lowband_input_slice, x_lowband_out_slice) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
quant_band_stereo(
&mut ctx,
x_band,
y_band_slice,
n,
b_allocation,
b_blocks_base,
x_lowband_input_slice,
lm,
x_lowband_out_slice,
lowband_scratch_storage.as_deref_mut(),
initial_fill,
coder,
)
};
let dist1 = weights[0] * celt_inner_prod(&x_before[..n], &x_band[..n])
+ weights[1] * celt_inner_prod(&y_before[..n], &y_band_slice[..n]);
if dist0 >= dist1 {
coder.restore_encoder_snapshot(&coder_after_first);
ctx = ctx_after_first;
x_band[..n].copy_from_slice(&x_after_first[..n]);
y_band_slice[..n].copy_from_slice(&y_after_first[..n]);
if let Some((offset, data)) = lowband_after_first_left {
let len = data.len().min(norm.len().saturating_sub(offset));
norm[offset..offset + len].copy_from_slice(&data[..len]);
}
if let Some((offset, data)) = lowband_after_first_right
&& let Some(norm2_buf) = norm2.as_mut()
{
let len = data.len().min(norm2_buf.len().saturating_sub(offset));
norm2_buf[offset..offset + len].copy_from_slice(&data[..len]);
}
x_cm = cm_first;
} else {
x_cm = cm_second;
}
y_cm = x_cm;
ctx.theta_round = 0;
} else {
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band_stereo(
&mut ctx,
x_band,
y_band_slice,
n,
b_allocation,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
lowband_scratch_storage.as_deref_mut(),
initial_fill,
coder,
);
y_cm = x_cm;
}
} else {
let lowband_input_offset = effective_lowband;
let (x_lowband_input, x_lowband_out) =
lowband_in_out_mut(norm, lowband_input_offset, lowband_out_offset, n);
x_cm = quant_band(
&mut ctx,
x_band,
n,
b_allocation,
b_blocks_base,
x_lowband_input,
lm,
x_lowband_out,
1.0,
lowband_scratch_storage.as_deref_mut(),
x_cm | y_cm,
coder,
);
y_cm = x_cm;
}
if let Some(mask) = collapse_masks.get_mut(band * channels) {
*mask = x_cm as u8;
}
if let Some(mask) = collapse_masks.get_mut(band * channels + channels - 1) {
*mask = y_cm as u8;
}
balance += pulses.get(band).copied().unwrap_or(0) + tell;
let n_bits = (n as i32) << BITRES;
update_lowband = b_allocation > n_bits;
ctx.avoid_split_noise = false;
}
*seed = ctx.seed;
}
#[must_use]
pub(crate) fn compute_channel_weights(ex: OpusVal32, ey: OpusVal32) -> [OpusVal16; 2] {
let min_energy = ex.min(ey);
let adjusted_ex = ex + min_energy / 3.0;
let adjusted_ey = ey + min_energy / 3.0;
[adjusted_ex, adjusted_ey]
}
pub(crate) fn intensity_stereo(
mode: &OpusCustomMode<'_>,
x: &mut [OpusVal16],
y: &[OpusVal16],
band_e: &[OpusVal32],
band_id: usize,
n: usize,
) {
assert!(
band_id < mode.num_ebands,
"band index must be within the mode range"
);
assert!(x.len() >= n, "output band must contain at least n samples");
assert!(y.len() >= n, "side band must contain at least n samples");
let stride = mode.num_ebands;
assert!(
band_e.len() >= stride * 2,
"band energy buffer must store both channel energies",
);
assert!(
band_id + stride < band_e.len(),
"band energy buffer too small for right channel",
);
let left = band_e[band_id];
let right = band_e[band_id + stride];
let norm = EPSILON + celt_sqrt(EPSILON + left * left + right * right);
let a1 = left / norm;
let a2 = right / norm;
for idx in 0..n {
let l = x[idx];
let r = y[idx];
let mul2 = a2 * r;
let out = mul_add_f32(a1, l, mul2);
x[idx] = out;
}
}
pub(crate) fn stereo_split(x: &mut [f32], y: &mut [f32]) {
assert_eq!(
x.len(),
y.len(),
"stereo_split expects slices of equal length",
);
#[allow(clippy::approx_constant)]
let scale = 0.70710678_f32;
for (left, right) in x.iter_mut().zip(y.iter_mut()) {
let xl = *left;
let yr = *right;
let l = scale * xl;
let r = scale * yr;
let sum = l + r;
let diff = r - l;
*left = sum;
*right = diff;
}
}
#[cfg(feature = "fixed_point")]
#[inline]
fn mult16_16_q14(a: i16, b: i16) -> i16 {
((i32::from(a) * i32::from(b)) >> 14) as i16
}
#[cfg(feature = "fixed_point")]
fn celt_exp2_q10_fixed(x: i16) -> i32 {
const D0: i16 = 16_383;
const D1: i16 = 22_804;
const D2: i16 = 14_819;
const D3: i16 = 10_204;
let integer = x >> 10;
if integer > 14 {
return 0x7f00_0000;
}
if integer < -15 {
return 0;
}
let frac_input = x.wrapping_sub(integer.wrapping_shl(10));
let frac = frac_input.wrapping_shl(4);
let frac_q14 = D0.wrapping_add(mult16_16_q15(
frac,
D1.wrapping_add(mult16_16_q15(
frac,
D2.wrapping_add(mult16_16_q15(D3, frac)),
)),
));
vshr32(i32::from(frac_q14), i32::from(-integer - 2))
}
#[cfg(feature = "fixed_point")]
#[inline]
fn celt_exp2_db_fixed(x: FixedCeltGlog) -> i32 {
celt_exp2_q10_fixed(pshr32(x, DB_SHIFT - 10) as i16)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn anti_collapse(
mode: &OpusCustomMode<'_>,
x: &mut [OpusVal16],
collapse_masks: &[u8],
lm: usize,
channels: usize,
size: usize,
start: usize,
end: usize,
log_e: &[CeltGlog],
prev1_log_e: &[CeltGlog],
prev2_log_e: &[CeltGlog],
pulses: &[i32],
mut seed: u32,
encode: bool,
arch: i32,
) {
assert!(channels > 0, "anti_collapse requires at least one channel");
assert!(start <= end, "start band must not exceed end band");
assert!(end <= mode.num_ebands, "band range exceeds mode span");
assert!(
collapse_masks.len() >= channels * end,
"collapse masks too short"
);
assert!(
log_e.len() >= channels * mode.num_ebands,
"logE buffer too small"
);
assert!(
prev1_log_e.len() >= channels * mode.num_ebands,
"prev1 buffer too small"
);
assert!(
prev2_log_e.len() >= channels * mode.num_ebands,
"prev2 buffer too small"
);
assert!(
pulses.len() >= end,
"pulse buffer too small for requested bands"
);
let expected_stride = mode.short_mdct_size << lm;
assert_eq!(
size, expected_stride,
"channel stride must match the MDCT length for the block size",
);
assert!(
x.len() >= channels * size,
"spectrum buffer shorter than the requested channel span",
);
let block_count = 1usize << lm;
let band_stride = mode.num_ebands;
for (band, &pulses_for_band) in pulses.iter().enumerate().take(end).skip(start) {
let band_begin =
usize::try_from(mode.e_bands[band]).expect("band index must be non-negative");
let band_end =
usize::try_from(mode.e_bands[band + 1]).expect("band index must be non-negative");
let width = band_end.saturating_sub(band_begin);
if width == 0 {
continue;
}
assert!(pulses_for_band >= 0, "pulse counts must be non-negative");
let numerator = u32::try_from(pulses_for_band)
.expect("pulse count fits in u32")
.wrapping_add(1);
let denom = u32::try_from(width).expect("band width fits in u32");
debug_assert!(denom > 0, "band width must be positive");
let depth = (celt_udiv(numerator, denom) >> lm) as i32;
let thresh = 0.5 * celt_exp2(-0.125 * depth as f32);
let sqrt_1 = celt_rsqrt((width << lm) as f32);
for channel in 0..channels {
let mask = u32::from(collapse_masks[band * channels + channel]);
let channel_base = channel * size;
let band_base = channel_base + (band_begin << lm);
let band_len = width << lm;
assert!(
band_base + band_len <= x.len(),
"band slice exceeds spectrum length"
);
let mut prev1 = prev1_log_e[channel * band_stride + band];
let mut prev2 = prev2_log_e[channel * band_stride + band];
if !encode && channels == 1 {
let alt = band_stride + band;
if alt < prev1_log_e.len() {
prev1 = prev1.max(prev1_log_e[alt]);
}
if alt < prev2_log_e.len() {
prev2 = prev2.max(prev2_log_e[alt]);
}
}
let mut ediff = log_e[channel * band_stride + band] - prev1.min(prev2);
if ediff < 0.0 {
ediff = 0.0;
}
let mut r = 2.0 * celt_exp2(-ediff);
if lm == 3 {
r *= SQRT_2;
}
r = r.min(thresh);
r *= sqrt_1;
let mut needs_renorm = false;
for k in 0..block_count {
if mask & (1u32 << k) == 0 {
for j in 0..width {
seed = celt_lcg_rand(seed);
let idx = band_base + (j << lm) + k;
x[idx] = if seed & 0x8000 != 0 { r } else { -r };
}
needs_renorm = true;
}
}
if needs_renorm {
let end_idx = band_base + band_len;
pvq_renormalise_runtime(&mut x[band_base..end_idx], band_len, 1.0, arch);
}
}
}
}
#[cfg(feature = "fixed_point")]
#[allow(clippy::too_many_arguments)]
pub(crate) fn anti_collapse_fixed(
mode: &OpusCustomMode<'_>,
x: &mut [FixedCeltNorm],
collapse_masks: &[u8],
lm: usize,
channels: usize,
size: usize,
start: usize,
end: usize,
log_e: &[FixedCeltGlog],
prev1_log_e: &[FixedCeltGlog],
prev2_log_e: &[FixedCeltGlog],
pulses: &[i32],
mut seed: u32,
encode: bool,
arch: i32,
) {
assert!(channels > 0, "anti_collapse requires at least one channel");
assert!(start <= end, "start band must not exceed end band");
assert!(end <= mode.num_ebands, "band range exceeds mode span");
assert!(
collapse_masks.len() >= channels * end,
"collapse masks too short"
);
assert!(
log_e.len() >= channels * mode.num_ebands,
"logE buffer too small"
);
assert!(
prev1_log_e.len() >= channels * mode.num_ebands,
"prev1 buffer too small"
);
assert!(
prev2_log_e.len() >= channels * mode.num_ebands,
"prev2 buffer too small"
);
assert!(
pulses.len() >= end,
"pulse buffer too small for requested bands"
);
let expected_stride = mode.short_mdct_size << lm;
assert_eq!(
size, expected_stride,
"channel stride must match the MDCT length for the block size",
);
assert!(
x.len() >= channels * size,
"spectrum buffer shorter than the requested channel span",
);
for band in start..end {
let width = (mode.e_bands[band + 1] - mode.e_bands[band]) as usize;
if width == 0 {
continue;
}
let depth = (celt_udiv(
u32::try_from(pulses[band])
.expect("pulse count fits in u32")
.wrapping_add(1),
width as u32,
) >> lm) as i32;
let thresh32 = shr32(celt_exp2_q10_fixed((-(depth << (10 - BITRES))) as i16), 1);
let thresh = mult16_32_q15(qconst16(0.5, 15), 32_767.min(thresh32)) as i16;
let t = (width as i32) << lm;
let shift = celt_ilog2(t) >> 1;
let sqrt_1 = celt_rsqrt_norm_fixed(shl32(t, ((7 - shift) << 1) as u32));
for channel in 0..channels {
let mut prev1 = prev1_log_e[channel * mode.num_ebands + band];
let mut prev2 = prev2_log_e[channel * mode.num_ebands + band];
if !encode && channels == 1 {
prev1 = prev1.max(prev1_log_e[mode.num_ebands + band]);
prev2 = prev2.max(prev2_log_e[mode.num_ebands + band]);
}
let ediff =
0.max(log_e[channel * mode.num_ebands + band].wrapping_sub(prev1.min(prev2)));
let mut r = if ediff < qconst32(16.0, DB_SHIFT) {
let r32 = shr32(celt_exp2_db_fixed(-ediff), 1);
(2 * 16_383.min(r32)) as i16
} else {
0
};
if lm == 3 {
r = mult16_16_q14(23_170, 23_169.min(i32::from(r)) as i16);
}
r = shr32(i32::from(thresh.min(r)), 1) as i16;
r = shr32(i32::from(mult16_16_q15(sqrt_1, r)), shift as u32) as i16;
let band_base = channel * size + ((mode.e_bands[band] as usize) << lm);
let mut renormalize = false;
for k in 0..(1usize << lm) {
if (collapse_masks[band * channels + channel] & (1 << k)) == 0 {
for j in 0..width {
seed = celt_lcg_rand(seed);
x[band_base + ((j << lm) + k)] = if (seed & 0x8000) != 0 { r } else { -r };
}
renormalize = true;
}
}
if renormalize {
renormalise_vector_fixed(
&mut x[band_base..band_base + (width << lm)],
width << lm,
Q31_ONE,
arch,
);
}
}
}
}
pub(crate) fn stereo_merge(x: &mut [OpusVal16], y: &mut [OpusVal16], mid: OpusVal32) {
assert_eq!(
x.len(),
y.len(),
"stereo_merge expects slices of equal length",
);
if x.is_empty() {
return;
}
let (mut cross, side_energy) = dual_inner_prod(y, x, y);
cross *= mid;
let mid_energy = mid * mid;
let el = mid_energy + side_energy - 2.0 * cross;
let er = mid_energy + side_energy + 2.0 * cross;
if er < 6e-4 || el < 6e-4 {
y.copy_from_slice(x);
return;
}
let lgain = celt_rsqrt_norm(el);
let rgain = celt_rsqrt_norm(er);
for (left, right) in x.iter_mut().zip(y.iter_mut()) {
let mid_scaled = mid * *left;
let side_val = *right;
*left = lgain * (mid_scaled - side_val);
*right = rgain * (mid_scaled + side_val);
}
}
pub(crate) fn special_hybrid_folding(
mode: &OpusCustomMode,
norm: &mut [OpusVal16],
norm2: Option<&mut [OpusVal16]>,
start: usize,
m: usize,
dual_stereo: bool,
) {
debug_assert!(
start + 2 < mode.e_bands.len(),
"hybrid folding requires two successor bands"
);
let e_bands = mode.e_bands;
let n1 = m * (e_bands[start + 1] - e_bands[start]) as usize;
let n2 = m * (e_bands[start + 2] - e_bands[start + 1]) as usize;
if n2 <= n1 {
return;
}
let copy_len = n2 - n1;
let src_start = 2 * n1 - n2;
debug_assert!(
n1 + copy_len <= norm.len(),
"destination slice exceeds bounds"
);
debug_assert!(
src_start + copy_len <= norm.len(),
"source slice exceeds bounds"
);
let temp: Vec<OpusVal16> = norm[src_start..src_start + copy_len].to_vec();
norm[n1..n1 + copy_len].copy_from_slice(&temp);
if let (true, Some(norm2)) = (dual_stereo, norm2) {
debug_assert!(
n1 + copy_len <= norm2.len(),
"destination slice exceeds bounds"
);
debug_assert!(
src_start + copy_len <= norm2.len(),
"source slice exceeds bounds"
);
let temp2: Vec<OpusVal16> = norm2[src_start..src_start + copy_len].to_vec();
norm2[n1..n1 + copy_len].copy_from_slice(&temp2);
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn spreading_decision(
mode: &OpusCustomMode,
x: &[OpusVal16],
average: &mut i32,
last_decision: i32,
hf_average: &mut i32,
tapset_decision: &mut i32,
update_hf: bool,
end: usize,
channels: usize,
m: usize,
spread_weight: &[i32],
) -> i32 {
assert!(end > 0, "band range must contain at least one band");
assert!(end <= mode.num_ebands, "band range exceeds mode span");
assert!(spread_weight.len() >= end, "insufficient spread weights");
let n0 = m * mode.short_mdct_size;
assert!(x.len() >= channels * n0, "spectrum buffer too small");
let last_band_width =
m * (mode.e_bands[end] as usize).saturating_sub(mode.e_bands[end - 1] as usize);
if last_band_width <= 8 {
return SPREAD_NONE;
}
let mut sum = 0i32;
let mut nb_bands = 0i32;
let mut hf_sum = 0i32;
for c in 0..channels {
let channel_base = c * n0;
for (band, &weight) in spread_weight.iter().take(end).enumerate() {
let start = m * (mode.e_bands[band] as usize);
let stop = m * (mode.e_bands[band + 1] as usize);
let n = stop - start;
if n <= 8 {
continue;
}
let slice = &x[channel_base + start..channel_base + stop];
let mut tcount = [0i32; 3];
for &value in slice {
let x2n = value * value * n as OpusVal16;
if x2n < 0.25 {
tcount[0] += 1;
}
if x2n < 0.0625 {
tcount[1] += 1;
}
if x2n < 0.015625 {
tcount[2] += 1;
}
}
if band + 4 > mode.num_ebands {
let numerator = 32 * (tcount[1] + tcount[0]);
hf_sum += celt_udiv(numerator as u32, n as u32) as i32;
}
let mut tmp = 0i32;
if 2 * tcount[2] >= n as i32 {
tmp += 1;
}
if 2 * tcount[1] >= n as i32 {
tmp += 1;
}
if 2 * tcount[0] >= n as i32 {
tmp += 1;
}
sum += tmp * weight;
nb_bands += weight;
}
}
if update_hf {
if hf_sum != 0 {
let denom = (channels as i32) * (4 - mode.num_ebands as i32 + end as i32);
if denom > 0 {
hf_sum = celt_udiv(hf_sum as u32, denom as u32) as i32;
} else {
hf_sum = 0;
}
}
*hf_average = (*hf_average + hf_sum) >> 1;
hf_sum = *hf_average;
match *tapset_decision {
2 => hf_sum += 4,
0 => hf_sum -= 4,
_ => {}
}
if hf_sum > 22 {
*tapset_decision = 2;
} else if hf_sum > 18 {
*tapset_decision = 1;
} else {
*tapset_decision = 0;
}
}
assert!(
nb_bands > 0,
"spreading analysis requires at least one band"
);
let scaled = (i64::from(sum) << 8) as u32;
let denom = nb_bands as u32;
let mut sum = celt_udiv(scaled, denom) as i32;
sum = (sum + *average) >> 1;
*average = sum;
let hysteresis = ((3 - last_decision) << 7) + 64;
sum = (3 * sum + hysteresis + 2) >> 2;
if sum < 80 {
SPREAD_AGGRESSIVE
} else if sum < 256 {
SPREAD_NORMAL
} else if sum < 384 {
SPREAD_LIGHT
} else {
SPREAD_NONE
}
}
pub(crate) fn deinterleave_hadamard(x: &mut [OpusVal16], n0: usize, stride: usize, hadamard: bool) {
if stride == 0 {
return;
}
let n = n0.checked_mul(stride).expect("stride * n0 overflowed");
assert!(x.len() >= n, "input buffer too small for deinterleave");
if n == 0 {
return;
}
let mut tmp = vec![0.0f32; n];
if hadamard {
let ordery = hadamard_ordery(stride)
.expect("hadamard interleave only defined for strides of 2, 4, 8, or 16");
assert_eq!(ordery.len(), stride);
for (i, &ord) in ordery.iter().enumerate() {
for j in 0..n0 {
tmp[ord * n0 + j] = x[j * stride + i];
}
}
} else {
for i in 0..stride {
for j in 0..n0 {
tmp[i * n0 + j] = x[j * stride + i];
}
}
}
x[..n].copy_from_slice(&tmp);
}
pub(crate) fn interleave_hadamard(x: &mut [OpusVal16], n0: usize, stride: usize, hadamard: bool) {
if stride == 0 {
return;
}
let n = n0.checked_mul(stride).expect("stride * n0 overflowed");
assert!(x.len() >= n, "input buffer too small for interleave");
if n == 0 {
return;
}
let mut tmp = vec![0.0f32; n];
if hadamard {
let ordery = hadamard_ordery(stride)
.expect("hadamard interleave only defined for strides of 2, 4, 8, or 16");
assert_eq!(ordery.len(), stride);
for (i, &ord) in ordery.iter().enumerate() {
for j in 0..n0 {
tmp[j * stride + i] = x[ord * n0 + j];
}
}
} else {
for i in 0..stride {
for j in 0..n0 {
tmp[j * stride + i] = x[i * n0 + j];
}
}
}
x[..n].copy_from_slice(&tmp);
}
pub(crate) fn haar1(x: &mut [OpusVal16], n0: usize, stride: usize) {
if stride == 0 || n0 < 2 {
return;
}
let half = n0 / 2;
if half == 0 {
return;
}
let required = stride * n0;
assert!(
x.len() >= required,
"haar1 expects at least stride * n0 coefficients"
);
#[allow(clippy::approx_constant)]
let scale = 0.70710678_f32 as OpusVal16;
for i in 0..stride {
for j in 0..half {
let idx0 = stride * (2 * j) + i;
let idx1 = idx0 + stride;
debug_assert!(idx1 < x.len());
let tmp1 = scale * x[idx0];
let tmp2 = scale * x[idx1];
x[idx0] = tmp1 + tmp2;
x[idx1] = tmp1 - tmp2;
}
}
}
pub(crate) fn compute_band_energies(
mode: &OpusCustomMode<'_>,
x: &[CeltSig],
band_e: &mut [CeltGlog],
end: usize,
channels: usize,
lm: usize,
arch: i32,
) {
let _ = arch;
assert!(
end <= mode.num_ebands,
"end band must not exceed mode bands"
);
assert!(
mode.e_bands.len() > end,
"eBands must contain end + 1 entries"
);
let n = mode.short_mdct_size << lm;
assert!(
x.len() >= channels * n,
"input spectrum is too short for the mode"
);
let stride = mode.num_ebands;
assert!(
band_e.len() >= channels * stride,
"band energy buffer too small"
);
for c in 0..channels {
let signal_base = c * n;
let energy_base = c * stride;
for band in 0..end {
let band_start = (mode.e_bands[band] as usize) << lm;
let band_end = (mode.e_bands[band + 1] as usize) << lm;
assert!(band_end <= n, "band end exceeds MDCT length");
let slice = &x[signal_base + band_start..signal_base + band_end];
let sum = 1e-27_f32 + celt_inner_prod(slice, slice);
band_e[energy_base + band] = celt_sqrt(sum);
}
}
}
#[cfg(feature = "fixed_point")]
pub(crate) fn compute_band_energies_fixed(
mode: &OpusCustomMode<'_>,
x: &[FixedCeltSig],
band_e: &mut [FixedCeltEner],
end: usize,
channels: usize,
lm: usize,
) {
assert!(
end <= mode.num_ebands,
"end band must not exceed mode bands"
);
assert!(
mode.e_bands.len() > end,
"eBands must contain end + 1 entries"
);
let n = mode.short_mdct_size << lm;
assert!(
x.len() >= channels * n,
"input spectrum is too short for the mode"
);
let stride = mode.num_ebands;
assert!(
band_e.len() >= channels * stride,
"band energy buffer too small"
);
for c in 0..channels {
let signal_base = c * n;
let energy_base = c * stride;
for band in 0..end {
let band_start = (mode.e_bands[band] as usize) << lm;
let band_end = (mode.e_bands[band + 1] as usize) << lm;
let slice = &x[signal_base + band_start..signal_base + band_end];
let mut maxval = 0i32;
for &value in slice {
maxval = maxval.max(abs32(value));
}
if maxval > 0 {
let mut sum = 0i32;
let mut shift = celt_ilog2(maxval) - 14;
let shift2 = ((i32::from(mode.log_n[band]) >> BITRES) + lm as i32 + 1) >> 1;
if shift > 0 {
for &value in slice {
let sample = extract16(shr32(value, shift as u32));
sum =
sum.wrapping_add(shr32(mult16_16(sample, sample), (2 * shift2) as u32));
}
} else {
for &value in slice {
let sample = extract16(shl32(value, (-shift) as u32));
sum =
sum.wrapping_add(shr32(mult16_16(sample, sample), (2 * shift2) as u32));
}
}
shift += shift2;
while sum < (1 << 28) {
sum <<= 2;
shift -= 1;
}
band_e[energy_base + band] =
FixedCeltEner::from(FIXED_EPSILON) + vshr32(celt_sqrt_fixed(sum), -shift);
} else {
band_e[energy_base + band] = FixedCeltEner::from(FIXED_EPSILON);
}
}
}
}
pub(crate) fn normalise_bands(
mode: &OpusCustomMode<'_>,
freq: &[CeltSig],
x: &mut [OpusVal16],
band_e: &[CeltGlog],
end: usize,
channels: usize,
m: usize,
) {
assert!(
end <= mode.num_ebands,
"end band must not exceed mode bands"
);
assert!(
mode.e_bands.len() > end,
"eBands must contain end + 1 entries"
);
let n = m * mode.short_mdct_size;
assert!(freq.len() >= channels * n, "frequency buffer too small");
assert!(x.len() >= channels * n, "normalisation buffer too small");
let stride = mode.num_ebands;
assert!(
band_e.len() >= channels * stride,
"band energy buffer too small"
);
for c in 0..channels {
let freq_base = c * n;
let energy_base = c * stride;
for band in 0..end {
let start = m * (mode.e_bands[band] as usize);
let stop = m * (mode.e_bands[band + 1] as usize);
assert!(stop <= n, "band end exceeds MDCT length");
let gain = 1.0 / (1e-27_f32 + band_e[energy_base + band]);
for idx in start..stop {
x[freq_base + idx] = freq[freq_base + idx] * gain;
}
}
}
}
#[cfg(feature = "fixed_point")]
pub(crate) fn normalise_bands_fixed(
mode: &OpusCustomMode<'_>,
freq: &[FixedCeltSig],
x: &mut [FixedCeltNorm],
band_e: &[FixedCeltEner],
end: usize,
channels: usize,
m: usize,
) {
assert!(
end <= mode.num_ebands,
"end band must not exceed mode bands"
);
assert!(
mode.e_bands.len() > end,
"eBands must contain end + 1 entries"
);
let n = m * mode.short_mdct_size;
assert!(freq.len() >= channels * n);
assert!(x.len() >= channels * n);
let stride = mode.num_ebands;
assert!(band_e.len() >= channels * stride);
for c in 0..channels {
let signal_base = c * n;
let energy_base = c * stride;
for band in 0..end {
let shift = celt_zlog2(band_e[energy_base + band]) - 14;
let e = vshr32(band_e[energy_base + band], shift - 2);
let g = extract16(celt_rcp_fixed(e));
let band_start = (mode.e_bands[band] as usize) * m;
let band_end = (mode.e_bands[band + 1] as usize) * m;
if shift > 0 {
for j in band_start..band_end {
let idx = signal_base + j;
let value = mult16_32_q15(g, freq[idx]);
x[idx] = extract16(pshr32(value, shift as u32));
}
} else {
for j in band_start..band_end {
let idx = signal_base + j;
let value = mult16_32_q15(g, freq[idx]);
x[idx] = extract16(shl32(value, (-shift) as u32));
}
}
}
}
}
#[cfg(feature = "fixed_point")]
const E_MEANS_Q4: [i8; 25] = [
103, 100, 92, 85, 81, 77, 72, 70, 78, 75, 73, 71, 78, 74, 69, 72, 70, 74, 76, 71, 60, 60, 60,
60, 60,
];
#[cfg(feature = "fixed_point")]
fn celt_exp2_db_frac(x: FixedCeltGlog) -> FixedCeltSig {
const D0: i16 = 16_383;
const D1: i16 = 22_804;
const D2: i16 = 14_819;
const D3: i16 = 10_204;
let frac = ((pshr32(x, DB_SHIFT - 10) as i16) << 4) as i16;
let mut acc = mult16_16_q15(D3, frac);
acc = D2.wrapping_add(acc);
acc = mult16_16_q15(frac, acc);
acc = D1.wrapping_add(acc);
acc = mult16_16_q15(frac, acc);
let res = D0.wrapping_add(acc);
shl32(res as i32, 14)
}
#[cfg(feature = "fixed_point")]
pub(crate) fn denormalise_bands_fixed_native(
mode: &OpusCustomMode<'_>,
x: &[FixedCeltNorm],
freq: &mut [FixedCeltSig],
band_log_e: &[FixedCeltGlog],
mut start: usize,
mut end: usize,
m: usize,
downsample: usize,
silence: bool,
) {
assert!(end <= mode.num_ebands);
assert!(mode.e_bands.len() > end);
assert!(band_log_e.len() >= end);
assert!(downsample > 0);
let n = m * mode.short_mdct_size;
assert!(freq.len() >= n);
assert!(x.len() >= n);
let mut bound = m * usize::try_from(mode.e_bands[end]).expect("band edge must be non-negative");
if bound > n {
bound = n;
}
if downsample != 1 {
bound = bound.min(n / downsample);
}
if silence {
bound = 0;
start = 0;
end = 0;
}
let start_edge =
m * usize::try_from(mode.e_bands[start]).expect("band edge must be non-negative");
freq[..start_edge].fill(0);
let mut freq_idx = start_edge;
let mut x_idx = start_edge;
for band in start..end {
let band_end =
m * usize::try_from(mode.e_bands[band + 1]).expect("band edge must be non-negative");
assert!(band_end <= n);
let e_mean = i32::from(E_MEANS_Q4[band]);
let lg = band_log_e[band].wrapping_add(shl32(e_mean, DB_SHIFT - 4));
let mut shift = 15 - (lg >> DB_SHIFT);
let mut g: FixedCeltSig;
if shift > 31 {
shift = 0;
g = 0;
} else {
g = celt_exp2_db_frac(lg & ((1 << DB_SHIFT) - 1));
}
if shift < 0 {
if shift <= -2 {
g = 16_384i32.wrapping_mul(32_768);
shift = -2;
}
while freq_idx < band_end {
let value = mult16_32_q15(x[x_idx], g);
freq[freq_idx] = shl32(value, (-shift) as u32);
freq_idx += 1;
x_idx += 1;
}
} else {
while freq_idx < band_end {
let value = mult16_32_q15(x[x_idx], g);
freq[freq_idx] = shr32(value, shift as u32);
freq_idx += 1;
x_idx += 1;
}
}
}
freq[bound..n].fill(0);
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn denormalise_bands(
mode: &OpusCustomMode<'_>,
x: &[OpusVal16],
freq: &mut [CeltSig],
band_log_e: &[CeltGlog],
mut start: usize,
mut end: usize,
m: usize,
downsample: usize,
silence: bool,
) {
assert!(
end <= mode.num_ebands,
"end band must not exceed mode bands"
);
assert!(
mode.e_bands.len() > end,
"eBands must contain end + 1 entries"
);
assert!(band_log_e.len() >= end, "bandLogE must provide end entries");
let n = m * mode.short_mdct_size;
assert!(freq.len() >= n, "frequency buffer too small");
assert!(x.len() >= n, "normalised spectrum buffer too small");
assert!(downsample > 0, "downsample factor must be non-zero");
let mut bound = m * usize::try_from(mode.e_bands[end])
.expect("band edge must be non-negative")
.min(n);
if downsample != 1 {
bound = bound.min(n / downsample);
}
if silence {
bound = 0;
start = 0;
end = 0;
}
let start_edge =
m * usize::try_from(mode.e_bands[start]).expect("band edge must be non-negative");
freq[..start_edge].fill(0.0);
let mut freq_idx = start_edge;
let mut x_idx = start_edge;
for (band, &band_gain_log) in band_log_e.iter().enumerate().take(end).skip(start) {
let band_end =
m * usize::try_from(mode.e_bands[band + 1]).expect("band edge must be non-negative");
assert!(band_end <= n, "band end exceeds MDCT length");
assert!(band < E_MEANS.len(), "E_MEANS lacks entry for band");
let gain = celt_exp2((band_gain_log + E_MEANS[band]).min(32.0));
while freq_idx < band_end {
freq[freq_idx] = x[x_idx] * gain;
freq_idx += 1;
x_idx += 1;
}
}
freq[bound..n].fill(0.0);
}
#[cfg(feature = "fixed_point")]
#[allow(clippy::too_many_arguments)]
pub(crate) fn denormalise_bands_fixed(
mode: &OpusCustomMode<'_>,
x: &[OpusVal16],
freq: &mut [FixedCeltSig],
band_log_e: &[CeltGlog],
start: usize,
end: usize,
m: usize,
downsample: usize,
silence: bool,
) {
let n = m * mode.short_mdct_size;
assert!(x.len() >= n);
assert!(band_log_e.len() >= end);
let mut x_fixed = Vec::with_capacity(n);
for &sample in x.iter().take(n) {
x_fixed.push(float2int16(sample));
}
let mut log_fixed = Vec::with_capacity(end);
let log_scale = (1u32 << DB_SHIFT) as f32;
for &value in band_log_e.iter().take(end) {
log_fixed.push(float2int(value * log_scale));
}
denormalise_bands_fixed_native(
mode, &x_fixed, freq, &log_fixed, start, end, m, downsample, silence,
);
}
#[cfg(test)]
mod tests {
use super::{
BandCodingState, BandCtx, DB_SHIFT, EPSILON, NORM_SCALING, SplitCtx, anti_collapse,
bitexact_cos, bitexact_log2tan, celt_lcg_rand, compute_band_energies,
compute_channel_weights, compute_qn, compute_theta, deinterleave_hadamard,
denormalise_bands, frac_mul16, haar1, hysteresis_decision, intensity_stereo,
interleave_hadamard, normalise_bands, quant_band_n1, special_hybrid_folding,
spreading_decision, stereo_merge, stereo_split,
};
#[cfg(feature = "fixed_point")]
use super::{
compute_band_energies_fixed, denormalise_bands_fixed_native, normalise_bands_fixed,
pvq_alg_quant_runtime, pvq_alg_unquant_runtime, pvq_renormalise_runtime,
};
use crate::celt::entcode::BITRES;
#[cfg(feature = "fixed_point")]
use crate::celt::fixed_arch::EPSILON as FIXED_EPSILON;
#[cfg(feature = "fixed_point")]
use crate::celt::fixed_ops::qconst32;
#[cfg(feature = "fixed_point")]
use crate::celt::float_cast::float2int16;
use crate::celt::math::celt_exp2;
use crate::celt::quant_bands::E_MEANS;
use crate::celt::types::{CeltSig, MdctLookup, OpusCustomMode, PulseCacheData};
#[cfg(feature = "fixed_point")]
use crate::celt::vq::{alg_quant_fixed, alg_unquant_fixed, renormalise_vector_fixed};
use crate::celt::{
EcDec, EcEnc, SPREAD_AGGRESSIVE, SPREAD_NONE, SPREAD_NORMAL, celt_rsqrt_norm,
dual_inner_prod,
};
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn hysteresis_matches_reference_logic() {
let thresholds = [0.2_f32, 0.4, 0.6, 0.8];
let hysteresis = [0.05_f32; 4];
fn reference(value: f32, thresholds: &[f32], hysteresis: &[f32], prev: usize) -> usize {
let count = thresholds.len();
let mut i = 0;
while i < count {
if value < thresholds[i] {
break;
}
i += 1;
}
if i > prev && prev < count && value < thresholds[prev] + hysteresis[prev] {
i = prev;
}
if i < prev && prev > 0 && value > thresholds[prev - 1] - hysteresis[prev - 1] {
i = prev;
}
i
}
let values = [0.0, 0.15, 0.25, 0.39, 0.41, 0.59, 0.61, 0.79, 0.81, 0.95];
for prev in 0..=thresholds.len() {
for &value in &values {
let expected = reference(value, &thresholds, &hysteresis, prev);
assert_eq!(
hysteresis_decision(value, &thresholds, &hysteresis, prev),
expected,
"value {value}, prev {prev}",
);
}
}
}
#[test]
fn haar1_preserves_signal_when_applied_twice() {
let mut data = vec![
0.25_f32, -1.5, 3.5, 0.75, -2.25, 1.0, 0.5, -0.125, 2.0, -3.0, 1.5, 0.25,
];
let original = data.clone();
haar1(&mut data, 12, 1);
haar1(&mut data, 12, 1);
for (expected, observed) in original.iter().zip(data.iter()) {
assert!(
(expected - observed).abs() <= 1e-6,
"expected {expected}, got {observed}"
);
}
}
#[test]
fn channel_weights_match_reference_formula() {
let cases = [
(0.0, 0.0),
(1.0, 4.0),
(4.0, 1.0),
(10.0, 10.0),
(3.75, 0.25),
];
for &(ex, ey) in &cases {
let weights = compute_channel_weights(ex, ey);
let min_energy = ex.min(ey);
let reference_ex = ex + min_energy / 3.0;
let reference_ey = ey + min_energy / 3.0;
assert!((weights[0] - reference_ex).abs() <= f32::EPSILON * 4.0);
assert!((weights[1] - reference_ey).abs() <= f32::EPSILON * 4.0);
}
}
#[test]
fn intensity_stereo_matches_reference_weights() {
let e_bands = [0i16, 2, 4, 6, 8];
let alloc_vectors = [0u8; 4];
let log_n = [0i16; 4];
let window = [0.0f32; 4];
let mdct = MdctLookup::new(4, 0);
let mode = OpusCustomMode::new_test(
48_000,
0,
&e_bands,
&alloc_vectors,
&log_n,
&window,
mdct,
PulseCacheData::default(),
);
let mut x = vec![0.5, -0.75, 0.25, -0.125];
let y = vec![0.25, 0.5, -0.5, 0.75];
let mut band_e = vec![0.0f32; mode.num_ebands * 2];
band_e[2] = 1.8;
band_e[2 + mode.num_ebands] = 0.9;
let left = band_e[2];
let right = band_e[2 + mode.num_ebands];
let norm = EPSILON + (EPSILON + left * left + right * right).sqrt();
let a1 = left / norm;
let a2 = right / norm;
let mut expected = x.clone();
for (idx, value) in expected.iter_mut().enumerate() {
*value = a1 * *value + a2 * y[idx];
}
intensity_stereo(&mode, &mut x, &y, &band_e, 2, y.len());
for (idx, (&observed, &reference)) in x.iter().zip(expected.iter()).enumerate() {
assert!(
(observed - reference).abs() <= 1e-6,
"sample {idx}: observed={observed}, expected={reference}"
);
}
}
#[test]
fn lcg_rand_produces_expected_sequence() {
let mut seed = 0xDEAD_BEEF_u32;
let mut expected = [0_u32; 5];
for slot in &mut expected {
let next = ((1_664_525_u64 * u64::from(seed)) + 1_013_904_223_u64) & 0xFFFF_FFFF;
*slot = next as u32;
seed = next as u32;
}
seed = 0xDEAD_BEEF_u32;
for &value in &expected {
seed = celt_lcg_rand(seed);
assert_eq!(seed, value);
}
}
#[test]
fn compute_qn_covers_reference_cases() {
let cases = [
((1, 12, 3, 8, false), 1),
((2, 20, 2, 16, true), 1),
((4, 64, 1, 24, false), 2),
((8, 200, 0, 32, true), 4),
((3, 48, 4, 12, false), 2),
];
for ((n, b, offset, pulse_cap, stereo), expected) in cases {
assert_eq!(
compute_qn(n, b, offset, pulse_cap, stereo),
expected,
"compute_qn({n}, {b}, {offset}, {pulse_cap}, {stereo})",
);
}
}
#[test]
fn spreading_returns_aggressive_for_concentrated_energy() {
let e_bands = [0i16, 16, 32];
let mode = dummy_mode(&e_bands, 32);
let channels = 1;
let m = 1;
let end = 2;
let spread_weight = [1, 1];
let spectrum = vec![1.0f32; channels * m * mode.short_mdct_size];
let mut average = 0;
let mut hf_average = 0;
let mut tapset = 1;
let decision = spreading_decision(
&mode,
&spectrum,
&mut average,
SPREAD_NORMAL,
&mut hf_average,
&mut tapset,
false,
end,
channels,
m,
&spread_weight,
);
assert_eq!(decision, SPREAD_AGGRESSIVE);
assert_eq!(tapset, 1);
assert_eq!(hf_average, 0);
assert_eq!(average, 0);
}
#[test]
fn spreading_returns_normal_when_single_threshold_met() {
let e_bands = [0i16, 16, 32];
let mode = dummy_mode(&e_bands, 32);
let channels = 1;
let m = 1;
let end = 2;
let spread_weight = [1, 1];
let mut spectrum = vec![1.0f32; channels * m * mode.short_mdct_size];
for slot in spectrum.iter_mut().take(8) {
*slot = 0.1;
}
let mut average = 0;
let mut hf_average = 0;
let mut tapset = 1;
let decision = spreading_decision(
&mode,
&spectrum,
&mut average,
SPREAD_NORMAL,
&mut hf_average,
&mut tapset,
false,
end,
channels,
m,
&spread_weight,
);
assert_eq!(decision, SPREAD_NORMAL);
assert_eq!(tapset, 1);
assert_eq!(hf_average, 0);
assert_eq!(average, 64);
}
#[test]
fn spreading_returns_none_when_all_thresholds_met() {
let e_bands = [0i16, 16, 32];
let mode = dummy_mode(&e_bands, 32);
let channels = 1;
let m = 1;
let end = 1;
let spread_weight = [1];
let mut spectrum = vec![1.0f32; channels * m * mode.short_mdct_size];
for slot in spectrum.iter_mut().take(8) {
*slot = 0.01;
}
let mut average = 0;
let mut hf_average = 0;
let mut tapset = 1;
let decision = spreading_decision(
&mode,
&spectrum,
&mut average,
SPREAD_NONE,
&mut hf_average,
&mut tapset,
false,
end,
channels,
m,
&spread_weight,
);
assert_eq!(decision, SPREAD_NONE);
assert_eq!(tapset, 1);
assert_eq!(hf_average, 0);
assert_eq!(average, 384);
}
#[test]
fn spreading_updates_hf_tracking() {
let e_bands: Vec<i16> = (0..=10).map(|i| (i * 24) as i16).collect();
let mode = dummy_mode(&e_bands, 256);
let channels = 1;
let m = 1;
let end = mode.num_ebands;
let spread_weight = vec![1; end];
let spectrum = vec![0.0f32; channels * m * mode.short_mdct_size];
let mut average = 0;
let mut hf_average = 0;
let mut tapset = 1;
let decision = spreading_decision(
&mode,
&spectrum,
&mut average,
SPREAD_NONE,
&mut hf_average,
&mut tapset,
true,
end,
channels,
m,
&spread_weight,
);
assert_eq!(decision, SPREAD_NONE);
assert_eq!(tapset, 2);
assert_eq!(hf_average, 24);
assert_eq!(average, 384);
}
#[test]
fn stereo_split_matches_reference_transform() {
let mut mid = [1.0_f32, -1.5, 0.25, 0.0];
let mut side = [0.5_f32, 2.0, -0.75, 1.25];
let mut expected_mid = mid;
let mut expected_side = side;
for idx in 0..mid.len() {
let m = core::f32::consts::FRAC_1_SQRT_2 * expected_mid[idx];
let s = core::f32::consts::FRAC_1_SQRT_2 * expected_side[idx];
expected_mid[idx] = m + s;
expected_side[idx] = s - m;
}
stereo_split(&mut mid, &mut side);
for (observed, reference) in mid.iter().zip(expected_mid.iter()) {
assert!((observed - reference).abs() <= f32::EPSILON * 16.0);
}
for (observed, reference) in side.iter().zip(expected_side.iter()) {
assert!((observed - reference).abs() <= f32::EPSILON * 16.0);
}
}
fn reference_stereo_merge(x: &[f32], y: &[f32], mid: f32) -> (Vec<f32>, Vec<f32>) {
let mut left = x.to_vec();
let mut right = y.to_vec();
let (mut cross, side_energy) = dual_inner_prod(&right, &left, &right);
cross *= mid;
let mid_energy = mid * mid;
let el = mid_energy + side_energy - 2.0 * cross;
let er = mid_energy + side_energy + 2.0 * cross;
if er < 6e-4 || el < 6e-4 {
right.copy_from_slice(&left);
return (left, right);
}
let lgain = celt_rsqrt_norm(el);
let rgain = celt_rsqrt_norm(er);
for (l, r) in left.iter_mut().zip(right.iter_mut()) {
let mid_scaled = mid * *l;
let side_val = *r;
*l = lgain * (mid_scaled - side_val);
*r = rgain * (mid_scaled + side_val);
}
(left, right)
}
#[test]
fn stereo_merge_matches_reference_transform() {
let mut left = [0.8, -0.25, 0.5, -0.75, 0.1, 0.3];
let mut right = [-0.2, 0.4, -0.6, 0.3, -0.1, 0.2];
let mid = 0.9;
let (expected_left, expected_right) = reference_stereo_merge(&left, &right, mid);
stereo_merge(&mut left, &mut right, mid);
for (idx, (&value, &expected)) in left.iter().zip(expected_left.iter()).enumerate() {
assert!(
(value - expected).abs() <= 1e-6,
"left[{idx}] mismatch: value={value}, expected={expected}"
);
}
for (idx, (&value, &expected)) in right.iter().zip(expected_right.iter()).enumerate() {
assert!(
(value - expected).abs() <= 1e-6,
"right[{idx}] mismatch: value={value}, expected={expected}"
);
}
}
#[test]
fn stereo_merge_copies_mid_for_low_energy() {
let mut left = [0.0f32; 4];
let mut right = [1e-3f32, -1e-3, 2e-3, -2e-3];
stereo_merge(&mut left, &mut right, 0.0);
assert_eq!(right, left);
}
#[test]
fn special_hybrid_folding_duplicates_primary_when_needed() {
let e_bands = [0i16, 1, 3, 6];
let mode = dummy_mode(&e_bands, 8);
let mut norm = vec![0.1f32, 0.2, 0.3, 0.4, 0.5, 0.6];
special_hybrid_folding(&mode, &mut norm, None, 0, 2, false);
assert_eq!(norm, vec![0.1, 0.2, 0.1, 0.2, 0.5, 0.6]);
}
#[test]
fn special_hybrid_folding_updates_secondary_when_dual_stereo() {
let e_bands = [0i16, 1, 3, 6];
let mode = dummy_mode(&e_bands, 8);
let mut norm = vec![0.1f32, 0.2, 0.3, 0.4, 0.5, 0.6];
let mut norm2 = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
special_hybrid_folding(&mode, &mut norm, Some(&mut norm2), 0, 2, true);
assert_eq!(norm, vec![0.1, 0.2, 0.1, 0.2, 0.5, 0.6]);
assert_eq!(norm2, vec![1.0, 2.0, 1.0, 2.0, 5.0, 6.0]);
}
#[test]
fn special_hybrid_folding_noops_when_second_band_not_wider() {
let e_bands = [0i16, 2, 3, 5];
let mode = dummy_mode(&e_bands, 4);
let mut norm = vec![0.0f32, 1.0, 2.0, 3.0];
let mut norm2 = vec![4.0f32, 5.0, 6.0, 7.0];
let expected_norm = norm.clone();
let expected_norm2 = norm2.clone();
special_hybrid_folding(&mode, &mut norm, Some(&mut norm2), 0, 1, true);
assert_eq!(norm, expected_norm);
assert_eq!(norm2, expected_norm2);
}
fn reference_ordery(stride: usize) -> &'static [usize] {
match stride {
2 => &[1, 0],
4 => &[3, 0, 2, 1],
8 => &[7, 0, 4, 3, 6, 1, 5, 2],
16 => &[15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5],
_ => panic!("unsupported stride"),
}
}
#[test]
fn hadamard_interleave_matches_reference_layout() {
for &stride in &[2, 4, 8, 16] {
let n0 = 4usize;
let n = n0 * stride;
let mut data: Vec<f32> = (0..n).map(|v| v as f32).collect();
let mut expected = data.clone();
let ordery = reference_ordery(stride);
for (i, &ord) in ordery.iter().enumerate() {
for j in 0..n0 {
expected[j * stride + i] = data[ord * n0 + j];
}
}
interleave_hadamard(&mut data, n0, stride, true);
assert_eq!(data[..n], expected[..n]);
}
}
#[test]
fn interleave_and_deinterleave_round_trip() {
let cases = [
(4usize, 2usize, false),
(4, 2, true),
(8, 4, false),
(8, 4, true),
];
for &(n0, stride, hadamard) in &cases {
let n = n0 * stride;
let data: Vec<f32> = (0..n).map(|v| (v as f32) * 0.5 - 3.0).collect();
let mut transformed = data.clone();
interleave_hadamard(&mut transformed, n0, stride, hadamard);
deinterleave_hadamard(&mut transformed, n0, stride, hadamard);
assert_eq!(transformed[..n], data[..n]);
}
}
#[test]
fn frac_mul16_matches_c_macro() {
fn reference(a: i32, b: i32) -> i32 {
let a = a as i16;
let b = b as i16;
(16_384 + i32::from(a) * i32::from(b)) >> 15
}
let samples = [
(-32_768, -32_768),
(-32_768, 32_767),
(-20_000, 16_000),
(-626, 8_000),
(8_277, -5_000),
(7_932, 2_000),
(32_767, 32_767),
];
for &(a, b) in &samples {
assert_eq!(frac_mul16(a, b), reference(a, b));
}
}
#[test]
fn bitexact_cos_matches_reference() {
let mut chk: i32 = 0;
let mut max_d: i32 = 0;
let mut min_d: i32 = 32_767;
let mut last: i32 = 32_767;
for i in 64..=16_320 {
let q = i32::from(bitexact_cos(i));
chk ^= q * i32::from(i);
let d = last - q;
if d > max_d {
max_d = d;
}
if d < min_d {
min_d = d;
}
last = q;
}
assert_eq!(chk, 89_408_644, "checksum mismatch");
assert_eq!(max_d, 5, "max_d mismatch");
assert_eq!(min_d, 0, "min_d mismatch");
assert_eq!(bitexact_cos(64), 32_767, "bitexact_cos(64) mismatch");
assert_eq!(bitexact_cos(16_320), 200, "bitexact_cos(16320) mismatch");
assert_eq!(bitexact_cos(8_192), 23_171, "bitexact_cos(8192) mismatch");
}
#[test]
fn bitexact_log2tan_matches_reference() {
let mut fail = false;
let mut chk: i32 = 0;
let mut max_d: i32 = 0;
let mut min_d: i32 = 15_059;
let mut last: i32 = 15_059;
for i in 64..8_193 {
let mid = i32::from(bitexact_cos(i));
let side = i32::from(bitexact_cos(16_384 - i));
let q = bitexact_log2tan(mid, side);
chk ^= q * i32::from(i);
let d = last - q;
if q != -bitexact_log2tan(side, mid) {
fail = true;
}
if d > max_d {
max_d = d;
}
if d < min_d {
min_d = d;
}
last = q;
}
assert_eq!(chk, 15_821_257, "checksum mismatch");
assert_eq!(max_d, 61, "max_d mismatch");
assert_eq!(min_d, -2, "min_d mismatch");
assert!(!fail, "antisymmetry check failed");
assert_eq!(
bitexact_log2tan(32_767, 200),
15_059,
"bitexact_log2tan(32767,200) mismatch"
);
assert_eq!(
bitexact_log2tan(30_274, 12_540),
2_611,
"bitexact_log2tan(30274,12540) mismatch"
);
assert_eq!(
bitexact_log2tan(23_171, 23_171),
0,
"bitexact_log2tan(23171,23171) mismatch"
);
}
#[test]
fn bitexact_cos_matches_reference_samples() {
let inputs = [-16_383, -12_000, -6_000, -1, 0, 1, 6_000, 12_000, 16_383];
let expected = [
3, 13_371, 27_494, -32_768, -32_768, -32_768, 27_494, 13_371, 3,
];
for (&input, &value) in inputs.iter().zip(expected.iter()) {
assert_eq!(bitexact_cos(input), value);
}
}
#[test]
fn bitexact_log2tan_matches_reference_samples() {
let inputs = [
(23_170, 32_767),
(11_585, 32_767),
(16_384, 23_170),
(30_000, 12_345),
(12_345, 30_000),
(1, 32_767),
(32_767, 1),
];
let expected = [-1_025, -3_073, -993, 2_631, -2_631, -30_690, 30_690];
for ((isin, icos), &value) in inputs.iter().zip(expected.iter()) {
assert_eq!(bitexact_log2tan(*isin, *icos), value);
}
}
fn dummy_mode<'a>(e_bands: &'a [i16], short_mdct_size: usize) -> OpusCustomMode<'a> {
let mdct = Box::leak(Box::new(MdctLookup::new(short_mdct_size, 0)));
let cache = Box::leak(Box::new(PulseCacheData::default()));
OpusCustomMode {
sample_rate: 48_000,
overlap: 0,
num_ebands: e_bands.len() - 1,
effective_ebands: e_bands.len() - 1,
pre_emphasis: [0.0; 4],
e_bands,
max_lm: 0,
num_short_mdcts: 1,
short_mdct_size,
num_alloc_vectors: 0,
alloc_vectors: &[],
log_n: &[],
window: &[],
mdct,
cache: cache.as_view(),
}
}
#[test]
fn quant_band_n1_round_trips_sign_information() {
let e_bands = [0i16, 1];
let mode = dummy_mode(&e_bands, 4);
let bit_budget = (1_i32) << BITRES;
let mut storage = vec![0u8; 8];
let mut x = [-0.5_f32];
let mut y = [0.25_f32];
let mut lowband = [0.0_f32];
{
let mut enc = EcEnc::new(&mut storage);
let mut ctx = BandCtx {
encode: true,
resynth: true,
mode: &mode,
band: 0,
intensity: 0,
spread: 0,
tf_change: 0,
remaining_bits: 2 * bit_budget,
band_e: &[],
seed: 0,
arch: 0,
theta_round: 0,
disable_inv: false,
avoid_split_noise: false,
};
{
let mut coder = BandCodingState::Encoder(&mut enc);
let coded = quant_band_n1(
&mut ctx,
&mut x,
Some(&mut y),
Some(&mut lowband),
&mut coder,
);
assert_eq!(coded, 1);
}
assert_eq!(ctx.remaining_bits, 0);
assert!((x[0] + NORM_SCALING).abs() <= f32::EPSILON * 2.0);
assert!((y[0] - NORM_SCALING).abs() <= f32::EPSILON * 2.0);
assert_eq!(lowband[0], x[0]);
enc.enc_done();
}
let mut decode_buf = storage.clone();
let mut dec = EcDec::new(&mut decode_buf);
let mut ctx = BandCtx {
encode: false,
resynth: true,
mode: &mode,
band: 0,
intensity: 0,
spread: 0,
tf_change: 0,
remaining_bits: 2 * bit_budget,
band_e: &[],
seed: 0,
arch: 0,
theta_round: 0,
disable_inv: false,
avoid_split_noise: false,
};
let mut x_dec = [0.0_f32];
let mut y_dec = [0.0_f32];
{
let mut coder = BandCodingState::Decoder(&mut dec);
let coded = quant_band_n1(&mut ctx, &mut x_dec, Some(&mut y_dec), None, &mut coder);
assert_eq!(coded, 1);
}
assert_eq!(ctx.remaining_bits, 0);
assert!((x_dec[0] + NORM_SCALING).abs() <= f32::EPSILON * 2.0);
assert!((y_dec[0] - NORM_SCALING).abs() <= f32::EPSILON * 2.0);
}
#[test]
fn compute_theta_encode_decode_round_trip() {
let e_bands = [0i16, 2, 4];
let log_n = [0i16, 0];
let mdct = MdctLookup::new(4, 0);
let mode = OpusCustomMode::new_test(
48_000,
0,
&e_bands,
&[],
&log_n,
&[],
mdct,
PulseCacheData::default(),
);
let band_e = vec![0.75_f32, 0.6, 0.65, 0.7];
let n = 4;
let initial_b = 48 << BITRES;
let b_current = 2;
let b0 = 2;
let lm = 1;
let stereo = true;
let initial_fill = (1u32 << (b0 as u32)) - 1;
let mut x_encode = vec![0.45_f32, -0.2, 0.05, -0.35];
let mut y_encode = vec![0.15_f32, 0.32, -0.28, 0.4];
let x_original = x_encode.clone();
let y_original = y_encode.clone();
let mut ctx_encode = BandCtx {
encode: true,
resynth: false,
mode: &mode,
band: 1,
intensity: mode.num_ebands + 4,
spread: SPREAD_NORMAL,
tf_change: 0,
remaining_bits: 160 << BITRES,
band_e: &band_e,
seed: 0x4567_89ab,
arch: 0,
theta_round: 0,
disable_inv: false,
avoid_split_noise: false,
};
let mut sctx_encode = SplitCtx::default();
let mut b_encode = initial_b;
let mut fill_encode = initial_fill;
let mut storage = vec![0u8; 32];
{
let mut enc = EcEnc::new(&mut storage);
{
let mut coder = BandCodingState::Encoder(&mut enc);
compute_theta(
&mut ctx_encode,
&mut sctx_encode,
&mut x_encode,
&mut y_encode,
n,
&mut b_encode,
b_current,
b0,
lm,
stereo,
&mut fill_encode,
&mut coder,
);
}
enc.enc_done();
}
let mut x_decode = x_original;
let mut y_decode = y_original;
let mut ctx_decode = BandCtx {
encode: false,
resynth: false,
mode: &mode,
band: 1,
intensity: mode.num_ebands + 4,
spread: SPREAD_NORMAL,
tf_change: 0,
remaining_bits: 160 << BITRES,
band_e: &band_e,
seed: 0x4567_89ab,
arch: 0,
theta_round: 0,
disable_inv: false,
avoid_split_noise: false,
};
let mut sctx_decode = SplitCtx::default();
let mut b_decode = initial_b;
let mut fill_decode = initial_fill;
let mut decode_buf = storage.clone();
{
let mut dec = EcDec::new(&mut decode_buf);
let mut coder = BandCodingState::Decoder(&mut dec);
compute_theta(
&mut ctx_decode,
&mut sctx_decode,
&mut x_decode,
&mut y_decode,
n,
&mut b_decode,
b_current,
b0,
lm,
stereo,
&mut fill_decode,
&mut coder,
);
}
assert_eq!(sctx_encode, sctx_decode);
assert_eq!(b_encode, b_decode);
assert_eq!(fill_encode, fill_decode);
}
#[test]
fn compute_band_energies_matches_manual_sum() {
let e_bands = [0i16, 2, 4];
let mode = dummy_mode(&e_bands, 4);
let channels = 2;
let lm = 1usize;
let n = mode.short_mdct_size << lm;
let mut spectrum = Vec::with_capacity(channels * n);
for idx in 0..channels * n {
spectrum.push((idx as f32 * 0.13 - 0.5).sin());
}
let mut band_e = vec![0.0; mode.num_ebands * channels];
compute_band_energies(
&mode,
&spectrum,
&mut band_e,
mode.num_ebands,
channels,
lm,
0,
);
for c in 0..channels {
for b in 0..mode.num_ebands {
let start = ((mode.e_bands[b] as usize) << lm) + c * n;
let stop = ((mode.e_bands[b + 1] as usize) << lm) + c * n;
let sum: f32 = spectrum[start..stop].iter().map(|v| v * v).sum();
let expected = (1e-27_f32 + sum).sqrt();
let idx = b + c * mode.num_ebands;
assert!(
(band_e[idx] - expected).abs() <= 1e-6,
"channel {c}, band {b}"
);
}
}
}
#[test]
fn normalise_bands_scales_by_inverse_energy() {
let e_bands = [0i16, 2, 4];
let mode = dummy_mode(&e_bands, 4);
let channels = 1usize;
let m = 2usize;
let n = mode.short_mdct_size * m;
let freq: Vec<CeltSig> = (0..n).map(|i| (i as f32 * 0.21 - 0.4).cos()).collect();
let mut norm = vec![0.0f32; freq.len()];
let mut band_e = vec![0.0f32; mode.num_ebands * channels];
for (b, value) in band_e.iter_mut().enumerate().take(mode.num_ebands) {
let start = m * (mode.e_bands[b] as usize);
let stop = m * (mode.e_bands[b + 1] as usize);
let sum: f32 = freq[start..stop].iter().map(|v| v * v).sum();
*value = (1e-27_f32 + sum).sqrt();
}
normalise_bands(
&mode,
&freq,
&mut norm,
&band_e,
mode.num_ebands,
channels,
m,
);
for (b, _) in band_e.iter().enumerate().take(mode.num_ebands) {
let start = m * (mode.e_bands[b] as usize);
let stop = m * (mode.e_bands[b + 1] as usize);
let gain = 1.0 / (1e-27_f32 + band_e[b]);
for j in start..stop {
assert!(
(norm[j] - freq[j] * gain).abs() <= 1e-6,
"band {b}, index {j}"
);
}
}
}
#[test]
fn denormalise_bands_restores_scaled_spectrum() {
let e_bands = [0i16, 2, 4];
let mode = dummy_mode(&e_bands, 4);
let m = 1usize;
let n = mode.short_mdct_size * m;
let x: Vec<f32> = (0..n).map(|i| (i as f32 * 0.17 - 0.3).sin()).collect();
let mut freq = vec![1.0f32; n];
let band_log_e = vec![0.5f32, -0.25];
denormalise_bands(
&mode,
&x,
&mut freq,
&band_log_e,
0,
mode.num_ebands,
m,
1,
false,
);
let mut expected = vec![0.0f32; n];
let mut idx = 0usize;
for band in 0..mode.num_ebands {
let band_end = m * (mode.e_bands[band + 1] as usize);
let gain = celt_exp2((band_log_e[band] + E_MEANS[band]).min(32.0));
while idx < band_end {
expected[idx] = x[idx] * gain;
idx += 1;
}
}
for (i, (&observed, &reference)) in freq.iter().zip(expected.iter()).enumerate() {
assert!(
(observed - reference).abs() <= 1e-6,
"index {i}: observed={observed}, expected={reference}"
);
}
}
#[test]
fn denormalise_bands_honours_downsample_and_silence() {
let e_bands = [0i16, 2, 4];
let mode = dummy_mode(&e_bands, 4);
let m = 1usize;
let n = mode.short_mdct_size * m;
let x = vec![0.5f32, -0.25, 0.125, -0.375];
let mut freq = vec![0.75f32; n];
let band_log_e = vec![0.0f32];
denormalise_bands(&mode, &x, &mut freq, &band_log_e, 0, 1, m, 2, false);
let gain = celt_exp2((band_log_e[0] + E_MEANS[0]).min(32.0));
assert!((freq[0] - x[0] * gain).abs() <= 1e-6);
assert!((freq[1] - x[1] * gain).abs() <= 1e-6);
assert_eq!(freq[2], 0.0);
assert_eq!(freq[3], 0.0);
denormalise_bands(&mode, &x, &mut freq, &band_log_e, 0, 1, m, 1, true);
assert!(freq.iter().all(|v| *v == 0.0));
}
#[test]
fn anti_collapse_fills_collapsed_band_with_noise() {
let e_bands = [0i16, 2];
let mode = dummy_mode(&e_bands, 4);
let lm = 1usize;
let channels = 1usize;
let size = mode.short_mdct_size << lm;
let mut spectrum = vec![0.0f32; channels * size];
let collapse_masks = vec![0u8; mode.num_ebands * channels];
let log_e = vec![5.0f32; mode.num_ebands * channels];
let prev1 = vec![0.0f32; mode.num_ebands * channels];
let prev2 = vec![0.0f32; mode.num_ebands * channels];
let pulses = vec![0i32; mode.num_ebands];
anti_collapse(
&mode,
&mut spectrum,
&collapse_masks,
lm,
channels,
size,
0,
mode.num_ebands,
&log_e,
&prev1,
&prev2,
&pulses,
0xDEAD_BEEF,
false,
0,
);
let band_width = usize::try_from(e_bands[1] - e_bands[0]).unwrap();
let samples = band_width << lm;
let energy: f32 = spectrum[..samples].iter().map(|v| v * v).sum();
assert!(spectrum[..samples].iter().any(|v| *v != 0.0));
assert!(energy > 0.0);
#[cfg(not(feature = "fixed_point"))]
let expected_energy = 1.0f32;
#[cfg(feature = "fixed_point")]
let expected_energy = 0.25f32;
assert!(
(energy - expected_energy).abs() <= 2e-3,
"renormalised energy {energy}"
);
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_runtime_pvq_wrappers_match_direct_fixed_impl() {
let n = 8usize;
let k = 3i32;
let spread = SPREAD_NORMAL;
let block_count = 2usize;
let gain = 0.875f32;
let arch = 0;
let input = vec![0.12, -0.34, 0.56, -0.27, 0.18, -0.09, 0.41, -0.22];
let mut wrapped_quant = input.clone();
let mut direct_quant: Vec<i16> = input.iter().map(|&sample| float2int16(sample)).collect();
let mut wrapped_bits = vec![0u8; 96];
let mut direct_bits = vec![0u8; 96];
let wrapped_mask;
{
let mut enc = EcEnc::new(&mut wrapped_bits);
wrapped_mask = pvq_alg_quant_runtime(
&mut wrapped_quant,
n,
k,
spread,
block_count,
&mut enc,
gain,
true,
arch,
);
enc.enc_done();
}
let direct_mask;
{
let mut enc = EcEnc::new(&mut direct_bits);
direct_mask = alg_quant_fixed(
&mut direct_quant,
n,
k,
spread,
block_count,
&mut enc,
qconst32(f64::from(gain), 31),
true,
arch,
);
enc.enc_done();
}
assert_eq!(wrapped_mask, direct_mask);
for (idx, (&wrapped, &direct)) in wrapped_quant.iter().zip(direct_quant.iter()).enumerate()
{
let expected = f32::from(direct) * (1.0 / 32_768.0);
assert!(
(wrapped - expected).abs() <= f32::EPSILON,
"quant sample {idx}: wrapped={wrapped}, expected={expected}"
);
}
let mut wrapped_unquant = vec![0.0f32; n];
let mut direct_unquant = vec![0i16; n];
let wrapped_umask;
{
let mut dec = EcDec::new(&mut wrapped_bits);
wrapped_umask = pvq_alg_unquant_runtime(
&mut wrapped_unquant,
n,
k,
spread,
block_count,
&mut dec,
gain,
);
}
let direct_umask;
{
let mut dec = EcDec::new(&mut direct_bits);
direct_umask = alg_unquant_fixed(
&mut direct_unquant,
n,
k,
spread,
block_count,
&mut dec,
qconst32(f64::from(gain), 31),
);
}
assert_eq!(wrapped_umask, direct_umask);
for (idx, (&wrapped, &direct)) in wrapped_unquant
.iter()
.zip(direct_unquant.iter())
.enumerate()
{
let expected = f32::from(direct) * (1.0 / 32_768.0);
assert!(
(wrapped - expected).abs() <= f32::EPSILON,
"unquant sample {idx}: wrapped={wrapped}, expected={expected}"
);
}
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_runtime_renormalise_wrapper_matches_direct_fixed_impl() {
let n = 8usize;
let gain = 1.0f32;
let arch = 0;
let input = vec![0.08, -0.21, 0.37, -0.45, 0.19, -0.11, 0.29, -0.33];
let mut wrapped = input.clone();
pvq_renormalise_runtime(&mut wrapped, n, gain, arch);
let mut direct: Vec<i16> = input.iter().map(|&sample| float2int16(sample)).collect();
renormalise_vector_fixed(&mut direct, n, qconst32(f64::from(gain), 31), arch);
for (idx, (&wrapped, &direct)) in wrapped.iter().zip(direct.iter()).enumerate() {
let expected = f32::from(direct) * (1.0 / 32_768.0);
assert!(
(wrapped - expected).abs() <= f32::EPSILON,
"sample {idx}: wrapped={wrapped}, expected={expected}"
);
}
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_band_energies_return_epsilon_on_silence() {
let e_bands = [0i16, 4, 8];
let log_n = [0i16, 0];
let mdct = MdctLookup::new(16, 0);
let window = crate::celt::modes::compute_mdct_window(8);
let mut mode = OpusCustomMode::new_test(
48_000,
8,
&e_bands,
&[],
&log_n,
&window,
mdct,
PulseCacheData::default(),
);
mode.short_mdct_size = 8;
mode.num_short_mdcts = 1;
let mut band_e = vec![0i32; mode.num_ebands];
let spectrum = vec![0i32; mode.short_mdct_size];
compute_band_energies_fixed(&mode, &spectrum, &mut band_e, mode.num_ebands, 1, 0);
for value in band_e {
assert_eq!(value, i32::from(FIXED_EPSILON));
}
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_normalise_bands_preserves_silence() {
let e_bands = [0i16, 4, 8];
let log_n = [0i16, 0];
let mdct = MdctLookup::new(16, 0);
let window = crate::celt::modes::compute_mdct_window(8);
let mut mode = OpusCustomMode::new_test(
48_000,
8,
&e_bands,
&[],
&log_n,
&window,
mdct,
PulseCacheData::default(),
);
mode.short_mdct_size = 8;
mode.num_short_mdcts = 1;
let freq = vec![0i32; mode.short_mdct_size];
let band_e = vec![i32::from(FIXED_EPSILON); mode.num_ebands];
let mut x = vec![0i16; mode.short_mdct_size];
normalise_bands_fixed(&mode, &freq, &mut x, &band_e, mode.num_ebands, 1, 1);
assert!(x.iter().all(|&v| v == 0));
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_normalise_bands_matches_reference() {
let e_bands = [0i16, 1, 2, 4];
let log_n = [0i16, 0, 0];
let mdct = MdctLookup::new(16, 0);
let window = crate::celt::modes::compute_mdct_window(8);
let mut mode = OpusCustomMode::new_test(
48_000,
8,
&e_bands,
&[],
&log_n,
&window,
mdct,
PulseCacheData::default(),
);
mode.short_mdct_size = 4;
mode.num_short_mdcts = 1;
let freq = vec![1000i32, -2000, 3000, -4000];
let band_e = vec![1 << 10, 1 << 20, 1 << 15];
let mut x = vec![0i16; 4];
normalise_bands_fixed(&mode, &freq, &mut x, &band_e, mode.num_ebands, 1, 1);
assert_eq!(x, vec![15984, -31, 1500, -2000]);
}
#[cfg(feature = "fixed_point")]
#[test]
fn fixed_denormalise_bands_matches_reference() {
let e_bands = [0i16, 1, 2, 4];
let log_n = [0i16, 0, 0];
let mdct = MdctLookup::new(16, 0);
let window = crate::celt::modes::compute_mdct_window(8);
let mut mode = OpusCustomMode::new_test(
48_000,
8,
&e_bands,
&[],
&log_n,
&window,
mdct,
PulseCacheData::default(),
);
mode.short_mdct_size = 4;
mode.num_short_mdcts = 1;
let x_in = vec![1234i16, -2345, 3456, -4567];
let band_log_e = vec![-(18i32 << DB_SHIFT), 17i32 << DB_SHIFT, 10i32 << DB_SHIFT];
let mut freq = vec![0i32; 4];
denormalise_bands_fixed_native(&mode, &x_in, &mut freq, &band_log_e, 0, 3, 1, 1, false);
assert_eq!(freq, vec![0, -153_681_920, 47_616_768, -62_924_126]);
let mut freq_downsample = vec![0i32; 4];
denormalise_bands_fixed_native(
&mode,
&x_in,
&mut freq_downsample,
&band_log_e,
0,
3,
1,
2,
false,
);
assert_eq!(freq_downsample, vec![0, -153_681_920, 0, 0]);
let mut freq_silence = vec![1i32, -1, 2, -2];
denormalise_bands_fixed_native(
&mode,
&x_in,
&mut freq_silence,
&band_log_e,
0,
3,
1,
1,
true,
);
assert_eq!(freq_silence, vec![0, 0, 0, 0]);
}
}