#![allow(
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::indexing_slicing,
clippy::too_many_arguments,
clippy::arithmetic_side_effects
)]
use crate::silk::apply_sine_window_flp::apply_sine_window_flp;
use crate::silk::autocorrelation_flp::autocorrelation;
use crate::silk::bwexpander_flp::bwexpander;
use crate::silk::encoder::control_flp::EncoderControlFlp;
use crate::silk::encoder::state::{FIND_PITCH_LPC_WIN_MS, MAX_FIND_PITCH_LPC_ORDER, MAX_FS_KHZ};
use crate::silk::encoder::state_flp::EncoderStateFlp;
use crate::silk::k2a_flp::k2a_flp;
use crate::silk::lpc_analysis_filter_flp::lpc_analysis_filter_flp;
use crate::silk::pitch_analysis_core_flp::pitch_analysis_core_flp;
use crate::silk::schur_flp::silk_schur_flp;
use crate::silk::tuning_parameters::{
FIND_PITCH_BANDWIDTH_EXPANSION, FIND_PITCH_WHITE_NOISE_FRACTION,
};
use crate::silk::{FrameSignalType, MAX_NB_SUBFR};
use core::convert::TryFrom;
const MAX_PITCH_LPC_WIN_LENGTH: usize = FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ;
pub fn find_pitch_lags_flp(
encoder: &mut EncoderStateFlp,
control: &mut EncoderControlFlp,
res: &mut [f32],
x: &[f32],
arch: i32,
) {
let nb_subfr = encoder.common.nb_subfr;
assert!(
nb_subfr == MAX_NB_SUBFR || nb_subfr == MAX_NB_SUBFR / 2,
"nb_subfr must be 2 or 4"
);
let la_pitch = usize::try_from(encoder.common.la_pitch).expect("la_pitch must fit in usize");
let buf_len = la_pitch + encoder.common.frame_length + encoder.common.ltp_mem_length;
assert!(res.len() >= buf_len, "residual buffer too short");
assert!(x.len() >= buf_len, "input buffer too short");
let pitch_lpc_win_length = encoder.common.pitch_lpc_win_length;
assert!(
pitch_lpc_win_length <= MAX_PITCH_LPC_WIN_LENGTH,
"pitch LPC window exceeds static scratch space"
);
assert!(
pitch_lpc_win_length >= la_pitch * 2,
"pitch LPC window shorter than the required taper"
);
assert!(
buf_len >= pitch_lpc_win_length,
"window length exceeds available samples"
);
let order = usize::try_from(encoder.common.pitch_estimation_lpc_order)
.expect("pitch_estimation_lpc_order must be non-negative");
assert!(
(6..=MAX_FIND_PITCH_LPC_ORDER as usize).contains(&order),
"pitch_estimation_lpc_order must be in [6, MAX_FIND_PITCH_LPC_ORDER]"
);
assert!(
order.is_multiple_of(2),
"pitch_estimation_lpc_order must be even"
);
assert!(
matches!(encoder.common.fs_khz, 8 | 12 | 16),
"unsupported sampling rate"
);
let x_ptr = &x[buf_len - pitch_lpc_win_length..buf_len];
let mut wsig = [0f32; MAX_PITCH_LPC_WIN_LENGTH];
let window = &mut wsig[..pitch_lpc_win_length];
let (head, rest) = window.split_at_mut(la_pitch);
apply_sine_window_flp(head, &x_ptr[..la_pitch], 1);
let (middle, tail) = rest.split_at_mut(pitch_lpc_win_length - la_pitch * 2);
middle.copy_from_slice(&x_ptr[la_pitch..pitch_lpc_win_length - la_pitch]);
apply_sine_window_flp(
tail,
&x_ptr[pitch_lpc_win_length - la_pitch..pitch_lpc_win_length],
2,
);
let corr_count = order + 1;
let mut auto_corr = [0f32; MAX_FIND_PITCH_LPC_ORDER as usize + 1];
autocorrelation(&mut auto_corr[..corr_count], window, corr_count);
auto_corr[0] += auto_corr[0] * FIND_PITCH_WHITE_NOISE_FRACTION + 1.0;
let mut refl_coef = [0f32; MAX_FIND_PITCH_LPC_ORDER as usize];
let res_nrg = silk_schur_flp(&mut refl_coef[..order], &auto_corr[..corr_count], order);
control.pred_gain = auto_corr[0] / res_nrg.max(1.0);
let mut a = [0f32; MAX_FIND_PITCH_LPC_ORDER as usize];
k2a_flp(&mut a[..order], &refl_coef[..order]);
bwexpander(&mut a[..order], FIND_PITCH_BANDWIDTH_EXPANSION);
lpc_analysis_filter_flp(
&mut res[..buf_len],
&a[..order],
&x[..buf_len],
buf_len,
order,
);
if encoder.common.indices.signal_type != FrameSignalType::Inactive
&& !encoder.common.first_frame_after_reset
{
let mut thrhld = 0.6f32;
thrhld -= 0.004f32 * encoder.common.pitch_estimation_lpc_order as f32;
thrhld -= 0.1f32 * encoder.common.speech_activity_q8 as f32 * (1.0 / 256.0);
thrhld -= 0.15f32 * (i32::from(encoder.common.prev_signal_type) >> 1) as f32;
thrhld -= 0.1f32 * encoder.common.input_tilt_q15 as f32 * (1.0 / 32768.0);
let voiced = pitch_analysis_core_flp(
&res[..buf_len],
&mut control.pitch_l[..nb_subfr],
&mut encoder.common.indices.lag_index,
&mut encoder.common.indices.contour_index,
&mut encoder.ltp_corr,
encoder.common.prev_lag,
encoder.common.pitch_estimation_threshold_q16 as f32 * (1.0 / 65536.0),
thrhld,
encoder.common.fs_khz,
encoder.common.pitch_estimation_complexity,
nb_subfr as i32,
arch,
) == 0;
encoder.common.indices.signal_type = if voiced {
FrameSignalType::Voiced
} else {
FrameSignalType::Unvoiced
};
} else {
control.pitch_l = [0; MAX_NB_SUBFR];
encoder.common.indices.lag_index = 0;
encoder.common.indices.contour_index = 0;
encoder.ltp_corr = 0.0;
}
}