#![allow(dead_code)]
use crate::celt::cpu_support::OPUS_ARCHMASK;
use crate::celt::math::{celt_float2int16, opus_limit2_checkwithin1};
use crate::celt::mdct::{clt_mdct_backward, clt_mdct_forward};
use crate::celt::pitch::{celt_inner_prod, celt_pitch_xcorr, dual_inner_prod, xcorr_kernel};
use crate::celt::types::{CeltCoef, MdctLookup, OpusVal16, OpusVal32};
use crate::celt::{KissFftCpx, KissFftState, opus_fft, opus_ifft};
const ARCH_IMPL_COUNT: usize = (OPUS_ARCHMASK as usize) + 1;
pub type CeltFloat2Int16Impl = fn(&[f32], &mut [i16]);
pub const CELT_FLOAT2INT16_IMPL: [CeltFloat2Int16Impl; ARCH_IMPL_COUNT] =
[celt_float2int16; ARCH_IMPL_COUNT];
pub type OpusLimit2CheckWithin1Impl = fn(&mut [f32]) -> bool;
pub const OPUS_LIMIT2_CHECKWITHIN1_IMPL: [OpusLimit2CheckWithin1Impl; ARCH_IMPL_COUNT] =
[opus_limit2_checkwithin1; ARCH_IMPL_COUNT];
pub type CeltInnerProdImpl = fn(&[OpusVal16], &[OpusVal16]) -> OpusVal32;
pub const CELT_INNER_PROD_IMPL: [CeltInnerProdImpl; ARCH_IMPL_COUNT] =
[celt_inner_prod; ARCH_IMPL_COUNT];
pub type DualInnerProdImpl = fn(&[OpusVal16], &[OpusVal16], &[OpusVal16]) -> (OpusVal32, OpusVal32);
pub const DUAL_INNER_PROD_IMPL: [DualInnerProdImpl; ARCH_IMPL_COUNT] =
[dual_inner_prod; ARCH_IMPL_COUNT];
pub type CeltPitchXcorrImpl = fn(&[OpusVal16], &[OpusVal16], usize, usize, &mut [OpusVal32]);
pub const CELT_PITCH_XCORR_IMPL: [CeltPitchXcorrImpl; ARCH_IMPL_COUNT] =
[celt_pitch_xcorr; ARCH_IMPL_COUNT];
pub type XcorrKernelImpl = fn(&[OpusVal16], &[OpusVal16], &mut [OpusVal32; 4], usize);
pub const XCORR_KERNEL_IMPL: [XcorrKernelImpl; ARCH_IMPL_COUNT] = [xcorr_kernel; ARCH_IMPL_COUNT];
fn opus_fft_alloc_arch_stub(_state: &mut KissFftState) -> i32 {
0
}
fn opus_fft_free_arch_stub(_state: &mut KissFftState) {}
pub type OpusFftAllocArchImpl = fn(&mut KissFftState) -> i32;
pub const OPUS_FFT_ALLOC_ARCH_IMPL: [OpusFftAllocArchImpl; ARCH_IMPL_COUNT] =
[opus_fft_alloc_arch_stub; ARCH_IMPL_COUNT];
pub type OpusFftFreeArchImpl = fn(&mut KissFftState);
pub const OPUS_FFT_FREE_ARCH_IMPL: [OpusFftFreeArchImpl; ARCH_IMPL_COUNT] =
[opus_fft_free_arch_stub; ARCH_IMPL_COUNT];
pub type OpusFftImpl = fn(&KissFftState, &[KissFftCpx], &mut [KissFftCpx]);
pub const OPUS_FFT: [OpusFftImpl; ARCH_IMPL_COUNT] = [opus_fft; ARCH_IMPL_COUNT];
pub const OPUS_IFFT: [OpusFftImpl; ARCH_IMPL_COUNT] = [opus_ifft; ARCH_IMPL_COUNT];
pub type CltMdctForwardImpl = fn(&MdctLookup, &[f32], &mut [f32], &[CeltCoef], usize, usize, usize);
pub const CLT_MDCT_FORWARD_IMPL: [CltMdctForwardImpl; ARCH_IMPL_COUNT] =
[clt_mdct_forward; ARCH_IMPL_COUNT];
pub type CltMdctBackwardImpl =
fn(&MdctLookup, &[f32], &mut [f32], &[CeltCoef], usize, usize, usize);
pub const CLT_MDCT_BACKWARD_IMPL: [CltMdctBackwardImpl; ARCH_IMPL_COUNT] =
[clt_mdct_backward; ARCH_IMPL_COUNT];
#[inline]
fn dispatch_index(arch: i32) -> usize {
assert!(arch >= 0, "arch must be non-negative");
assert_eq!(
arch & OPUS_ARCHMASK,
arch,
"arch {arch} exceeds OPUS_ARCHMASK {OPUS_ARCHMASK}"
);
arch as usize
}
#[inline]
pub fn select_celt_float2int16_impl(arch: i32) -> CeltFloat2Int16Impl {
CELT_FLOAT2INT16_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_opus_limit2_checkwithin1_impl(arch: i32) -> OpusLimit2CheckWithin1Impl {
OPUS_LIMIT2_CHECKWITHIN1_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_celt_inner_prod_impl(arch: i32) -> CeltInnerProdImpl {
CELT_INNER_PROD_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_dual_inner_prod_impl(arch: i32) -> DualInnerProdImpl {
DUAL_INNER_PROD_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_celt_pitch_xcorr_impl(arch: i32) -> CeltPitchXcorrImpl {
CELT_PITCH_XCORR_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_xcorr_kernel_impl(arch: i32) -> XcorrKernelImpl {
XCORR_KERNEL_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_opus_fft_alloc_arch_impl(arch: i32) -> OpusFftAllocArchImpl {
OPUS_FFT_ALLOC_ARCH_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_opus_fft_free_arch_impl(arch: i32) -> OpusFftFreeArchImpl {
OPUS_FFT_FREE_ARCH_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_opus_fft_impl(arch: i32) -> OpusFftImpl {
OPUS_FFT[dispatch_index(arch)]
}
#[inline]
pub fn select_opus_ifft_impl(arch: i32) -> OpusFftImpl {
OPUS_IFFT[dispatch_index(arch)]
}
#[inline]
pub fn select_clt_mdct_forward_impl(arch: i32) -> CltMdctForwardImpl {
CLT_MDCT_FORWARD_IMPL[dispatch_index(arch)]
}
#[inline]
pub fn select_clt_mdct_backward_impl(arch: i32) -> CltMdctBackwardImpl {
CLT_MDCT_BACKWARD_IMPL[dispatch_index(arch)]
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn float2int16_dispatch_matches_scalar() {
let input = vec![0.9, -1.25, 0.5, 2.5];
let mut via_dispatch = vec![0i16; input.len()];
let mut expected = vec![0i16; input.len()];
select_celt_float2int16_impl(0)(&input, &mut via_dispatch);
celt_float2int16(&input, &mut expected);
assert_eq!(via_dispatch, expected);
}
#[test]
fn mdct_dispatch_matches_scalar_forward() {
let lookup = MdctLookup::new(32, 0);
let n = lookup.len();
let overlap = n >> 1;
let input = vec![0.0f32; overlap + n];
let window = vec![0.5f32; lookup.len() >> 1];
let mut via_dispatch = vec![0.0f32; n >> 1];
let mut expected = vec![0.0f32; n >> 1];
select_clt_mdct_forward_impl(0)(&lookup, &input, &mut via_dispatch, &window, overlap, 0, 1);
clt_mdct_forward(&lookup, &input, &mut expected, &window, overlap, 0, 1);
assert_eq!(via_dispatch, expected);
}
#[test]
fn fft_dispatch_matches_scalar() {
let state = KissFftState::new(8);
let input = vec![KissFftCpx::default(); state.nfft()];
let mut via_dispatch = vec![KissFftCpx::default(); state.nfft()];
let mut expected = vec![KissFftCpx::default(); state.nfft()];
select_opus_fft_impl(0)(&state, &input, &mut via_dispatch);
opus_fft(&state, &input, &mut expected);
assert_eq!(via_dispatch, expected);
}
}