M9.13: Opus decoder (WIP: range decoder, packet parsing, CELT core, SILK tables)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-09-30 22:21:51 -04:00
parent 498ac6da23
commit ed47db6861
15 changed files with 4065 additions and 0 deletions

4
Cargo.lock generated
View File

@ -1518,6 +1518,10 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "filmcraft-opus"
version = "0.1.0"
[[package]]
name = "filmcraft-project"
version = "0.1.0"

View File

@ -22,6 +22,7 @@ filmcraft-h264 = { path = "crates/h264" }
filmcraft-hevc = { path = "crates/hevc" }
filmcraft-prores = { path = "crates/prores" }
filmcraft-aac = { path = "crates/aac" }
filmcraft-opus = { path = "crates/opus" }
filmcraft-h264enc = { path = "crates/h264enc" }
filmcraft-audio-dsp = { path = "crates/audio-dsp" }
filmcraft-frame = { path = "crates/frame" }

12
crates/opus/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "filmcraft-opus"
description = "Clean-room pure-Rust Opus decoder (RFC 6716 / RFC 8251; OpusHead, multistream surround)"
version.workspace = true
edition.workspace = true
license.workspace = true
rust-version.workspace = true
[lints]
workspace = true
[dependencies]

View File

@ -0,0 +1,970 @@
//! Band shape decoding: PVQ, spreading, TF changes, band splitting, stereo, folding
//! (RFC 6716 §4.3.4 – §4.3.6).
use super::rate::{Mode, QTHETA_OFFSET, QTHETA_OFFSET_TWOPHASE, get_pulses};
use super::tables::*;
use crate::range::{BITRES, RangeDecoder, ilog};
pub const SPREAD_NONE: usize = 0;
pub const SPREAD_AGGRESSIVE: usize = 3;
#[inline]
pub fn lcg_rand(seed: u32) -> u32 {
seed.wrapping_mul(1_664_525).wrapping_add(1_013_904_223)
}
/// Decodes a PVQ codeword of `k` pulses in `n` dimensions; returns the sum of squares.
fn decode_pulses(y: &mut [i32], n: usize, k: usize, dec: &mut RangeDecoder, v: &mut Vec<u64>) -> f32 {
// Table of V(nn, kk) for nn in 0..=n, kk in 0..=k (saturating).
let w = k + 1;
v.clear();
v.resize((n + 1) * w, 0);
v[0] = 1;
for nn in 1..=n {
v[nn * w] = 1;
for kk in 1..=k {
let a = v[(nn - 1) * w + kk];
let b = v[nn * w + kk - 1];
let c = v[(nn - 1) * w + kk - 1];
v[nn * w + kk] = a.saturating_add(b).saturating_add(c);
}
}
let total = v[n * w + k];
let ft = total.min(u32::MAX as u64) as u32;
let mut i = if ft >= 2 { dec.uint(ft) as u64 } else { 0 };
let mut kk = k;
let mut ryy = 0f32;
for j in 0..n {
let rem = n - j;
if kk == 0 {
y[j] = 0;
continue;
}
let vv = |nn: usize, kx: usize| v[nn * w + kx];
let mut p = (vv(rem - 1, kk) + vv(rem, kk)) / 2;
let neg = i >= p;
if neg {
i -= p;
}
let k0 = kk;
p -= vv(rem - 1, kk);
while p > i && kk > 0 {
kk -= 1;
p -= vv(rem - 1, kk);
}
let mag = (k0 - kk) as i32;
y[j] = if neg { -mag } else { mag };
i -= p.min(i);
ryy += (mag * mag) as f32;
}
ryy
}
fn exp_rotation1(x: &mut [f32], len: usize, stride: usize, c: f32, s: f32) {
let ms = -s;
if len <= stride {
return;
}
for i in 0..len - stride {
let x1 = x[i];
let x2 = x[i + stride];
x[i + stride] = c * x2 + s * x1;
x[i] = c * x1 + ms * x2;
}
if len >= 2 * stride + 1 {
for i in (0..=len - 2 * stride - 1).rev() {
let x1 = x[i];
let x2 = x[i + stride];
x[i + stride] = c * x2 + s * x1;
x[i] = c * x1 + ms * x2;
}
}
}
/// Inverse spreading rotation (decoder direction).
fn exp_rotation(x: &mut [f32], len: usize, stride: usize, k: usize, spread: usize) {
const SPREAD_FACTOR: [usize; 3] = [15, 10, 5];
if 2 * k >= len || spread == SPREAD_NONE {
return;
}
let factor = SPREAD_FACTOR[spread - 1];
let gain = len as f32 / (len + factor * k) as f32;
let theta = 0.5 * gain * gain;
let c = (0.5 * std::f32::consts::PI * theta).cos();
let s = (0.5 * std::f32::consts::PI * (1.0 - theta)).cos();
let mut stride2 = 0;
if len >= 8 * stride {
stride2 = 1;
while (stride2 * stride2 + stride2) * stride + (stride >> 2) < len {
stride2 += 1;
}
}
let sub = len / stride;
for i in 0..stride {
let xs = &mut x[i * sub..(i + 1) * sub];
if stride2 != 0 {
exp_rotation1(xs, sub, stride2, s, c);
}
exp_rotation1(xs, sub, 1, c, s);
}
}
fn extract_collapse_mask(iy: &[i32], n: usize, b: usize) -> u32 {
if b <= 1 {
return 1;
}
let n0 = n / b;
let mut mask = 0u32;
for i in 0..b {
if iy[i * n0..(i + 1) * n0].iter().any(|&v| v != 0) {
mask |= 1 << i;
}
}
mask
}
pub fn renormalise_vector(x: &mut [f32], gain: f32) {
let e: f32 = 1e-15 + x.iter().map(|v| v * v).sum::<f32>();
let g = gain / e.sqrt();
for v in x.iter_mut() {
*v *= g;
}
}
fn haar1(x: &mut [f32], n0: usize, stride: usize) {
let n0 = n0 >> 1;
const S: f32 = std::f32::consts::FRAC_1_SQRT_2;
for i in 0..stride {
for j in 0..n0 {
let a = x[stride * 2 * j + i] * S;
let b = x[stride * (2 * j + 1) + i] * S;
x[stride * 2 * j + i] = a + b;
x[stride * (2 * j + 1) + i] = a - b;
}
}
}
fn ordery(stride: usize) -> &'static [usize] {
&ORDERY[stride - 2..2 * stride - 2]
}
fn deinterleave_hadamard(x: &mut [f32], n0: usize, stride: usize, hadamard: bool, tmp: &mut Vec<f32>) {
let n = n0 * stride;
tmp.clear();
tmp.resize(n, 0.0);
if hadamard {
let ord = ordery(stride);
for i in 0..stride {
for j in 0..n0 {
tmp[ord[i] * 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);
}
fn interleave_hadamard(x: &mut [f32], n0: usize, stride: usize, hadamard: bool, tmp: &mut Vec<f32>) {
let n = n0 * stride;
tmp.clear();
tmp.resize(n, 0.0);
if hadamard {
let ord = ordery(stride);
for i in 0..stride {
for j in 0..n0 {
tmp[j * stride + i] = x[ord[i] * 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);
}
#[inline]
fn frac_mul16(a: i32, b: i32) -> i32 {
(16384 + (a as i16 as i32) * (b as i16 as i32)) >> 15
}
fn bitexact_cos(x: i32) -> i32 {
let tmp = (4096 + x * x) >> 13;
let x2 = tmp;
let x2 = (32767 - x2) + frac_mul16(x2, -7651 + frac_mul16(x2, 8277 + frac_mul16(-626, x2)));
1 + x2
}
fn bitexact_log2tan(isin: i32, icos: i32) -> i32 {
let lc = ilog(icos as u32);
let ls = ilog(isin as u32);
let icos = icos << (15 - lc);
let isin = isin << (15 - ls);
(ls - lc) * (1 << 11) + frac_mul16(isin, frac_mul16(isin, -2597) + 7932) - frac_mul16(icos, frac_mul16(icos, -2597) + 7932)
}
fn isqrt32(v: u32) -> u32 {
let mut r = (v as f64).sqrt() as u32;
while (r as u64) * (r as u64) > v as u64 {
r -= 1;
}
while ((r + 1) as u64) * ((r + 1) as u64) <= v as u64 {
r += 1;
}
r
}
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 = sdiv(b + n2 * offset, n2);
qb = qb.min(b - pulse_cap - (4 << BITRES));
qb = qb.min(8 << BITRES);
if qb < (1 << BITRES >> 1) {
1
} else {
let qn = EXP2_TABLE8[(qb & 0x7) as usize] >> (14 - (qb >> BITRES));
(qn + 1) >> 1 << 1
}
}
/// C-style truncating signed division.
#[inline]
fn sdiv(a: i32, b: i32) -> i32 {
a / b
}
pub struct BandCtx<'m, 'd, 'b> {
pub m: &'m Mode,
pub dec: &'d mut RangeDecoder<'b>,
pub i: usize,
pub intensity: usize,
pub spread: usize,
pub tf_change: i32,
pub remaining_bits: i32,
pub seed: u32,
pub disable_inv: bool,
pub avoid_split_noise: bool,
pub pvq_v: Vec<u64>,
pub iy: Vec<i32>,
pub tmp: Vec<f32>,
}
struct Split {
inv: bool,
imid: i32,
iside: i32,
delta: i32,
itheta: i32,
qalloc: i32,
}
impl BandCtx<'_, '_, '_> {
fn compute_theta(&mut self, n: i32, b: &mut i32, bb: usize, b0: usize, lm: i32, stereo: bool, fill: &mut u32) -> Split {
let i = self.i;
let pulse_cap = self.m.log_n[i] + lm * (1 << BITRES);
let offset = (pulse_cap >> 1) - if stereo && n == 2 { QTHETA_OFFSET_TWOPHASE } else { QTHETA_OFFSET };
let mut qn = compute_qn(n, *b, offset, pulse_cap, stereo);
if stereo && i >= self.intensity {
qn = 1;
}
let tell = self.dec.tell_frac() as i32;
let mut itheta = 0i32;
let mut inv = false;
if qn != 1 {
if stereo && n > 2 {
let p0 = 3u32;
let x0 = (qn / 2) as u32;
let ft = p0 * (x0 + 1) + x0;
let fs = self.dec.decode(ft);
let x = if fs < (x0 + 1) * p0 { fs / p0 } else { x0 + 1 + (fs - (x0 + 1) * p0) };
let (fl, fh) = if x <= x0 { (p0 * x, p0 * (x + 1)) } else { ((x - 1 - x0) + (x0 + 1) * p0, (x - x0) + (x0 + 1) * p0) };
self.dec.update(fl, fh, ft);
itheta = x as i32;
} else if b0 > 1 || stereo {
itheta = self.dec.uint(qn as u32 + 1) as i32;
} else {
let half = (qn >> 1) as u32;
let ft = (half + 1) * (half + 1);
let fm = self.dec.decode(ft);
let (fl, fs);
if fm < (half * (half + 1)) >> 1 {
let it = (isqrt32(8 * fm + 1) - 1) >> 1;
fs = it + 1;
fl = it * (it + 1) >> 1;
itheta = it as i32;
} else {
let q = qn as u32;
let it = (2 * (q + 1) - isqrt32(8 * (ft - fm - 1) + 1)) >> 1;
fs = q + 1 - it;
fl = ft - ((q + 1 - it) * (q + 2 - it) >> 1);
itheta = it as i32;
}
self.dec.update(fl, fl + fs, ft);
}
itheta = ((itheta as u32 * 16384) / qn as u32) as i32;
} else if stereo {
if *b > 2 << BITRES && self.remaining_bits > 2 << BITRES {
inv = self.dec.bit_logp(2);
}
if self.disable_inv {
inv = false;
}
itheta = 0;
}
let qalloc = self.dec.tell_frac() as i32 - tell;
*b -= qalloc;
let (imid, iside, delta);
if itheta == 0 {
imid = 32767;
iside = 0;
*fill &= (1 << bb) - 1;
delta = -16384;
} else if itheta == 16384 {
imid = 0;
iside = 32767;
*fill &= ((1 << bb) - 1) << bb;
delta = 16384;
} else {
imid = bitexact_cos(itheta);
iside = bitexact_cos(16384 - itheta);
delta = frac_mul16((n - 1) << 7, bitexact_log2tan(iside, imid));
}
Split { inv, imid, iside, delta, itheta, qalloc }
}
fn quant_band_n1(&mut self, x: &mut [f32], y: Option<&mut [f32]>, lowband_out: Option<&mut [f32]>) -> u32 {
let dec_sign = |ctx: &mut Self| -> f32 {
let mut sign = 0;
if ctx.remaining_bits >= 1 << BITRES {
sign = ctx.dec.bits(1);
ctx.remaining_bits -= 1 << BITRES;
}
if sign != 0 { -1.0 } else { 1.0 }
};
x[0] = dec_sign(self);
if let Some(y) = y {
y[0] = dec_sign(self);
}
if let Some(lo) = lowband_out {
lo[0] = x[0];
}
1
}
#[allow(clippy::too_many_arguments)]
fn quant_partition(&mut self, x: &mut [f32], n: usize, mut b: i32, mut bb: usize, lowband: Option<&[f32]>, mut lm: i32, gain: f32, mut fill: u32) -> u32 {
let b0 = bb;
let i = self.i;
let cache = self.m.cache(lm, i);
let cache_max = cache[cache[0] as usize] as i32;
if lm != -1 && b > cache_max + 12 && n > 2 {
let n = n >> 1;
let (xa, ya) = x.split_at_mut(n);
lm -= 1;
if bb == 1 {
fill = (fill & 1) | (fill << 1);
}
bb = (bb + 1) >> 1;
let sp = self.compute_theta(n as i32, &mut b, bb, b0, lm, false, &mut fill);
let mid = sp.imid as f32 / 32768.0;
let side = sp.iside as f32 / 32768.0;
let mut delta = sp.delta;
if b0 > 1 && (sp.itheta & 0x3fff) != 0 {
if sp.itheta > 8192 {
delta -= delta >> (4 - lm);
} else {
delta = 0.min(delta + ((n as i32) << BITRES >> (5 - lm)));
}
}
let mut mbits = 0.max(b.min((b - delta) / 2));
let mut sbits = b - mbits;
self.remaining_bits -= sp.qalloc;
let next_lowband2 = lowband.map(|l| &l[n..]);
let mut rebalance = self.remaining_bits;
let mut cm;
if mbits >= sbits {
cm = self.quant_partition(xa, n, mbits, bb, lowband, lm, gain * mid, fill);
rebalance = mbits - (rebalance - self.remaining_bits);
if rebalance > 3 << BITRES && sp.itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
cm |= self.quant_partition(ya, n, sbits, bb, next_lowband2, lm, gain * side, fill >> bb) << (b0 >> 1);
} else {
cm = self.quant_partition(ya, n, sbits, bb, next_lowband2, lm, gain * side, fill >> bb) << (b0 >> 1);
rebalance = sbits - (rebalance - self.remaining_bits);
if rebalance > 3 << BITRES && sp.itheta != 16384 {
mbits += rebalance - (3 << BITRES);
}
cm |= self.quant_partition(xa, n, mbits, bb, lowband, lm, gain * mid, fill);
}
return cm;
}
// No split.
let m = self.m;
let mut q = m.bits2pulses(i, lm, b);
let mut curr_bits = m.pulses2bits(i, lm, q);
self.remaining_bits -= curr_bits;
while self.remaining_bits < 0 && q > 0 {
self.remaining_bits += curr_bits;
q -= 1;
curr_bits = m.pulses2bits(i, lm, q);
self.remaining_bits -= curr_bits;
}
if q != 0 {
let k = get_pulses(q) as usize;
let mut iy = std::mem::take(&mut self.iy);
iy.clear();
iy.resize(n, 0);
let ryy = decode_pulses(&mut iy, n, k, self.dec, &mut self.pvq_v);
let g = gain / ryy.sqrt();
for (xv, &yv) in x[..n].iter_mut().zip(iy.iter()) {
*xv = g * yv as f32;
}
exp_rotation(&mut x[..n], n, bb, k, self.spread);
let cm = extract_collapse_mask(&iy, n, bb);
self.iy = iy;
cm
} else {
let cm_mask = (1u32 << bb) - 1;
fill &= cm_mask;
if fill == 0 {
x[..n].fill(0.0);
0
} else {
let cm;
match lowband {
None => {
for v in x[..n].iter_mut() {
self.seed = lcg_rand(self.seed);
*v = ((self.seed as i32) >> 20) as f32;
}
cm = cm_mask;
}
Some(lb) => {
for j in 0..n {
self.seed = lcg_rand(self.seed);
let tmp = if self.seed & 0x8000 != 0 { 1.0 / 256.0 } else { -1.0 / 256.0 };
x[j] = lb[j] + tmp;
}
cm = fill;
}
}
renormalise_vector(&mut x[..n], gain);
cm
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn quant_band(
&mut self,
x: &mut [f32],
n: usize,
b: i32,
mut bb: usize,
mut lowband: Option<&mut [f32]>,
lm: i32,
lowband_out: Option<&mut [f32]>,
gain: f32,
mut fill: u32,
) -> u32 {
let n0 = n;
let mut n_b = n;
let b0_orig = bb;
let mut time_divide = 0;
let mut recombine = 0;
let long_blocks = b0_orig == 1;
let mut tf_change = self.tf_change;
n_b /= bb;
if n == 1 {
return self.quant_band_n1(x, None, lowband_out);
}
if tf_change > 0 {
recombine = tf_change;
}
const BIT_INTERLEAVE: [u32; 16] = [0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3];
for k in 0..recombine {
if let Some(lb) = lowband.as_deref_mut() {
haar1(lb, n >> k, 1 << k);
}
fill = BIT_INTERLEAVE[(fill & 0xF) as usize] | (BIT_INTERLEAVE[(fill >> 4) as usize] << 2);
}
bb >>= recombine;
n_b <<= recombine;
while (n_b & 1) == 0 && tf_change < 0 {
if let Some(lb) = lowband.as_deref_mut() {
haar1(lb, n_b, bb);
}
fill |= fill << bb;
bb <<= 1;
n_b >>= 1;
time_divide += 1;
tf_change += 1;
}
let b0 = bb;
let n_b0 = n_b;
let mut tmp = std::mem::take(&mut self.tmp);
if b0 > 1
&& let Some(lb) = lowband.as_deref_mut()
{
deinterleave_hadamard(lb, n_b >> recombine, b0 << recombine, long_blocks, &mut tmp);
}
let mut cm = self.quant_partition(x, n, b, bb, lowband.as_deref(), lm, gain, fill);
if b0 > 1 {
interleave_hadamard(x, n_b >> recombine, b0 << recombine, long_blocks, &mut tmp);
}
self.tmp = tmp;
let mut n_b = n_b0;
bb = b0;
for _ in 0..time_divide {
bb >>= 1;
n_b <<= 1;
cm |= cm >> bb;
haar1(x, n_b, bb);
}
const BIT_DEINTERLEAVE: [u32; 16] = [0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF];
for k in 0..recombine {
cm = BIT_DEINTERLEAVE[(cm & 0xF) as usize];
haar1(x, n0 >> k, 1 << k);
}
bb <<= recombine;
if let Some(lo) = lowband_out {
let s = (n0 as f32).sqrt();
for j in 0..n0 {
lo[j] = s * x[j];
}
}
cm & ((1u32 << bb) - 1)
}
#[allow(clippy::too_many_arguments)]
pub fn quant_band_stereo(
&mut self,
x: &mut [f32],
y: &mut [f32],
n: usize,
mut b: i32,
bb: usize,
lowband: Option<&mut [f32]>,
lm: i32,
lowband_out: Option<&mut [f32]>,
mut fill: u32,
) -> u32 {
let orig_fill = fill;
if n == 1 {
return self.quant_band_n1(x, Some(y), lowband_out);
}
let sp = self.compute_theta(n as i32, &mut b, bb, bb, lm, true, &mut fill);
let mid = sp.imid as f32 / 32768.0;
let side = sp.iside as f32 / 32768.0;
let mut cm;
if n == 2 {
let mut mbits = b;
let mut sbits = 0;
if sp.itheta != 0 && sp.itheta != 16384 {
sbits = 1 << BITRES;
}
mbits -= sbits;
let c = sp.itheta > 8192;
self.remaining_bits -= sp.qalloc + sbits;
let mut sign = 0;
if sbits != 0 {
sign = self.dec.bits(1) as i32;
}
let sign = (1 - 2 * sign) as f32;
if c {
cm = self.quant_band(y, n, mbits, bb, lowband, lm, lowband_out, 1.0, orig_fill);
x[0] = -sign * y[1];
x[1] = sign * y[0];
} else {
cm = self.quant_band(x, n, mbits, bb, lowband, lm, lowband_out, 1.0, orig_fill);
y[0] = -sign * x[1];
y[1] = sign * x[0];
}
x[0] *= mid;
x[1] *= mid;
y[0] *= side;
y[1] *= side;
let t = x[0];
x[0] = t - y[0];
y[0] += t;
let t = x[1];
x[1] = t - y[1];
y[1] += t;
} else {
let mut mbits = 0.max(b.min((b - sp.delta) / 2));
let mut sbits = b - mbits;
self.remaining_bits -= sp.qalloc;
let mut rebalance = self.remaining_bits;
if mbits >= sbits {
cm = self.quant_band(x, n, mbits, bb, lowband, lm, lowband_out, 1.0, fill);
rebalance = mbits - (rebalance - self.remaining_bits);
if rebalance > 3 << BITRES && sp.itheta != 0 {
sbits += rebalance - (3 << BITRES);
}
cm |= self.quant_band(y, n, sbits, bb, None, lm, None, side, fill >> bb);
} else {
cm = self.quant_band(y, n, sbits, bb, None, lm, None, side, fill >> bb);
rebalance = sbits - (rebalance - self.remaining_bits);
if rebalance > 3 << BITRES && sp.itheta != 16384 {
mbits += rebalance - (3 << BITRES);
}
cm |= self.quant_band(x, n, mbits, bb, lowband, lm, lowband_out, 1.0, fill);
}
}
if n != 2 {
stereo_merge(&mut x[..n], &mut y[..n], mid);
}
if sp.inv {
for v in y[..n].iter_mut() {
*v = -*v;
}
}
cm
}
}
fn stereo_merge(x: &mut [f32], y: &mut [f32], mid: f32) {
let mut xp = 0f32;
let mut side = 0f32;
for (a, b) in x.iter().zip(y.iter()) {
xp += a * b;
side += b * b;
}
xp *= mid;
let mid2 = mid;
let el = mid2 * mid2 + side - 2.0 * xp;
let er = mid2 * mid2 + side + 2.0 * xp;
if er < 6e-4 || el < 6e-4 {
y.copy_from_slice(x);
return;
}
let lgain = 1.0 / el.sqrt();
let rgain = 1.0 / er.sqrt();
for (a, b) in x.iter_mut().zip(y.iter_mut()) {
let l = mid * *a;
let r = *b;
*a = lgain * (l - r);
*b = rgain * (l + r);
}
}
/// Decodes all band shapes (`quant_all_bands`, decoder side).
#[allow(clippy::too_many_arguments)]
pub fn quant_all_bands(
m: &Mode,
start: usize,
end: usize,
x_buf: &mut [f32],
y_buf: Option<&mut [f32]>,
collapse_masks: &mut [u32],
pulses: &[i32; NB_EBANDS],
short_blocks: bool,
spread: usize,
mut dual_stereo: bool,
intensity: usize,
tf_res: &[i32; NB_EBANDS],
total_bits: i32,
mut balance: i32,
dec: &mut RangeDecoder,
lm: usize,
coded_bands: usize,
seed: &mut u32,
disable_inv: bool,
) {
let mm = 1usize << lm;
let bb = if short_blocks { mm } else { 1 };
let norm_offset = mm * EBANDS[start] as usize;
let norm_len = mm * EBANDS[NB_EBANDS - 1] as usize - norm_offset;
let c = if y_buf.is_some() { 2 } else { 1 };
let mut norm = vec![0f32; norm_len];
let mut norm2 = vec![0f32; if c == 2 { norm_len } else { 0 }];
let mut scratch = vec![0f32; mm * (EBANDS[NB_EBANDS] - EBANDS[NB_EBANDS - 1]) as usize];
let mut scratch2 = scratch.clone();
let mut y_buf = y_buf;
let mut lowband_offset = 0usize;
let mut update_lowband = true;
let mut ctx = BandCtx {
m,
dec,
i: 0,
intensity,
spread,
tf_change: 0,
remaining_bits: 0,
seed: *seed,
disable_inv,
avoid_split_noise: bb > 1,
pvq_v: Vec::new(),
iy: Vec::new(),
tmp: Vec::new(),
};
for i in start..end {
ctx.i = i;
let last = i == end - 1;
let xo = mm * EBANDS[i] as usize;
let n = mm * EBANDS[i + 1] as usize - xo;
let tell = ctx.dec.tell_frac() as i32;
if i != start {
balance -= tell;
}
let remaining_bits = total_bits - tell - 1;
ctx.remaining_bits = remaining_bits;
let b = if i < coded_bands {
let curr_balance = sdiv(balance, 3.min(coded_bands as i32 - i as i32));
0.max(16383.min((remaining_bits + 1).min(pulses[i] + curr_balance)))
} else {
0
};
if (mm * EBANDS[i] as usize >= n + norm_offset || i == start + 1) && (update_lowband || lowband_offset == 0) {
lowband_offset = i;
}
if i == start + 1 {
let n1 = mm * (EBANDS[start + 1] - EBANDS[start]) as usize;
let n2 = mm * (EBANDS[start + 2] - EBANDS[start + 1]) as usize;
if n2 > n1 {
norm.copy_within(2 * n1 - n2..n1, n1);
if c == 2 {
norm2.copy_within(2 * n1 - n2..n1, n1);
}
}
}
let tf_change = tf_res[i];
ctx.tf_change = tf_change;
let mut effective_lowband: Option<usize> = None;
let (mut x_cm, mut y_cm);
if lowband_offset != 0 && (spread != SPREAD_AGGRESSIVE || bb > 1 || tf_change < 0) {
let eff = (mm * EBANDS[lowband_offset] as usize).saturating_sub(norm_offset + n);
effective_lowband = Some(eff);
let mut fold_start = lowband_offset;
loop {
fold_start -= 1;
if mm * (EBANDS[fold_start] as usize) <= eff + norm_offset {
break;
}
}
let mut fold_end = lowband_offset - 1;
loop {
fold_end += 1;
if !(fold_end < i && mm * (EBANDS[fold_end] as usize) < eff + norm_offset + n) {
break;
}
}
x_cm = 0;
y_cm = 0;
let mut fi = fold_start;
loop {
x_cm |= collapse_masks[fi * c];
y_cm |= collapse_masks[fi * c + c - 1];
fi += 1;
if fi >= fold_end {
break;
}
}
} else {
x_cm = (1u32 << bb) - 1;
y_cm = x_cm;
}
if dual_stereo && i == intensity {
dual_stereo = false;
for j in 0..(mm * EBANDS[i] as usize - norm_offset) {
norm[j] = 0.5 * (norm[j] + norm2[j]);
}
}
let out_off = xo - norm_offset;
let x = &mut x_buf[xo..xo + n];
if dual_stereo {
let y = &mut y_buf.as_deref_mut().expect("stereo")[xo..xo + n];
let lb = effective_lowband.map(|e| {
scratch[..n].copy_from_slice(&norm[e..e + n]);
&mut scratch[..n]
});
let lo = if last { None } else { Some(&mut norm[out_off..out_off + n]) };
x_cm = ctx.quant_band(x, n, b / 2, bb, lb, lm as i32, lo, 1.0, x_cm);
let lb2 = effective_lowband.map(|e| {
scratch2[..n].copy_from_slice(&norm2[e..e + n]);
&mut scratch2[..n]
});
let lo2 = if last { None } else { Some(&mut norm2[out_off..out_off + n]) };
y_cm = ctx.quant_band(y, n, b / 2, bb, lb2, lm as i32, lo2, 1.0, y_cm);
} else {
let lb = effective_lowband.map(|e| {
scratch[..n].copy_from_slice(&norm[e..e + n]);
&mut scratch[..n]
});
let lo = if last { None } else { Some(&mut norm[out_off..out_off + n]) };
if let Some(yb) = y_buf.as_deref_mut() {
let y = &mut yb[xo..xo + n];
x_cm = ctx.quant_band_stereo(x, y, n, b, bb, lb, lm as i32, lo, x_cm | y_cm);
} else {
x_cm = ctx.quant_band(x, n, b, bb, lb, lm as i32, lo, 1.0, x_cm | y_cm);
}
y_cm = x_cm;
}
collapse_masks[i * c] = x_cm;
collapse_masks[i * c + c - 1] = y_cm;
balance += pulses[i] + tell;
update_lowband = b > (n as i32) << BITRES;
ctx.avoid_split_noise = false;
}
*seed = ctx.seed;
}
/// Anti-collapse noise injection (RFC 6716 §4.3.5).
#[allow(clippy::too_many_arguments)]
pub fn anti_collapse(
x_buf: &mut [f32],
collapse_masks: &[u32],
lm: usize,
c: usize,
size: usize,
start: usize,
end: usize,
log_e: &[f32],
prev1: &[f32],
prev2: &[f32],
pulses: &[i32; NB_EBANDS],
mut seed: u32,
) {
for i in start..end {
let n0 = (EBANDS[i + 1] - EBANDS[i]) as usize;
let depth = ((1 + pulses[i]) as u32 / n0 as u32) >> lm;
let thresh = 0.5 * (-0.125 * depth as f32).exp2();
let sqrt_1 = 1.0 / ((n0 << lm) as f32).sqrt();
for ch in 0..c {
let mut p1 = prev1[ch * NB_EBANDS + i];
let mut p2 = prev2[ch * NB_EBANDS + i];
if c == 1 {
p1 = p1.max(prev1[NB_EBANDS + i]);
p2 = p2.max(prev2[NB_EBANDS + i]);
}
let ediff = (log_e[ch * NB_EBANDS + i] - p1.min(p2)).max(0.0);
let mut r = 2.0 * (-ediff).exp2();
if lm == 3 {
r *= std::f32::consts::SQRT_2;
}
r = r.min(thresh);
r *= sqrt_1;
let off = ch * size + ((EBANDS[i] as usize) << lm);
let xb = &mut x_buf[off..off + (n0 << lm)];
let mut renorm = false;
for k in 0..(1usize << lm) {
if collapse_masks[i * c + ch] & (1 << k) == 0 {
for j in 0..n0 {
seed = lcg_rand(seed);
xb[(j << lm) + k] = if seed & 0x8000 != 0 { r } else { -r };
}
renorm = true;
}
}
if renorm {
renormalise_vector(xb, 1.0);
}
}
}
}
/// Multiplies the normalised shapes by the band energies (`denormalise_bands`).
#[allow(clippy::too_many_arguments)]
pub fn denormalise_bands(x: &[f32], freq: &mut [f32], band_log_e: &[f32], mut start: usize, mut end: usize, mm: usize, downsample: usize, silence: bool) {
let n = mm * SHORT_MDCT;
let mut bound = mm * EBANDS[end] as usize;
if downsample != 1 {
bound = bound.min(n / downsample);
}
if silence {
bound = 0;
start = 0;
end = 0;
}
let s0 = mm * EBANDS[start] as usize;
freq[..s0].fill(0.0);
for i in start..end {
let lo = mm * EBANDS[i] as usize;
let hi = mm * EBANDS[i + 1] as usize;
let lg = band_log_e[i] + E_MEANS[i];
let g = lg.min(32.0).exp2();
for j in lo..hi {
freq[j] = x[j] * g;
}
}
let from = bound;
if from < n {
freq[from..n].fill(0.0);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bitexact_trig_endpoints() {
assert_eq!(bitexact_cos(0), 32768);
let mid = bitexact_cos(8192);
assert!((mid - 23170).abs() < 20, "{mid}");
assert_eq!(bitexact_log2tan(16384, 16384), 0);
}
#[test]
fn isqrt_exact() {
for v in [0u32, 1, 2, 3, 4, 15, 16, 17, 99, 100, 1 << 20, u32::MAX] {
let r = isqrt32(v) as u64;
assert!(r * r <= v as u64 && (r + 1) * (r + 1) > v as u64);
}
}
#[test]
fn pvq_roundtrip_all_codewords_small() {
use crate::range::enc::RangeEncoder;
// Enumerate every index for small N,K, decode, and check uniqueness + sum |y| == K.
for n in 1..6usize {
for k in 1..5usize {
let total = super::super::rate::pvq_v(n, k) as u32;
let mut seen = std::collections::HashSet::new();
for idx in 0..total {
let mut e = RangeEncoder::new(16);
e.uint(idx, total);
let buf = e.done();
let mut d = RangeDecoder::new(&buf);
let mut y = vec![0i32; n];
let mut v = Vec::new();
let ryy = decode_pulses(&mut y, n, k, &mut d, &mut v);
assert_eq!(y.iter().map(|v| v.unsigned_abs() as usize).sum::<usize>(), k);
assert_eq!(ryy as i32, y.iter().map(|v| v * v).sum::<i32>());
assert!(seen.insert(y.clone()), "duplicate codeword n={n} k={k} idx={idx}");
}
}
}
}
#[test]
fn haar_is_involution() {
let mut x: Vec<f32> = (0..16).map(|i| i as f32).collect();
let orig = x.clone();
haar1(&mut x, 16, 1);
haar1(&mut x, 16, 1);
for (a, b) in x.iter().zip(&orig) {
assert!((a - b).abs() < 1e-4);
}
let mut tmp = Vec::new();
for &h in &[false, true] {
let mut y = orig.clone();
deinterleave_hadamard(&mut y, 4, 4, h, &mut tmp);
interleave_hadamard(&mut y, 4, 4, h, &mut tmp);
assert_eq!(y, orig);
}
}
}

View File

@ -0,0 +1,171 @@
//! Band energy decoding: Laplace-coded coarse energy, fine energy and the final refinement
//! (RFC 6716 §4.3.2).
use super::rate::MAX_FINE_BITS;
use super::tables::*;
use crate::range::RangeDecoder;
const LAPLACE_MINP: u32 = 1;
const LAPLACE_NMIN: u32 = 16;
fn laplace_get_freq1(fs0: u32, decay: u32) -> u32 {
let ft = 32768 - LAPLACE_MINP * (2 * LAPLACE_NMIN) - fs0;
(ft * (16384 - decay)) >> 15
}
/// Decodes a Laplace-distributed integer (`fs` = probability of 0 in Q15, `decay` in Q14).
pub fn laplace_decode(dec: &mut RangeDecoder, mut fs: u32, decay: u32) -> i32 {
let mut val = 0i32;
let fm = dec.decode_bin(15);
let mut fl = 0u32;
if fm >= fs {
val += 1;
fl = fs;
fs = laplace_get_freq1(fs, decay) + LAPLACE_MINP;
while fs > LAPLACE_MINP && fm >= fl + 2 * fs {
fs *= 2;
fl += fs;
fs = (((fs - 2 * LAPLACE_MINP) * decay) >> 15) + LAPLACE_MINP;
val += 1;
}
if fs <= LAPLACE_MINP {
let di = (fm - fl) >> 1;
val += di as i32;
fl += 2 * di * LAPLACE_MINP;
}
if fm < fl + fs {
val = -val;
} else {
fl += fs;
}
}
dec.update_bin(fl, (fl + fs).min(32768), 15);
val
}
/// `unquant_coarse_energy`.
#[allow(clippy::too_many_arguments)]
pub fn unquant_coarse_energy(start: usize, end: usize, old_e: &mut [f32], intra: bool, dec: &mut RangeDecoder, c: usize, lm: usize) {
let prob = &E_PROB_MODEL[lm][intra as usize];
let (coef, beta) = if intra { (0.0, BETA_INTRA) } else { (PRED_COEF[lm], BETA_COEF[lm]) };
let budget = dec.storage() as i32 * 8;
let mut prev = [0f32; 2];
for i in start..end {
for ch in 0..c {
let tell = dec.tell();
let qi = if budget - tell >= 15 {
let pi = 2 * i.min(20);
laplace_decode(dec, (prob[pi] as u32) << 7, (prob[pi + 1] as u32) << 6)
} else if budget - tell >= 2 {
let q = dec.icdf(&SMALL_ENERGY_ICDF, 2) as i32;
(q >> 1) ^ -(q & 1)
} else if budget - tell >= 1 {
-(dec.bit_logp(1) as i32)
} else {
-1
};
let q = qi as f32;
let idx = i + ch * NB_EBANDS;
old_e[idx] = old_e[idx].max(-9.0);
let tmp = coef * old_e[idx] + prev[ch] + q;
old_e[idx] = tmp;
prev[ch] = prev[ch] + q - beta * q;
}
}
}
pub fn unquant_fine_energy(start: usize, end: usize, old_e: &mut [f32], fine_quant: &[i32; NB_EBANDS], dec: &mut RangeDecoder, c: usize) {
for i in start..end {
let fq = fine_quant[i];
if fq <= 0 {
continue;
}
for ch in 0..c {
let q2 = dec.bits(fq as u32);
let offset = (q2 as f32 + 0.5) * (1 << (14 - fq)) as f32 / 16384.0 - 0.5;
old_e[i + ch * NB_EBANDS] += offset;
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn unquant_energy_finalise(
start: usize,
end: usize,
old_e: &mut [f32],
fine_quant: &[i32; NB_EBANDS],
fine_priority: &[i32; NB_EBANDS],
mut bits_left: i32,
dec: &mut RangeDecoder,
c: usize,
) {
for prio in 0..2 {
let mut i = start;
while i < end && bits_left >= c as i32 {
if fine_quant[i] >= MAX_FINE_BITS || fine_priority[i] != prio {
i += 1;
continue;
}
for ch in 0..c {
let q2 = dec.bits(1);
let offset = (q2 as f32 - 0.5) * (1 << (14 - fine_quant[i] - 1)) as f32 / 16384.0;
old_e[i + ch * NB_EBANDS] += offset;
bits_left -= 1;
}
i += 1;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::range::enc::RangeEncoder;
fn laplace_encode(e: &mut RangeEncoder, value: i32, mut fs: u32, decay: u32) {
let mut fl = 0u32;
let mut val = value;
if val != 0 {
let s: i32 = if val < 0 { -1 } else { 0 };
val = val.abs();
fl = fs;
fs = laplace_get_freq1(fs, decay);
let mut i = 1;
while fs > 0 && i < val {
fs *= 2;
fl += fs + 2 * LAPLACE_MINP;
fs = (fs * decay) >> 15;
i += 1;
}
if fs == 0 {
let ndi_max = (32768 - fl + LAPLACE_MINP - 1) as i32;
let ndi_max = (ndi_max - s) >> 1;
let di = (val - i).min(ndi_max - 1);
fl = (fl as i32 + (2 * di + 1 + s) * LAPLACE_MINP as i32) as u32;
fs = LAPLACE_MINP.min(32768 - fl);
} else {
fs += LAPLACE_MINP;
if s == 0 {
fl += fs;
}
}
}
e.encode(fl, fl + fs, 32768);
}
#[test]
fn laplace_roundtrip() {
for &(fs, decay) in &[(72u32 << 7, 127u32 << 6), (24 << 7, 179 << 6), (177 << 7, 11 << 6)] {
let vals: Vec<i32> = (-12..=12).collect();
let mut e = RangeEncoder::new(400);
for &v in &vals {
laplace_encode(&mut e, v, fs, decay);
}
let buf = e.done();
let mut d = RangeDecoder::new(&buf);
for &v in &vals {
assert_eq!(laplace_decode(&mut d, fs, decay), v, "fs={fs} v={v}");
}
}
}
}

View File

@ -0,0 +1,201 @@
//! Inverse MDCT with the low-overlap window and in-place TDAC (RFC 6716 §4.3.7).
//!
//! The IMDCT is computed through an N/4-point complex FFT (pre-rotation, FFT, post-rotation),
//! producing the N/2 "folded" time samples; the window overlap region is then unfolded against the
//! folded tail of the previous block, which the caller keeps in place in the output buffer.
#[derive(Clone, Copy, Default, Debug)]
pub struct Cpx {
pub re: f32,
pub im: f32,
}
impl Cpx {
#[inline]
fn mul(self, o: Cpx) -> Cpx {
Cpx { re: self.re * o.re - self.im * o.im, im: self.re * o.im + self.im * o.re }
}
#[inline]
fn add(self, o: Cpx) -> Cpx {
Cpx { re: self.re + o.re, im: self.im + o.im }
}
}
/// Mixed-radix (2, 3, 4, 5) forward complex FFT, unscaled.
pub struct Fft {
n: usize,
factors: Vec<usize>,
twiddle: Vec<Cpx>,
}
impl Fft {
pub fn new(n: usize) -> Fft {
let mut factors = Vec::new();
let mut m = n;
for p in [4usize, 2, 3, 5] {
while m.is_multiple_of(p) {
factors.push(p);
m /= p;
}
}
assert_eq!(m, 1, "unsupported FFT size {n}");
let twiddle = (0..n)
.map(|k| {
let ph = -2.0 * std::f64::consts::PI * k as f64 / n as f64;
Cpx { re: ph.cos() as f32, im: ph.sin() as f32 }
})
.collect();
Fft { n, factors, twiddle }
}
pub fn process(&self, data: &mut [Cpx], scratch: &mut Vec<Cpx>) {
scratch.clear();
scratch.extend_from_slice(&data[..self.n]);
self.rec(&mut data[..self.n], scratch, 1, self.n, 0, 1);
}
fn rec(&self, out: &mut [Cpx], inp: &[Cpx], in_stride: usize, n: usize, fi: usize, tw_stride: usize) {
let p = self.factors[fi];
let m = n / p;
if m == 1 {
for (i, o) in out.iter_mut().enumerate().take(p) {
*o = inp[i * in_stride];
}
} else {
for q in 0..p {
self.rec(&mut out[q * m..(q + 1) * m], &inp[q * in_stride..], in_stride * p, m, fi + 1, tw_stride * p);
}
}
let big = self.n;
let mut t = [Cpx::default(); 5];
for k in 0..m {
for q in 0..p {
let w = self.twiddle[(q * k * tw_stride) % big];
t[q] = out[q * m + k].mul(w);
}
for q2 in 0..p {
let mut acc = Cpx::default();
for (q, tq) in t.iter().enumerate().take(p) {
let w = self.twiddle[((q * q2) % p) * (big / p)];
acc = acc.add(tq.mul(w));
}
out[q2 * m + k] = acc;
}
}
}
}
pub struct Imdct {
/// Full MDCT length (2x the number of coefficients).
n: usize,
trig: Vec<f32>,
fft: Fft,
}
impl Imdct {
pub fn new(n: usize) -> Imdct {
let trig = (0..n / 2).map(|i| (2.0 * std::f64::consts::PI * (i as f64 + 0.125) / n as f64).cos() as f32).collect();
Imdct { n, trig, fft: Fft::new(n / 4) }
}
/// Inverse transform of `n/2` coefficients read from `input` at `stride`.
///
/// Writes the folded block to `out[overlap/2 .. overlap/2 + n/2]` and unfolds the first
/// `overlap` samples against the previous block's folded tail already stored in
/// `out[0 .. overlap/2]`.
pub fn backward(&self, input: &[f32], stride: usize, out: &mut [f32], window: &[f32], overlap: usize, work: &mut ImdctScratch) {
let n2 = self.n >> 1;
let n4 = self.n >> 2;
let t = &self.trig;
let z = &mut work.z;
z.clear();
for i in 0..n4 {
let x1 = input[2 * i * stride];
let x2 = input[stride * (n2 - 1 - 2 * i)];
let yr = x2 * t[i] + x1 * t[n4 + i];
let yi = x1 * t[i] - x2 * t[n4 + i];
z.push(Cpx { re: yi, im: yr });
}
self.fft.process(z, &mut work.scratch);
let base = overlap >> 1;
let y = &mut out[base..base + n2];
for i in 0..n4.div_ceil(2) {
let front = z[i];
let back = z[n4 - 1 - i];
let (re, im) = (front.im, front.re);
let (t0, t1) = (t[i], t[n4 + i]);
let yr0 = re * t0 + im * t1;
let yi0 = re * t1 - im * t0;
let (re, im) = (back.im, back.re);
let (t0, t1) = (t[n4 - i - 1], t[n2 - i - 1]);
let yr1 = re * t0 + im * t1;
let yi1 = re * t1 - im * t0;
y[2 * i] = yr0;
y[n2 - 1 - 2 * i] = yi0;
y[n2 - 2 - 2 * i] = yr1;
y[2 * i + 1] = yi1;
}
// Mirror on both sides for TDAC.
for i in 0..overlap / 2 {
let x1 = out[overlap - 1 - i];
let x2 = out[i];
let w1 = window[i];
let w2 = window[overlap - 1 - i];
out[i] = x2 * w2 - x1 * w1;
out[overlap - 1 - i] = x2 * w1 + x1 * w2;
}
}
}
#[derive(Default)]
pub struct ImdctScratch {
z: Vec<Cpx>,
scratch: Vec<Cpx>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fft_matches_dft() {
for &n in &[60usize, 120, 240, 480] {
let fft = Fft::new(n);
let x: Vec<Cpx> = (0..n).map(|i| Cpx { re: ((i * 7) % 13) as f32 - 6.0, im: ((i * 3) % 5) as f32 - 2.0 }).collect();
let mut y = x.clone();
fft.process(&mut y, &mut Vec::new());
for k in [0, 1, 7, n / 2, n - 1] {
let mut acc = (0f64, 0f64);
for (i, v) in x.iter().enumerate() {
let ph = -2.0 * std::f64::consts::PI * (i * k) as f64 / n as f64;
acc.0 += v.re as f64 * ph.cos() - v.im as f64 * ph.sin();
acc.1 += v.re as f64 * ph.sin() + v.im as f64 * ph.cos();
}
assert!((acc.0 - y[k].re as f64).abs() < 1e-2 && (acc.1 - y[k].im as f64).abs() < 1e-2, "n={n} k={k}");
}
}
}
/// The folded output must equal the direct IMDCT formula folded by TDAC symmetry.
#[test]
fn imdct_matches_direct_formula() {
let n = 240;
let n2 = n / 2;
let im = Imdct::new(n);
let x: Vec<f32> = (0..n2).map(|k| ((k * 37 % 11) as f32 - 5.0) / 5.0).collect();
let overlap = 0;
let mut out = vec![0f32; n2];
im.backward(&x, 1, &mut out, &[], overlap, &mut ImdctScratch::default());
// Direct IMDCT y[t] = sum X[k] cos(2pi/N (t + 1/2 + N/4)(k + 1/2)), t in 0..N.
let y: Vec<f64> = (0..n)
.map(|t| (0..n2).map(|k| x[k] as f64 * (2.0 * std::f64::consts::PI / n as f64 * (t as f64 + 0.5 + n as f64 / 4.0) * (k as f64 + 0.5)).cos()).sum())
.collect();
// The folded half: out[i] relates to y in the middle half; check proportionality.
let mid: Vec<f64> = (0..n2).map(|i| y[n / 4 + i]).collect();
let dot: f64 = mid.iter().zip(&out).map(|(a, b)| a * *b as f64).sum();
let ea: f64 = mid.iter().map(|a| a * a).sum();
let eb: f64 = out.iter().map(|b| (*b as f64).powi(2)).sum();
let corr = dot.abs() / (ea.sqrt() * eb.sqrt());
assert!(corr > 0.999, "corr {corr}");
}
}

638
crates/opus/src/celt/mod.rs Normal file
View File

@ -0,0 +1,638 @@
//! CELT layer decoder (RFC 6716 §4.3).
pub(crate) mod bands;
pub(crate) mod energy;
pub(crate) mod mdct;
pub(crate) mod rate;
pub(crate) mod tables;
use std::sync::OnceLock;
use bands::{anti_collapse, denormalise_bands, quant_all_bands, renormalise_vector};
use energy::{unquant_coarse_energy, unquant_energy_finalise, unquant_fine_energy};
use mdct::ImdctScratch;
use rate::{Mode, compute_allocation};
use tables::*;
use crate::range::{BITRES, RangeDecoder};
const DECODE_BUFFER_SIZE: usize = 2048;
const COMBFILTER_MINPERIOD: i32 = 15;
const PLC_PITCH_LAG_MAX: usize = 720;
const PLC_PITCH_LAG_MIN: usize = 100;
pub(crate) fn mode() -> &'static Mode {
static MODE: OnceLock<Mode> = OnceLock::new();
MODE.get_or_init(Mode::new)
}
/// CELT decoder state for one (mono or stereo) stream.
pub struct CeltDecoder {
m: &'static Mode,
/// Output channels.
channels: usize,
/// Channels coded in the stream.
pub stream_channels: usize,
downsample: usize,
pub start: usize,
pub end: usize,
pub disable_inv: bool,
pub rng: u32,
loss_count: u32,
skip_plc: bool,
postfilter_period: i32,
postfilter_period_old: i32,
postfilter_gain: f32,
postfilter_gain_old: f32,
postfilter_tapset: usize,
postfilter_tapset_old: usize,
preemph_mem: [f32; 2],
decode_mem: Vec<f32>,
old_band_e: [f32; 2 * NB_EBANDS],
old_log_e: [f32; 2 * NB_EBANDS],
old_log_e2: [f32; 2 * NB_EBANDS],
background_log_e: [f32; 2 * NB_EBANDS],
// scratch
x: Vec<f32>,
freq: Vec<f32>,
imdct: ImdctScratch,
pcm_scratch: Vec<f32>,
}
impl CeltDecoder {
/// `sample_rate` is the output rate (48000, 24000, 16000, 12000 or 8000).
pub fn new(sample_rate: u32, channels: usize) -> CeltDecoder {
let downsample = (48000 / sample_rate) as usize;
let mut d = CeltDecoder {
m: mode(),
channels,
stream_channels: channels,
downsample,
start: 0,
end: NB_EBANDS,
disable_inv: channels == 1,
rng: 0,
loss_count: 0,
skip_plc: true,
postfilter_period: 0,
postfilter_period_old: 0,
postfilter_gain: 0.0,
postfilter_gain_old: 0.0,
postfilter_tapset: 0,
postfilter_tapset_old: 0,
preemph_mem: [0.0; 2],
decode_mem: vec![0.0; channels * (DECODE_BUFFER_SIZE + OVERLAP)],
old_band_e: [0.0; 2 * NB_EBANDS],
old_log_e: [0.0; 2 * NB_EBANDS],
old_log_e2: [0.0; 2 * NB_EBANDS],
background_log_e: [0.0; 2 * NB_EBANDS],
x: Vec::new(),
freq: Vec::new(),
imdct: ImdctScratch::default(),
pcm_scratch: Vec::new(),
};
d.reset();
d
}
/// `OPUS_RESET_STATE`.
pub fn reset(&mut self) {
self.rng = 0;
self.loss_count = 0;
self.skip_plc = true;
self.postfilter_period = 0;
self.postfilter_period_old = 0;
self.postfilter_gain = 0.0;
self.postfilter_gain_old = 0.0;
self.postfilter_tapset = 0;
self.postfilter_tapset_old = 0;
self.preemph_mem = [0.0; 2];
self.decode_mem.fill(0.0);
self.old_band_e = [0.0; 2 * NB_EBANDS];
self.old_log_e = [-28.0; 2 * NB_EBANDS];
self.old_log_e2 = [-28.0; 2 * NB_EBANDS];
self.background_log_e = [0.0; 2 * NB_EBANDS];
}
fn mem_len(&self) -> usize {
DECODE_BUFFER_SIZE + OVERLAP
}
/// Decodes one CELT frame of `frame_size` samples (at the output rate) into interleaved `pcm`
/// (`channels` wide). With `accum`, the output is added to `pcm`. `data = None` (or fewer than
/// two bytes) runs the packet-loss concealment.
pub fn decode(
&mut self,
data: Option<&[u8]>,
frame_size: usize,
pcm: &mut [f32],
accum: bool,
dec: Option<&mut RangeDecoder>,
) -> Result<usize, crate::Error> {
let n_full = frame_size * self.downsample;
let lm = match n_full {
120 => 0,
240 => 1,
480 => 2,
960 => 3,
_ => return Err(crate::Error::InvalidArgument("CELT frame size")),
};
let data = match data {
Some(d) if d.len() > 1 => d,
_ => {
self.decode_lost(n_full, lm);
self.deemphasis(n_full, pcm, accum);
return Ok(frame_size);
}
};
if data.len() > 1275 {
return Err(crate::Error::InvalidPacket("CELT frame too long"));
}
match dec {
Some(d) => self.decode_frame(d, data.len(), n_full, lm),
None => {
let mut own = RangeDecoder::new(data);
self.decode_frame(&mut own, data.len(), n_full, lm)
}
}
self.deemphasis(n_full, pcm, accum);
Ok(frame_size)
}
fn decode_frame(&mut self, dec: &mut RangeDecoder, len: usize, n: usize, lm: usize) {
let cc = self.channels;
let c = self.stream_channels;
let m = self.m;
let mm = 1usize << lm;
let start = self.start;
let end = self.end;
let eff_end = end.min(NB_EBANDS);
if self.loss_count == 0 {
self.skip_plc = false;
}
if c == 1 {
for i in 0..NB_EBANDS {
self.old_band_e[i] = self.old_band_e[i].max(self.old_band_e[NB_EBANDS + i]);
}
}
let total_bits_raw = len as i32 * 8;
let mut tell = dec.tell();
let silence = if tell >= total_bits_raw {
true
} else if tell == 1 {
dec.bit_logp(15)
} else {
false
};
if silence {
// Pretend we've read all the remaining bits.
dec.skip_to_end(total_bits_raw);
tell = total_bits_raw;
}
let mut postfilter_gain = 0.0f32;
let mut postfilter_pitch = 0i32;
let mut postfilter_tapset = 0usize;
if start == 0 && tell + 16 <= total_bits_raw {
if dec.bit_logp(1) {
let octave = dec.uint(6);
postfilter_pitch = ((16 << octave) + dec.bits(4 + octave)) as i32 - 1;
let qg = dec.bits(3);
if dec.tell() + 2 <= total_bits_raw {
postfilter_tapset = dec.icdf(&TAPSET_ICDF, 2);
}
postfilter_gain = 0.09375 * (qg + 1) as f32;
}
tell = dec.tell();
}
let is_transient = if lm > 0 && tell + 3 <= total_bits_raw {
let t = dec.bit_logp(3);
tell = dec.tell();
t
} else {
false
};
let short_blocks = is_transient;
let intra = if tell + 3 <= total_bits_raw { dec.bit_logp(3) } else { false };
unquant_coarse_energy(start, end, &mut self.old_band_e, intra, dec, c, lm);
let mut tf_res = [0i32; NB_EBANDS];
tf_decode(start, end, is_transient, &mut tf_res, lm, dec);
tell = dec.tell();
let mut spread = 2usize;
if tell + 4 <= total_bits_raw {
spread = dec.icdf(&SPREAD_ICDF, 5);
}
let cap = m.init_caps(lm, c);
let mut offsets = [0i32; NB_EBANDS];
let mut dynalloc_logp = 6;
let mut total_bits = total_bits_raw << BITRES;
let mut tellf = dec.tell_frac() as i32;
for i in start..end {
let width = (c as i32 * (EBANDS[i + 1] - EBANDS[i])) << lm;
let quanta = (width << BITRES).min((6 << BITRES).max(width));
let mut loop_logp = dynalloc_logp;
let mut boost = 0;
while tellf + (loop_logp << BITRES) < total_bits && boost < cap[i] {
let flag = dec.bit_logp(loop_logp as u32);
tellf = dec.tell_frac() as i32;
if !flag {
break;
}
boost += quanta;
total_bits -= quanta;
loop_logp = 1;
}
offsets[i] = boost;
if boost > 0 {
dynalloc_logp = 2.max(dynalloc_logp - 1);
}
}
let alloc_trim = if tellf + (6 << BITRES) <= total_bits { dec.icdf(&TRIM_ICDF, 7) as i32 } else { 5 };
let mut bits = ((len as i32 * 8) << BITRES) - dec.tell_frac() as i32 - 1;
let anti_collapse_rsv = if is_transient && lm >= 2 && bits >= ((lm as i32 + 2) << BITRES) { 1 << BITRES } else { 0 };
bits -= anti_collapse_rsv;
let alloc = compute_allocation(m, start, end, &offsets, &cap, alloc_trim, bits, c, lm, dec);
unquant_fine_energy(start, end, &mut self.old_band_e, &alloc.fine_quant, dec, c);
// Shift the decode memory by one frame.
let ml = self.mem_len();
for ch in 0..cc {
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
mem.copy_within(n..DECODE_BUFFER_SIZE + OVERLAP / 2, 0);
}
let mut collapse_masks = vec![0u32; c * NB_EBANDS];
let mut x = std::mem::take(&mut self.x);
x.clear();
x.resize(c * n, 0.0);
{
let (xa, xb) = x.split_at_mut(n);
let yb = if c == 2 { Some(xb) } else { None };
let mut seed = self.rng;
quant_all_bands(
m,
start,
end,
xa,
yb,
&mut collapse_masks,
&alloc.pulses,
short_blocks,
spread,
alloc.dual_stereo,
alloc.intensity,
&tf_res,
((len as i32) * (8 << BITRES)) - anti_collapse_rsv,
alloc.balance,
dec,
lm,
alloc.coded_bands,
&mut seed,
self.disable_inv,
);
self.rng = seed;
}
let mut anti_collapse_on = false;
if anti_collapse_rsv > 0 {
anti_collapse_on = dec.bits(1) != 0;
}
let bits_left = len as i32 * 8 - dec.tell();
unquant_energy_finalise(start, end, &mut self.old_band_e, &alloc.fine_quant, &alloc.fine_priority, bits_left, dec, c);
if anti_collapse_on {
anti_collapse(&mut x, &collapse_masks, lm, c, n, start, end, &self.old_band_e, &self.old_log_e, &self.old_log_e2, &alloc.pulses, self.rng);
}
if silence {
for v in self.old_band_e[..c * NB_EBANDS].iter_mut() {
*v = -28.0;
}
}
self.synthesis(&x, n, start, eff_end, c, is_transient, lm, silence);
self.x = x;
// Post-filter.
for ch in 0..cc {
self.postfilter_period = self.postfilter_period.max(COMBFILTER_MINPERIOD);
self.postfilter_period_old = self.postfilter_period_old.max(COMBFILTER_MINPERIOD);
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
let off = DECODE_BUFFER_SIZE - n;
comb_filter(
mem,
off,
self.postfilter_period_old,
self.postfilter_period,
SHORT_MDCT,
self.postfilter_gain_old,
self.postfilter_gain,
self.postfilter_tapset_old,
self.postfilter_tapset,
&m.window,
);
if lm != 0 {
comb_filter(
mem,
off + SHORT_MDCT,
self.postfilter_period,
postfilter_pitch,
n - SHORT_MDCT,
self.postfilter_gain,
postfilter_gain,
self.postfilter_tapset,
postfilter_tapset,
&m.window,
);
}
}
self.postfilter_period_old = self.postfilter_period;
self.postfilter_gain_old = self.postfilter_gain;
self.postfilter_tapset_old = self.postfilter_tapset;
self.postfilter_period = postfilter_pitch;
self.postfilter_gain = postfilter_gain;
self.postfilter_tapset = postfilter_tapset;
if lm != 0 {
self.postfilter_period_old = self.postfilter_period;
self.postfilter_gain_old = self.postfilter_gain;
self.postfilter_tapset_old = self.postfilter_tapset;
}
if c == 1 {
let (a, b) = self.old_band_e.split_at_mut(NB_EBANDS);
b.copy_from_slice(a);
}
if !is_transient {
self.old_log_e2 = self.old_log_e;
self.old_log_e = self.old_band_e;
for i in 0..2 * NB_EBANDS {
self.background_log_e[i] = (self.background_log_e[i] + mm as f32 * 0.001).min(self.old_band_e[i]);
}
} else {
for i in 0..2 * NB_EBANDS {
self.old_log_e[i] = self.old_log_e[i].min(self.old_band_e[i]);
}
}
for ch in 0..2 {
for i in (0..start).chain(end..NB_EBANDS) {
self.old_band_e[ch * NB_EBANDS + i] = 0.0;
self.old_log_e[ch * NB_EBANDS + i] = -28.0;
self.old_log_e2[ch * NB_EBANDS + i] = -28.0;
}
}
self.rng = dec.rng();
self.loss_count = 0;
}
/// Denormalisation + IMDCT into the decode memory (`celt_synthesis`).
#[allow(clippy::too_many_arguments)]
fn synthesis(&mut self, x: &[f32], n: usize, start: usize, eff_end: usize, c: usize, is_transient: bool, lm: usize, silence: bool) {
let cc = self.channels;
let m = self.m;
let mm = 1usize << lm;
let (bcount, nb, shift) = if is_transient { (mm, SHORT_MDCT, MAX_LM) } else { (1, SHORT_MDCT << lm, MAX_LM - lm) };
let ml = self.mem_len();
let mut freq = std::mem::take(&mut self.freq);
freq.clear();
freq.resize(2 * n, 0.0);
let (f0, f1) = freq.split_at_mut(n);
let out_off = DECODE_BUFFER_SIZE - n;
if cc == 2 && c == 1 {
denormalise_bands(x, f0, &self.old_band_e, start, eff_end, mm, self.downsample, silence);
f1.copy_from_slice(f0);
for (ch, f) in [(0usize, &*f1), (1usize, &*f0)] {
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
for b in 0..bcount {
m.mdct[shift].backward(&f[b..], bcount, &mut mem[out_off + nb * b..], &m.window, OVERLAP, &mut self.imdct);
}
}
} else if cc == 1 && c == 2 {
denormalise_bands(x, f0, &self.old_band_e, start, eff_end, mm, self.downsample, silence);
denormalise_bands(&x[n..], f1, &self.old_band_e[NB_EBANDS..], start, eff_end, mm, self.downsample, silence);
for i in 0..n {
f0[i] = 0.5 * (f0[i] + f1[i]);
}
let mem = &mut self.decode_mem[..ml];
for b in 0..bcount {
m.mdct[shift].backward(&f0[b..], bcount, &mut mem[out_off + nb * b..], &m.window, OVERLAP, &mut self.imdct);
}
} else {
for ch in 0..cc {
denormalise_bands(&x[ch * n..], f0, &self.old_band_e[ch * NB_EBANDS..], start, eff_end, mm, self.downsample, silence);
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
for b in 0..bcount {
m.mdct[shift].backward(&f0[b..], bcount, &mut mem[out_off + nb * b..], &m.window, OVERLAP, &mut self.imdct);
}
}
}
self.freq = freq;
}
fn deemphasis(&mut self, n: usize, pcm: &mut [f32], accum: bool) {
let cc = self.channels;
let ml = self.mem_len();
let ds = self.downsample;
let out_off = DECODE_BUFFER_SIZE - n;
let mut scratch = std::mem::take(&mut self.pcm_scratch);
for ch in 0..cc {
let mem = &self.decode_mem[ch * ml + out_off..ch * ml + out_off + n];
let mut mstate = self.preemph_mem[ch];
scratch.clear();
for &v in mem {
let tmp = v + 1e-30 + mstate;
mstate = PREEMPH * tmp;
scratch.push(tmp);
}
self.preemph_mem[ch] = mstate;
for j in 0..n / ds {
let v = scratch[j * ds] * (1.0 / 32768.0);
let o = &mut pcm[j * cc + ch];
if accum {
*o += v;
} else {
*o = v;
}
}
}
self.pcm_scratch = scratch;
}
/// Packet-loss concealment: pitch-periodic extension for the first lost frames, then
/// decaying shaped noise.
fn decode_lost(&mut self, n: usize, lm: usize) {
let cc = self.channels;
let ml = self.mem_len();
let m = self.m;
let pitch_based = self.loss_count < 5 && self.start == 0 && !self.skip_plc;
if !pitch_based {
let decay = if self.loss_count == 0 { 1.5 } else { 0.5 };
for ch in 0..cc {
for i in self.start..self.end {
let k = ch * NB_EBANDS + i;
self.old_band_e[k] = self.background_log_e[k].max(self.old_band_e[k] - decay);
}
}
let mut seed = self.rng;
let mut x = std::mem::take(&mut self.x);
x.clear();
x.resize(cc * n, 0.0);
let eff_end = self.end.min(NB_EBANDS);
for ch in 0..cc {
for i in self.start..eff_end {
let off = n * ch + ((EBANDS[i] as usize) << lm);
let blen = ((EBANDS[i + 1] - EBANDS[i]) as usize) << lm;
for v in x[off..off + blen].iter_mut() {
seed = bands::lcg_rand(seed);
*v = ((seed as i32) >> 20) as f32;
}
renormalise_vector(&mut x[off..off + blen], 1.0);
}
}
self.rng = seed;
for ch in 0..cc {
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
mem.copy_within(n..DECODE_BUFFER_SIZE + OVERLAP / 2, 0);
}
let saved_sc = self.stream_channels;
self.stream_channels = cc;
self.synthesis(&x, n, self.start, eff_end, cc, false, lm, false);
self.stream_channels = saved_sc;
self.x = x;
} else {
// Pitch search on the (mono-mixed) history.
let hist_len = 1024usize;
let base = DECODE_BUFFER_SIZE - hist_len;
let mut mono = vec![0f32; hist_len];
for ch in 0..cc {
for (i, v) in mono.iter_mut().enumerate() {
*v += self.decode_mem[ch * ml + base + i];
}
}
let period = if self.loss_count == 0 { find_pitch(&mono) } else { self.postfilter_period_old.max(PLC_PITCH_LAG_MIN as i32) as usize };
let period = period.clamp(PLC_PITCH_LAG_MIN, PLC_PITCH_LAG_MAX);
// Remember the period for subsequent losses in the (otherwise unused) old period slot.
self.postfilter_period_old = period as i32;
let fade = 0.8f32.powi(self.loss_count as i32 + 1);
let mut ext = vec![0f32; n + OVERLAP];
for ch in 0..cc {
let mem = &mut self.decode_mem[ch * ml..(ch + 1) * ml];
// Energy decay across the last two periods.
let e1: f32 = mem[DECODE_BUFFER_SIZE - period..DECODE_BUFFER_SIZE].iter().map(|v| v * v).sum();
let e0: f32 = mem[DECODE_BUFFER_SIZE - 2 * period..DECODE_BUFFER_SIZE - period].iter().map(|v| v * v).sum();
let decay = if e0 > 0.0 { (e1 / e0).sqrt().min(1.0) } else { 0.0 };
let mut g = 1.0f32;
for (i, e) in ext.iter_mut().enumerate() {
if i > 0 && i % period == 0 {
g *= decay;
}
let src = DECODE_BUFFER_SIZE - period + (i % period);
*e = mem[src] * g * fade;
}
mem.copy_within(n..DECODE_BUFFER_SIZE + OVERLAP / 2, 0);
let out_off = DECODE_BUFFER_SIZE - n;
// Cross-fade the start with the previous overlap so the transition is smooth.
mem[out_off..out_off + n].copy_from_slice(&ext[..n]);
let tail = &ext[n..n + OVERLAP];
for i in 0..OVERLAP / 2 {
mem[DECODE_BUFFER_SIZE + i] = m.window[i] * tail[OVERLAP - 1 - i] + m.window[OVERLAP - 1 - i] * tail[i];
}
}
}
self.loss_count += 1;
}
}
fn find_pitch(x: &[f32]) -> usize {
let n = x.len();
let win = 512.min(n - PLC_PITCH_LAG_MAX);
let tgt = &x[n - win..];
let mut best = PLC_PITCH_LAG_MIN;
let mut best_score = f32::MIN;
let e_t: f32 = tgt.iter().map(|v| v * v).sum::<f32>() + 1e-9;
for lag in PLC_PITCH_LAG_MIN..=PLC_PITCH_LAG_MAX {
let src = &x[n - win - lag..n - lag];
let mut xy = 0f32;
let mut yy = 1e-9f32;
for (a, b) in tgt.iter().zip(src) {
xy += a * b;
yy += b * b;
}
let score = xy / (e_t * yy).sqrt();
if score > best_score {
best_score = score;
best = lag;
}
}
best
}
fn tf_decode(start: usize, end: usize, is_transient: bool, tf_res: &mut [i32; NB_EBANDS], lm: usize, dec: &mut RangeDecoder) {
let mut budget = dec.storage() as i32 * 8;
let mut tell = dec.tell();
let mut logp: u32 = if is_transient { 2 } else { 4 };
let tf_select_rsv = lm > 0 && tell + logp as i32 + 1 <= budget;
budget -= tf_select_rsv as i32;
let mut tf_changed = 0;
let mut curr = 0;
for r in tf_res.iter_mut().take(end).skip(start) {
if tell + logp as i32 <= budget {
curr ^= dec.bit_logp(logp) as i32;
tell = dec.tell();
tf_changed |= curr;
}
*r = curr;
logp = if is_transient { 4 } else { 5 };
}
let mut tf_select = 0;
let ti = 4 * is_transient as usize;
if tf_select_rsv && TF_SELECT_TABLE[lm][ti + tf_changed as usize] != TF_SELECT_TABLE[lm][ti + 2 + tf_changed as usize] {
tf_select = dec.bit_logp(1) as usize;
}
for r in tf_res.iter_mut().take(end).skip(start) {
*r = TF_SELECT_TABLE[lm][ti + 2 * tf_select + *r as usize] as i32;
}
}
/// Pitch post-filter (in place on `buf[off .. off + n]`, reading history before `off`).
#[allow(clippy::too_many_arguments)]
fn comb_filter(buf: &mut [f32], off: usize, t0: i32, t1: i32, n: usize, g0: f32, g1: f32, tapset0: usize, tapset1: usize, window: &[f32; OVERLAP]) {
if g0 == 0.0 && g1 == 0.0 {
return;
}
let t0 = t0.max(COMBFILTER_MINPERIOD) as usize;
let t1 = t1.max(COMBFILTER_MINPERIOD) as usize;
let g00 = g0 * COMB_GAINS[tapset0][0];
let g01 = g0 * COMB_GAINS[tapset0][1];
let g02 = g0 * COMB_GAINS[tapset0][2];
let g10 = g1 * COMB_GAINS[tapset1][0];
let g11 = g1 * COMB_GAINS[tapset1][1];
let g12 = g1 * COMB_GAINS[tapset1][2];
let mut x1 = buf[off + 1 - t1];
let mut x2 = buf[off - t1];
let mut x3 = buf[off - t1 - 1];
let mut x4 = buf[off - t1 - 2];
let overlap = if g0 == g1 && t0 == t1 && tapset0 == tapset1 { 0 } else { OVERLAP.min(n) };
let mut i = 0;
while i < overlap {
let p = off + i;
let x0 = buf[p + 2 - t1];
let f = window[i] * window[i];
let a = 1.0 - f;
buf[p] = buf[p]
+ a * g00 * buf[p - t0]
+ a * g01 * (buf[p + 1 - t0] + buf[p - t0 - 1])
+ a * g02 * (buf[p + 2 - t0] + buf[p - t0 - 2])
+ f * g10 * x2
+ f * g11 * (x1 + x3)
+ f * g12 * (x0 + x4);
x4 = x3;
x3 = x2;
x2 = x1;
x1 = x0;
i += 1;
}
if g1 == 0.0 {
return;
}
// Constant filter for the rest of the block.
let t = t1;
for i in overlap..n {
let p = off + i;
buf[p] = buf[p] + g10 * buf[p - t] + g11 * (buf[p + 1 - t] + buf[p - t - 1]) + g12 * (buf[p + 2 - t] + buf[p - t - 2]);
}
}

View File

@ -0,0 +1,585 @@
//! Pulse cache and bit allocation (RFC 6716 §4.3.3, §4.3.4.1).
use super::tables::*;
use crate::range::{BITRES, RangeDecoder};
const MAX_PSEUDO: i32 = 40;
const LOG_MAX_PSEUDO: i32 = 6;
pub const MAX_FINE_BITS: i32 = 8;
const FINE_OFFSET: i32 = 21;
pub const QTHETA_OFFSET: i32 = 4;
pub const QTHETA_OFFSET_TWOPHASE: i32 = 16;
const ALLOC_STEPS: i32 = 6;
/// Number of pulses represented by pseudo-pulse index `i`.
pub fn get_pulses(i: i32) -> i32 {
if i < 8 { i } else { (8 + (i & 7)) << ((i >> 3) - 1) }
}
/// Conservative (rounded up) log2 of `val` with `frac` fractional bits.
pub fn log2_frac(mut val: u32, mut frac: u32) -> i32 {
let mut l = crate::range::ilog(val);
if val & val.wrapping_sub(1) != 0 {
if l > 16 {
val = ((val - 1) >> (l - 16)) + 1;
} else {
val <<= 16 - l;
}
let mut l = (l - 1) << frac;
loop {
let b = (val >> 16) as i32;
l += b << frac;
val = (val + b as u32) >> b;
val = (val * val + 0x7FFF) >> 15;
if frac == 0 {
break;
}
frac -= 1;
}
l + (val > 0x8000) as i32
} else {
l -= 1;
l << frac
}
}
/// PVQ codebook size V(N, K) as u128 (saturating far above 2^32).
pub fn pvq_v(n: usize, k: usize) -> u128 {
// V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1); computed row by row.
if k == 0 {
return 1;
}
if n == 0 {
return 0;
}
let mut row = vec![0u128; k + 1]; // V(0, k)
row[0] = 1;
for _ in 0..n {
let mut prev_diag = row[0]; // V(n-1, 0)
// V(n, 0) = 1
for kk in 1..=k {
let up = row[kk]; // V(n-1, kk)
let v = up.saturating_add(row[kk - 1]).saturating_add(prev_diag);
prev_diag = up;
row[kk] = v.min(u128::MAX >> 8);
}
row[0] = 1;
}
row[k]
}
fn fits_in32(n: usize, k: i32) -> bool {
pvq_v(n, k as usize) <= u32::MAX as u128
}
/// Precomputed per-mode data shared by all CELT decoders.
pub struct Mode {
/// log2 of band width in 1/8 bits.
pub log_n: [i32; NB_EBANDS],
/// Index into `cache_bits` for `(LM+1)*NB_EBANDS + band` (-1 when unused).
pub cache_index: Vec<i16>,
/// `cache[0]` = max pseudo-pulses; `cache[k]` = bits(k) - 1 in 1/8 bits.
pub cache_bits: Vec<u8>,
/// Per-band maximum allocation: `[(2*LM + C-1)*NB_EBANDS + band]`.
pub caps: Vec<u8>,
pub window: [f32; OVERLAP],
pub mdct: [super::mdct::Imdct; MAX_LM + 1],
}
impl Mode {
pub fn new() -> Mode {
let mut log_n = [0i32; NB_EBANDS];
for (i, l) in log_n.iter_mut().enumerate() {
*l = log2_frac((EBANDS[i + 1] - EBANDS[i]) as u32, BITRES);
}
let (cache_index, cache_bits) = compute_pulse_cache(MAX_LM as i32);
let mut m = Mode {
log_n,
cache_index,
cache_bits,
caps: Vec::new(),
window: [0.0; OVERLAP],
mdct: [super::mdct::Imdct::new(1920), super::mdct::Imdct::new(960), super::mdct::Imdct::new(480), super::mdct::Imdct::new(240)],
};
m.caps = compute_caps(&m);
for i in 0..OVERLAP {
let x = std::f64::consts::FRAC_PI_2 * (i as f64 + 0.5) / OVERLAP as f64;
let s = x.sin();
m.window[i] = (std::f64::consts::FRAC_PI_2 * s * s).sin() as f32;
}
m
}
#[inline]
pub fn cache(&self, lm: i32, band: usize) -> &[u8] {
let idx = self.cache_index[((lm + 1) as usize) * NB_EBANDS + band];
&self.cache_bits[idx.max(0) as usize..]
}
pub fn bits2pulses(&self, band: usize, lm: i32, bits: i32) -> i32 {
let cache = self.cache(lm, band);
let mut lo = 0i32;
let mut hi = cache[0] as i32;
let bits = bits - 1;
for _ in 0..LOG_MAX_PSEUDO {
let mid = (lo + hi + 1) >> 1;
if cache[mid as usize] as i32 >= bits {
hi = mid;
} else {
lo = mid;
}
}
let lo_bits = if lo == 0 { -1 } else { cache[lo as usize] as i32 };
if bits - lo_bits <= cache[hi as usize] as i32 - bits { lo } else { hi }
}
pub fn pulses2bits(&self, band: usize, lm: i32, pulses: i32) -> i32 {
if pulses == 0 { 0 } else { self.cache(lm, band)[pulses as usize] as i32 + 1 }
}
/// Per-band allocation caps for this frame (`init_caps`).
pub fn init_caps(&self, lm: usize, c: usize) -> [i32; NB_EBANDS] {
let mut cap = [0i32; NB_EBANDS];
for (i, cp) in cap.iter_mut().enumerate() {
let n = (EBANDS[i + 1] - EBANDS[i]) << lm;
*cp = (self.caps[NB_EBANDS * (2 * lm + c - 1) + i] as i32 + 64) * c as i32 * n >> 2;
}
cap
}
}
fn compute_pulse_cache(lm_max: i32) -> (Vec<i16>, Vec<u8>) {
let nb = NB_EBANDS;
let rows = (lm_max + 2) as usize;
let mut index = vec![-1i16; nb * rows];
let mut entries: Vec<(usize, i32, usize)> = Vec::new(); // (N, K, offset)
let mut curr = 0usize;
for i in 0..rows {
for j in 0..nb {
let n = (((EBANDS[j + 1] - EBANDS[j]) << i) >> 1) as usize;
index[i * nb + j] = -1;
// Reuse the entry of an earlier band with the same size.
'search: for k in 0..=i {
for nn in 0..nb {
if k == i && nn >= j {
break;
}
if n == (((EBANDS[nn + 1] - EBANDS[nn]) << k) >> 1) as usize {
index[i * nb + j] = index[k * nb + nn];
break 'search;
}
}
}
if index[i * nb + j] == -1 && n != 0 {
let mut k = 0;
while k < MAX_PSEUDO && fits_in32(n, get_pulses(k + 1)) {
k += 1;
}
index[i * nb + j] = curr as i16;
entries.push((n, k, curr));
curr += (k + 1) as usize;
}
}
}
let mut bits = vec![0u8; curr];
for &(n, k, off) in &entries {
let maxk = get_pulses(k) as usize;
let tmp = required_bits(n, maxk, BITRES);
for j in 1..=k {
bits[off + j as usize] = (tmp[get_pulses(j) as usize] - 1) as u8;
}
bits[off] = k as u8;
}
(index, bits)
}
/// Bits (1/2^frac units, rounded up) needed for each K in `0..=maxk` for dimension `n`.
fn required_bits(n: usize, maxk: usize, frac: u32) -> Vec<i32> {
let mut out = vec![0i32; maxk + 1];
if n == 1 {
for o in out.iter_mut().skip(1) {
*o = 1 << frac;
}
} else {
for (k, o) in out.iter_mut().enumerate().skip(1) {
let v = pvq_v(n, k);
*o = log2_frac(v as u32, frac);
}
}
out
}
fn compute_caps(m: &Mode) -> Vec<u8> {
let nb = NB_EBANDS;
let mut caps = vec![0u8; (MAX_LM + 1) * 2 * nb];
for i in 0..=MAX_LM as i32 {
for c in 1..=2i32 {
for j in 0..nb {
let mut n0 = EBANDS[j + 1] - EBANDS[j];
let max_bits;
if n0 << i == 1 {
max_bits = c * (1 + MAX_FINE_BITS) << BITRES;
} else {
let mut lm0 = 0;
if n0 > 2 {
n0 >>= 1;
lm0 -= 1;
} else if n0 <= 1 {
lm0 = i.min(1);
n0 <<= lm0;
}
let pcache = m.cache(lm0, j);
let mut mb = pcache[pcache[0] as usize] as i32 + 1;
let mut n = n0;
for k in 0..(i - lm0) {
mb <<= 1;
let offset = ((m.log_n[j] + ((lm0 + k) << BITRES)) >> 1) - QTHETA_OFFSET;
let num = 459 * ((2 * n - 1) * offset + mb);
let den = ((2 * n - 1) << 9) - 459;
let qb = ((num + (den >> 1)) / den).min(57);
mb += qb;
n <<= 1;
}
if c == 2 {
mb <<= 1;
let offset = ((m.log_n[j] + (i << BITRES)) >> 1) - if n == 2 { QTHETA_OFFSET_TWOPHASE } else { QTHETA_OFFSET };
let ndof = 2 * n - 1 - (n == 2) as i32;
let p = if n == 2 { 512 } else { 487 };
let num = p * (mb + ndof * offset);
let den = (ndof << 9) - p;
let qb = ((num + (den >> 1)) / den).min(if n == 2 { 64 } else { 61 });
mb += qb;
}
let ndof = c * n + if c == 2 && n > 2 { 1 } else { 0 };
let mut offset = ((m.log_n[j] + (i << BITRES)) >> 1) - FINE_OFFSET;
if n == 2 {
offset += (1 << BITRES) >> 2;
}
let num = mb + ndof * offset;
let den = (ndof - 1) << BITRES;
let qb = ((num + (den >> 1)) / den).min(MAX_FINE_BITS);
mb += c * qb << BITRES;
max_bits = mb;
}
let w = c * ((EBANDS[j + 1] - EBANDS[j]) << i);
let v = (4 * max_bits / w) - 64;
caps[((i * 2 + c - 1) as usize) * nb + j] = v.clamp(0, 255) as u8;
}
}
}
caps
}
/// Result of the allocation process.
pub struct Allocation {
pub coded_bands: usize,
pub intensity: usize,
pub dual_stereo: bool,
pub balance: i32,
pub pulses: [i32; NB_EBANDS],
pub fine_quant: [i32; NB_EBANDS],
pub fine_priority: [i32; NB_EBANDS],
}
/// `clt_compute_allocation` (decoder side).
#[allow(clippy::too_many_arguments)]
pub fn compute_allocation(
m: &Mode,
start: usize,
end: usize,
offsets: &[i32; NB_EBANDS],
cap: &[i32; NB_EBANDS],
alloc_trim: i32,
total: i32,
c: usize,
lm: usize,
dec: &mut RangeDecoder,
) -> Allocation {
let ci = c as i32;
let lmi = lm as i32;
let mut total = total.max(0);
let mut skip_start = start;
let skip_rsv = if total >= 1 << BITRES { 1 << BITRES } else { 0 };
total -= skip_rsv;
let mut intensity_rsv = 0;
let mut dual_stereo_rsv = 0;
if c == 2 {
intensity_rsv = LOG2_FRAC_TABLE[end - start];
if intensity_rsv > total {
intensity_rsv = 0;
} else {
total -= intensity_rsv;
dual_stereo_rsv = if total >= 1 << BITRES { 1 << BITRES } else { 0 };
total -= dual_stereo_rsv;
}
}
let mut bits1 = [0i32; NB_EBANDS];
let mut bits2 = [0i32; NB_EBANDS];
let mut thresh = [0i32; NB_EBANDS];
let mut trim_offset = [0i32; NB_EBANDS];
for j in start..end {
let w = EBANDS[j + 1] - EBANDS[j];
thresh[j] = (ci << BITRES).max((3 * w << lmi << BITRES) >> 4);
trim_offset[j] = ci * w * (alloc_trim - 5 - lmi) * (end as i32 - j as i32 - 1) * (1 << (lmi + BITRES as i32)) >> 6;
if w << lmi == 1 {
trim_offset[j] -= ci << BITRES;
}
}
let nb_alloc = ALLOC.len() as i32;
let mut lo = 1;
let mut hi = nb_alloc - 1;
loop {
let mut done = false;
let mut psum = 0;
let mid = (lo + hi) >> 1;
for j in (start..end).rev() {
let n = EBANDS[j + 1] - EBANDS[j];
let mut bitsj = ci * n * (ALLOC[mid as usize][j] as i32) << lmi >> 2;
if bitsj > 0 {
bitsj = (bitsj + trim_offset[j]).max(0);
}
bitsj += offsets[j];
if bitsj >= thresh[j] || done {
done = true;
psum += bitsj.min(cap[j]);
} else if bitsj >= ci << BITRES {
psum += ci << BITRES;
}
}
if psum > total {
hi = mid - 1;
} else {
lo = mid + 1;
}
if lo > hi {
break;
}
}
hi = lo;
lo -= 1;
for j in start..end {
let n = EBANDS[j + 1] - EBANDS[j];
let mut bits1j = ci * n * (ALLOC[lo as usize][j] as i32) << lmi >> 2;
let mut bits2j = if hi >= nb_alloc { cap[j] } else { ci * n * (ALLOC[hi as usize][j] as i32) << lmi >> 2 };
if bits1j > 0 {
bits1j = (bits1j + trim_offset[j]).max(0);
}
if bits2j > 0 {
bits2j = (bits2j + trim_offset[j]).max(0);
}
if lo > 0 {
bits1j += offsets[j];
}
bits2j += offsets[j];
if offsets[j] > 0 {
skip_start = j;
}
bits2j = (bits2j - bits1j).max(0);
bits1[j] = bits1j;
bits2[j] = bits2j;
}
interp_bits2pulses(m, start, end, skip_start, &bits1, &bits2, &thresh, cap, total, skip_rsv, intensity_rsv, dual_stereo_rsv, c, lm, dec)
}
#[allow(clippy::too_many_arguments)]
fn interp_bits2pulses(
m: &Mode,
start: usize,
end: usize,
skip_start: usize,
bits1: &[i32; NB_EBANDS],
bits2: &[i32; NB_EBANDS],
thresh: &[i32; NB_EBANDS],
cap: &[i32; NB_EBANDS],
mut total: i32,
skip_rsv: i32,
mut intensity_rsv: i32,
mut dual_stereo_rsv: i32,
c: usize,
lm: usize,
dec: &mut RangeDecoder,
) -> Allocation {
let ci = c as i32;
let alloc_floor = ci << BITRES;
let stereo = (c > 1) as i32;
let log_m = (lm as i32) << BITRES;
let mut lo = 0;
let mut hi = 1 << ALLOC_STEPS;
for _ in 0..ALLOC_STEPS {
let mid = (lo + hi) >> 1;
let mut psum = 0;
let mut done = false;
for j in (start..end).rev() {
let tmp = bits1[j] + (mid * bits2[j] >> ALLOC_STEPS);
if tmp >= thresh[j] || done {
done = true;
psum += tmp.min(cap[j]);
} else if tmp >= alloc_floor {
psum += alloc_floor;
}
}
if psum > total {
hi = mid;
} else {
lo = mid;
}
}
let mut bits = [0i32; NB_EBANDS];
let mut psum = 0;
let mut done = false;
for j in (start..end).rev() {
let mut tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS);
if tmp < thresh[j] && !done {
tmp = if tmp >= alloc_floor { alloc_floor } else { 0 };
} else {
done = true;
}
tmp = tmp.min(cap[j]);
bits[j] = tmp;
psum += tmp;
}
let s = start;
let mut coded_bands = end;
loop {
let j = coded_bands - 1;
if j <= skip_start {
total += skip_rsv;
break;
}
let mut left = total - psum;
let span = EBANDS[coded_bands] - EBANDS[s];
let percoeff = left / span;
left -= span * percoeff;
let rem = (left - (EBANDS[j] - EBANDS[s])).max(0);
let band_width = EBANDS[coded_bands] - EBANDS[j];
let mut band_bits = bits[j] + percoeff * band_width + rem;
if band_bits >= thresh[j].max(alloc_floor + (1 << BITRES)) {
if dec.bit_logp(1) {
break;
}
psum += 1 << BITRES;
band_bits -= 1 << BITRES;
}
psum -= bits[j] + intensity_rsv;
if intensity_rsv > 0 {
intensity_rsv = LOG2_FRAC_TABLE[j - s];
}
psum += intensity_rsv;
if band_bits >= alloc_floor {
psum += alloc_floor;
bits[j] = alloc_floor;
} else {
bits[j] = 0;
}
coded_bands -= 1;
}
let intensity = if intensity_rsv > 0 { s + dec.uint((coded_bands + 1 - s) as u32) as usize } else { 0 };
if intensity <= s {
total += dual_stereo_rsv;
dual_stereo_rsv = 0;
}
let dual_stereo = if dual_stereo_rsv > 0 { dec.bit_logp(1) } else { false };
let mut left = total - psum;
let span = EBANDS[coded_bands] - EBANDS[s];
let percoeff = left / span;
left -= span * percoeff;
for j in s..coded_bands {
bits[j] += percoeff * (EBANDS[j + 1] - EBANDS[j]);
}
for j in s..coded_bands {
let tmp = left.min(EBANDS[j + 1] - EBANDS[j]);
bits[j] += tmp;
left -= tmp;
}
let mut ebits = [0i32; NB_EBANDS];
let mut fine_priority = [0i32; NB_EBANDS];
let mut balance = 0;
for j in s..coded_bands {
let n0 = EBANDS[j + 1] - EBANDS[j];
let n = n0 << lm;
let bit = bits[j] + balance;
let mut excess;
if n > 1 {
excess = (bit - cap[j]).max(0);
bits[j] = bit - excess;
let den = ci * n + if c == 2 && n > 2 && !dual_stereo && j < intensity { 1 } else { 0 };
let nclogn = den * (m.log_n[j] + log_m);
let mut offset = (nclogn >> 1) - den * FINE_OFFSET;
if n == 2 {
offset += (den << BITRES) >> 2;
}
if bits[j] + offset < den * 2 << BITRES {
offset += nclogn >> 2;
} else if bits[j] + offset < den * 3 << BITRES {
offset += nclogn >> 3;
}
let mut eb = (bits[j] + offset + (den << (BITRES - 1))).max(0);
eb = (eb / den) >> BITRES;
if ci * eb > (bits[j] >> BITRES) {
eb = bits[j] >> stereo >> BITRES;
}
eb = eb.min(MAX_FINE_BITS);
ebits[j] = eb;
fine_priority[j] = (eb * (den << BITRES) >= bits[j] + offset) as i32;
bits[j] -= ci * eb << BITRES;
} else {
excess = (bit - (ci << BITRES)).max(0);
bits[j] = bit - excess;
ebits[j] = 0;
fine_priority[j] = 1;
}
if excess > 0 {
let extra_fine = (excess >> (stereo + BITRES as i32)).min(MAX_FINE_BITS - ebits[j]);
ebits[j] += extra_fine;
let extra_bits = extra_fine * ci << BITRES;
fine_priority[j] = (extra_bits >= excess - balance) as i32;
excess -= extra_bits;
}
balance = excess;
}
for j in coded_bands..end {
ebits[j] = bits[j] >> stereo >> BITRES;
bits[j] = 0;
fine_priority[j] = (ebits[j] < 1) as i32;
}
Allocation { coded_bands, intensity, dual_stereo, balance, pulses: bits, fine_quant: ebits, fine_priority }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn log2_frac_values() {
assert_eq!(log2_frac(1, 3), 0);
assert_eq!(log2_frac(2, 3), 8);
assert_eq!(log2_frac(4, 3), 16);
assert_eq!(log2_frac(6, 3), 21);
assert_eq!(log2_frac(18, 3), 34);
assert_eq!(log2_frac(22, 3), 36);
}
#[test]
fn pvq_counts() {
// V(N,1) = 2N, V(1,K) = 2 (K>0), V(2,K) = 4K.
assert_eq!(pvq_v(5, 1), 10);
assert_eq!(pvq_v(1, 7), 2);
assert_eq!(pvq_v(2, 9), 36);
assert_eq!(pvq_v(3, 2), 18);
assert_eq!(pvq_v(0, 0), 1);
assert_eq!(pvq_v(0, 3), 0);
}
#[test]
fn caps_match_reference_shape() {
let m = Mode::new();
// 1-bin bands at LM=0 (mono and stereo) are capped at 224.
assert!(m.caps[..8].iter().all(|&c| c == 224));
assert!(m.caps[21..29].iter().all(|&c| c == 224));
let first_rows: [u8; 42] = [
224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40,
];
assert_eq!(&m.caps[..42], &first_rows[..]);
}
}

View File

@ -0,0 +1,128 @@
//! Constant tables of the 48 kHz CELT mode (RFC 6716 §4.3).
/// Number of energy bands.
pub const NB_EBANDS: usize = 21;
/// Band edges in units of 2.5 ms MDCT bins (Table 55).
pub const EBANDS: [i32; NB_EBANDS + 1] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100];
/// Overlap of the low-overlap window (samples at 48 kHz).
pub const OVERLAP: usize = 120;
/// Size of the shortest MDCT (2.5 ms).
pub const SHORT_MDCT: usize = 120;
/// Largest LM (20 ms frames).
pub const MAX_LM: usize = 3;
/// Pre-emphasis coefficient.
pub const PREEMPH: f32 = 0.850_006_1;
/// Static allocation table (Table 57), indexed `[quality][band]`, in 1/32 bit per MDCT bin.
pub const ALLOC: [[u8; NB_EBANDS]; 11] = transpose([
[0, 90, 110, 118, 126, 134, 144, 152, 162, 172, 200],
[0, 80, 100, 110, 119, 127, 137, 145, 155, 165, 200],
[0, 75, 90, 103, 112, 120, 130, 138, 148, 158, 200],
[0, 69, 84, 93, 104, 114, 124, 132, 142, 152, 200],
[0, 63, 78, 86, 95, 103, 113, 123, 133, 143, 200],
[0, 56, 71, 80, 89, 97, 107, 117, 127, 137, 200],
[0, 49, 65, 75, 83, 91, 101, 111, 121, 131, 200],
[0, 40, 58, 70, 78, 85, 95, 105, 115, 125, 200],
[0, 34, 51, 65, 72, 78, 88, 98, 108, 118, 198],
[0, 29, 45, 59, 66, 72, 82, 92, 102, 112, 193],
[0, 20, 39, 53, 60, 66, 76, 86, 96, 106, 188],
[0, 18, 32, 47, 54, 60, 70, 80, 90, 100, 183],
[0, 10, 26, 40, 47, 54, 64, 74, 84, 94, 178],
[0, 0, 20, 31, 39, 47, 57, 67, 77, 87, 173],
[0, 0, 12, 23, 32, 41, 51, 61, 71, 81, 168],
[0, 0, 0, 15, 25, 35, 45, 55, 65, 75, 163],
[0, 0, 0, 4, 17, 29, 39, 49, 59, 69, 158],
[0, 0, 0, 0, 12, 23, 33, 43, 53, 63, 153],
[0, 0, 0, 0, 1, 16, 26, 36, 46, 56, 148],
[0, 0, 0, 0, 0, 10, 15, 20, 30, 45, 129],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 20, 104],
]);
const fn transpose(t: [[u8; 11]; NB_EBANDS]) -> [[u8; NB_EBANDS]; 11] {
let mut out = [[0u8; NB_EBANDS]; 11];
let mut b = 0;
while b < NB_EBANDS {
let mut q = 0;
while q < 11 {
out[q][b] = t[b][q];
q += 1;
}
b += 1;
}
out
}
/// Mean band energy (log2 domain) removed before coarse quantisation.
pub const E_MEANS: [f32; 25] = [
6.4375, 6.25, 5.75, 5.3125, 5.0625, 4.8125, 4.5, 4.375, 4.875, 4.6875, 4.5625, 4.4375, 4.875, 4.625, 4.3125, 4.5, 4.375, 4.625, 4.75, 4.4375, 3.75, 3.75,
3.75, 3.75, 3.75,
];
/// Inter-frame prediction coefficient (alpha) per LM, Q15.
pub const PRED_COEF: [f32; 4] = [29440.0 / 32768.0, 26112.0 / 32768.0, 21248.0 / 32768.0, 16384.0 / 32768.0];
/// Inter-band prediction coefficient (beta) per LM for inter frames, Q15.
pub const BETA_COEF: [f32; 4] = [30147.0 / 32768.0, 22282.0 / 32768.0, 12124.0 / 32768.0, 6554.0 / 32768.0];
/// Beta for intra frames.
pub const BETA_INTRA: f32 = 4915.0 / 32768.0;
/// Laplace model parameters for coarse energy: `[LM][intra][2*band + {0: prob, 1: decay}]`.
pub const E_PROB_MODEL: [[[u8; 42]; 2]; 4] = [
[
[
72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, 114, 40, 132, 26, 132,
26, 145, 17, 161, 12, 176, 10, 177, 11,
],
[
24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, 91, 67, 100, 59, 108, 50,
120, 40, 122, 37, 97, 43, 78, 50,
],
],
[
[
83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, 146, 19, 162, 12, 165, 10,
178, 7, 189, 6, 190, 8, 177, 9,
],
[
23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, 104, 60, 117, 52, 123, 44,
138, 35, 133, 31, 97, 38, 77, 45,
],
],
[
[
61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, 158, 18, 170, 13, 177,
10, 187, 8, 192, 6, 175, 9, 159, 10,
],
[
21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, 112, 56, 129, 51, 132, 40,
150, 33, 140, 29, 98, 35, 77, 42,
],
],
[
[
42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, 154, 26, 166, 21, 173,
16, 184, 13, 184, 10, 150, 13, 139, 15,
],
[
22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, 117, 55, 135, 49, 137, 39,
157, 32, 145, 29, 97, 33, 77, 40,
],
],
];
/// Inverse CDF for coarse energy when only a few bits remain.
pub const SMALL_ENERGY_ICDF: [u8; 3] = [2, 1, 0];
/// Conservative log2 in 1/8 bits of the number of coded bands (intensity reservation).
pub const LOG2_FRAC_TABLE: [i32; 24] = [0, 8, 13, 16, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37];
/// TF resolution changes: `[LM][4*transient + 2*tf_select + tf_flag]`.
pub const TF_SELECT_TABLE: [[i8; 8]; 4] = [[0, -1, 0, -1, 0, -1, 0, -1], [0, -1, 0, -2, 1, 0, 1, -1], [0, -2, 0, -3, 2, 0, 1, -1], [0, -2, 0, -3, 3, 0, 1, -1]];
/// Spreading decision `{7, 2, 21, 2}/32`.
pub const SPREAD_ICDF: [u8; 4] = [25, 23, 2, 0];
/// Allocation trim (Table 58).
pub const TRIM_ICDF: [u8; 11] = [126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0];
/// Post-filter tapset `{2, 1, 1}/4`.
pub const TAPSET_ICDF: [u8; 3] = [2, 1, 0];
/// Post-filter tap gains per tapset.
pub const COMB_GAINS: [[f32; 3]; 3] = [[0.306_640_62, 0.217_041_02, 0.129_638_67], [0.463_867_2, 0.268_066_4, 0.0], [0.799_804_7, 0.100_097_656, 0.0]];
/// Hadamard "sequency" ordering for 2, 4, 8 and 16 blocks, concatenated.
pub const ORDERY: [usize; 30] = [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];

38
crates/opus/src/lib.rs Normal file
View File

@ -0,0 +1,38 @@
//! Clean-room pure-Rust Opus decoder (RFC 6716, updated by RFC 8251).
//!
//! Layer L0: no dependencies beyond `std`; no `unsafe`; builds for `wasm32-unknown-unknown`.
#![allow(dead_code)] // WIP: top-level decoder not wired yet
// The fixed-point parts mirror the normative integer arithmetic; keep C-like shift expressions.
#![allow(clippy::precedence, clippy::int_plus_one)]
pub(crate) mod celt;
pub mod packet;
pub(crate) mod range;
pub(crate) mod silk;
pub use packet::{Bandwidth, Mode, Packet, Toc};
/// Errors from header parsing and decoding.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
InvalidArgument(&'static str),
InvalidPacket(&'static str),
InvalidHeader(&'static str),
Unsupported(&'static str),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::InvalidArgument(s) => write!(f, "invalid argument: {s}"),
Error::InvalidPacket(s) => write!(f, "invalid packet: {s}"),
Error::InvalidHeader(s) => write!(f, "invalid header: {s}"),
Error::Unsupported(s) => write!(f, "unsupported: {s}"),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;

279
crates/opus/src/packet.rs Normal file
View File

@ -0,0 +1,279 @@
//! TOC byte and frame packing (RFC 6716 §3).
use crate::Error;
/// Coding mode of an Opus frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Mode {
SilkOnly,
Hybrid,
CeltOnly,
}
/// Audio bandwidth.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Bandwidth {
/// 4 kHz.
Narrowband,
/// 6 kHz.
Mediumband,
/// 8 kHz.
Wideband,
/// 12 kHz.
SuperWideband,
/// 20 kHz.
Fullband,
}
impl Bandwidth {
/// Number of CELT bands coded for this bandwidth.
pub fn celt_end_band(self) -> usize {
match self {
Bandwidth::Narrowband => 13,
Bandwidth::Mediumband | Bandwidth::Wideband => 17,
Bandwidth::SuperWideband => 19,
Bandwidth::Fullband => 21,
}
}
}
/// Decoded table-of-contents byte.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Toc {
pub config: u8,
pub mode: Mode,
pub bandwidth: Bandwidth,
pub stereo: bool,
/// Frame count code (0..=3).
pub code: u8,
}
impl Toc {
pub fn parse(b: u8) -> Toc {
let config = b >> 3;
let (mode, bandwidth) = match config {
0..=3 => (Mode::SilkOnly, Bandwidth::Narrowband),
4..=7 => (Mode::SilkOnly, Bandwidth::Mediumband),
8..=11 => (Mode::SilkOnly, Bandwidth::Wideband),
12..=13 => (Mode::Hybrid, Bandwidth::SuperWideband),
14..=15 => (Mode::Hybrid, Bandwidth::Fullband),
16..=19 => (Mode::CeltOnly, Bandwidth::Narrowband),
20..=23 => (Mode::CeltOnly, Bandwidth::Wideband),
24..=27 => (Mode::CeltOnly, Bandwidth::SuperWideband),
_ => (Mode::CeltOnly, Bandwidth::Fullband),
};
Toc { config, mode, bandwidth, stereo: b & 4 != 0, code: b & 3 }
}
/// Samples per frame at 48 kHz.
pub fn frame_samples_48k(&self) -> usize {
self.frame_samples(48000)
}
/// Samples per frame at `rate`.
pub fn frame_samples(&self, rate: u32) -> usize {
let rate = rate as usize;
let c = self.config as usize;
match self.mode {
Mode::CeltOnly => (rate << (c & 3)) / 400,
Mode::Hybrid => {
if c & 1 != 0 {
rate / 50
} else {
rate / 100
}
}
Mode::SilkOnly => match c & 3 {
3 => rate * 60 / 1000,
s => (rate << s) / 100,
},
}
}
pub fn channels(&self) -> usize {
if self.stereo { 2 } else { 1 }
}
}
/// A parsed packet: TOC plus the byte ranges of each frame.
#[derive(Clone, Debug)]
pub struct Packet<'a> {
pub toc: Toc,
pub frames: Vec<&'a [u8]>,
/// Bytes of padding (code 3 only).
pub padding: usize,
}
fn parse_size(data: &[u8]) -> Option<(usize, usize)> {
match data.first() {
None => None,
Some(&b) if b < 252 => Some((b as usize, 1)),
Some(&b) => data.get(1).map(|&b1| (4 * b1 as usize + b as usize, 2)),
}
}
impl<'a> Packet<'a> {
/// Parses a packet (RFC 6716 §3.2), enforcing requirements R1–R7.
pub fn parse(data: &'a [u8]) -> Result<Packet<'a>, Error> {
const BAD: Error = Error::InvalidPacket("malformed packet framing");
if data.is_empty() {
return Err(Error::InvalidPacket("empty packet"));
}
let toc = Toc::parse(data[0]);
let fs = toc.frame_samples_48k();
let mut p = &data[1..];
let mut frames = Vec::new();
let mut padding = 0usize;
match toc.code {
0 => frames.push(p),
1 => {
if !p.len().is_multiple_of(2) {
return Err(BAD);
}
let h = p.len() / 2;
frames.push(&p[..h]);
frames.push(&p[h..]);
}
2 => {
let (s, n) = parse_size(p).ok_or(BAD)?;
p = &p[n..];
if s > p.len() {
return Err(BAD);
}
frames.push(&p[..s]);
frames.push(&p[s..]);
}
_ => {
let &ch = p.first().ok_or(BAD)?;
p = &p[1..];
let count = (ch & 0x3F) as usize;
if count == 0 || fs * count > 5760 {
return Err(BAD);
}
let mut len = p.len() as isize;
if ch & 0x40 != 0 {
loop {
if len <= 0 {
return Err(BAD);
}
let b = p[0];
p = &p[1..];
len -= 1;
let tmp = if b == 255 { 254 } else { b as isize };
len -= tmp;
padding += tmp as usize;
if b != 255 {
break;
}
}
}
if len < 0 {
return Err(BAD);
}
let len = len as usize;
// `p` still includes the padding at its end; only the first `len` bytes are frames.
let body = &p[..len.min(p.len())];
if ch & 0x80 != 0 {
// VBR
let mut q = body;
let mut sizes = Vec::with_capacity(count);
let mut remaining = len as isize;
for _ in 0..count - 1 {
let (s, n) = parse_size(q).ok_or(BAD)?;
q = &q[n..];
remaining -= n as isize;
if s as isize > remaining {
return Err(BAD);
}
remaining -= s as isize;
sizes.push(s);
}
if remaining < 0 {
return Err(BAD);
}
sizes.push(remaining as usize);
let mut off = 0;
for s in sizes {
frames.push(&q[off..off + s]);
off += s;
}
} else {
let s = len / count;
if s * count != len {
return Err(BAD);
}
for i in 0..count {
frames.push(&body[i * s..(i + 1) * s]);
}
}
}
}
if frames.last().is_some_and(|f| f.len() > 1275) || frames.iter().any(|f| f.len() > 1275) {
return Err(BAD);
}
Ok(Packet { toc, frames, padding })
}
}
/// Number of samples (at 48 kHz) in a packet, or an error for malformed framing.
pub fn packet_samples_48k(data: &[u8]) -> Result<usize, Error> {
let p = Packet::parse(data)?;
Ok(p.toc.frame_samples_48k() * p.frames.len())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn toc_configs() {
for cfg in 0u8..32 {
let t = Toc::parse(cfg << 3);
let ms10 = t.frame_samples(48000) * 10 / 48; // tenths of ms
let expect = match cfg {
0..=11 => [100, 200, 400, 600][cfg as usize & 3],
12..=15 => [100, 200][cfg as usize & 1],
_ => [25, 50, 100, 200][cfg as usize & 3],
};
assert_eq!(ms10, expect, "config {cfg}");
}
assert!(Toc::parse(0x04).stereo);
}
#[test]
fn frame_codes() {
// code 0
let p = Packet::parse(&[0x00, 1, 2, 3]).unwrap();
assert_eq!(p.frames, vec![&[1u8, 2, 3][..]]);
// code 1 (odd payload is invalid)
assert!(Packet::parse(&[0x01, 1, 2, 3]).is_err());
let p = Packet::parse(&[0x01, 1, 2, 3, 4]).unwrap();
assert_eq!(p.frames.len(), 2);
// code 2
let p = Packet::parse(&[0x02, 1, 9, 8, 7]).unwrap();
assert_eq!(p.frames, vec![&[9u8][..], &[8u8, 7][..]]);
assert!(Packet::parse(&[0x02, 5, 1]).is_err());
// code 3 CBR with padding: 2 frames of 2 bytes, 3 bytes padding
let p = Packet::parse(&[0x03, 0x42, 3, 1, 2, 3, 4, 0, 0, 0]).unwrap();
assert_eq!(p.frames, vec![&[1u8, 2][..], &[3u8, 4][..]]);
assert_eq!(p.padding, 3);
// code 3 VBR
let p = Packet::parse(&[0x03, 0x83, 1, 2, 10, 20, 21, 30]).unwrap();
assert_eq!(p.frames, vec![&[10u8][..], &[20u8, 21][..], &[30u8][..]]);
// too many frames (> 120 ms)
assert!(Packet::parse(&[0x03 | (3 << 3), 0x03, 0]).is_err());
// zero frames
assert!(Packet::parse(&[0x03, 0x00]).is_err());
assert!(Packet::parse(&[]).is_err());
}
#[test]
fn two_byte_sizes() {
let mut pkt = vec![0x02u8, 252, 1];
pkt.extend(std::iter::repeat_n(7u8, 256));
pkt.extend([1, 2]);
let p = Packet::parse(&pkt).unwrap();
assert_eq!(p.frames[0].len(), 256);
assert_eq!(p.frames[1], &[1, 2]);
}
}

496
crates/opus/src/range.rs Normal file
View File

@ -0,0 +1,496 @@
//! Range decoder (RFC 6716 §4.1).
//!
//! The decoder reads range-coded symbols from the front of the buffer and raw bits from the back.
//! Reading past either end yields zeros (never panics); callers detect corruption through
//! [`RangeDecoder::tell`] exceeding the budget or through out-of-range values.
const SYM_BITS: u32 = 8;
const CODE_BITS: u32 = 32;
const SYM_MAX: u32 = (1 << SYM_BITS) - 1;
const CODE_SHIFT: u32 = CODE_BITS - SYM_BITS - 1;
const CODE_TOP: u32 = 1 << (CODE_BITS - 1);
const CODE_BOT: u32 = CODE_TOP >> SYM_BITS;
const CODE_EXTRA: u32 = (CODE_BITS - 2) % SYM_BITS + 1;
/// Bit resolution of [`RangeDecoder::tell_frac`] (1/8 bit).
pub const BITRES: u32 = 3;
/// Number of bits needed to represent `x` (0 for 0).
#[inline]
pub fn ilog(x: u32) -> i32 {
(32 - x.leading_zeros()) as i32
}
#[derive(Clone, Debug)]
pub struct RangeDecoder<'a> {
buf: &'a [u8],
/// Bytes available to the decoder (may be reduced, e.g. for redundancy).
storage: usize,
offs: usize,
end_offs: usize,
end_window: u32,
nend_bits: i32,
nbits_total: i32,
rng: u32,
val: u32,
rem: u32,
/// Set when an out-of-range value was decoded.
pub error: bool,
}
impl<'a> RangeDecoder<'a> {
pub fn new(buf: &'a [u8]) -> Self {
let mut d = RangeDecoder {
buf,
storage: buf.len(),
offs: 0,
end_offs: 0,
end_window: 0,
nend_bits: 0,
nbits_total: (CODE_BITS + 1 - ((CODE_BITS - CODE_EXTRA) / SYM_BITS) * SYM_BITS) as i32,
rng: 1 << CODE_EXTRA,
val: 0,
rem: 0,
error: false,
};
d.rem = d.read_byte();
d.val = d.rng - 1 - (d.rem >> (SYM_BITS - CODE_EXTRA));
d.normalize();
d
}
/// Size of the buffer in bytes as seen by the decoder.
pub fn storage(&self) -> usize {
self.storage
}
/// Shrinks the buffer seen by the decoder (raw bits are then read from the new end).
pub fn shrink_storage(&mut self, by: usize) {
self.storage = self.storage.saturating_sub(by);
}
pub fn rng(&self) -> u32 {
self.rng
}
#[inline]
fn read_byte(&mut self) -> u32 {
if self.offs < self.storage {
let b = self.buf[self.offs];
self.offs += 1;
b as u32
} else {
0
}
}
#[inline]
fn read_byte_from_end(&mut self) -> u32 {
if self.end_offs < self.storage {
self.end_offs += 1;
self.buf[self.storage - self.end_offs] as u32
} else {
0
}
}
#[inline]
fn normalize(&mut self) {
while self.rng <= CODE_BOT {
self.nbits_total += SYM_BITS as i32;
self.rng <<= SYM_BITS;
let sym = self.rem;
self.rem = self.read_byte();
let sym = ((sym << SYM_BITS) | self.rem) >> (SYM_BITS - CODE_EXTRA);
self.val = ((self.val << SYM_BITS).wrapping_add(SYM_MAX & !sym)) & (CODE_TOP - 1);
}
}
/// Returns the cumulative frequency of the next symbol for total `ft` (call [`Self::update`] next).
#[inline]
pub fn decode(&mut self, ft: u32) -> u32 {
let ext = self.rng / ft;
let s = self.val / ext;
// stash ext in rem-free form: recomputed by update()
ft - (s + 1).min(ft)
}
/// Like [`Self::decode`] with `ft = 1 << bits`.
#[inline]
pub fn decode_bin(&mut self, bits: u32) -> u32 {
let ext = self.rng >> bits;
let s = self.val / ext;
(1 << bits) - (s + 1).min(1 << bits)
}
/// Consumes the symbol with cumulative range `[fl, fh)` of total `ft`.
#[inline]
pub fn update(&mut self, fl: u32, fh: u32, ft: u32) {
let ext = self.rng / ft;
let s = ext * (ft - fh);
self.val = self.val.wrapping_sub(s);
self.rng = if fl > 0 { ext * (fh - fl) } else { self.rng - s };
self.normalize();
}
/// Like [`Self::update`] for a symbol decoded with [`Self::decode_bin`].
#[inline]
pub fn update_bin(&mut self, fl: u32, fh: u32, bits: u32) {
let ext = self.rng >> bits;
let ft = 1u32 << bits;
let s = ext * (ft - fh);
self.val = self.val.wrapping_sub(s);
self.rng = if fl > 0 { ext * (fh - fl) } else { self.rng - s };
self.normalize();
}
/// Decodes a binary symbol whose probability of being 1 is `1/2^logp`.
#[inline]
pub fn bit_logp(&mut self, logp: u32) -> bool {
let r = self.rng;
let d = self.val;
let s = r >> logp;
let ret = d < s;
if !ret {
self.val = d - s;
}
self.rng = if ret { s } else { r - s };
self.normalize();
ret
}
/// Decodes a symbol with an "inverse CDF" table (`icdf[i] = ft - cdf[i+1]`, `ft = 1 << ftb`).
#[inline]
pub fn icdf(&mut self, icdf: &[u8], ftb: u32) -> usize {
let mut s = self.rng;
let d = self.val;
let r = s >> ftb;
let mut ret = 0usize;
let mut t;
loop {
t = s;
let v = icdf.get(ret).copied().unwrap_or(0) as u32;
s = r * v;
if d >= s || ret + 1 >= icdf.len() {
break;
}
ret += 1;
}
// If the table is exhausted without d >= s, force the last symbol (only on corrupt tables).
if d < s {
s = 0;
}
self.val = d - s;
self.rng = t - s;
self.normalize();
ret
}
/// Decodes a uniformly distributed integer in `[0, ft)` (`ft >= 2`).
pub fn uint(&mut self, ft: u32) -> u32 {
debug_assert!(ft > 1);
let ft1 = ft - 1;
let ftb = ilog(ft1);
if ftb > 8 {
let ftb = (ftb - 8) as u32;
let top = (ft1 >> ftb) + 1;
let s = self.decode(top);
self.update(s, s + 1, top);
let t = (s << ftb) | self.bits(ftb);
if t <= ft1 {
return t;
}
self.error = true;
ft1
} else {
let s = self.decode(ft);
self.update(s, s + 1, ft);
s
}
}
/// Reads `bits` raw bits (0..=25) from the end of the buffer.
pub fn bits(&mut self, bits: u32) -> u32 {
if bits == 0 {
return 0;
}
let mut window = self.end_window;
let mut available = self.nend_bits;
if (available as u32) < bits {
loop {
window |= self.read_byte_from_end() << available;
available += SYM_BITS as i32;
if available > (CODE_BITS - SYM_BITS) as i32 {
break;
}
}
}
let ret = window & ((1u32 << bits) - 1);
window >>= bits;
available -= bits as i32;
self.end_window = window;
self.nend_bits = available;
self.nbits_total += bits as i32;
ret
}
/// Advances the bit counter so that [`Self::tell`] reports `total` (CELT silence frames).
pub fn skip_to_end(&mut self, total: i32) {
let t = self.tell();
self.nbits_total += total - t;
}
/// Number of bits consumed so far (rounded up).
#[inline]
pub fn tell(&self) -> i32 {
self.nbits_total - ilog(self.rng)
}
/// Number of 1/8 bits consumed so far (rounded up).
pub fn tell_frac(&self) -> u32 {
let nbits = (self.nbits_total as u32) << BITRES;
let mut l = ilog(self.rng) as u32;
let mut r = self.rng >> (l - 16);
for _ in 0..BITRES {
r = (r * r) >> 15;
let b = r >> 16;
l = (l << 1) | b;
r >>= b;
}
nbits.wrapping_sub(l)
}
}
#[cfg(test)]
pub(crate) mod enc {
//! Minimal range encoder (RFC 6716 §5.1), used only to build test streams.
use super::*;
pub struct RangeEncoder {
out: Vec<u8>,
end: Vec<u8>,
end_window: u32,
nend_bits: i32,
rng: u32,
low: u32,
rem: i32,
ext: u32,
size: usize,
}
impl RangeEncoder {
pub fn new(size: usize) -> Self {
RangeEncoder { out: Vec::new(), end: Vec::new(), end_window: 0, nend_bits: 0, rng: CODE_TOP, low: 0, rem: -1, ext: 0, size }
}
fn carry_out(&mut self, c: u32) {
if c != SYM_MAX {
let carry = c >> SYM_BITS;
if self.rem >= 0 {
self.out.push((self.rem as u32 + carry) as u8);
}
if self.ext > 0 {
let sym = (SYM_MAX + carry) & SYM_MAX;
for _ in 0..self.ext {
self.out.push(sym as u8);
}
self.ext = 0;
}
self.rem = (c & SYM_MAX) as i32;
} else {
self.ext += 1;
}
}
fn normalize(&mut self) {
while self.rng <= CODE_BOT {
self.carry_out(self.low >> CODE_SHIFT);
self.low = (self.low << SYM_BITS) & (CODE_TOP - 1);
self.rng <<= SYM_BITS;
}
}
pub fn encode(&mut self, fl: u32, fh: u32, ft: u32) {
let r = self.rng / ft;
if fl > 0 {
self.low += self.rng - r * (ft - fl);
self.rng = r * (fh - fl);
} else {
self.rng -= r * (ft - fh);
}
self.normalize();
}
pub fn bit_logp(&mut self, val: bool, logp: u32) {
let r = self.rng;
let s = r >> logp;
let r2 = r - s;
if val {
self.low += r2;
self.rng = s;
} else {
self.rng = r2;
}
self.normalize();
}
pub fn icdf(&mut self, s: usize, icdf: &[u8], ftb: u32) {
let r = self.rng >> ftb;
if s > 0 {
self.low += self.rng - r * icdf[s - 1] as u32;
self.rng = r * (icdf[s - 1] as u32 - icdf[s] as u32);
} else {
self.rng -= r * icdf[s] as u32;
}
self.normalize();
}
pub fn uint(&mut self, fl: u32, ft: u32) {
let ft1 = ft - 1;
let ftb = ilog(ft1);
if ftb > 8 {
let ftb = (ftb - 8) as u32;
let top = (ft1 >> ftb) + 1;
let v = fl >> ftb;
self.encode(v, v + 1, top);
self.bits(fl & ((1 << ftb) - 1), ftb);
} else {
self.encode(fl, fl + 1, ft);
}
}
pub fn bits(&mut self, val: u32, bits: u32) {
let mut window = self.end_window;
let mut used = self.nend_bits;
if used as u32 + bits > CODE_BITS {
while used >= SYM_BITS as i32 {
self.end.push((window & SYM_MAX) as u8);
window >>= SYM_BITS;
used -= SYM_BITS as i32;
}
}
window |= val << used;
used += bits as i32;
self.end_window = window;
self.nend_bits = used;
}
/// Finalises and returns a buffer of exactly `size` bytes.
pub fn done(mut self) -> Vec<u8> {
let mut l = CODE_BITS as i32 - ilog(self.rng);
let mut msk = (CODE_TOP - 1) >> l;
let mut end = (self.low + msk) & !msk;
if (end | msk) >= self.low + self.rng {
l += 1;
msk >>= 1;
end = (self.low + msk) & !msk;
}
while l > 0 {
self.carry_out(end >> CODE_SHIFT);
end = (end << SYM_BITS) & (CODE_TOP - 1);
l -= SYM_BITS as i32;
}
if self.rem >= 0 || self.ext > 0 {
self.carry_out(0);
}
let mut window = self.end_window;
let mut used = self.nend_bits;
while used > 0 {
self.end.push((window & SYM_MAX) as u8);
window >>= SYM_BITS;
used -= SYM_BITS as i32;
}
assert!(self.out.len() + self.end.len() <= self.size, "range encoder overflow");
let mut buf = self.out;
buf.resize(self.size - self.end.len(), 0);
for &b in self.end.iter().rev() {
buf.push(b);
}
buf
}
}
}
#[cfg(test)]
mod tests {
use super::enc::RangeEncoder;
use super::*;
struct Lcg(u32);
impl Lcg {
fn next(&mut self) -> u32 {
self.0 = self.0.wrapping_mul(1664525).wrapping_add(1013904223);
self.0 >> 8
}
}
#[test]
fn roundtrip_mixed_symbols() {
let mut rng = Lcg(1);
for trial in 0..200 {
let n = 1 + (rng.next() % 300) as usize;
let mut ops = Vec::new();
for _ in 0..n {
match rng.next() % 5 {
0 => {
let ft = 2 + rng.next() % 1000;
let v = rng.next() % ft;
ops.push((0u8, v, ft));
}
1 => {
let logp = 1 + rng.next() % 15;
ops.push((1, rng.next().is_multiple_of(7) as u32, logp));
}
2 => {
let bits = 1 + rng.next() % 24;
ops.push((2, rng.next() & ((1 << bits) - 1), bits));
}
3 => {
let ft = 2 + rng.next() % 100_000_000;
ops.push((3, rng.next() % ft, ft));
}
_ => ops.push((4, rng.next() % 4, 0)),
}
}
let icdf: [u8; 4] = [200, 120, 30, 0];
let mut e = RangeEncoder::new(8 * n + 16);
for &(k, v, p) in &ops {
match k {
0 => e.encode(v, v + 1, p),
1 => e.bit_logp(v != 0, p),
2 => e.bits(v, p),
3 => e.uint(v, p),
_ => e.icdf(v as usize, &icdf, 8),
}
}
let buf = e.done();
let mut d = RangeDecoder::new(&buf);
for (i, &(k, v, p)) in ops.iter().enumerate() {
let got = match k {
0 => {
let s = d.decode(p);
d.update(s, s + 1, p);
s
}
1 => d.bit_logp(p) as u32,
2 => d.bits(p),
3 => d.uint(p),
_ => d.icdf(&icdf, 8) as u32,
};
assert_eq!(got, v, "trial {trial} op {i} kind {k}");
}
assert!(!d.error);
}
}
#[test]
fn tell_starts_at_one_bit() {
let buf = [0u8; 8];
let d = RangeDecoder::new(&buf);
assert_eq!(d.tell(), 1);
assert_eq!(d.tell_frac(), 8);
}
#[test]
fn empty_and_garbage_never_panic() {
let mut d = RangeDecoder::new(&[]);
for i in 0..100 {
d.bits(1 + i % 20);
d.uint(3 + i * 77);
d.icdf(&[250, 100, 0], 8);
d.bit_logp(1 + i % 15);
}
let _ = d.tell_frac();
}
}

View File

@ -0,0 +1,4 @@
//! SILK layer decoder (RFC 6716 §4.2).
#[allow(dead_code)]
pub(crate) mod tables;

View File

@ -0,0 +1,537 @@
//! SILK probability tables and codebooks, transcribed from RFC 6716 §4.2 (Tables 4–53).
//!
//! PDFs are written as in the RFC (`{...}/256`) and converted at compile time to the inverse-CDF
//! form consumed by the range decoder.
/// Converts a PDF (summing to 256) into an inverse CDF (`256 - cdf[i+1]`).
pub const fn icdf<const N: usize>(pdf: &[u8; N]) -> [u8; N] {
let mut out = [0u8; N];
let mut acc: u32 = 0;
let mut i = 0;
while i < N {
acc += pdf[i] as u32;
out[i] = (256 - acc) as u8;
i += 1;
}
out
}
pub const STEREO_PRED_JOINT: [u8; 25] = icdf(&[7, 2, 1, 1, 1, 10, 24, 8, 1, 1, 3, 23, 92, 23, 3, 1, 1, 8, 24, 10, 1, 1, 1, 2, 7]);
pub const UNIFORM3: [u8; 3] = icdf(&[85, 86, 85]);
pub const UNIFORM5: [u8; 5] = icdf(&[51, 51, 52, 51, 51]);
pub const STEREO_WEIGHTS_Q13: [i32; 16] = [-13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732];
pub const MID_ONLY: [u8; 2] = icdf(&[192, 64]);
pub const TYPE_INACTIVE: [u8; 2] = icdf(&[26, 230]);
pub const TYPE_ACTIVE: [u8; 4] = icdf(&[24, 74, 148, 10]);
pub const GAIN_MSB: [&[u8]; 3] =
[&icdf::<8>(&[32, 112, 68, 29, 12, 1, 1, 1]), &icdf::<8>(&[2, 17, 45, 60, 62, 47, 19, 4]), &icdf::<8>(&[1, 3, 26, 71, 94, 50, 9, 2])];
pub const UNIFORM8: [u8; 8] = icdf(&[32, 32, 32, 32, 32, 32, 32, 32]);
pub const DELTA_GAIN: [u8; 41] =
icdf(&[6, 5, 11, 31, 132, 21, 8, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
pub const NLSF_STAGE1: [&[u8]; 4] = [
&icdf::<32>(&[44, 34, 30, 19, 21, 12, 11, 3, 3, 2, 16, 2, 2, 1, 5, 2, 1, 3, 3, 1, 1, 2, 2, 2, 3, 1, 9, 9, 2, 7, 2, 1]),
&icdf::<32>(&[1, 10, 1, 8, 3, 8, 8, 14, 13, 14, 1, 14, 12, 13, 11, 11, 12, 11, 10, 10, 11, 8, 9, 8, 7, 8, 1, 1, 6, 1, 6, 5]),
&icdf::<32>(&[31, 21, 3, 17, 1, 8, 17, 4, 1, 18, 16, 4, 2, 3, 1, 10, 1, 3, 16, 11, 16, 2, 2, 3, 2, 11, 1, 4, 9, 8, 7, 3]),
&icdf::<32>(&[1, 4, 16, 5, 18, 11, 5, 14, 15, 1, 3, 12, 13, 14, 14, 6, 14, 12, 2, 6, 1, 12, 12, 11, 10, 3, 10, 5, 1, 1, 1, 3]),
];
pub const NLSF_STAGE2: [&[u8]; 16] = [
&icdf::<9>(&[1, 1, 1, 15, 224, 11, 1, 1, 1]),
&icdf::<9>(&[1, 1, 2, 34, 183, 32, 1, 1, 1]),
&icdf::<9>(&[1, 1, 4, 42, 149, 55, 2, 1, 1]),
&icdf::<9>(&[1, 1, 8, 52, 123, 61, 8, 1, 1]),
&icdf::<9>(&[1, 3, 16, 53, 101, 74, 6, 1, 1]),
&icdf::<9>(&[1, 3, 17, 55, 90, 73, 15, 1, 1]),
&icdf::<9>(&[1, 7, 24, 53, 74, 67, 26, 3, 1]),
&icdf::<9>(&[1, 1, 18, 63, 78, 58, 30, 6, 1]),
&icdf::<9>(&[1, 1, 1, 9, 232, 9, 1, 1, 1]),
&icdf::<9>(&[1, 1, 2, 28, 186, 35, 1, 1, 1]),
&icdf::<9>(&[1, 1, 3, 42, 152, 53, 2, 1, 1]),
&icdf::<9>(&[1, 1, 10, 49, 126, 65, 2, 1, 1]),
&icdf::<9>(&[1, 4, 19, 48, 100, 77, 5, 1, 1]),
&icdf::<9>(&[1, 1, 14, 54, 100, 72, 12, 1, 1]),
&icdf::<9>(&[1, 1, 15, 61, 87, 61, 25, 4, 1]),
&icdf::<9>(&[1, 7, 21, 50, 77, 81, 17, 1, 1]),
];
pub const NLSF_SEL_NBMB: [[u8; 10]; 32] = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 3, 1, 2, 2, 1, 2, 1, 1, 1],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 1, 2, 1, 1, 1],
[2, 3, 3, 3, 3, 2, 2, 2, 2, 2],
[0, 5, 3, 3, 2, 2, 2, 2, 1, 1],
[0, 2, 2, 2, 2, 2, 2, 2, 2, 1],
[2, 3, 6, 4, 4, 4, 5, 4, 5, 5],
[2, 4, 5, 5, 4, 5, 4, 6, 4, 4],
[2, 4, 4, 7, 4, 5, 4, 5, 5, 4],
[4, 3, 3, 3, 2, 3, 2, 2, 2, 2],
[1, 5, 5, 6, 4, 5, 4, 5, 5, 5],
[2, 7, 4, 6, 5, 5, 5, 5, 5, 5],
[2, 7, 5, 5, 5, 5, 5, 6, 5, 4],
[3, 3, 5, 4, 4, 5, 4, 5, 4, 4],
[2, 3, 3, 5, 5, 4, 4, 4, 4, 4],
[2, 4, 4, 6, 4, 5, 4, 5, 5, 5],
[2, 5, 4, 6, 5, 5, 5, 4, 5, 4],
[2, 7, 4, 5, 4, 5, 4, 5, 5, 5],
[2, 5, 4, 6, 7, 6, 5, 6, 5, 4],
[3, 6, 7, 4, 6, 5, 5, 6, 4, 5],
[2, 7, 6, 4, 4, 4, 5, 4, 5, 5],
[4, 5, 5, 4, 6, 6, 5, 6, 5, 4],
[2, 5, 5, 6, 5, 6, 4, 6, 4, 4],
[4, 5, 5, 5, 3, 7, 4, 5, 5, 4],
[2, 3, 4, 5, 5, 6, 4, 5, 5, 4],
[2, 3, 2, 3, 3, 4, 2, 3, 3, 3],
[1, 1, 2, 2, 2, 2, 2, 3, 2, 2],
[4, 5, 5, 6, 6, 6, 5, 6, 4, 5],
[3, 5, 5, 4, 4, 4, 4, 3, 3, 2],
[2, 5, 3, 7, 5, 5, 4, 4, 5, 4],
[4, 4, 5, 4, 5, 6, 5, 6, 5, 4],
];
pub const NLSF_SEL_WB: [[u8; 16]; 32] = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 0, 3],
[2, 5, 5, 3, 7, 4, 4, 5, 2, 5, 4, 5, 5, 4, 3, 3],
[0, 2, 1, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1],
[0, 6, 5, 4, 6, 4, 7, 5, 4, 4, 4, 5, 5, 4, 4, 3],
[0, 3, 5, 5, 4, 3, 3, 5, 3, 3, 3, 3, 3, 3, 2, 4],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 2, 6, 3, 7, 2, 5, 3, 4, 5, 5, 4, 3, 3, 2, 3],
[0, 6, 2, 6, 6, 4, 5, 4, 6, 5, 4, 4, 5, 3, 3, 3],
[2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 3],
[2, 2, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 3],
[3, 4, 4, 4, 6, 4, 4, 5, 3, 5, 4, 4, 5, 4, 3, 4],
[0, 6, 4, 5, 4, 7, 5, 2, 6, 5, 7, 4, 4, 3, 5, 3],
[0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0],
[1, 6, 5, 7, 5, 4, 5, 3, 4, 5, 4, 4, 4, 3, 3, 4],
[1, 3, 3, 4, 4, 3, 3, 5, 2, 3, 3, 5, 5, 5, 3, 4],
[2, 3, 3, 2, 2, 2, 3, 2, 1, 2, 1, 2, 1, 1, 1, 4],
[0, 2, 3, 5, 3, 3, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0],
[3, 4, 3, 5, 3, 3, 2, 2, 1, 1, 1, 1, 1, 2, 2, 4],
[2, 6, 3, 7, 7, 4, 5, 4, 5, 3, 5, 3, 3, 2, 3, 3],
[2, 3, 5, 6, 6, 3, 5, 3, 4, 4, 3, 3, 3, 3, 2, 4],
[1, 3, 3, 4, 4, 4, 4, 3, 5, 5, 5, 3, 1, 1, 1, 1],
[2, 5, 3, 6, 6, 4, 7, 4, 4, 5, 3, 4, 4, 3, 3, 3],
[0, 6, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 6, 6, 3, 5, 2, 5, 5, 3, 4, 4, 7, 7, 4, 4, 4],
[3, 3, 7, 3, 5, 4, 3, 3, 3, 2, 2, 3, 3, 3, 2, 3],
[0, 0, 1, 0, 0, 0, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1],
[0, 3, 2, 5, 3, 3, 2, 3, 2, 1, 0, 0, 1, 0, 0, 1],
[3, 5, 5, 4, 7, 5, 3, 3, 2, 3, 2, 2, 1, 0, 1, 0],
[2, 3, 5, 3, 4, 3, 3, 3, 2, 1, 2, 6, 4, 0, 0, 0],
];
pub const NLSF_EXT: [u8; 7] = icdf(&[156, 60, 24, 9, 4, 2, 1]);
pub const NLSF_PRED_NBMB: [[i32; 9]; 2] = [[179, 138, 140, 148, 151, 149, 153, 151, 163], [116, 67, 82, 59, 92, 72, 100, 89, 92]];
pub const NLSF_PRED_WB: [[i32; 15]; 2] =
[[175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198, 192, 182], [68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142, 160, 142, 155]];
pub const NLSF_PSEL_NBMB: [[u8; 9]; 32] = [
[0, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 1, 0, 0, 0, 1, 0],
[0, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 1, 0, 1, 1],
[0, 0, 1, 1, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 0, 1, 1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 1, 1, 0, 0, 1, 1, 1, 0],
[0, 0, 0, 1, 1, 1, 0, 1, 0],
[0, 1, 1, 0, 0, 1, 0, 1, 0],
[0, 1, 1, 0, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 1, 1, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 1, 0, 1, 0],
[1, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 1],
[1, 0, 1, 1, 0, 1, 1, 1, 1],
];
pub const NLSF_PSEL_WB: [[u8; 15]; 32] = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0],
[0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
];
pub const NLSF_CB_NBMB: [[i32; 10]; 32] = [
[12, 35, 60, 83, 108, 132, 157, 180, 206, 228],
[15, 32, 55, 77, 101, 125, 151, 175, 201, 225],
[19, 42, 66, 89, 114, 137, 162, 184, 209, 230],
[12, 25, 50, 72, 97, 120, 147, 172, 200, 223],
[26, 44, 69, 90, 114, 135, 159, 180, 205, 225],
[13, 22, 53, 80, 106, 130, 156, 180, 205, 228],
[15, 25, 44, 64, 90, 115, 142, 168, 196, 222],
[19, 24, 62, 82, 100, 120, 145, 168, 190, 214],
[22, 31, 50, 79, 103, 120, 151, 170, 203, 227],
[21, 29, 45, 65, 106, 124, 150, 171, 196, 224],
[30, 49, 75, 97, 121, 142, 165, 186, 209, 229],
[19, 25, 52, 70, 93, 116, 143, 166, 192, 219],
[26, 34, 62, 75, 97, 118, 145, 167, 194, 217],
[25, 33, 56, 70, 91, 113, 143, 165, 196, 223],
[21, 34, 51, 72, 97, 117, 145, 171, 196, 222],
[20, 29, 50, 67, 90, 117, 144, 168, 197, 221],
[22, 31, 48, 66, 95, 117, 146, 168, 196, 222],
[24, 33, 51, 77, 116, 134, 158, 180, 200, 224],
[21, 28, 70, 87, 106, 124, 149, 170, 194, 217],
[26, 33, 53, 64, 83, 117, 152, 173, 204, 225],
[27, 34, 65, 95, 108, 129, 155, 174, 210, 225],
[20, 26, 72, 99, 113, 131, 154, 176, 200, 219],
[34, 43, 61, 78, 93, 114, 155, 177, 205, 229],
[23, 29, 54, 97, 124, 138, 163, 179, 209, 229],
[30, 38, 56, 89, 118, 129, 158, 178, 200, 231],
[21, 29, 49, 63, 85, 111, 142, 163, 193, 222],
[27, 48, 77, 103, 133, 158, 179, 196, 215, 232],
[29, 47, 74, 99, 124, 151, 176, 198, 220, 237],
[33, 42, 61, 76, 93, 121, 155, 174, 207, 225],
[29, 53, 87, 112, 136, 154, 170, 188, 208, 227],
[24, 30, 52, 84, 131, 150, 166, 186, 203, 229],
[37, 48, 64, 84, 104, 118, 156, 177, 201, 230],
];
pub const NLSF_CB_WB: [[i32; 16]; 32] = [
[7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208, 223, 239],
[13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171, 187, 203, 220, 236],
[15, 21, 34, 51, 61, 78, 92, 106, 126, 136, 152, 167, 185, 205, 225, 240],
[10, 21, 36, 50, 63, 79, 95, 110, 126, 141, 157, 173, 189, 205, 221, 237],
[17, 20, 37, 51, 59, 78, 89, 107, 123, 134, 150, 164, 184, 205, 224, 240],
[10, 15, 32, 51, 67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236],
[8, 21, 37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, 218],
[12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203, 219, 236],
[16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171, 186, 204, 220, 237],
[11, 28, 43, 58, 74, 89, 105, 120, 135, 150, 165, 180, 196, 211, 226, 241],
[6, 16, 33, 46, 60, 75, 92, 107, 123, 137, 156, 169, 185, 199, 214, 225],
[11, 19, 30, 44, 57, 74, 89, 105, 121, 135, 152, 169, 186, 202, 218, 234],
[12, 19, 29, 46, 57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233],
[17, 23, 35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, 222, 237],
[14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206, 221, 240],
[9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171, 189, 205, 222, 237],
[16, 19, 36, 48, 57, 76, 87, 105, 118, 132, 150, 167, 185, 202, 218, 236],
[12, 17, 29, 54, 71, 81, 94, 104, 126, 136, 149, 164, 182, 201, 221, 237],
[15, 28, 47, 62, 79, 97, 115, 129, 142, 155, 168, 180, 194, 208, 223, 238],
[8, 14, 30, 45, 62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239],
[17, 30, 49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, 204, 220, 235],
[14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189, 205, 222, 238],
[12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154, 171, 187, 204, 221, 236],
[13, 17, 31, 43, 53, 70, 83, 103, 114, 131, 149, 167, 185, 203, 220, 237],
[17, 22, 35, 42, 58, 78, 93, 110, 125, 139, 155, 170, 188, 206, 224, 240],
[8, 15, 34, 50, 67, 83, 99, 115, 131, 146, 162, 178, 193, 209, 224, 239],
[13, 16, 41, 66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241],
[17, 25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, 175, 191, 212, 231],
[19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200, 213, 227, 242],
[18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163, 177, 192, 207, 223, 239],
[16, 29, 47, 61, 76, 90, 106, 119, 133, 147, 161, 176, 193, 209, 224, 240],
[15, 21, 35, 50, 61, 73, 86, 97, 110, 119, 129, 141, 175, 198, 218, 237],
];
pub const NLSF_MIN_SPACING_NBMB: [i32; 11] = [250, 3, 6, 3, 3, 3, 4, 3, 3, 3, 461];
pub const NLSF_MIN_SPACING_WB: [i32; 17] = [100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347];
pub const NLSF_INTERP: [u8; 5] = icdf(&[13, 22, 29, 11, 181]);
pub const LSF_ORDER_NBMB: [usize; 10] = [0, 9, 6, 3, 4, 5, 8, 1, 2, 7];
pub const LSF_ORDER_WB: [usize; 16] = [0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1];
pub const COS_Q12: [i32; 129] = [
4096, 4095, 4091, 4085, 4076, 4065, 4052, 4036, 4017, 3997, 3973, 3948, 3920, 3889, 3857, 3822, 3784, 3745, 3703, 3659, 3613, 3564, 3513, 3461, 3406, 3349,
3290, 3229, 3166, 3102, 3035, 2967, 2896, 2824, 2751, 2676, 2599, 2520, 2440, 2359, 2276, 2191, 2106, 2019, 1931, 1842, 1751, 1660, 1568, 1474, 1380, 1285,
1189, 1093, 995, 897, 799, 700, 601, 501, 401, 301, 201, 101, 0, -101, -201, -301, -401, -501, -601, -700, -799, -897, -995, -1093, -1189, -1285, -1380,
-1474, -1568, -1660, -1751, -1842, -1931, -2019, -2106, -2191, -2276, -2359, -2440, -2520, -2599, -2676, -2751, -2824, -2896, -2967, -3035, -3102, -3166,
-3229, -3290, -3349, -3406, -3461, -3513, -3564, -3613, -3659, -3703, -3745, -3784, -3822, -3857, -3889, -3920, -3948, -3973, -3997, -4017, -4036, -4052,
-4065, -4076, -4085, -4091, -4095, -4096,
];
pub const PITCH_HIGH: [u8; 32] = icdf(&[3, 3, 6, 11, 21, 30, 32, 19, 11, 10, 12, 13, 13, 12, 11, 9, 8, 7, 6, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
pub const PITCH_LOW: [&[u8]; 3] = [&icdf::<4>(&[64, 64, 64, 64]), &icdf::<6>(&[43, 42, 43, 43, 42, 43]), &icdf::<8>(&[32, 32, 32, 32, 32, 32, 32, 32])];
pub const PITCH_DELTA: [u8; 21] = icdf(&[46, 2, 2, 3, 4, 6, 10, 15, 26, 38, 30, 22, 15, 10, 7, 6, 4, 4, 2, 2, 2]);
pub const PITCH_CONTOUR: [&[u8]; 4] = [
&icdf::<3>(&[143, 50, 63]),
&icdf::<11>(&[68, 12, 21, 17, 19, 22, 30, 24, 17, 16, 10]),
&icdf::<12>(&[91, 46, 39, 19, 14, 12, 8, 7, 6, 5, 5, 4]),
&icdf::<34>(&[33, 22, 18, 16, 15, 14, 14, 13, 13, 10, 9, 9, 8, 6, 6, 6, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]),
];
pub const CB_NB_10: [[i32; 2]; 3] = [[0, 0], [1, 0], [0, 1]];
pub const CB_NB_20: [[i32; 4]; 11] = [
[0, 0, 0, 0],
[2, 1, 0, -1],
[-1, 0, 1, 2],
[-1, 0, 0, 1],
[-1, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 1],
[1, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, -1],
[1, 0, 0, -1],
];
pub const CB_WB_10: [[i32; 2]; 12] = [[0, 0], [0, 1], [1, 0], [-1, 1], [1, -1], [-1, 2], [2, -1], [-2, 2], [2, -2], [-2, 3], [3, -2], [-3, 3]];
pub const CB_WB_20: [[i32; 4]; 34] = [
[0, 0, 0, 0],
[0, 0, 1, 1],
[1, 1, 0, 0],
[-1, 0, 0, 0],
[0, 0, 0, 1],
[1, 0, 0, 0],
[-1, 0, 0, 1],
[0, 0, 0, -1],
[-1, 0, 1, 2],
[1, 0, 0, -1],
[-2, -1, 1, 2],
[2, 1, 0, -1],
[-2, 0, 0, 2],
[-2, 0, 1, 3],
[2, 1, -1, -2],
[-3, -1, 1, 3],
[2, 0, 0, -2],
[3, 1, 0, -2],
[-3, -1, 2, 4],
[-4, -1, 1, 4],
[3, 1, -1, -3],
[-4, -1, 2, 5],
[4, 2, -1, -3],
[4, 1, -1, -4],
[-5, -1, 2, 6],
[5, 2, -1, -4],
[-6, -2, 2, 6],
[-5, -2, 2, 5],
[6, 2, -1, -5],
[-7, -2, 3, 8],
[6, 2, -2, -6],
[5, 2, -2, -5],
[8, 3, -2, -7],
[-9, -3, 3, 9],
];
pub const LTP_PERIODICITY: [u8; 3] = icdf(&[77, 80, 99]);
pub const LTP_FILTER: [&[u8]; 3] = [
&icdf::<8>(&[185, 15, 13, 13, 9, 9, 6, 6]),
&icdf::<16>(&[57, 34, 21, 20, 15, 13, 12, 13, 10, 10, 9, 10, 9, 8, 7, 8]),
&icdf::<32>(&[15, 16, 14, 12, 12, 12, 11, 11, 11, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 6, 6, 5, 4, 5, 4, 4, 4, 3, 4, 3, 2]),
];
pub const LTP_TAPS_0: [[i32; 5]; 8] = [
[4, 6, 24, 7, 5],
[0, 0, 2, 0, 0],
[12, 28, 41, 13, -4],
[-9, 15, 42, 25, 14],
[1, -2, 62, 41, -9],
[-10, 37, 65, -4, 3],
[-6, 4, 66, 7, -8],
[16, 14, 38, -3, 33],
];
pub const LTP_TAPS_1: [[i32; 5]; 16] = [
[13, 22, 39, 23, 12],
[-1, 36, 64, 27, -6],
[-7, 10, 55, 43, 17],
[1, 1, 8, 1, 1],
[6, -11, 74, 53, -9],
[-12, 55, 76, -12, 8],
[-3, 3, 93, 27, -4],
[26, 39, 59, 3, -8],
[2, 0, 77, 11, 9],
[-8, 22, 44, -6, 7],
[40, 9, 26, 3, 9],
[-7, 20, 101, -7, 4],
[3, -8, 42, 26, 0],
[-15, 33, 68, 2, 23],
[-2, 55, 46, -2, 15],
[3, -1, 21, 16, 41],
];
pub const LTP_TAPS_2: [[i32; 5]; 32] = [
[-6, 27, 61, 39, 5],
[-11, 42, 88, 4, 1],
[-2, 60, 65, 6, -4],
[-1, -5, 73, 56, 1],
[-9, 19, 94, 29, -9],
[0, 12, 99, 6, 4],
[8, -19, 102, 46, -13],
[3, 2, 13, 3, 2],
[9, -21, 84, 72, -18],
[-11, 46, 104, -22, 8],
[18, 38, 48, 23, 0],
[-16, 70, 83, -21, 11],
[5, -11, 117, 22, -8],
[-6, 23, 117, -12, 3],
[3, -8, 95, 28, 4],
[-10, 15, 77, 60, -15],
[-1, 4, 124, 2, -4],
[3, 38, 84, 24, -25],
[2, 13, 42, 13, 31],
[21, -4, 56, 46, -1],
[-1, 35, 79, -13, 19],
[-7, 65, 88, -9, -14],
[20, 4, 81, 49, -29],
[20, 0, 75, 3, -17],
[5, -9, 44, 92, -8],
[1, -3, 22, 69, 31],
[-6, 95, 41, -12, 5],
[39, 67, 16, -4, 1],
[0, -6, 120, 55, -36],
[-13, 44, 122, 4, -24],
[81, 5, 11, 3, 7],
[2, 0, 9, 10, 88],
];
pub const LTP_SCALE: [u8; 3] = icdf(&[128, 64, 64]);
pub const UNIFORM4: [u8; 4] = icdf(&[64, 64, 64, 64]);
pub const RATE_LEVEL: [&[u8]; 2] = [&icdf::<9>(&[15, 51, 12, 46, 45, 13, 33, 27, 14]), &icdf::<9>(&[33, 30, 36, 17, 34, 49, 18, 21, 18])];
pub const PULSE_COUNT: [&[u8]; 11] = [
&icdf::<18>(&[131, 74, 25, 8, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
&icdf::<18>(&[58, 93, 60, 23, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
&icdf::<18>(&[43, 51, 46, 33, 24, 16, 11, 8, 6, 3, 3, 3, 2, 1, 1, 2, 1, 2]),
&icdf::<18>(&[17, 52, 71, 57, 31, 12, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
&icdf::<18>(&[6, 21, 41, 53, 49, 35, 21, 11, 6, 3, 2, 2, 1, 1, 1, 1, 1, 1]),
&icdf::<18>(&[7, 14, 22, 28, 29, 28, 25, 20, 17, 13, 11, 9, 7, 5, 4, 4, 3, 10]),
&icdf::<18>(&[2, 5, 14, 29, 42, 46, 41, 31, 19, 11, 6, 3, 2, 1, 1, 1, 1, 1]),
&icdf::<18>(&[1, 2, 4, 10, 19, 29, 35, 37, 34, 28, 20, 14, 8, 5, 4, 2, 2, 2]),
&icdf::<18>(&[1, 2, 2, 5, 9, 14, 20, 24, 27, 28, 26, 23, 20, 15, 11, 8, 6, 15]),
&icdf::<18>(&[1, 1, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2]),
&icdf::<18>(&[2, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2, 0]),
];
pub const SHELL_16: [&[u8]; 16] = [
&icdf::<2>(&[126, 130]),
&icdf::<3>(&[56, 142, 58]),
&icdf::<4>(&[25, 101, 104, 26]),
&icdf::<5>(&[12, 60, 108, 64, 12]),
&icdf::<6>(&[7, 35, 84, 87, 37, 6]),
&icdf::<7>(&[4, 20, 59, 86, 63, 21, 3]),
&icdf::<8>(&[3, 12, 38, 72, 75, 42, 12, 2]),
&icdf::<9>(&[2, 8, 25, 54, 73, 59, 27, 7, 1]),
&icdf::<10>(&[2, 5, 17, 39, 63, 65, 42, 18, 4, 1]),
&icdf::<11>(&[1, 4, 12, 28, 49, 63, 54, 30, 11, 3, 1]),
&icdf::<12>(&[1, 4, 8, 20, 37, 55, 57, 41, 22, 8, 2, 1]),
&icdf::<13>(&[1, 3, 7, 15, 28, 44, 53, 48, 33, 16, 6, 1, 1]),
&icdf::<14>(&[1, 2, 6, 12, 21, 35, 47, 48, 40, 25, 12, 5, 1, 1]),
&icdf::<15>(&[1, 1, 4, 10, 17, 27, 37, 47, 43, 33, 21, 9, 4, 1, 1]),
&icdf::<16>(&[1, 1, 1, 8, 14, 22, 33, 40, 43, 38, 28, 16, 8, 1, 1, 1]),
&icdf::<17>(&[1, 1, 1, 1, 13, 18, 27, 36, 41, 41, 34, 24, 14, 1, 1, 1, 1]),
];
pub const SHELL_8: [&[u8]; 16] = [
&icdf::<2>(&[127, 129]),
&icdf::<3>(&[53, 149, 54]),
&icdf::<4>(&[22, 105, 106, 23]),
&icdf::<5>(&[11, 61, 111, 63, 10]),
&icdf::<6>(&[6, 35, 86, 88, 36, 5]),
&icdf::<7>(&[4, 20, 59, 87, 62, 21, 3]),
&icdf::<8>(&[3, 13, 40, 71, 73, 41, 13, 2]),
&icdf::<9>(&[3, 9, 27, 53, 70, 56, 28, 9, 1]),
&icdf::<10>(&[3, 8, 19, 37, 57, 61, 44, 20, 6, 1]),
&icdf::<11>(&[3, 7, 15, 28, 44, 54, 49, 33, 17, 5, 1]),
&icdf::<12>(&[1, 7, 13, 22, 34, 46, 48, 38, 28, 14, 4, 1]),
&icdf::<13>(&[1, 1, 11, 22, 27, 35, 42, 47, 33, 25, 10, 1, 1]),
&icdf::<14>(&[1, 1, 6, 14, 26, 37, 43, 43, 37, 26, 14, 6, 1, 1]),
&icdf::<15>(&[1, 1, 4, 10, 20, 31, 40, 42, 40, 31, 20, 10, 4, 1, 1]),
&icdf::<16>(&[1, 1, 3, 8, 16, 26, 35, 38, 38, 35, 26, 16, 8, 3, 1, 1]),
&icdf::<17>(&[1, 1, 2, 6, 12, 21, 30, 36, 38, 36, 30, 21, 12, 6, 2, 1, 1]),
];
pub const SHELL_4: [&[u8]; 16] = [
&icdf::<2>(&[127, 129]),
&icdf::<3>(&[49, 157, 50]),
&icdf::<4>(&[20, 107, 109, 20]),
&icdf::<5>(&[11, 60, 113, 62, 10]),
&icdf::<6>(&[7, 36, 84, 87, 36, 6]),
&icdf::<7>(&[6, 24, 57, 82, 60, 23, 4]),
&icdf::<8>(&[5, 18, 39, 64, 68, 42, 16, 4]),
&icdf::<9>(&[6, 14, 29, 47, 61, 52, 30, 14, 3]),
&icdf::<10>(&[1, 15, 23, 35, 51, 50, 40, 30, 10, 1]),
&icdf::<11>(&[1, 1, 21, 32, 42, 52, 46, 41, 18, 1, 1]),
&icdf::<12>(&[1, 6, 16, 27, 36, 42, 42, 36, 27, 16, 6, 1]),
&icdf::<13>(&[1, 5, 12, 21, 31, 38, 40, 38, 31, 21, 12, 5, 1]),
&icdf::<14>(&[1, 3, 9, 17, 26, 34, 38, 38, 34, 26, 17, 9, 3, 1]),
&icdf::<15>(&[1, 3, 7, 14, 22, 29, 34, 36, 34, 29, 22, 14, 7, 3, 1]),
&icdf::<16>(&[1, 2, 5, 11, 18, 25, 31, 35, 35, 31, 25, 18, 11, 5, 2, 1]),
&icdf::<17>(&[1, 1, 4, 9, 15, 21, 28, 32, 34, 32, 28, 21, 15, 9, 4, 1, 1]),
];
pub const SHELL_2: [&[u8]; 16] = [
&icdf::<2>(&[128, 128]),
&icdf::<3>(&[42, 172, 42]),
&icdf::<4>(&[21, 107, 107, 21]),
&icdf::<5>(&[12, 60, 112, 61, 11]),
&icdf::<6>(&[8, 34, 86, 86, 35, 7]),
&icdf::<7>(&[8, 23, 55, 90, 55, 20, 5]),
&icdf::<8>(&[5, 15, 38, 72, 72, 36, 15, 3]),
&icdf::<9>(&[6, 12, 27, 52, 77, 47, 20, 10, 5]),
&icdf::<10>(&[6, 19, 28, 35, 40, 40, 35, 28, 19, 6]),
&icdf::<11>(&[4, 14, 22, 31, 37, 40, 37, 31, 22, 14, 4]),
&icdf::<12>(&[3, 10, 18, 26, 33, 38, 38, 33, 26, 18, 10, 3]),
&icdf::<13>(&[2, 8, 13, 21, 29, 36, 38, 36, 29, 21, 13, 8, 2]),
&icdf::<14>(&[1, 5, 10, 17, 25, 32, 38, 38, 32, 25, 17, 10, 5, 1]),
&icdf::<15>(&[1, 4, 7, 13, 21, 29, 35, 36, 35, 29, 21, 13, 7, 4, 1]),
&icdf::<16>(&[1, 2, 5, 10, 17, 25, 32, 36, 36, 32, 25, 17, 10, 5, 2, 1]),
&icdf::<17>(&[1, 2, 4, 7, 13, 21, 28, 34, 36, 34, 28, 21, 13, 7, 4, 2, 1]),
];
pub const EXC_LSB: [u8; 2] = icdf(&[136, 120]);
pub const EXC_SIGN: [&[u8]; 42] = [
&icdf::<2>(&[2, 254]),
&icdf::<2>(&[207, 49]),
&icdf::<2>(&[189, 67]),
&icdf::<2>(&[179, 77]),
&icdf::<2>(&[174, 82]),
&icdf::<2>(&[163, 93]),
&icdf::<2>(&[157, 99]),
&icdf::<2>(&[58, 198]),
&icdf::<2>(&[245, 11]),
&icdf::<2>(&[238, 18]),
&icdf::<2>(&[232, 24]),
&icdf::<2>(&[225, 31]),
&icdf::<2>(&[220, 36]),
&icdf::<2>(&[211, 45]),
&icdf::<2>(&[1, 255]),
&icdf::<2>(&[210, 46]),
&icdf::<2>(&[190, 66]),
&icdf::<2>(&[178, 78]),
&icdf::<2>(&[169, 87]),
&icdf::<2>(&[162, 94]),
&icdf::<2>(&[152, 104]),
&icdf::<2>(&[48, 208]),
&icdf::<2>(&[242, 14]),
&icdf::<2>(&[235, 21]),
&icdf::<2>(&[224, 32]),
&icdf::<2>(&[214, 42]),
&icdf::<2>(&[205, 51]),
&icdf::<2>(&[190, 66]),
&icdf::<2>(&[1, 255]),
&icdf::<2>(&[162, 94]),
&icdf::<2>(&[152, 104]),
&icdf::<2>(&[147, 109]),
&icdf::<2>(&[144, 112]),
&icdf::<2>(&[141, 115]),
&icdf::<2>(&[138, 118]),
&icdf::<2>(&[8, 248]),
&icdf::<2>(&[203, 53]),
&icdf::<2>(&[187, 69]),
&icdf::<2>(&[176, 80]),
&icdf::<2>(&[168, 88]),
&icdf::<2>(&[161, 95]),
&icdf::<2>(&[154, 102]),
];
pub const LBRR_FLAGS: [&[u8]; 2] = [&icdf::<3>(&[53, 53, 150]), &icdf::<7>(&[41, 20, 29, 41, 15, 28, 82])];

View File

@ -25,6 +25,7 @@ const LAYERS: &[(&str, u8)] = &[
("mjpeg", 0),
("dnx", 0),
("aac", 0),
("opus", 0),
("frame", 1),
("media", 1),
("project", 1),