mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-29 04:56:58 -06:00
652 lines
24 KiB
Rust
652 lines
24 KiB
Rust
//! 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::{COMB_GAINS, EBANDS, MAX_LM, NB_EBANDS, OVERLAP, PREEMPH, SHORT_MDCT, SPREAD_ICDF, TAPSET_ICDF, TF_SELECT_TABLE, TRIM_ICDF};
|
|
|
|
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) < 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]);
|
|
}
|
|
}
|