#![cfg_attr(
all(feature = "fcma", target_arch = "aarch64"),
feature(stdarch_neon_fcma)
)]
#[cfg(all(target_arch = "x86_64", feature = "avx"))]
mod avx;
mod dct2;
mod dct3;
mod dst2;
mod dst3;
mod mla;
#[cfg(all(target_arch = "aarch64", feature = "neon"))]
mod neon;
mod pxdct_error;
mod spectrum_mul;
mod twiddles;
mod util;
use crate::dct2::Dct2Fft;
use crate::dct3::Dct3Fft;
use crate::dst2::Dst2Fft;
use crate::dst3::Dst3Fft;
pub use pxdct_error::PxdctError;
use std::sync::Arc;
pub struct Pxdct {}
impl Pxdct {
pub fn make_dct2_f32(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f32> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dct2Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f32> + Send + Sync>)
}
pub fn make_dct2_f64(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f64> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dct2Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f64> + Send + Sync>)
}
pub fn make_dct3_f32(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f32> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dct3Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f32> + Send + Sync>)
}
pub fn make_dct3_f64(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f64> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dct3Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f64> + Send + Sync>)
}
pub fn make_dst2_f32(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f32> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dst2Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f32> + Send + Sync>)
}
pub fn make_dst2_f64(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f64> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dst2Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f64> + Send + Sync>)
}
pub fn make_dst3_f32(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f32> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dst3Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f32> + Send + Sync>)
}
pub fn make_dst3_f64(
length: usize,
) -> Result<Arc<dyn PxdctExecutor<f64> + Send + Sync>, PxdctError> {
if length == 0 {
return Err(PxdctError::ZeroSizedDct);
}
Dst3Fft::new(length).map(|x| Arc::new(x) as Arc<dyn PxdctExecutor<f64> + Send + Sync>)
}
}
pub trait PxdctExecutor<T> {
fn execute(&self, data: &mut [T]) -> Result<(), PxdctError>;
fn length(&self) -> usize;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dct2_roundtrip() {
for i in 1..250 {
let mut array = vec![0f32; i];
for i in 1..i + 1 {
array[i - 1] = i as f32;
}
let mut working_array = array.clone();
let dct_forward = Pxdct::make_dct2_f32(array.len()).unwrap();
let dct_inverse = Pxdct::make_dct3_f32(array.len()).unwrap();
dct_forward.execute(&mut working_array).unwrap();
dct_inverse.execute(&mut working_array).unwrap();
for k in working_array.iter_mut() {
*k = *k / (i as f32) * 2.;
}
working_array.iter().zip(array.iter()).enumerate().for_each(|(k, (&x, &c))| {
assert!((x - c).abs() < 0.01, "Difference to control values exceeded 0.01 when it shouldn't, value {x}, control {c} at {k} for size {i}");
});
}
}
#[test]
fn dst2_roundtrip() {
for i in 4..250 {
let mut array = vec![0f32; i];
for i in 1..i + 1 {
array[i - 1] = i as f32;
}
let mut working_array = array.clone();
let dct_forward = Pxdct::make_dst2_f32(array.len()).unwrap();
let dct_inverse = Pxdct::make_dst3_f32(array.len()).unwrap();
dct_forward.execute(&mut working_array).unwrap();
dct_inverse.execute(&mut working_array).unwrap();
for k in working_array.iter_mut() {
*k = *k / (i as f32) * 2.;
}
working_array.iter().zip(array.iter()).enumerate().for_each(|(k, (&x, &c))| {
assert!((x - c).abs() < 0.01, "Difference to control values exceeded 0.01 when it shouldn't, value {x}, control {c} at {k} for size {i}");
});
}
}
}