aubio_rs/
fft.rs

1use crate::{
2    check_init, ffi,
3    vec::{CVec, CVecMut, CVecNormMut, CVecPhasMut, FVec, FVecMut},
4    Result, Status,
5};
6
7/**
8 * FFT (Fast Fourier Transformation) object
9 *
10 * This object computes forward and backward FFTs.
11 *
12 * Depending on how _aubio_ was compiled, FFT are computed using one of:
13 *
14 * - Ooura
15 * - FFTW3
16 * - vDSP
17 */
18pub struct FFT {
19    fft: *mut ffi::aubio_fft_t,
20    win_size: usize,
21}
22
23impl Drop for FFT {
24    fn drop(&mut self) {
25        unsafe {
26            ffi::del_aubio_fft(self.fft);
27        }
28    }
29}
30
31impl FFT {
32    /**
33     * Create new FFT computation object
34     */
35    pub fn new(win_size: usize) -> Result<Self> {
36        let fft = unsafe { ffi::new_aubio_fft(win_size as ffi::uint_t) };
37
38        check_init(fft)?;
39
40        Ok(Self { fft, win_size })
41    }
42
43    /**
44     * Get window size
45     */
46    pub fn get_win(&self) -> usize {
47        self.win_size
48    }
49
50    /**
51     * Get fft size
52     */
53    pub fn get_fft(&self) -> usize {
54        self.get_win() / 2 + 1
55    }
56
57    /**
58     * Compute forward (direct) FFT
59     */
60    pub fn do_<'i, 'o, I, O>(&mut self, input: I, spectrum: O) -> Status
61    where
62        I: Into<FVec<'i>>,
63        O: Into<CVecMut<'o>>,
64    {
65        let input = input.into();
66        let mut spectrum = spectrum.into();
67
68        input.check_size(self.get_win())?;
69
70        unsafe {
71            ffi::aubio_fft_do(self.fft, input.as_ptr(), spectrum.as_mut_ptr());
72        }
73        Ok(())
74    }
75
76    /**
77     * Compute backward (inverse) FFT
78     */
79    pub fn rdo<'i, 'o, I, O>(&mut self, spectrum: I, output: O) -> Status
80    where
81        I: Into<CVec<'i>>,
82        O: Into<FVecMut<'o>>,
83    {
84        let spectrum = spectrum.into();
85        let mut output = output.into();
86
87        output.check_size(self.get_win())?;
88
89        unsafe {
90            ffi::aubio_fft_rdo(self.fft, spectrum.as_ptr(), output.as_mut_ptr());
91        }
92        Ok(())
93    }
94
95    /**
96     * Compute forward (direct) FFT
97     */
98    pub fn do_complex<'i, 'o, I, O>(&mut self, input: I, compspec: O) -> Status
99    where
100        I: Into<FVec<'i>>,
101        O: Into<FVecMut<'o>>,
102    {
103        let input = input.into();
104        let mut compspec = compspec.into();
105
106        input.check_size(self.get_win())?;
107        compspec.check_size(self.get_win())?;
108
109        unsafe {
110            ffi::aubio_fft_do_complex(self.fft, input.as_ptr(), compspec.as_mut_ptr());
111        }
112        Ok(())
113    }
114
115    /**
116     * Compute backward (inverse) FFT
117     */
118    pub fn rdo_complex<'i, 'o, I, O>(&mut self, compspec: I, output: O) -> Status
119    where
120        I: Into<FVec<'i>>,
121        O: Into<FVecMut<'o>>,
122    {
123        let compspec = compspec.into();
124        let mut output = output.into();
125
126        compspec.check_size(self.get_win())?;
127        output.check_size(self.get_win())?;
128
129        unsafe {
130            ffi::aubio_fft_rdo_complex(self.fft, compspec.as_ptr(), output.as_mut_ptr());
131        }
132        Ok(())
133    }
134
135    /**
136     * Convert real/imag spectrum to norm/phas spectrum
137     */
138    pub fn get_spectrum<'i, 'o, I, O>(compspec: I, spectrum: O) -> Status
139    where
140        I: Into<FVec<'i>>,
141        O: Into<CVecMut<'o>>,
142    {
143        let compspec = compspec.into();
144        let mut spectrum = spectrum.into();
145
146        spectrum.check_size(compspec.size())?;
147
148        unsafe {
149            ffi::aubio_fft_get_spectrum(compspec.as_ptr(), spectrum.as_mut_ptr());
150        }
151        Ok(())
152    }
153
154    /**
155     * Convert norm/phas spectrum to real/imag spectrum
156     */
157    pub fn get_realimag<'i, 'o, I, O>(spectrum: I, compspec: O) -> Status
158    where
159        I: Into<CVec<'i>>,
160        O: Into<FVecMut<'o>>,
161    {
162        let spectrum = spectrum.into();
163        let mut compspec = compspec.into();
164
165        compspec.check_size(spectrum.size())?;
166
167        unsafe {
168            ffi::aubio_fft_get_realimag(spectrum.as_ptr(), compspec.as_mut_ptr());
169        }
170        Ok(())
171    }
172
173    /**
174     * Compute phas spectrum from real/imag parts
175     */
176    pub fn get_phas<'i, 'o, I, O>(compspec: I, spectrum_phas: O) -> Status
177    where
178        I: Into<FVec<'i>>,
179        O: Into<CVecPhasMut<'o>>,
180    {
181        let compspec = compspec.into();
182        let mut spectrum_phas = spectrum_phas.into();
183
184        spectrum_phas.check_size(compspec.size())?;
185
186        unsafe {
187            ffi::aubio_fft_get_phas(compspec.as_ptr(), spectrum_phas.as_mut_ptr());
188        }
189        Ok(())
190    }
191
192    /**
193     * Compute norm component from real/imag parts
194     */
195    pub fn get_norm<'i, 'o, I, O>(compspec: I, spectrum_norm: O) -> Status
196    where
197        I: Into<FVec<'i>>,
198        O: Into<CVecNormMut<'o>>,
199    {
200        let compspec = compspec.into();
201        let mut spectrum_norm = spectrum_norm.into();
202
203        spectrum_norm.check_size(compspec.size())?;
204
205        unsafe {
206            ffi::aubio_fft_get_norm(compspec.as_ptr(), spectrum_norm.as_mut_ptr());
207        }
208        Ok(())
209    }
210
211    /**
212     * Compute imaginary part from the norm/phas cvec
213     */
214    pub fn get_imag<'i, 'o, I, O>(spectrum: I, compspec: O) -> Status
215    where
216        I: Into<CVec<'i>>,
217        O: Into<FVecMut<'o>>,
218    {
219        let spectrum = spectrum.into();
220        let mut compspec = compspec.into();
221
222        compspec.check_size(spectrum.size())?;
223
224        unsafe {
225            ffi::aubio_fft_get_imag(spectrum.as_ptr(), compspec.as_mut_ptr());
226        }
227        Ok(())
228    }
229
230    /**
231     * Compute real part from the norm/phas cvec
232     */
233    pub fn get_real<'i, 'o, I, O>(spectrum: I, compspec: O) -> Status
234    where
235        I: Into<CVec<'i>>,
236        O: Into<FVecMut<'o>>,
237    {
238        let spectrum = spectrum.into();
239        let mut compspec = compspec.into();
240
241        compspec.check_size(spectrum.size())?;
242
243        unsafe {
244            ffi::aubio_fft_get_real(spectrum.as_ptr(), compspec.as_mut_ptr());
245        }
246        Ok(())
247    }
248}
249
250#[cfg(test)]
251mod test {
252    use crate::*;
253
254    #[test]
255    fn test() {
256        const ITERS: usize = 100; // number of iterations
257        const WIN: usize = 512; // window size
258
259        let mut in_ = [0.; WIN]; // input buffer
260                                 //let mut in_ = farr!(WIN); // input buffer
261                                 //let mut fftgrain = [0.; (WIN+1)*2]; // fft norm and phase
262        let mut fftgrain = carr!(WIN); // fft norm and phase
263        let mut out = [0.; WIN]; // output buffer
264                                 // create fft object
265        let mut fft = FFT::new(WIN).unwrap();
266
267        // fill input with some data
268        in_[0] = 1.0;
269        in_[1] = 2.0;
270        in_[2] = 3.0;
271        in_[3] = 4.0;
272        in_[4] = 5.0;
273        in_[5] = 6.0;
274        in_[6] = 5.0;
275        in_[7] = 6.0;
276        println!("in: {:?}", in_.as_ref());
277
278        for _i in 0..ITERS {
279            // execute stft
280            fft.do_(in_.as_ref(), fftgrain.as_mut()).unwrap();
281            println!("fftgrain: {:?}", fftgrain.as_ref());
282            // execute inverse fourier transform
283            fft.rdo(fftgrain.as_ref(), out.as_mut()).unwrap();
284        }
285
286        println!("out: {:?}", out.as_ref());
287    }
288}