use crate::filterbank;
use crate::fixedpoint::*;
use crate::tables::ANALYSIS_WINDOW;
pub fn analysis_filter(
pcm_input: &[i16],
memory: &mut [i16],
subband_output: &mut [i16],
frame_size: i16,
) -> i16 {
let n = frame_size as usize;
let half = shr(frame_size, 1) as usize; let mut windowed = [0i16; 320];
for k in 0..half {
let acc = l_mac(0, ANALYSIS_WINDOW[half - 1 - k], memory[half - 1 - k]);
let acc = l_mac(acc, ANALYSIS_WINDOW[half + k], memory[half + k]);
windowed[k] = extract_h(acc);
}
for k in 0..half {
let acc = l_mac(0, ANALYSIS_WINDOW[n - 1 - k], pcm_input[k]);
let neg = negate(ANALYSIS_WINDOW[k]);
let acc = l_mac(acc, neg, pcm_input[n - 1 - k]);
windowed[half + k] = extract_h(acc);
}
memory[..n].copy_from_slice(&pcm_input[..n]);
let mut max_abs: i16 = 0;
for i in 0..n {
let a = abs_s(windowed[i]);
if sub(a, max_abs) > 0 {
max_abs = a;
}
}
let mut scale_param = if sub(max_abs, 14000) >= 0 {
0
} else {
let adj = if sub(max_abs, 0x1b6) < 0 {
add(max_abs, 1)
} else {
max_abs
};
let product = l_mult(adj, 0x2573); let shifted = l_shr(product, 0x14); let val = extract_l(shifted);
let norm_val = norm_s(val);
if norm_val == 0 {
9
} else {
sub(norm_val, 6)
}
};
let mut sum_abs: i32 = 0;
for i in 0..n {
let a = abs_s(windowed[i]);
sum_abs = l_add(sum_abs, a as i32);
}
let sum_shifted = l_shr(sum_abs, 7);
if (max_abs as i32) < sum_shifted {
scale_param = sub(scale_param, 1);
}
if scale_param > 0 {
for i in 0..n {
windowed[i] = shl(windowed[i], scale_param);
}
} else if scale_param < 0 {
let shift = negate(scale_param);
for i in 0..n {
windowed[i] = shr(windowed[i], shift);
}
}
filterbank::forward(&windowed, subband_output, frame_size);
scale_param
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analysis_zeros() {
let pcm = [0i16; 320];
let mut memory = [0i16; 320];
let mut output = [0i16; 320];
let sp = analysis_filter(&pcm, &mut memory, &mut output, 320);
assert_eq!(sp, 9); for (i, &s) in output.iter().enumerate() {
assert_eq!(s, 0, "subband[{}] should be 0", i);
}
}
}