use crate::range::RangeEncoder;
use crate::silk::decode_indices::{ConditionalCoding, SideInfoIndices};
use crate::silk::icdf::{
DELTA_QUANTIZATION_GAIN, INDEPENDENT_QUANTIZATION_GAIN_LSB,
INDEPENDENT_QUANTIZATION_GAIN_MSB_INACTIVE, INDEPENDENT_QUANTIZATION_GAIN_MSB_UNVOICED,
INDEPENDENT_QUANTIZATION_GAIN_MSB_VOICED,
};
use crate::silk::nlsf_unpack::nlsf_unpack;
use crate::silk::tables_gain::{DELTA_GAIN_QUANT_LEVELS, N_LEVELS_QGAIN};
use crate::silk::tables_ltp::{SILK_LTP_GAIN_ICDF, SILK_LTP_PER_INDEX_ICDF};
use crate::silk::tables_nlsf_cb_wb::SILK_NLSF_CB_WB;
use crate::silk::tables_other::{
SILK_LTPSCALE_ICDF, SILK_NLSF_EXT_ICDF, SILK_NLSF_INTERPOLATION_FACTOR_ICDF,
SILK_TYPE_OFFSET_NO_VAD_ICDF, SILK_TYPE_OFFSET_VAD_ICDF, SILK_UNIFORM4_ICDF,
SILK_UNIFORM8_ICDF,
};
use crate::silk::tables_pitch_lag::{PITCH_CONTOUR_ICDF, PITCH_DELTA_ICDF, PITCH_LAG_ICDF};
use crate::silk::{
FrameQuantizationOffsetType, FrameSignalType, MAX_LPC_ORDER, MAX_NB_SUBFR, SilkNlsfCb,
};
const NLSF_QUANT_MAX_AMPLITUDE: i32 = 4;
const NLSF_STAGE2_SYMBOLS: usize = (NLSF_QUANT_MAX_AMPLITUDE as usize * 2) + 1;
#[derive(Clone, Debug)]
pub struct EncoderIndicesState {
pub nb_subfr: usize,
pub fs_khz: i32,
pub predict_lpc_order: usize,
pub nlsf_codebook: &'static SilkNlsfCb,
pub pitch_lag_low_bits_icdf: &'static [u8],
pub pitch_contour_icdf: &'static [u8],
pub prev_signal_type: FrameSignalType,
pub prev_lag_index: i16,
}
impl Default for EncoderIndicesState {
fn default() -> Self {
Self {
nb_subfr: MAX_NB_SUBFR,
fs_khz: 16,
predict_lpc_order: MAX_LPC_ORDER,
nlsf_codebook: &SILK_NLSF_CB_WB,
pitch_lag_low_bits_icdf: &SILK_UNIFORM8_ICDF,
pitch_contour_icdf: &PITCH_CONTOUR_ICDF,
prev_signal_type: FrameSignalType::Inactive,
prev_lag_index: 0,
}
}
}
impl EncoderIndicesState {
pub fn new(nlsf_codebook: &'static SilkNlsfCb) -> Self {
Self {
nlsf_codebook,
..Self::default()
}
}
pub fn encode_indices(
&mut self,
range_encoder: &mut RangeEncoder,
indices: &SideInfoIndices,
coding: ConditionalCoding,
encode_lbrr: bool,
) {
assert!(
self.nb_subfr == MAX_NB_SUBFR || self.nb_subfr == MAX_NB_SUBFR / 2,
"nb_subfr must be 2 or 4"
);
assert!(
self.predict_lpc_order <= MAX_LPC_ORDER,
"predict_lpc_order exceeds MAX_LPC_ORDER"
);
self.encode_signal_type(range_encoder, indices, encode_lbrr);
self.encode_gains(range_encoder, indices, coding);
self.encode_nlsf(range_encoder, indices);
if self.nb_subfr == MAX_NB_SUBFR {
let coef = indices.nlsf_interp_coef_q2 as usize;
range_encoder.encode_icdf(coef, &SILK_NLSF_INTERPOLATION_FACTOR_ICDF, 8);
}
self.encode_pitch_and_ltp(range_encoder, indices, coding);
range_encoder.encode_icdf(indices.seed as usize, &SILK_UNIFORM4_ICDF, 8);
self.prev_signal_type = indices.signal_type;
if indices.signal_type == FrameSignalType::Voiced {
self.prev_lag_index = indices.lag_index;
}
}
fn encode_signal_type(
&self,
encoder: &mut RangeEncoder,
indices: &SideInfoIndices,
encode_lbrr: bool,
) {
let quant_offset = match indices.quant_offset_type {
FrameQuantizationOffsetType::Low => 0,
FrameQuantizationOffsetType::High => 1,
};
let type_offset = 2 * i32::from(indices.signal_type) + quant_offset;
if encode_lbrr || type_offset >= 2 {
encoder.encode_icdf((type_offset - 2) as usize, &SILK_TYPE_OFFSET_VAD_ICDF, 8);
} else {
encoder.encode_icdf(type_offset as usize, &SILK_TYPE_OFFSET_NO_VAD_ICDF, 8);
}
}
fn encode_gains(
&self,
encoder: &mut RangeEncoder,
indices: &SideInfoIndices,
coding: ConditionalCoding,
) {
if matches!(
coding,
ConditionalCoding::Independent | ConditionalCoding::IndependentNoLtpScaling
) {
let gain_index = i32::from(indices.gains_indices[0]);
assert!(
(0..N_LEVELS_QGAIN as i32).contains(&gain_index),
"gain index exceeds N_LEVELS_QGAIN"
);
let msb_ctx = match indices.signal_type {
FrameSignalType::Inactive => INDEPENDENT_QUANTIZATION_GAIN_MSB_INACTIVE,
FrameSignalType::Unvoiced => INDEPENDENT_QUANTIZATION_GAIN_MSB_UNVOICED,
FrameSignalType::Voiced => INDEPENDENT_QUANTIZATION_GAIN_MSB_VOICED,
};
let msb = (gain_index >> 3) as usize;
let lsb = (gain_index & 7) as usize;
encoder.encode_symbol_with_icdf(msb, msb_ctx);
encoder.encode_symbol_with_icdf(lsb, INDEPENDENT_QUANTIZATION_GAIN_LSB);
} else {
let gain_index = i32::from(indices.gains_indices[0]);
assert!(
(0..DELTA_GAIN_QUANT_LEVELS as i32).contains(&gain_index),
"delta gain index out of range"
);
encoder.encode_symbol_with_icdf(gain_index as usize, DELTA_QUANTIZATION_GAIN);
}
for subframe in 1..self.nb_subfr {
let gain_index = i32::from(indices.gains_indices[subframe]);
assert!(
(0..DELTA_GAIN_QUANT_LEVELS as i32).contains(&gain_index),
"delta gain index out of range"
);
encoder.encode_symbol_with_icdf(gain_index as usize, DELTA_QUANTIZATION_GAIN);
}
}
fn encode_nlsf(&self, encoder: &mut RangeEncoder, indices: &SideInfoIndices) {
let order = self.predict_lpc_order;
assert!(
order <= self.nlsf_codebook.order as usize,
"predict_lpc_order exceeds codebook order"
);
let vectors = self.nlsf_codebook.n_vectors as usize;
let stage_class = match indices.signal_type {
FrameSignalType::Voiced => 1,
_ => 0,
};
let stage1_index = indices.nlsf_indices[0] as usize;
assert!(
stage1_index < vectors,
"stage-one NLSF index exceeds codebook entries"
);
let offset = stage_class * vectors;
encoder.encode_icdf(
stage1_index,
&self.nlsf_codebook.cb1_icdf[offset..offset + vectors],
8,
);
let mut ec_ix = [0i16; MAX_LPC_ORDER];
let mut pred_q8 = [0u8; MAX_LPC_ORDER];
nlsf_unpack(
&mut ec_ix[..order],
&mut pred_q8[..order],
self.nlsf_codebook,
stage1_index,
);
for (i, &entropy_offset) in ec_ix.iter().take(order).enumerate() {
let symbol = i32::from(indices.nlsf_indices[i + 1]);
let table_start = entropy_offset as usize;
let table = &self.nlsf_codebook.ec_icdf[table_start..table_start + NLSF_STAGE2_SYMBOLS];
if symbol >= NLSF_QUANT_MAX_AMPLITUDE {
encoder.encode_icdf((2 * NLSF_QUANT_MAX_AMPLITUDE) as usize, table, 8);
encoder.encode_icdf(
(symbol - NLSF_QUANT_MAX_AMPLITUDE) as usize,
&SILK_NLSF_EXT_ICDF,
8,
);
} else if symbol <= -NLSF_QUANT_MAX_AMPLITUDE {
encoder.encode_icdf(0, table, 8);
encoder.encode_icdf(
(-symbol - NLSF_QUANT_MAX_AMPLITUDE) as usize,
&SILK_NLSF_EXT_ICDF,
8,
);
} else {
encoder.encode_icdf((symbol + NLSF_QUANT_MAX_AMPLITUDE) as usize, table, 8);
}
}
}
fn encode_pitch_and_ltp(
&mut self,
encoder: &mut RangeEncoder,
indices: &SideInfoIndices,
coding: ConditionalCoding,
) {
if indices.signal_type != FrameSignalType::Voiced {
return;
}
let mut encode_absolute_lag = true;
if matches!(coding, ConditionalCoding::Conditional)
&& self.prev_signal_type == FrameSignalType::Voiced
{
let delta = i32::from(indices.lag_index) - i32::from(self.prev_lag_index);
let mut symbol = 0;
if (-8..=11).contains(&delta) {
encode_absolute_lag = false;
symbol = (delta + 9) as usize;
}
encoder.encode_icdf(symbol, &PITCH_DELTA_ICDF, 8);
}
if encode_absolute_lag {
let fs_div_2 = self.fs_khz >> 1;
assert!(fs_div_2 > 0, "fs_khz must be positive");
let lag = i32::from(indices.lag_index);
let pitch_high_bits = (lag / fs_div_2) as usize;
let pitch_low_bits = (lag - (pitch_high_bits as i32 * fs_div_2)) as usize;
encoder.encode_icdf(pitch_high_bits, &PITCH_LAG_ICDF, 8);
encoder.encode_icdf(pitch_low_bits, self.pitch_lag_low_bits_icdf, 8);
}
self.prev_lag_index = indices.lag_index;
encoder.encode_icdf(indices.contour_index as usize, self.pitch_contour_icdf, 8);
let per_index = indices.per_index as usize;
encoder.encode_icdf(per_index, &SILK_LTP_PER_INDEX_ICDF, 8);
let gain_table = SILK_LTP_GAIN_ICDF[per_index];
for subframe in 0..self.nb_subfr {
encoder.encode_icdf(indices.ltp_index[subframe] as usize, gain_table, 8);
}
if matches!(coding, ConditionalCoding::Independent) {
encoder.encode_icdf(indices.ltp_scale_index as usize, &SILK_LTPSCALE_ICDF, 8);
} else {
debug_assert_eq!(
indices.ltp_scale_index, 0,
"conditional coding expects zero LTP scale index"
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::celt::EcDec;
use crate::silk::decode_indices::DecoderIndicesState;
use crate::silk::tables_pitch_lag::PITCH_CONTOUR_ICDF;
#[test]
fn encode_decode_unvoiced_independent_frame() {
let mut encoder_state = EncoderIndicesState::default();
let mut indices = SideInfoIndices::default();
indices.signal_type = FrameSignalType::Unvoiced;
indices.quant_offset_type = FrameQuantizationOffsetType::High;
indices.gains_indices = [21, 0, 1, 2];
indices.nlsf_indices[0] = 3;
indices.nlsf_interp_coef_q2 = 2;
indices.seed = 2;
let mut encoder = RangeEncoder::new();
encoder_state.encode_indices(
&mut encoder,
&indices,
ConditionalCoding::Independent,
false,
);
let mut payload = encoder.finish();
let mut decoder = EcDec::new(payload.as_mut_slice());
let mut decoder_state = DecoderIndicesState::new(&SILK_NLSF_CB_WB);
decoder_state.vad_flags[0] = true;
let decoded =
decoder_state.decode_indices(&mut decoder, 0, false, ConditionalCoding::Independent);
assert_eq!(decoded.signal_type, indices.signal_type);
assert_eq!(decoded.quant_offset_type, indices.quant_offset_type);
assert_eq!(decoded.gains_indices, indices.gains_indices);
assert_eq!(decoded.nlsf_indices, indices.nlsf_indices);
assert_eq!(decoded.nlsf_interp_coef_q2, indices.nlsf_interp_coef_q2);
assert_eq!(decoded.seed, indices.seed);
}
#[test]
fn encode_decode_voiced_conditional_frame_with_delta_pitch() {
let mut encoder_state = EncoderIndicesState {
prev_signal_type: FrameSignalType::Voiced,
prev_lag_index: 120,
pitch_contour_icdf: &PITCH_CONTOUR_ICDF,
..EncoderIndicesState::default()
};
let mut indices = SideInfoIndices::default();
indices.signal_type = FrameSignalType::Voiced;
indices.quant_offset_type = FrameQuantizationOffsetType::Low;
indices.gains_indices = [4, 3, 2, 1];
indices.nlsf_indices[0] = 4;
indices.nlsf_indices[1] = 5;
indices.nlsf_indices[2] = -5;
indices.lag_index = 125;
indices.contour_index = 10;
indices.per_index = 1;
indices.ltp_index = [3, 5, 7, 9];
indices.ltp_scale_index = 0;
indices.seed = 1;
let mut encoder = RangeEncoder::new();
encoder_state.encode_indices(
&mut encoder,
&indices,
ConditionalCoding::Conditional,
false,
);
assert_eq!(encoder_state.prev_signal_type, indices.signal_type);
assert_eq!(encoder_state.prev_lag_index, indices.lag_index);
let mut payload = encoder.finish();
let mut decoder = EcDec::new(payload.as_mut_slice());
let mut decoder_state = DecoderIndicesState::new(&SILK_NLSF_CB_WB);
decoder_state.vad_flags[0] = true;
decoder_state.prev_signal_type = FrameSignalType::Voiced;
decoder_state.prev_lag_index = 120;
let decoded =
decoder_state.decode_indices(&mut decoder, 0, false, ConditionalCoding::Conditional);
assert_eq!(decoded.signal_type, indices.signal_type);
assert_eq!(decoded.quant_offset_type, indices.quant_offset_type);
assert_eq!(decoded.gains_indices, indices.gains_indices);
assert_eq!(decoded.nlsf_indices, indices.nlsf_indices);
assert_eq!(decoded.lag_index, indices.lag_index);
assert_eq!(decoded.contour_index, indices.contour_index);
assert_eq!(decoded.per_index, indices.per_index);
assert_eq!(decoded.ltp_index, indices.ltp_index);
assert_eq!(decoded.ltp_scale_index, indices.ltp_scale_index);
assert_eq!(decoded.seed, indices.seed);
}
}