use crate::{CodecError, CodecResult};
use super::silk_range::SilkRangeDecoder;
use super::silk_tables as t;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SilkBandwidth {
Narrowband,
Mediumband,
Wideband,
}
impl SilkBandwidth {
pub const fn khz(self) -> usize {
match self {
Self::Narrowband => 8,
Self::Mediumband => 12,
Self::Wideband => 16,
}
}
pub const fn hz(self) -> u32 {
(self.khz() as u32) * 1000
}
pub const fn lpc_order(self) -> usize {
match self {
Self::Wideband => 16,
_ => 10,
}
}
pub const fn is_wideband(self) -> bool {
matches!(self, Self::Wideband)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SilkSignalType {
Inactive,
Unvoiced,
Voiced,
}
pub const MAX_LPC_ORDER: usize = 16;
pub const MAX_SUBFRAMES: usize = 4;
const SHELL_BLOCK_LEN: usize = 16;
const MAX_PITCH_LAG_WB: i32 = 18 * 16;
#[derive(Debug, Clone)]
pub struct SilkChannelState {
pub prev_nlsf_q15: Vec<i16>,
pub have_prev_nlsf: bool,
pub prev_pitch_lag: i32,
pub lpc_history: Vec<f32>,
pub ltp_history: Vec<f32>,
pub prev_gain_index: i32,
pub have_prev_frame: bool,
pub prev_voiced: bool,
}
impl SilkChannelState {
pub fn new() -> Self {
Self {
prev_nlsf_q15: vec![0; MAX_LPC_ORDER],
have_prev_nlsf: false,
prev_pitch_lag: 0,
lpc_history: vec![0.0; MAX_LPC_ORDER],
ltp_history: vec![0.0; (MAX_PITCH_LAG_WB as usize) + 32],
prev_gain_index: 0,
have_prev_frame: false,
prev_voiced: false,
}
}
pub fn reset(&mut self) {
*self = Self::new();
}
}
impl Default for SilkChannelState {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct SilkFrameResult {
pub samples: Vec<f32>,
pub signal_type: SilkSignalType,
}
pub fn decode_silk_frame(
dec: &mut SilkRangeDecoder,
bw: SilkBandwidth,
state: &mut SilkChannelState,
subframe_count: usize,
is_stereo_side: bool,
vad_flag: bool,
) -> CodecResult<SilkFrameResult> {
let order = bw.lpc_order();
let subframe_len = bw.khz() * 5;
let frame_len = subframe_len * subframe_count;
let (signal_type, quant_offset_type) = decode_frame_type(dec, vad_flag)?;
let voiced = signal_type == SilkSignalType::Voiced;
let gains_q16 = decode_subframe_gains(dec, signal_type, subframe_count, state)?;
let nlsf_q15 = decode_nlsf(dec, bw, signal_type)?;
let interp_factor_q2 = if subframe_count == MAX_SUBFRAMES {
dec.decode_icdf(&t::NLSF_INTERP_ICDF, 8)? as i32
} else {
4
};
let lpc_q12_cur = nlsf_to_lpc(&nlsf_q15, order);
let lpc_q12_first = if interp_factor_q2 < 4 && state.have_prev_nlsf {
let mut interp = vec![0i16; order];
for i in 0..order {
let prev = i32::from(state.prev_nlsf_q15[i]);
let cur = i32::from(nlsf_q15[i]);
interp[i] = (prev + ((interp_factor_q2 * (cur - prev)) >> 2)) as i16;
}
nlsf_to_lpc(&interp, order)
} else {
lpc_q12_cur.clone()
};
let mut pitch_lags = [0i32; MAX_SUBFRAMES];
let mut ltp_filters_q7 = [[0i32; 5]; MAX_SUBFRAMES];
let mut ltp_scale_q14 = t::LTP_SCALES_Q14[0];
if voiced {
decode_ltp(
dec,
bw,
subframe_count,
state,
&mut pitch_lags,
&mut ltp_filters_q7,
)?;
let need_scale_index = !state.have_prev_frame || is_stereo_side || !state.prev_voiced;
let scale_index = if need_scale_index {
dec.decode_icdf(&t::LTP_SCALE_ICDF, 8)?
} else {
0
};
ltp_scale_q14 = t::LTP_SCALES_Q14[scale_index.min(2)];
}
let lcg_seed = dec.decode_icdf(&t::UNIFORM4_ICDF, 8)? as u32;
let excitation = decode_excitation(dec, frame_len, signal_type, quant_offset_type, lcg_seed)?;
let samples = synthesise(
&excitation,
&gains_q16,
&lpc_q12_first,
&lpc_q12_cur,
order,
subframe_count,
subframe_len,
voiced,
&pitch_lags,
<p_filters_q7,
ltp_scale_q14,
state,
);
state.prev_nlsf_q15[..order].copy_from_slice(&nlsf_q15[..order]);
state.have_prev_nlsf = true;
state.have_prev_frame = true;
state.prev_voiced = voiced;
if voiced {
state.prev_pitch_lag = pitch_lags[subframe_count - 1];
}
Ok(SilkFrameResult {
samples,
signal_type,
})
}
fn decode_frame_type(
dec: &mut SilkRangeDecoder,
vad_flag: bool,
) -> CodecResult<(SilkSignalType, usize)> {
if !vad_flag {
let sym = dec.decode_icdf(&t::TYPE_OFFSET_NO_VAD_ICDF, 8)?;
Ok((SilkSignalType::Inactive, sym))
} else {
let sym = dec.decode_icdf(&t::TYPE_OFFSET_VAD_ICDF, 8)?;
let signal_type = if sym >= 2 {
SilkSignalType::Voiced
} else {
SilkSignalType::Unvoiced
};
let quant_offset_type = sym & 1;
Ok((signal_type, quant_offset_type))
}
}
fn decode_subframe_gains(
dec: &mut SilkRangeDecoder,
signal_type: SilkSignalType,
subframe_count: usize,
state: &mut SilkChannelState,
) -> CodecResult<Vec<i32>> {
let mut log_gain = [0i32; MAX_SUBFRAMES];
let type_index = match signal_type {
SilkSignalType::Inactive => 0,
SilkSignalType::Unvoiced => 1,
SilkSignalType::Voiced => 2,
};
let mut prev_log_gain = state.prev_gain_index;
for sf in 0..subframe_count {
let independent = sf == 0 && !state.have_prev_frame;
let coded_independently = sf == 0;
let gain_index = if coded_independently {
let msb = dec.decode_icdf(&t::GAIN_ICDF[type_index], 8)? as i32;
let lsb = dec.decode_icdf(&t::UNIFORM8_ICDF, 8)? as i32;
let idx = (msb << 3) + lsb;
if independent {
idx
} else {
idx.max(prev_log_gain - 16)
}
} else {
let delta = dec.decode_icdf(&t::DELTA_GAIN_ICDF, 8)? as i32;
let step = if delta < 16 {
delta - 4
} else {
2 * delta - 20
};
(prev_log_gain + step).clamp(0, 63)
};
let gain_index = gain_index.clamp(0, 63);
log_gain[sf] = gain_index;
prev_log_gain = gain_index;
}
state.prev_gain_index = prev_log_gain;
let mut gains = vec![0i32; subframe_count];
for sf in 0..subframe_count {
gains[sf] = log_gain_to_linear_q16(log_gain[sf]);
}
Ok(gains)
}
fn log_gain_to_linear_q16(index: i32) -> i32 {
let log_q7 = ((0x001D_1C71_i64 * i64::from(index)) >> 16) as i32 + 2090;
log2lin(log_q7)
}
fn log2lin(in_log_q7: i32) -> i32 {
if in_log_q7 < 0 {
return 0;
}
if in_log_q7 >= 3967 {
return i32::MAX;
}
let mut out = 1i32 << (in_log_q7 >> 7);
let frac = in_log_q7 & 127;
let refinement = ((out >> 7) * ((frac * (128 - frac)) >> 11)) - ((out >> 7) * 0);
out = out.wrapping_add(((out as i64 * i64::from(frac)) >> 7) as i32);
out.wrapping_add(refinement)
}
fn decode_nlsf(
dec: &mut SilkRangeDecoder,
bw: SilkBandwidth,
signal_type: SilkSignalType,
) -> CodecResult<Vec<i16>> {
let order = bw.lpc_order();
let wb = bw.is_wideband();
let voiced = signal_type == SilkSignalType::Voiced;
let voiced_idx = usize::from(voiced);
let stage1_icdf: &[u8] = if wb {
&t::NLSF_CB1_ICDF_WB[voiced_idx]
} else {
&t::NLSF_CB1_ICDF_NB_MB[voiced_idx]
};
let i1 = dec.decode_icdf(stage1_icdf, 8)?;
let select_table: &[u8] = if wb {
&t::NLSF_CB2_SELECT_WB
} else {
&t::NLSF_CB2_SELECT_NB_MB
};
let pred_row0: &[u8] = if wb {
&t::NLSF_PRED_WB_Q8[0]
} else {
&t::NLSF_PRED_NB_MB_Q8[0]
};
let pred_row1: &[u8] = if wb {
&t::NLSF_PRED_WB_Q8[1]
} else {
&t::NLSF_PRED_NB_MB_Q8[1]
};
let mut residual_cb = vec![0usize; order]; let mut pred_q8 = vec![0i32; order]; for pair in 0..order / 2 {
let entry = select_table[i1 * (order / 2) + pair];
let even = 2 * pair;
let odd = even + 1;
residual_cb[even] = usize::from((entry >> 1) & 0x07);
residual_cb[odd] = usize::from((entry >> 5) & 0x07);
if even < order - 1 {
pred_q8[even] = if entry & 0x01 != 0 {
i32::from(pred_row1[even])
} else {
i32::from(pred_row0[even])
};
}
if odd < order - 1 {
pred_q8[odd] = if (entry >> 4) & 0x01 != 0 {
i32::from(pred_row1[odd])
} else {
i32::from(pred_row0[odd])
};
}
}
let mut res_idx = vec![0i32; order];
for coeff in 0..order {
let icdf: &[u8] = if wb {
&t::NLSF_CB2_ICDF_WB[residual_cb[coeff]]
} else {
&t::NLSF_CB2_ICDF_NB_MB[residual_cb[coeff]]
};
let mut value = dec.decode_icdf(icdf, 8)? as i32 - 4;
if value == 4 {
value += dec.decode_icdf(&t::NLSF_EXT_ICDF, 8)? as i32;
} else if value == -4 {
value -= dec.decode_icdf(&t::NLSF_EXT_ICDF, 8)? as i32;
}
res_idx[coeff] = value;
}
let qstep = if wb {
t::NLSF_QSTEP_WB
} else {
t::NLSF_QSTEP_NB_MB
};
let mut residual_q10 = vec![0i32; order];
let mut out_q10 = 0i32;
for coeff in (0..order).rev() {
let pred_q10 = (out_q10 * pred_q8[coeff]) >> 8;
let mut raw = res_idx[coeff] << 10;
if raw > 0 {
raw -= 102;
} else if raw < 0 {
raw += 102;
}
out_q10 = pred_q10 + (((raw as i64) * (qstep as i64)) >> 16) as i32;
residual_q10[coeff] = out_q10;
}
let mut nlsf_q15 = vec![0i32; order];
for coeff in 0..order {
let cb_q8 = if wb {
i32::from(t::NLSF_CB1_WB_Q8[i1][coeff])
} else {
i32::from(t::NLSF_CB1_NB_MB_Q8[i1][coeff])
};
let wght_q9 = if wb {
i32::from(t::NLSF_CB1_WGHT_WB_Q9[i1][coeff])
} else {
i32::from(t::NLSF_CB1_WGHT_NB_MB_Q9[i1][coeff])
};
let add = if wght_q9 != 0 {
(residual_q10[coeff] << 14) / wght_q9
} else {
0
};
nlsf_q15[coeff] = (add + (cb_q8 << 7)).clamp(0, 32767);
}
let min_spacing: &[i16] = if wb {
&t::NLSF_DELTA_MIN_WB_Q15
} else {
&t::NLSF_DELTA_MIN_NB_MB_Q15
};
stabilise_nlsf(&mut nlsf_q15, min_spacing, order);
Ok(nlsf_q15.iter().map(|&v| v as i16).collect())
}
fn stabilise_nlsf(nlsf: &mut [i32], min_spacing: &[i16], order: usize) {
for _ in 0..20 {
let mut min_diff = i32::MAX;
let mut min_idx = 0usize;
for i in 0..=order {
let prev = if i == 0 { 0 } else { nlsf[i - 1] };
let next = if i == order { 32768 } else { nlsf[i] };
let diff = next - prev - i32::from(min_spacing[i]);
if diff < min_diff {
min_diff = diff;
min_idx = i;
}
}
if min_diff >= 0 {
return;
}
if min_idx == 0 {
nlsf[0] = i32::from(min_spacing[0]);
} else if min_idx == order {
nlsf[order - 1] = 32768 - i32::from(min_spacing[order]);
} else {
let mut min_center = 0i32;
for k in 0..=min_idx {
min_center += i32::from(min_spacing[k]);
}
min_center -= i32::from(min_spacing[min_idx]) / 2;
let mut max_center = 32768;
for k in min_idx..=order {
max_center -= i32::from(min_spacing[k]);
}
max_center += i32::from(min_spacing[min_idx]) / 2;
let center =
((nlsf[min_idx - 1] + nlsf[min_idx] + 1) >> 1).clamp(min_center, max_center);
nlsf[min_idx - 1] = center - i32::from(min_spacing[min_idx]) / 2;
nlsf[min_idx] = nlsf[min_idx - 1] + i32::from(min_spacing[min_idx]);
}
}
nlsf[0] = nlsf[0].max(i32::from(min_spacing[0]));
for i in 1..order {
nlsf[i] = nlsf[i].max(nlsf[i - 1] + i32::from(min_spacing[i]));
}
for i in (0..order).rev() {
let ceil = if i == order - 1 {
32768 - i32::from(min_spacing[order])
} else {
nlsf[i + 1] - i32::from(min_spacing[i + 1])
};
nlsf[i] = nlsf[i].min(ceil);
}
}
const NLSF2A_ORDERING_NB: [usize; 10] = [0, 9, 6, 3, 4, 5, 8, 1, 2, 7];
const NLSF2A_ORDERING_WB: [usize; 16] = [0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1];
const NLSF2A_QA: u32 = 16;
fn nlsf_to_lpc(nlsf_q15: &[i16], order: usize) -> Vec<i32> {
let ordering: &[usize] = if order == 16 {
&NLSF2A_ORDERING_WB
} else {
&NLSF2A_ORDERING_NB
};
let mut cos_q12 = [0i32; MAX_LPC_ORDER];
for k in 0..order {
let nlsf = i32::from(nlsf_q15[k]).clamp(0, 32767);
let f_int = (nlsf >> 8) as usize;
let f_frac = nlsf & 0xFF;
let lo = t::LSF_COS_Q12[f_int.min(128)];
let hi = t::LSF_COS_Q12[(f_int + 1).min(128)];
let interp = ((i64::from(hi - lo) * i64::from(f_frac)) >> 16) as i32;
cos_q12[ordering[k]] = lo + interp;
}
let dd = order / 2;
let mut p = [0i64; MAX_LPC_ORDER / 2 + 1];
let mut q = [0i64; MAX_LPC_ORDER / 2 + 1];
nlsf2a_find_poly(&mut p, &cos_q12, dd, 0);
nlsf2a_find_poly(&mut q, &cos_q12, dd, 1);
let mut a_qa1 = [0i64; MAX_LPC_ORDER];
for k in 0..dd {
let p_tmp = p[k + 1] + p[k];
let q_tmp = q[k + 1] - q[k];
a_qa1[k] = -q_tmp - p_tmp;
a_qa1[order - k - 1] = q_tmp - p_tmp;
}
limit_and_quantise_lpc(&a_qa1, order)
}
fn nlsf2a_find_poly(out: &mut [i64], cos_q12: &[i32], dd: usize, parity: usize) {
out[0] = 1i64 << NLSF2A_QA;
out[1] = -i64::from(cos_q12[parity]);
for k in 1..dd {
let ftmp = i64::from(cos_q12[2 * k + parity]);
out[k + 1] = (out[k - 1] << 1) - rshift_round(ftmp * out[k], NLSF2A_QA - 4);
for n in (2..=k).rev() {
out[n] += out[n - 2] - rshift_round(ftmp * out[n - 1], NLSF2A_QA - 4);
}
out[1] -= ftmp;
}
}
fn rshift_round(value: i64, shift: u32) -> i64 {
if shift == 0 {
value
} else {
(value + (1i64 << (shift - 1))) >> shift
}
}
fn limit_and_quantise_lpc(a_qa1: &[i64], order: usize) -> Vec<i32> {
let mut a = [0i64; MAX_LPC_ORDER];
a[..order].copy_from_slice(&a_qa1[..order]);
for _ in 0..10 {
let mut maxabs = 0i64;
let mut idx = 0usize;
for (i, &c) in a.iter().take(order).enumerate() {
if c.abs() > maxabs {
maxabs = c.abs();
idx = i;
}
}
let maxabs_q12 = rshift_round(maxabs, NLSF2A_QA + 1 - 12);
if maxabs_q12 <= 32767 {
break;
}
let maxabs_clamped = maxabs.max(163_838); let sc_q16 = 65_470 - ((65_470i64 * 32_773 / (maxabs_clamped >> 4).max(1)).min(65_470));
let chirp = sc_q16.clamp(0, 65_536) as u32;
bwexpander_32(&mut a[..order], chirp);
let _ = idx;
}
let mut lpc_q12 = vec![0i32; order];
for i in 0..order {
let v = rshift_round(a[i], NLSF2A_QA + 1 - 12);
lpc_q12[i] = v.clamp(-32768, 32767) as i32;
}
lpc_q12
}
fn bwexpander_32(coeffs: &mut [i64], chirp_q16: u32) {
let mut chirp = i64::from(chirp_q16);
let chirp_minus_one = chirp - 65_536;
let n = coeffs.len();
for c in coeffs.iter_mut().take(n - 1) {
*c = rshift_round(chirp * *c, 16);
chirp = chirp + rshift_round(chirp * chirp_minus_one, 16);
}
if let Some(last) = coeffs.last_mut() {
*last = rshift_round(chirp * *last, 16);
}
}
fn decode_ltp(
dec: &mut SilkRangeDecoder,
bw: SilkBandwidth,
subframe_count: usize,
state: &mut SilkChannelState,
pitch_lags: &mut [i32; MAX_SUBFRAMES],
ltp_filters_q7: &mut [[i32; 5]; MAX_SUBFRAMES],
) -> CodecResult<()> {
let khz = bw.khz() as i32;
let use_relative = state.have_prev_frame && state.prev_voiced && state.prev_pitch_lag > 0;
let primary_lag = if use_relative {
let delta = dec.decode_icdf(&t::PITCH_DELTA_ICDF, 8)? as i32;
if delta == 0 {
decode_absolute_lag(dec, bw)?
} else {
state.prev_pitch_lag + delta - 9
}
} else {
decode_absolute_lag(dec, bw)?
};
let (contour_icdf, contour_table): (&[u8], &[[i8; 4]]) = match (bw, subframe_count) {
(SilkBandwidth::Narrowband, 2) => (&t::PITCH_CONTOUR_10MS_NB_ICDF, &CONTOUR_NB_10MS),
(SilkBandwidth::Narrowband, _) => (&t::PITCH_CONTOUR_NB_ICDF, &CONTOUR_NB_20MS),
(_, 2) => (&t::PITCH_CONTOUR_10MS_ICDF, &CONTOUR_MBWB_10MS),
(_, _) => (&t::PITCH_CONTOUR_ICDF, &CONTOUR_MBWB_20MS),
};
let contour_index = dec.decode_icdf(contour_icdf, 8)?;
let contour = contour_table.get(contour_index).copied().unwrap_or([0; 4]);
let lag_min = 2 * khz;
let lag_max = 18 * khz;
for sf in 0..subframe_count {
let lag = primary_lag + i32::from(contour[sf]);
pitch_lags[sf] = lag.clamp(lag_min, lag_max);
}
let periodicity = dec.decode_icdf(&t::LTP_PER_INDEX_ICDF, 8)?;
let (filter_icdf, codebook): (&[u8], &[[i8; 5]]) = match periodicity {
0 => (&t::LTP_GAIN_ICDF_0, &t::LTP_FILTER_CB0_Q7),
1 => (&t::LTP_GAIN_ICDF_1, &t::LTP_FILTER_CB1_Q7),
_ => (&t::LTP_GAIN_ICDF_2, &t::LTP_FILTER_CB2_Q7),
};
for sf in 0..subframe_count {
let filter_index = dec.decode_icdf(filter_icdf, 8)?;
let taps = codebook.get(filter_index).copied().unwrap_or([0; 5]);
for (k, &tap) in taps.iter().enumerate() {
ltp_filters_q7[sf][k] = i32::from(tap);
}
}
Ok(())
}
fn decode_absolute_lag(dec: &mut SilkRangeDecoder, bw: SilkBandwidth) -> CodecResult<i32> {
let khz = bw.khz() as i32;
let high = dec.decode_icdf(&t::PITCH_LAG_ICDF, 8)? as i32;
let (low_icdf, low_scale): (&[u8], i32) = match bw {
SilkBandwidth::Narrowband => (&t::UNIFORM4_ICDF, 4),
SilkBandwidth::Mediumband => (&t::UNIFORM6_ICDF, 6),
SilkBandwidth::Wideband => (&t::UNIFORM8_ICDF, 8),
};
let low = dec.decode_icdf(low_icdf, 8)? as i32;
let _ = low_scale;
Ok(high * low_scale + low + 2 * khz)
}
fn decode_excitation(
dec: &mut SilkRangeDecoder,
frame_len: usize,
signal_type: SilkSignalType,
quant_offset_type: usize,
lcg_seed: u32,
) -> CodecResult<Vec<f32>> {
let voiced = signal_type == SilkSignalType::Voiced;
let voiced_idx = usize::from(voiced);
let rate_level = dec.decode_icdf(&t::RATE_LEVELS_ICDF[voiced_idx], 8)?;
let shell_blocks = frame_len.div_ceil(SHELL_BLOCK_LEN);
let mut e_raw = vec![0i32; shell_blocks * SHELL_BLOCK_LEN];
let mut pulse_counts = vec![0i32; shell_blocks];
let mut lsb_counts = vec![0i32; shell_blocks];
for blk in 0..shell_blocks {
let (count, lsbs) = decode_pulse_count(dec, rate_level)?;
pulse_counts[blk] = count;
lsb_counts[blk] = lsbs;
}
for blk in 0..shell_blocks {
let base = blk * SHELL_BLOCK_LEN;
let mut block = [0i32; SHELL_BLOCK_LEN];
decode_shell_block(dec, pulse_counts[blk], &mut block)?;
let lsbs = lsb_counts[blk];
for (i, magnitude) in block.iter().enumerate() {
let mut mag = *magnitude;
for _ in 0..lsbs {
let bit = dec.decode_icdf(&t::LSB_ICDF, 8)? as i32;
mag = (mag << 1) | bit;
}
e_raw[base + i] = mag;
}
}
for blk in 0..shell_blocks {
let base = blk * SHELL_BLOCK_LEN;
let pulses = pulse_counts[blk];
let sign_ctx = sign_context(signal_type, quant_offset_type, pulses);
let sign_icdf = &t::SIGN_ICDF[sign_ctx];
for i in 0..SHELL_BLOCK_LEN {
if e_raw[base + i] > 0 {
let s = dec.decode_icdf(sign_icdf, 8)?;
if s == 0 {
e_raw[base + i] = -e_raw[base + i];
}
}
}
}
let offset_q23 = i32::from(t::QUANTIZATION_OFFSETS_Q10[voiced_idx][quant_offset_type]) << 13;
let mut seed = lcg_seed;
let mut excitation = vec![0.0f32; frame_len];
for (i, slot) in excitation.iter_mut().enumerate() {
let e = e_raw[i];
let mut e_q23 = (e << 8).wrapping_sub(if e > 0 {
20
} else if e < 0 {
-20
} else {
0
});
e_q23 = e_q23.wrapping_add(offset_q23);
seed = seed.wrapping_mul(196_314_165).wrapping_add(907_633_515);
if seed & 0x8000_0000 != 0 {
e_q23 = e_q23.wrapping_neg();
}
seed = seed.wrapping_add(e as u32);
*slot = (e_q23 as f32) / (1i32 << 23) as f32;
}
Ok(excitation)
}
fn decode_pulse_count(dec: &mut SilkRangeDecoder, rate_level: usize) -> CodecResult<(i32, i32)> {
let mut lsbs = 0i32;
let mut level = rate_level.min(t::PULSES_PER_BLOCK_ICDF.len() - 1);
loop {
let sym = dec.decode_icdf(&t::PULSES_PER_BLOCK_ICDF[level], 8)? as i32;
if sym < 17 {
return Ok((sym, lsbs));
}
lsbs += 1;
level = 9;
if lsbs > 10 {
return Ok((16, lsbs));
}
}
}
fn decode_shell_block(
dec: &mut SilkRangeDecoder,
pulse_count: i32,
out: &mut [i32; SHELL_BLOCK_LEN],
) -> CodecResult<()> {
if pulse_count == 0 {
return Ok(());
}
split_pulses(dec, pulse_count, &t::SHELL_CODE_TABLE0, out, 0, 16)?;
Ok(())
}
fn split_pulses(
dec: &mut SilkRangeDecoder,
total: i32,
table0: &[u8],
out: &mut [i32; SHELL_BLOCK_LEN],
start: usize,
len: usize,
) -> CodecResult<()> {
if total == 0 {
return Ok(());
}
if len == 1 {
out[start] = total;
return Ok(());
}
let (table, offsets): (&[u8], &[u8]) = match len {
16 => (table0, &t::SHELL_CODE_TABLE_OFFSETS),
8 => (&t::SHELL_CODE_TABLE1, &t::SHELL_CODE_TABLE_OFFSETS),
4 => (&t::SHELL_CODE_TABLE2, &t::SHELL_CODE_TABLE_OFFSETS),
_ => (&t::SHELL_CODE_TABLE3, &t::SHELL_CODE_TABLE_OFFSETS),
};
let count = total.clamp(0, 16) as usize;
let off = usize::from(offsets[count]);
let table_len = if count + 1 < offsets.len() {
usize::from(offsets[count + 1]) - off
} else {
table.len() - off
};
let icdf = &table[off..off + table_len];
let left = dec.decode_icdf(icdf, 8)? as i32;
let right = total - left;
let half = len / 2;
split_pulses(dec, left, table0, out, start, half)?;
split_pulses(dec, right, table0, out, start + half, len - half)?;
Ok(())
}
fn sign_context(signal_type: SilkSignalType, quant_offset_type: usize, pulse_count: i32) -> usize {
let type_idx = match signal_type {
SilkSignalType::Inactive => 0,
SilkSignalType::Unvoiced => 2,
SilkSignalType::Voiced => 4,
};
let row = type_idx + quant_offset_type.min(1);
let _ = pulse_count;
row.min(t::SIGN_ICDF.len() - 1)
}
#[allow(clippy::too_many_arguments)]
fn synthesise(
excitation: &[f32],
gains_q16: &[i32],
lpc_q12_first: &[i32],
lpc_q12_cur: &[i32],
order: usize,
subframe_count: usize,
subframe_len: usize,
voiced: bool,
pitch_lags: &[i32; MAX_SUBFRAMES],
ltp_filters_q7: &[[i32; 5]; MAX_SUBFRAMES],
ltp_scale_q14: i32,
state: &mut SilkChannelState,
) -> Vec<f32> {
let frame_len = subframe_len * subframe_count;
let mut output = vec![0.0f32; frame_len];
let ltp_scale = (ltp_scale_q14 as f32) / 16384.0;
let mut lpc_buf = vec![0.0f32; order + frame_len];
let hist_n = state.lpc_history.len().min(order);
lpc_buf[order - hist_n..order].copy_from_slice(&state.lpc_history[..hist_n]);
let ltp_hist_len = state.ltp_history.len();
let mut res_buf = vec![0.0f32; ltp_hist_len + frame_len];
res_buf[..ltp_hist_len].copy_from_slice(&state.ltp_history);
for sf in 0..subframe_count {
let gain = (gains_q16[sf] as f32) / 65536.0;
let lpc_q12 = if sf < subframe_count / 2 {
lpc_q12_first
} else {
lpc_q12_cur
};
let sf_start = sf * subframe_len;
for n in 0..subframe_len {
let global_idx = sf_start + n;
let exc = excitation[global_idx] * gain;
let ltp_value = if voiced {
let lag = pitch_lags[sf].max(0) as usize;
let pos = (ltp_hist_len + global_idx) as isize;
let mut sum = 0.0f32;
for (k, &tap_q7) in ltp_filters_q7[sf].iter().enumerate() {
let idx = pos - lag as isize + 2 - k as isize;
if idx >= 0 && (idx as usize) < res_buf.len() {
sum += res_buf[idx as usize] * (tap_q7 as f32 / 128.0);
}
}
sum
} else {
0.0
};
let _ = ltp_scale;
let res = exc + ltp_value;
res_buf[ltp_hist_len + global_idx] = res;
let mut acc = res;
for (j, &coeff_q12) in lpc_q12.iter().take(order).enumerate() {
let prev = lpc_buf[order + global_idx - 1 - j];
acc -= prev * (coeff_q12 as f32 / 4096.0);
}
lpc_buf[order + global_idx] = acc;
output[global_idx] = acc;
}
}
state.lpc_history = lpc_buf[lpc_buf.len() - order..].to_vec();
let keep_res = ltp_hist_len.min(res_buf.len());
state.ltp_history = res_buf[res_buf.len() - keep_res..].to_vec();
for s in output.iter_mut() {
if !s.is_finite() {
*s = 0.0;
}
*s = s.clamp(-4.0, 4.0);
}
output
}
const CONTOUR_NB_10MS: [[i8; 4]; 3] = [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0]];
const CONTOUR_NB_20MS: [[i8; 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],
];
const CONTOUR_MBWB_10MS: [[i8; 4]; 12] = [
[0, 0, 0, 0],
[0, 1, 0, 0],
[1, 0, 0, 0],
[-1, 1, 0, 0],
[1, -1, 0, 0],
[-1, 2, 0, 0],
[2, -1, 0, 0],
[-2, 2, 0, 0],
[2, -2, 0, 0],
[-2, 3, 0, 0],
[3, -2, 0, 0],
[-3, 3, 0, 0],
];
const CONTOUR_MBWB_20MS: [[i8; 4]; 34] = [
[0, 0, 0, 0],
[0, 0, 1, 1],
[1, 1, 0, 0],
[-1, 1, 2, 2],
[2, 2, 1, -1],
[-2, 2, 4, 4],
[4, 4, 2, -2],
[-3, 4, 6, 6],
[6, 6, 4, -3],
[-4, 5, 8, 8],
[8, 8, 5, -4],
[-5, 7, 9, 10],
[10, 9, 7, -5],
[-6, 8, 11, 12],
[12, 11, 8, -6],
[-7, 9, 13, 14],
[14, 13, 9, -7],
[-9, 11, 16, 17],
[17, 16, 11, -9],
[-10, 13, 19, 20],
[20, 19, 13, -10],
[-12, 16, 23, 24],
[24, 23, 16, -12],
[-14, 18, 27, 28],
[28, 27, 18, -14],
[-17, 22, 32, 34],
[34, 32, 22, -17],
[-21, 26, 39, 41],
[41, 39, 26, -21],
[-25, 31, 47, 49],
[49, 47, 31, -25],
[-29, 37, 56, 59],
[59, 56, 37, -29],
[-35, 44, 67, 70],
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nlsf_to_lpc_finite_and_bounded() {
for &order in &[10usize, 16] {
let mut nlsf = vec![0i16; order];
for (i, slot) in nlsf.iter_mut().enumerate() {
*slot = ((i + 1) as i32 * 32768 / (order as i32 + 1)) as i16;
}
let lpc = nlsf_to_lpc(&nlsf, order);
assert_eq!(lpc.len(), order);
for &c in &lpc {
assert!((-32768..=32767).contains(&c), "LPC coeff out of Q12 range");
}
}
}
#[test]
fn test_nlsf_to_lpc_from_codebook_entry() {
let mut nlsf = [0i16; 10];
for (i, slot) in nlsf.iter_mut().enumerate() {
slot.clone_from(&((i32::from(t::NLSF_CB1_NB_MB_Q8[0][i]) << 7) as i16));
}
let lpc = nlsf_to_lpc(&nlsf, 10);
assert!(lpc.iter().all(|&c| (-32768..=32767).contains(&c)));
}
#[test]
fn test_bwexpander_shrinks() {
let mut coeffs = [20_000i64, -18_000, 15_000, -12_000];
let before: i64 = coeffs.iter().map(|c| c.abs()).sum();
bwexpander_32(&mut coeffs, 60_000);
let after: i64 = coeffs.iter().map(|c| c.abs()).sum();
assert!(after < before, "bandwidth expansion must reduce energy");
}
#[test]
fn test_decode_silk_frame_direct() {
let data: Vec<u8> = (0u8..48)
.map(|i| i.wrapping_mul(67).wrapping_add(13))
.collect();
let mut dec = SilkRangeDecoder::new(&data).expect("init");
let mut state = SilkChannelState::new();
let result = decode_silk_frame(
&mut dec,
SilkBandwidth::Wideband,
&mut state,
MAX_SUBFRAMES,
false,
true,
)
.expect("decode");
assert_eq!(result.samples.len(), 16 * 5 * MAX_SUBFRAMES);
assert!(result.samples.iter().all(|s| s.is_finite()));
}
#[test]
fn test_decode_silk_frame_cross_frame_stable() {
let data: Vec<u8> = (0u8..56)
.map(|i| i.wrapping_mul(101).wrapping_add(19))
.collect();
let mut state = SilkChannelState::new();
let mut peak = 0.0f32;
for _ in 0..8 {
let mut dec = SilkRangeDecoder::new(&data).expect("init");
let result = decode_silk_frame(
&mut dec,
SilkBandwidth::Narrowband,
&mut state,
MAX_SUBFRAMES,
false,
true,
)
.expect("decode");
for &s in &result.samples {
assert!(s.is_finite());
peak = peak.max(s.abs());
}
}
assert!(peak <= 4.0, "synthesis must stay bounded across frames");
}
#[test]
fn test_decode_excitation_deterministic() {
let data: Vec<u8> = (0u8..40)
.map(|i| i.wrapping_mul(53).wrapping_add(3))
.collect();
let run = || {
let mut dec = SilkRangeDecoder::new(&data).expect("init");
decode_excitation(&mut dec, 80, SilkSignalType::Voiced, 0, 1).expect("exc")
};
let a = run();
let b = run();
assert_eq!(a.len(), 80);
assert_eq!(a, b, "excitation decode must be deterministic");
assert!(a.iter().all(|s| s.is_finite()));
}
}