use crate::g729::basic_operations::*;
use crate::g729::codebooks::B30;
use crate::g729::ld8k::*;
use crate::g729::utils::{correlate_vectors, dot_product_16_32_q12};
pub fn generate_adaptative_codebook_vector(
excitation_vector: &mut [Word16],
current_idx: usize,
mut int_pitch_delay: i16,
mut frac_pitch_delay: i16,
) {
frac_pitch_delay = -frac_pitch_delay;
if frac_pitch_delay < 0 {
int_pitch_delay += 1;
frac_pitch_delay = 2;
}
let delayed_idx = (current_idx as isize - int_pitch_delay as isize) as usize;
let b30_increased_idx = frac_pitch_delay as usize;
let b30_decreased_idx = (3 - frac_pitch_delay) as usize;
for n in 0..L_SUBFRAME {
let mut acc: Word32 = 0; let mut j = 0;
for i in 0..10 {
let idx1 = (delayed_idx as isize + n as isize - i as isize) as usize;
let idx2 = (delayed_idx as isize + n as isize + 1 + i as isize) as usize;
acc = mac16_16(acc, excitation_vector[idx1], B30[b30_increased_idx + j]);
acc = mac16_16(acc, excitation_vector[idx2], B30[b30_decreased_idx + j]);
j += 3;
}
excitation_vector[current_idx + n] =
saturate(pshr(acc, 15) as Word32, MAX_16 as Word32) as Word16;
}
}
pub fn adaptative_codebook_search(
excitation_vector: &mut [Word16],
current_idx: usize,
int_pitch_delay_min: &mut i16,
int_pitch_delay_max: &mut i16,
impulse_response: &[Word16],
target_signal: &[Word16],
int_pitch_delay: &mut i16,
frac_pitch_delay: &mut i16,
pitch_delay_codeword: &mut u16,
sub_frame_index: u16,
) {
let mut backward_filtered_target_signal = [0 as Word32; L_SUBFRAME];
let mut correlation_max: Word32 = Word32::MIN;
correlate_vectors(
target_signal,
impulse_response,
&mut backward_filtered_target_signal,
);
for i in *int_pitch_delay_min..=*int_pitch_delay_max {
let idx = (current_idx as isize - i as isize) as usize;
let correlation = dot_product_16_32_q12(
&excitation_vector[idx..idx + L_SUBFRAME],
&backward_filtered_target_signal,
);
if correlation > correlation_max {
correlation_max = correlation;
*int_pitch_delay = i;
}
}
generate_adaptative_codebook_vector(excitation_vector, current_idx, *int_pitch_delay, 0);
*frac_pitch_delay = 0;
if !(sub_frame_index == 0 && *int_pitch_delay >= 85) {
let mut adaptative_codebook_vector_backup = [0 as Word16; L_SUBFRAME];
correlation_max = dot_product_16_32_q12(
&excitation_vector[current_idx..current_idx + L_SUBFRAME],
&backward_filtered_target_signal,
);
adaptative_codebook_vector_backup
.copy_from_slice(&excitation_vector[current_idx..current_idx + L_SUBFRAME]);
generate_adaptative_codebook_vector(excitation_vector, current_idx, *int_pitch_delay, -1);
let mut correlation = dot_product_16_32_q12(
&excitation_vector[current_idx..current_idx + L_SUBFRAME],
&backward_filtered_target_signal,
);
if correlation > correlation_max {
*frac_pitch_delay = -1;
correlation_max = correlation;
adaptative_codebook_vector_backup
.copy_from_slice(&excitation_vector[current_idx..current_idx + L_SUBFRAME]);
}
generate_adaptative_codebook_vector(excitation_vector, current_idx, *int_pitch_delay, 1);
correlation = dot_product_16_32_q12(
&excitation_vector[current_idx..current_idx + L_SUBFRAME],
&backward_filtered_target_signal,
);
if correlation > correlation_max {
*frac_pitch_delay = 1;
} else {
excitation_vector[current_idx..current_idx + L_SUBFRAME]
.copy_from_slice(&adaptative_codebook_vector_backup);
}
}
if sub_frame_index == 0 {
*int_pitch_delay_min = *int_pitch_delay - 5;
if *int_pitch_delay_min < 20 {
*int_pitch_delay_min = 20;
}
*int_pitch_delay_max = *int_pitch_delay_min + 9;
if *int_pitch_delay_max > MAXIMUM_INT_PITCH_DELAY as i16 {
*int_pitch_delay_max = MAXIMUM_INT_PITCH_DELAY as i16;
*int_pitch_delay_min = MAXIMUM_INT_PITCH_DELAY as i16 - 9;
}
if *int_pitch_delay <= 85 {
*pitch_delay_codeword = (3 * (*int_pitch_delay) - 58 + *frac_pitch_delay) as u16;
} else {
*pitch_delay_codeword = (*int_pitch_delay + 112) as u16;
}
} else {
*pitch_delay_codeword =
(3 * (*int_pitch_delay - *int_pitch_delay_min) + *frac_pitch_delay + 2) as u16;
}
}