#![allow(unsafe_code)]
#![allow(clippy::missing_safety_doc)]
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
use crate::features::{FRAME_LENGTH_SAMPLES, NUM_MEL_BINS, scalar};
#[inline]
#[target_feature(enable = "avx512f")]
pub(crate) unsafe fn dc_remove(window: &[f32], out: &mut [f32]) {
debug_assert_eq!(window.len(), FRAME_LENGTH_SAMPLES);
debug_assert_eq!(out.len(), FRAME_LENGTH_SAMPLES);
let n = FRAME_LENGTH_SAMPLES;
unsafe {
let mut acc = _mm512_setzero_ps();
let mut i = 0usize;
while i + 16 <= n {
let v = _mm512_loadu_ps(window.as_ptr().add(i));
acc = _mm512_add_ps(acc, v);
i += 16;
}
let mut sum = _mm512_reduce_add_ps(acc);
for k in i..n {
sum += *window.get_unchecked(k);
}
let mean = sum / FRAME_LENGTH_SAMPLES as f32;
let mean_v = _mm512_set1_ps(mean);
let mut i = 0usize;
while i + 16 <= n {
let v = _mm512_loadu_ps(window.as_ptr().add(i));
_mm512_storeu_ps(out.as_mut_ptr().add(i), _mm512_sub_ps(v, mean_v));
i += 16;
}
debug_assert_eq!(i, n);
}
}
#[inline]
#[target_feature(enable = "avx512f")]
pub(crate) unsafe fn window_apply(samples: &mut [f32], window: &[f32]) {
debug_assert_eq!(samples.len(), FRAME_LENGTH_SAMPLES);
debug_assert_eq!(window.len(), FRAME_LENGTH_SAMPLES);
let n = FRAME_LENGTH_SAMPLES;
unsafe {
let mut i = 0usize;
while i + 16 <= n {
let s = _mm512_loadu_ps(samples.as_ptr().add(i));
let w = _mm512_loadu_ps(window.as_ptr().add(i));
_mm512_storeu_ps(samples.as_mut_ptr().add(i), _mm512_mul_ps(s, w));
i += 16;
}
debug_assert_eq!(i, n);
}
}
#[inline]
#[target_feature(enable = "avx512f")]
pub(crate) unsafe fn power_spectrum(
complex: &[rustfft::num_complex::Complex<f32>],
out: &mut [f32],
) {
debug_assert_eq!(complex.len(), out.len());
let n = complex.len();
unsafe {
let idx_re = _mm512_setr_epi32(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30);
let idx_im = _mm512_setr_epi32(1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31);
let mut i = 0usize;
let base = complex.as_ptr() as *const f32;
while i + 16 <= n {
let a = _mm512_loadu_ps(base.add(i * 2));
let b = _mm512_loadu_ps(base.add(i * 2 + 16));
let re = _mm512_permutex2var_ps(a, idx_re, b);
let im = _mm512_permutex2var_ps(a, idx_im, b);
let p = _mm512_fmadd_ps(im, im, _mm512_mul_ps(re, re));
_mm512_storeu_ps(out.as_mut_ptr().add(i), p);
i += 16;
}
if i < n {
scalar::power_spectrum(&complex[i..], &mut out[i..]);
}
}
}
#[inline]
#[target_feature(enable = "avx512f")]
pub(crate) unsafe fn cmvn_apply(feature: &mut [f32], means: &[f32], istd: &[f32]) {
debug_assert_eq!(feature.len(), NUM_MEL_BINS);
debug_assert_eq!(means.len(), NUM_MEL_BINS);
debug_assert_eq!(istd.len(), NUM_MEL_BINS);
let n = NUM_MEL_BINS;
unsafe {
let mut i = 0usize;
while i + 16 <= n {
let f = _mm512_loadu_ps(feature.as_ptr().add(i));
let m = _mm512_loadu_ps(means.as_ptr().add(i));
let s = _mm512_loadu_ps(istd.as_ptr().add(i));
let r = _mm512_mul_ps(_mm512_sub_ps(f, m), s);
_mm512_storeu_ps(feature.as_mut_ptr().add(i), r);
i += 16;
}
debug_assert_eq!(i, n);
}
}
#[inline]
#[target_feature(enable = "avx512f")]
pub(crate) unsafe fn mel_dot_log(power_slice: &[f32], weights: &[f32]) -> f32 {
debug_assert_eq!(power_slice.len(), weights.len());
let n = power_slice.len();
let mut energy = 0.0f32;
unsafe {
let mut i = 0usize;
let mut acc = _mm512_setzero_ps();
while i + 16 <= n {
let p = _mm512_loadu_ps(power_slice.as_ptr().add(i));
let w = _mm512_loadu_ps(weights.as_ptr().add(i));
acc = _mm512_fmadd_ps(p, w, acc);
i += 16;
}
energy += _mm512_reduce_add_ps(acc);
for k in i..n {
energy += *power_slice.get_unchecked(k) * *weights.get_unchecked(k);
}
}
energy.max(crate::features::LOG_FLOOR).ln()
}