From 1377a10659b9ea02b92f6eba25246905b6b29c89 Mon Sep 17 00:00:00 2001 From: Luni-4 Date: Sun, 19 Apr 2020 23:54:03 +0200 Subject: [PATCH] Simplify fft's API --- fft/src/fftwrap.rs | 114 ++++++++++++++++++++++++++++------------- fft/src/lib.rs | 1 - fft/src/smallft.rs | 65 ++--------------------- fft/tests/fftwrap.rs | 119 ++++++++++++++++++++++++++++++++++++++++--- fft/tests/smallft.rs | 108 --------------------------------------- 5 files changed, 196 insertions(+), 211 deletions(-) delete mode 100644 fft/tests/smallft.rs diff --git a/fft/src/fftwrap.rs b/fft/src/fftwrap.rs index e8773d9..ccd6672 100644 --- a/fft/src/fftwrap.rs +++ b/fft/src/fftwrap.rs @@ -1,5 +1,3 @@ -use crate::smallft::*; - /* Copyright (C) 2005-2006 Jean-Marc Valin File: fftwrap.c @@ -33,46 +31,94 @@ use crate::smallft::*; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -pub fn spx_fft_init(size: usize) -> DrftLookup { - DrftLookup::new(size) + +use crate::smallft::*; + +#[derive(Clone)] +pub struct DrftLookup { + pub n: usize, + pub trigcache: Vec, + pub splitcache: Vec, } -pub fn spx_fft(table: &mut DrftLookup, in_0: &mut [f32], out: &mut [f32]) { - let scale = (1.0f64 / table.n as f64) as f32; - if in_0 == out { - eprintln!("FFT should not be done in-place"); +impl DrftLookup { + pub fn new(n: usize) -> Self { + let mut drft = Self { + n: n, + trigcache: vec![0.0; 3 * n], + splitcache: vec![0; 32], + }; + + fdrffti(n, &mut drft.trigcache, &mut drft.splitcache); + + drft } - out.iter_mut() - .zip(in_0.iter()) - .take(table.n as usize) - .for_each(|(o, i)| *o = scale * *i); + pub fn spx_fft(&mut self, in_0: &[f32], out: &mut [f32]) { + let scale = (1.0f64 / self.n as f64) as f32; + if in_0 == out { + eprintln!("FFT should not be done in-place"); + } - spx_drft_forward(table, out); -} + out.iter_mut() + .zip(in_0.iter()) + .take(self.n as usize) + .for_each(|(o, i)| *o = scale * *i); -pub fn spx_ifft(table: &mut DrftLookup, in_0: &mut [f32], out: &mut [f32]) { - if in_0 == out { - eprintln!("FFT should not be done in-place"); - } else { - out.copy_from_slice(&in_0[..table.n as usize]); + self.spx_drft_forward(out); } - spx_drft_backward(table, out); -} + pub fn spx_ifft(&mut self, in_0: &[f32], out: &mut [f32]) { + if in_0 == out { + eprintln!("FFT should not be done in-place"); + } else { + out.copy_from_slice(&in_0[..self.n as usize]); + } -pub fn spx_fft_float( - table: &mut DrftLookup, - in_0: &mut [f32], - out: &mut [f32], -) { - spx_fft(table, in_0, out); -} + self.spx_drft_backward(out); + } + + pub fn spx_fft_float(&mut self, in_0: &[f32], out: &mut [f32]) { + self.spx_fft(in_0, out); + } + + pub fn spx_ifft_float(&mut self, in_0: &[f32], out: &mut [f32]) { + self.spx_ifft(in_0, out); + } + + pub fn spx_drft_forward(&mut self, data: &mut [f32]) { + if self.n == 1 { + return; + } + + let mut trigcache_temp = self.trigcache[self.n as usize..].to_vec(); + + drftf1( + self.n as i32, + data, + &mut self.trigcache, + &mut trigcache_temp, + &mut self.splitcache, + ); -pub fn spx_ifft_float( - table: &mut DrftLookup, - in_0: &mut [f32], - out: &mut [f32], -) { - spx_ifft(table, in_0, out); + self.trigcache[self.n as usize..].copy_from_slice(&trigcache_temp); + } + + pub fn spx_drft_backward(&mut self, data: &mut [f32]) { + if self.n == 1 { + return; + } + + let mut trigcache_temp = self.trigcache[self.n as usize..].to_vec(); + + drftb1( + self.n as i32, + data, + &mut self.trigcache, + &mut trigcache_temp, + &mut self.splitcache, + ); + + self.trigcache[self.n as usize..].copy_from_slice(&trigcache_temp); + } } diff --git a/fft/src/lib.rs b/fft/src/lib.rs index 74e6239..ce2b455 100644 --- a/fft/src/lib.rs +++ b/fft/src/lib.rs @@ -4,4 +4,3 @@ mod fftwrap; mod smallft; pub use crate::fftwrap::*; -pub use crate::smallft::*; diff --git a/fft/src/smallft.rs b/fft/src/smallft.rs index 09e6744..e4c850c 100644 --- a/fft/src/smallft.rs +++ b/fft/src/smallft.rs @@ -1,27 +1,6 @@ use crate::dradb::*; use crate::dradf::*; -#[derive(Clone)] -pub struct DrftLookup { - pub n: usize, - pub trigcache: Vec, - pub splitcache: Vec, -} - -impl DrftLookup { - pub fn new(n: usize) -> Self { - let mut drft = Self { - n: n, - trigcache: vec![0.0; 3 * n], - splitcache: vec![0; 32], - }; - - fdrffti(n, &mut drft.trigcache, &mut drft.splitcache); - - drft - } -} - #[inline(always)] fn drfti1_c_10244(ifac: &mut [i32], n: i32, nf: &mut i32) { const NTRYH: [i32; 4] = [4, 2, 3, 5]; @@ -62,7 +41,7 @@ fn drfti1_c_10244(ifac: &mut [i32], n: i32, nf: &mut i32) { } } -fn drfti1(wa: &mut [f32], ifac: &mut [i32]) { +pub(crate) fn drfti1(wa: &mut [f32], ifac: &mut [i32]) { const TPI: f32 = 6.283_185_307_179_586_48; let n = wa.len() as i32; @@ -112,7 +91,7 @@ fn drfti1(wa: &mut [f32], ifac: &mut [i32]) { } } -fn fdrffti(n: usize, wsave: &mut [f32], ifac: &mut [i32]) { +pub(crate) fn fdrffti(n: usize, wsave: &mut [f32], ifac: &mut [i32]) { if n == 1 { return; } @@ -152,7 +131,7 @@ fn drftf1_l102( } } -fn drftf1( +pub(crate) fn drftf1( n: i32, c: &mut [f32], ch: &mut [f32], @@ -254,7 +233,7 @@ fn drftb1_l102( } } -fn drftb1( +pub(crate) fn drftb1( n: i32, c: &mut [f32], ch: &mut [f32], @@ -312,42 +291,6 @@ fn drftb1( c[..n as usize].copy_from_slice(&ch[..n as usize]); } -pub fn spx_drft_forward(l: &mut DrftLookup, data: &mut [f32]) { - if l.n == 1 { - return; - } - - let mut trigcache_temp = l.trigcache[l.n as usize..].to_vec(); - - drftf1( - l.n as i32, - data, - &mut l.trigcache, - &mut trigcache_temp, - &mut l.splitcache, - ); - - l.trigcache[l.n as usize..].copy_from_slice(&trigcache_temp); -} - -pub fn spx_drft_backward(l: &mut DrftLookup, data: &mut [f32]) { - if l.n == 1 { - return; - } - - let mut trigcache_temp = l.trigcache[l.n as usize..].to_vec(); - - drftb1( - l.n as i32, - data, - &mut l.trigcache, - &mut trigcache_temp, - &mut l.splitcache, - ); - - l.trigcache[l.n as usize..].copy_from_slice(&trigcache_temp); -} - #[cfg(test)] mod tests { use super::*; diff --git a/fft/tests/fftwrap.rs b/fft/tests/fftwrap.rs index 87ee622..df7cd31 100644 --- a/fft/tests/fftwrap.rs +++ b/fft/tests/fftwrap.rs @@ -2,9 +2,13 @@ extern crate speexdsp_fft; mod orig; -use crate::orig::fftwrap as original; +use std::ptr::null_mut; + use speexdsp_fft::*; +use crate::orig::fftwrap as original_fftwrap; +use crate::orig::smallft as original_smallft; + const INPUT: [f32; 64] = [ 1.0, 1.999002, @@ -73,26 +77,29 @@ const INPUT: [f32; 64] = [ ]; const EPSILON: f32 = 1e-8; +const N: usize = 2; +const SPLITCACHE_SIZE: usize = 32; macro_rules! test_fftwrap { ($func: ident) => { let mut output = [0.; 64]; - let mut table = spx_fft_init(INPUT.len()); + let mut drft_lookup = DrftLookup::new(INPUT.len()); let mut input = INPUT.clone(); - $func(&mut table, &mut input, &mut output); + drft_lookup.$func(&mut input, &mut output); let mut expected_output = [0.; 64]; unsafe { - let table = original::spx_fft_init(INPUT.len() as i32); + let drft_lookup = + original_fftwrap::spx_fft_init(INPUT.len() as i32); let mut input = INPUT.clone(); - original::$func( - table, + original_fftwrap::$func( + drft_lookup, input.as_mut_ptr(), expected_output.as_mut_ptr(), ); - original::spx_fft_destroy(table); + original_fftwrap::spx_fft_destroy(drft_lookup); }; assert!(output @@ -102,6 +109,56 @@ macro_rules! test_fftwrap { }; } +macro_rules! drft { + ($func: ident) => { + let mut drft_lookup = DrftLookup::new(N); + let mut data = vec![0.; 32]; + + drft_lookup.$func(&mut data); + + let mut original_drft_lookup = original_smallft::drft_lookup { + n: 0, + trigcache: null_mut(), + splitcache: null_mut(), + }; + let mut data_original = vec![0.; 32]; + unsafe { + original_smallft::spx_drft_init( + &mut original_drft_lookup, + N as i32, + ); + original_smallft::$func( + &mut original_drft_lookup, + data_original.as_mut_ptr(), + ); + } + + let expected_trigcache = unsafe { + Vec::from_raw_parts( + original_drft_lookup.trigcache as *mut f32, + 3 * N, + 3 * N, + ) + }; + + let expected_splitcache = unsafe { + Vec::from_raw_parts( + original_drft_lookup.splitcache as *mut i32, + SPLITCACHE_SIZE, + SPLITCACHE_SIZE, + ) + }; + + assert!(drft_lookup + .trigcache + .iter() + .zip(expected_trigcache.iter()) + .all(|(&a, &b)| (a - b).abs() < EPSILON)); + + assert_eq!(&drft_lookup.splitcache, &expected_splitcache); + }; +} + #[test] fn fft() { test_fftwrap!(spx_fft); @@ -111,3 +168,51 @@ fn fft() { fn ifft() { test_fftwrap!(spx_ifft); } + +#[test] +fn fdrffti() { + let drft_lookup = DrftLookup::new(N); + + let mut original_drft_lookup = original_smallft::drft_lookup { + n: 0, + trigcache: null_mut(), + splitcache: null_mut(), + }; + unsafe { + original_smallft::spx_drft_init(&mut original_drft_lookup, N as i32); + } + + let expected_trigcache = unsafe { + Vec::from_raw_parts( + original_drft_lookup.trigcache as *mut f32, + 3 * N, + 3 * N, + ) + }; + + let expected_splitcache = unsafe { + Vec::from_raw_parts( + original_drft_lookup.splitcache as *mut i32, + SPLITCACHE_SIZE, + SPLITCACHE_SIZE, + ) + }; + + assert!(drft_lookup + .trigcache + .iter() + .zip(expected_trigcache.iter()) + .all(|(&a, &b)| (a - b).abs() < EPSILON)); + + assert_eq!(&drft_lookup.splitcache, &expected_splitcache); +} + +#[test] +fn drftf1() { + drft!(spx_drft_forward); +} + +#[test] +fn drftb1() { + drft!(spx_drft_backward); +} diff --git a/fft/tests/smallft.rs b/fft/tests/smallft.rs deleted file mode 100644 index 3bacaf8..0000000 --- a/fft/tests/smallft.rs +++ /dev/null @@ -1,108 +0,0 @@ -extern crate speexdsp_fft; - -mod orig; - -use crate::orig::smallft as original; -use speexdsp_fft::*; - -use std::os::raw::{c_float, c_int}; -use std::ptr::null_mut; - -const EPSILON: c_float = 1e-6; -const N: usize = 2; -const SPLITCACHE_SIZE: usize = 32; - -macro_rules! drft { - ($func: ident) => { - let mut drft_lookup = DrftLookup::new(N); - let mut data = vec![0.; 32]; - - $func(&mut drft_lookup, &mut data); - - let mut original_drft_lookup = original::drft_lookup { - n: 0, - trigcache: null_mut(), - splitcache: null_mut(), - }; - let mut data_original = vec![0.; 32]; - unsafe { - original::spx_drft_init(&mut original_drft_lookup, N as c_int); - original::$func( - &mut original_drft_lookup, - data_original.as_mut_ptr(), - ); - } - - let expected_trigcache = unsafe { - Vec::from_raw_parts( - original_drft_lookup.trigcache as *mut c_float, - 3 * N, - 3 * N, - ) - }; - - let expected_splitcache = unsafe { - Vec::from_raw_parts( - original_drft_lookup.splitcache as *mut c_int, - SPLITCACHE_SIZE, - SPLITCACHE_SIZE, - ) - }; - - assert!(drft_lookup - .trigcache - .iter() - .zip(expected_trigcache.iter()) - .all(|(&a, &b)| (a - b).abs() < EPSILON)); - - assert_eq!(&drft_lookup.splitcache, &expected_splitcache); - }; -} - -#[test] -fn fdrffti() { - let drft_lookup = DrftLookup::new(N); - - let mut original_drft_lookup = original::drft_lookup { - n: 0, - trigcache: null_mut(), - splitcache: null_mut(), - }; - unsafe { - original::spx_drft_init(&mut original_drft_lookup, N as c_int); - } - - let expected_trigcache = unsafe { - Vec::from_raw_parts( - original_drft_lookup.trigcache as *mut c_float, - 3 * N, - 3 * N, - ) - }; - - let expected_splitcache = unsafe { - Vec::from_raw_parts( - original_drft_lookup.splitcache as *mut c_int, - SPLITCACHE_SIZE, - SPLITCACHE_SIZE, - ) - }; - - assert!(drft_lookup - .trigcache - .iter() - .zip(expected_trigcache.iter()) - .all(|(&a, &b)| (a - b).abs() < EPSILON)); - - assert_eq!(&drft_lookup.splitcache, &expected_splitcache); -} - -#[test] -fn drftf1() { - drft!(spx_drft_forward); -} - -#[test] -fn drftb1() { - drft!(spx_drft_backward); -}