use crate::codecs::g729::impls::codec::state::ENC_OLD_EXC_LEN;
use crate::codecs::g729::impls::constants::L_SUBFR;
use crate::codecs::g729::impls::dsp::arith::{round, sub};
use crate::codecs::g729::impls::dsp::arith32::{l_mac, l_sub};
use crate::codecs::g729::impls::dsp::div::div_s;
use crate::codecs::g729::impls::dsp::shift::{l_shl, norm_l, shr};
use crate::codecs::g729::impls::dsp::types::{DspContext, Word16, Word32, MIN_32};
use crate::codecs::g729::impls::fixed_cb::correlation::correlate_target_with_impulse;
use crate::codecs::g729::impls::pitch::pred_lt3::interpolate_excitation_encode;
fn dot_product_at(x: &[i16], x_off: usize, y: &[i16], y_off: usize, lg: usize) -> Word32 {
let mut ctx = DspContext::default();
let mut s = Word32(0);
for i in 0..lg {
s = l_mac(&mut ctx, s, Word16(x[x_off + i]), Word16(y[y_off + i]));
}
s
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn search_closed_loop(
old_exc: &mut [i16; ENC_OLD_EXC_LEN],
exc_index: usize,
xn: &[i16; L_SUBFR],
h: &[i16; L_SUBFR],
t0_min: i16,
t0_max: i16,
i_subfr: usize,
pit_frac: &mut i16,
) -> i16 {
let mut ctx = DspContext::default();
let mut dn = [0i16; L_SUBFR];
let mut exc_tmp = [0i16; L_SUBFR];
correlate_target_with_impulse(h, xn, &mut dn);
let mut max = Word32(MIN_32);
let mut t0 = t0_min;
for t in t0_min..=t0_max {
let corr = dot_product_at(&dn, 0, old_exc, exc_index - t as usize, L_SUBFR);
if l_sub(&mut ctx, corr, max).0 > 0 {
max = corr;
t0 = t;
}
}
interpolate_excitation_encode(old_exc, exc_index, t0, 0);
max = dot_product_at(&dn, 0, old_exc, exc_index, L_SUBFR);
*pit_frac = 0;
if i_subfr == 0 && t0 > 84 {
return t0;
}
exc_tmp.copy_from_slice(&old_exc[exc_index..exc_index + L_SUBFR]);
interpolate_excitation_encode(old_exc, exc_index, t0, -1);
let corr_m1 = dot_product_at(&dn, 0, old_exc, exc_index, L_SUBFR);
if l_sub(&mut ctx, corr_m1, max).0 > 0 {
max = corr_m1;
*pit_frac = -1;
exc_tmp.copy_from_slice(&old_exc[exc_index..exc_index + L_SUBFR]);
}
interpolate_excitation_encode(old_exc, exc_index, t0, 1);
let corr_p1 = dot_product_at(&dn, 0, old_exc, exc_index, L_SUBFR);
if l_sub(&mut ctx, corr_p1, max).0 > 0 {
*pit_frac = 1;
} else {
old_exc[exc_index..exc_index + L_SUBFR].copy_from_slice(&exc_tmp);
}
t0
}
pub(crate) fn g_pitch(xn: &[i16; L_SUBFR], y1: &[i16; L_SUBFR], g_coeff: &mut [i16; 4]) -> i16 {
let mut ctx = DspContext::default();
let mut scaled_y1 = [0i16; L_SUBFR];
for i in 0..L_SUBFR {
scaled_y1[i] = shr(&mut ctx, Word16(y1[i]), 2).0;
}
ctx.overflow = false;
let mut s = Word32(1);
for &v in y1 {
s = l_mac(&mut ctx, s, Word16(v), Word16(v));
}
let (exp_yy, yy) = if !ctx.overflow {
let e = norm_l(s);
let sy = l_shl(&mut ctx, s, e);
let y = round(&mut ctx, sy).0;
(e, y)
} else {
let mut s2 = Word32(1);
for &v in &scaled_y1 {
s2 = l_mac(&mut ctx, s2, Word16(v), Word16(v));
}
let e = sub(&mut ctx, Word16(norm_l(s2)), Word16(4)).0;
let sy = l_shl(&mut ctx, s2, e + 4);
let y = round(&mut ctx, sy).0;
(e, y)
};
ctx.overflow = false;
s = Word32(0);
for i in 0..L_SUBFR {
s = l_mac(&mut ctx, s, Word16(xn[i]), Word16(y1[i]));
}
let (exp_xy, xy) = if !ctx.overflow {
let e = norm_l(s);
let sx = l_shl(&mut ctx, s, e);
let x = round(&mut ctx, sx).0;
(e, x)
} else {
let mut s2 = Word32(0);
for i in 0..L_SUBFR {
s2 = l_mac(&mut ctx, s2, Word16(xn[i]), Word16(scaled_y1[i]));
}
let e = sub(&mut ctx, Word16(norm_l(s2)), Word16(2)).0;
let sx = l_shl(&mut ctx, s2, e + 2);
let x = round(&mut ctx, sx).0;
(e, x)
};
g_coeff[0] = yy;
g_coeff[1] = sub(&mut ctx, Word16(15), Word16(exp_yy)).0;
g_coeff[2] = xy;
g_coeff[3] = sub(&mut ctx, Word16(15), Word16(exp_xy)).0;
if xy <= 0 {
g_coeff[3] = -15;
return 0;
}
let xyh = shr(&mut ctx, Word16(xy), 1);
let mut gain = div_s(xyh, Word16(yy)).0;
let sh = sub(&mut ctx, Word16(exp_xy), Word16(exp_yy)).0;
gain = shr(&mut ctx, Word16(gain), sh).0;
if sub(&mut ctx, Word16(gain), Word16(19661)).0 > 0 {
gain = 19661;
}
gain
}