use crate::g729::basic_operations::*;
use crate::g729::codebooks::*;
use crate::g729::fixed_point_math::g729_cos_q13q15;
use crate::g729::ld8k::*;
use crate::g729::utils::{insertion_sort, rearrange_coefficients};
static PREVIOUS_L_CODE_WORD_INIT: [Word16; NB_LSP_COEFF] = [
2339, 4679, 7018, 9358, 11698, 14037, 16377, 18717, 21056, 23396,
];
pub fn init_decode_lsp(
previous_l_code_word: &mut [[Word16; NB_LSP_COEFF]; MA_MAX_K],
last_valid_l0: &mut u16,
last_q_lsf: &mut [Word16; NB_LSP_COEFF],
) {
for i in 0..MA_MAX_K {
for j in 0..NB_LSP_COEFF {
previous_l_code_word[i][j] = PREVIOUS_L_CODE_WORD_INIT[j];
}
}
*last_valid_l0 = 0;
for j in 0..NB_LSP_COEFF {
last_q_lsf[j] = PREVIOUS_L_CODE_WORD_INIT[j];
}
}
fn compute_q_lsf(
codebook_q_lsf: &mut [Word16; NB_LSP_COEFF],
previous_l_code_word: &mut [[Word16; NB_LSP_COEFF]; MA_MAX_K],
l0: usize,
current_ma_predictor: &[[[Word16; NB_LSP_COEFF]; MA_MAX_K]; L0_RANGE],
current_ma_predictor_sum: &[[Word16; NB_LSP_COEFF]; L0_RANGE],
) {
let mut acc: Word32;
rearrange_coefficients(codebook_q_lsf, GAP1);
rearrange_coefficients(codebook_q_lsf, GAP2);
for i in 0..NB_LSP_COEFF {
acc = mult16_16(current_ma_predictor_sum[l0][i], codebook_q_lsf[i]);
for j in (0..MA_MAX_K).rev() {
acc = mac16_16(
acc,
current_ma_predictor[l0][j][i],
previous_l_code_word[j][i],
);
if j > 0 {
previous_l_code_word[j][i] = previous_l_code_word[j - 1][i];
} else {
previous_l_code_word[j][i] = codebook_q_lsf[i];
}
}
codebook_q_lsf[i] = pshr(acc, 15) as Word16;
}
insertion_sort(codebook_q_lsf, NB_LSP_COEFF);
if codebook_q_lsf[0] < QLSF_MIN {
codebook_q_lsf[0] = QLSF_MIN;
}
for i in 0..NB_LSP_COEFF - 1 {
if sub16(codebook_q_lsf[i + 1], codebook_q_lsf[i]) < MIN_QLSF_DISTANCE {
codebook_q_lsf[i + 1] = add16(codebook_q_lsf[i], MIN_QLSF_DISTANCE);
}
}
if codebook_q_lsf[NB_LSP_COEFF - 1] > QLSF_MAX {
codebook_q_lsf[NB_LSP_COEFF - 1] = QLSF_MAX;
}
}
pub fn decode_lsp(
previous_l_code_word: &mut [[Word16; NB_LSP_COEFF]; MA_MAX_K],
last_valid_l0: &mut u16,
last_q_lsf: &mut [Word16; NB_LSP_COEFF],
l: &[u16],
q_lsp: &mut [Word16; NB_LSP_COEFF],
frame_erased: u8,
) {
let mut current_q_lsf = [0 as Word16; NB_LSP_COEFF];
if frame_erased == 0 {
for i in 0..NB_LSP_COEFF / 2 {
current_q_lsf[i] = add16(L1[l[1] as usize][i], L2L3[l[2] as usize][i]);
}
for i in NB_LSP_COEFF / 2..NB_LSP_COEFF {
current_q_lsf[i] = add16(L1[l[1] as usize][i], L2L3[l[3] as usize][i]);
}
compute_q_lsf(
&mut current_q_lsf,
previous_l_code_word,
l[0] as usize,
&MA_PREDICTOR,
&MA_PREDICTOR_SUM,
);
for i in 0..NB_LSP_COEFF {
last_q_lsf[i] = current_q_lsf[i];
}
*last_valid_l0 = l[0];
} else {
let mut acc: Word32;
for i in 0..NB_LSP_COEFF {
current_q_lsf[i] = last_q_lsf[i];
}
for i in 0..NB_LSP_COEFF {
acc = shl(last_q_lsf[i] as Word32, 15);
for j in 0..MA_MAX_K {
acc = msu16_16(
acc,
MA_PREDICTOR[*last_valid_l0 as usize][j][i],
previous_l_code_word[j][i],
);
}
acc = mult16_32_q12(INV_MA_PREDICTOR_SUM[*last_valid_l0 as usize][i], acc);
for j in (0..MA_MAX_K).rev() {
if j > 0 {
previous_l_code_word[j][i] = previous_l_code_word[j - 1][i];
} else {
previous_l_code_word[j][i] = pshr(acc, 15) as Word16;
}
}
}
}
for i in 0..NB_LSP_COEFF {
q_lsp[i] = g729_cos_q13q15(current_q_lsf[i]);
}
}