use crate::silk::a2nlsf::a2nlsf;
use crate::silk::decode_indices::SideInfoIndices;
use crate::silk::encoder::control_flp::EncoderControlFlp;
use crate::silk::encoder::state::{
EncoderStateCommon, MAX_FRAME_LENGTH, NoiseShapingQuantizerState,
};
use crate::silk::nlsf2a::nlsf2a;
use crate::silk::nsq::silk_nsq;
use crate::silk::nsq_del_dec::silk_nsq_del_dec;
use crate::silk::process_nlsfs::{ProcessNlsfConfig, process_nlsfs};
use crate::silk::quant_ltp_gains::silk_quant_ltp_gains;
use crate::silk::sigproc_flp::silk_float2int;
use crate::silk::tables_other::SILK_LTPSCALES_TABLE_Q14;
use crate::silk::vq_wmat_ec::LTP_ORDER;
use crate::silk::{FrameSignalType, MAX_LPC_ORDER, MAX_NB_SUBFR, MAX_SHAPE_LPC_ORDER};
use core::convert::TryFrom;
const Q12_SCALE: f32 = 1.0 / 4096.0;
const Q14_SCALE: f32 = 1.0 / 16384.0;
const Q16_SCALE: f32 = 1.0 / 65536.0;
#[allow(clippy::cast_possible_truncation)]
pub fn silk_a2nlsf_flp(nlsf_q15: &mut [i16], ar: &[f32], lpc_order: usize) {
assert!(lpc_order.is_multiple_of(2), "LPC order must be even");
assert!(
lpc_order <= MAX_LPC_ORDER,
"LPC order exceeds MAX_LPC_ORDER"
);
assert!(
ar.len() >= lpc_order,
"input LPC slice shorter than requested order"
);
assert!(
nlsf_q15.len() >= lpc_order,
"output NLSF slice shorter than requested order"
);
let mut a_q16 = [0i32; MAX_LPC_ORDER];
for (dst, &src) in a_q16.iter_mut().zip(ar.iter()).take(lpc_order) {
*dst = silk_float2int(src * Q16_SCALE.recip());
}
a2nlsf(&mut nlsf_q15[..lpc_order], &mut a_q16[..lpc_order]);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn silk_nlsf2a_flp(p_ar: &mut [f32], nlsf_q15: &[i16], lpc_order: usize, arch: i32) {
assert!(
lpc_order <= MAX_LPC_ORDER,
"LPC order exceeds MAX_LPC_ORDER"
);
assert!(
nlsf_q15.len() >= lpc_order,
"input NLSF slice shorter than requested order"
);
assert!(
p_ar.len() >= lpc_order,
"output LPC slice shorter than requested order"
);
let mut a_q12 = [0i16; MAX_LPC_ORDER];
nlsf2a(&mut a_q12[..lpc_order], &nlsf_q15[..lpc_order], arch);
for (dst, &src) in p_ar.iter_mut().zip(a_q12.iter()).take(lpc_order) {
*dst = f32::from(src) * Q12_SCALE;
}
}
#[allow(clippy::cast_sign_loss)]
pub fn silk_process_nlsfs_flp(
common: &mut EncoderStateCommon,
pred_coef: &mut [[f32; MAX_LPC_ORDER]; 2],
nlsf_q15: &mut [i16],
prev_nlsf_q15: &[i16],
) {
let order = common.predict_lpc_order;
assert!(matches!(order, 10 | 16), "SILK supports 10 or 16 taps");
assert!(
nlsf_q15.len() >= order,
"NLSF vector shorter than predict_lpc_order"
);
assert!(
prev_nlsf_q15.len() >= order,
"previous NLSF vector shorter than predict_lpc_order"
);
let mut pred_coef_q12 = [[0i16; MAX_LPC_ORDER]; 2];
let cfg = ProcessNlsfConfig {
speech_activity_q8: common.speech_activity_q8,
nb_subframes: common.nb_subfr,
predict_lpc_order: order,
use_interpolated_nlsfs: common.use_interpolated_nlsfs,
nlsf_msvq_survivors: common.nlsf_msvq_survivors as usize,
codebook: common.ps_nlsf_cb,
arch: common.arch,
};
process_nlsfs(
&cfg,
&mut common.indices,
&mut pred_coef_q12,
&mut nlsf_q15[..order],
&prev_nlsf_q15[..order],
);
for (dst_row, src_row) in pred_coef.iter_mut().zip(pred_coef_q12.iter()) {
for (dst, &src) in dst_row.iter_mut().zip(src_row.iter()).take(order) {
*dst = f32::from(src) * Q12_SCALE;
}
}
}
#[allow(
clippy::too_many_arguments,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss
)]
pub fn silk_nsq_wrapper_flp(
common: &EncoderStateCommon,
enc_ctrl: &EncoderControlFlp,
indices: &mut SideInfoIndices,
nsq: &mut NoiseShapingQuantizerState,
pulses: &mut [i8],
x: &[f32],
) {
let nb_subfr = common.nb_subfr;
let frame_length = common.frame_length;
let shaping_order = common.shaping_lpc_order as usize;
let predict_order = common.predict_lpc_order;
assert_eq!(pulses.len(), frame_length);
assert_eq!(x.len(), frame_length);
assert!(
nb_subfr == MAX_NB_SUBFR || nb_subfr == MAX_NB_SUBFR / 2,
"nb_subfr must be 4 or 2"
);
assert!(shaping_order <= MAX_SHAPE_LPC_ORDER);
assert!(predict_order <= MAX_LPC_ORDER);
assert!(
frame_length <= MAX_FRAME_LENGTH,
"frame_length exceeds MAX_FRAME_LENGTH"
);
let mut x16 = [0i16; MAX_FRAME_LENGTH];
for (dst, &src) in x16.iter_mut().zip(x.iter()).take(frame_length) {
*dst = silk_float2int(src) as i16;
}
let mut gains_q16 = [0i32; MAX_NB_SUBFR];
for (dst, &src) in gains_q16
.iter_mut()
.zip(enc_ctrl.gains.iter())
.take(nb_subfr)
{
*dst = silk_float2int(src * Q16_SCALE.recip());
assert!(*dst > 0, "quantiser gain must stay positive");
}
let mut pred_coef_q12 = [[0i16; MAX_LPC_ORDER]; 2];
for (dst_row, src_row) in pred_coef_q12.iter_mut().zip(enc_ctrl.pred_coef.iter()) {
for (dst, &src) in dst_row.iter_mut().zip(src_row.iter()).take(predict_order) {
*dst = silk_float2int(src * Q12_SCALE.recip()) as i16;
}
}
let mut ltp_coef_q14 = [0i16; MAX_NB_SUBFR * LTP_ORDER];
for (dst, &src) in ltp_coef_q14
.iter_mut()
.zip(enc_ctrl.ltp_coef.iter())
.take(nb_subfr * LTP_ORDER)
{
*dst = silk_float2int(src * Q14_SCALE.recip()) as i16;
}
let mut ar_q13 = [0i16; MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER];
for subfr in 0..nb_subfr {
let base = subfr * MAX_SHAPE_LPC_ORDER;
let src_base = subfr * MAX_SHAPE_LPC_ORDER;
for j in 0..shaping_order {
ar_q13[base + j] =
silk_float2int(enc_ctrl.ar[src_base + j] * Q14_SCALE.recip() / 2.0) as i16;
}
}
let mut lf_shp_q14 = [0i32; MAX_NB_SUBFR];
let mut tilt_q14 = [0i32; MAX_NB_SUBFR];
let mut harm_shape_gain_q14 = [0i32; MAX_NB_SUBFR];
for i in 0..nb_subfr {
let ar_q14 = silk_float2int(enc_ctrl.lf_ar_shp[i] * Q14_SCALE.recip());
let ma_q14 = silk_float2int(enc_ctrl.lf_ma_shp[i] * Q14_SCALE.recip());
lf_shp_q14[i] = (ar_q14 << 16) | (ma_q14 & 0xFFFF);
tilt_q14[i] = silk_float2int(enc_ctrl.tilt[i] * Q14_SCALE.recip());
harm_shape_gain_q14[i] = silk_float2int(enc_ctrl.harm_shape_gain[i] * Q14_SCALE.recip());
}
let lambda_q10 = silk_float2int(enc_ctrl.lambda * 1024.0);
let ltp_scale_q14: i32 = if matches!(indices.signal_type, FrameSignalType::Voiced) {
let idx = usize::try_from(indices.ltp_scale_index).expect("ltp_scale_index fits in usize");
i32::from(SILK_LTPSCALES_TABLE_Q14[idx])
} else {
0
};
if common.n_states_delayed_decision > 1 || common.warping_q16 > 0 {
silk_nsq_del_dec(
common,
nsq,
indices,
&x16[..frame_length],
pulses,
&pred_coef_q12[0][..predict_order],
<p_coef_q14[..nb_subfr * LTP_ORDER],
&ar_q13[..nb_subfr * MAX_SHAPE_LPC_ORDER],
&harm_shape_gain_q14[..nb_subfr],
&tilt_q14[..nb_subfr],
&lf_shp_q14[..nb_subfr],
&gains_q16[..nb_subfr],
&enc_ctrl.pitch_l[..nb_subfr],
lambda_q10,
ltp_scale_q14,
);
} else {
silk_nsq(
common,
nsq,
indices,
&x16[..frame_length],
pulses,
&pred_coef_q12[0][..predict_order],
<p_coef_q14[..nb_subfr * LTP_ORDER],
&ar_q13[..nb_subfr * MAX_SHAPE_LPC_ORDER],
&harm_shape_gain_q14[..nb_subfr],
&tilt_q14[..nb_subfr],
&lf_shp_q14[..nb_subfr],
&gains_q16[..nb_subfr],
&enc_ctrl.pitch_l[..nb_subfr],
lambda_q10,
ltp_scale_q14,
);
}
}
#[allow(
clippy::too_many_arguments,
clippy::cast_possible_truncation,
clippy::cast_sign_loss
)]
pub fn silk_quant_ltp_gains_flp(
b: &mut [f32],
cbk_index: &mut [i8],
periodicity_index: &mut i8,
sum_log_gain_q7: &mut i32,
pred_gain_db: &mut f32,
xx: &[f32],
x_x: &[f32],
subfr_len: i32,
nb_subfr: usize,
_arch: i32,
) {
assert_eq!(b.len(), nb_subfr * LTP_ORDER);
assert_eq!(cbk_index.len(), nb_subfr);
assert_eq!(xx.len(), nb_subfr * LTP_ORDER * LTP_ORDER);
assert_eq!(x_x.len(), nb_subfr * LTP_ORDER);
assert!(nb_subfr <= MAX_NB_SUBFR, "nb_subfr exceeds MAX_NB_SUBFR");
let mut b_q14 = [0i16; MAX_NB_SUBFR * LTP_ORDER];
let mut xx_q17 = [0i32; MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER];
let mut x_x_q17 = [0i32; MAX_NB_SUBFR * LTP_ORDER];
for (dst, &src) in xx_q17.iter_mut().zip(xx.iter()).take(xx.len()) {
*dst = silk_float2int(src * 131_072.0);
}
for (dst, &src) in x_x_q17.iter_mut().zip(x_x.iter()).take(x_x.len()) {
*dst = silk_float2int(src * 131_072.0);
}
let mut pred_gain_db_q7 = 0;
silk_quant_ltp_gains(
&mut b_q14[..nb_subfr * LTP_ORDER],
&mut cbk_index[..nb_subfr],
periodicity_index,
sum_log_gain_q7,
&mut pred_gain_db_q7,
&xx_q17[..nb_subfr * LTP_ORDER * LTP_ORDER],
&x_x_q17[..nb_subfr * LTP_ORDER],
subfr_len,
nb_subfr,
);
for (dst, &src) in b.iter_mut().zip(b_q14.iter()).take(nb_subfr * LTP_ORDER) {
*dst = f32::from(src) * Q14_SCALE;
}
*pred_gain_db = (pred_gain_db_q7 as f32) * (1.0 / 128.0);
}