aubio_rs/
pvoc.rs

1use crate::{
2    check_init, ffi,
3    vec::{CVec, CVecMut, FVec, FVecMut},
4    AsNativeStr, Error, Result, Status, WindowType,
5};
6
7/**
8 * Phase vocoder object
9 */
10pub struct PVoc {
11    pvoc: *mut ffi::aubio_pvoc_t,
12}
13
14impl Drop for PVoc {
15    fn drop(&mut self) {
16        unsafe {
17            ffi::del_aubio_pvoc(self.pvoc);
18        }
19    }
20}
21
22impl PVoc {
23    /**
24     * Create phase vocoder object
25     *
26     * - `win_size` Size of analysis buffer (and length the FFT transform)
27     * - `hop_size` Step size between two consecutive analysis
28     */
29    pub fn new(win_size: usize, hop_size: usize) -> Result<Self> {
30        let pvoc = unsafe { ffi::new_aubio_pvoc(win_size as ffi::uint_t, hop_size as ffi::uint_t) };
31
32        check_init(pvoc)?;
33
34        Ok(Self { pvoc })
35    }
36
37    /**
38     * Select window type
39     */
40    pub fn with_window(mut self, window_type: WindowType) -> Result<Self> {
41        self.set_window(window_type).map(|_| self)
42    }
43
44    /**
45     * Get hop size
46     */
47    pub fn get_hop(&self) -> usize {
48        unsafe { ffi::aubio_pvoc_get_hop(self.pvoc) as usize }
49    }
50
51    /**
52     * Get window size
53     */
54    pub fn get_win(&self) -> usize {
55        unsafe { ffi::aubio_pvoc_get_win(self.pvoc) as usize }
56    }
57
58    /**
59     * Compute spectral frame
60     *
61     * This function accepts an input vector of size `hop_size`.
62     * The analysis buffer is rotated and filled with the new data.
63     * After windowing of this signal window, the Fourier transform
64     * is computed and returned in fftgrain as two vectors, magnitude
65     * and phase.
66     *
67     * - `input` New input signal (`hop_size` long)
68     * - `fftgrain` Output spectral frame (`win_size` long)
69     */
70    pub fn do_<'i, 'o, I, O>(&mut self, input: I, fftgrain: O) -> Status
71    where
72        I: Into<FVec<'i>>,
73        O: Into<CVecMut<'o>>,
74    {
75        let input = input.into();
76        let mut fftgrain = fftgrain.into();
77
78        input.check_size(self.get_hop())?;
79        fftgrain.check_size(self.get_win())?;
80
81        unsafe {
82            ffi::aubio_pvoc_do(self.pvoc, input.as_ptr(), fftgrain.as_mut_ptr());
83        }
84        Ok(())
85    }
86
87    /**
88     * Compute signal from spectral frame
89     *
90     * This function takes an input spectral frame fftgrain of size `win_size`
91     * and computes its inverse Fourier transform. Overlap-add synthesis is then
92     * computed using the previously synthetised frames, and the output stored in out.
93     * - `fftgrain` Input spectral frame (`win_size` long)
94     * - `output` Output signal (`hop_size` long)
95     */
96    pub fn rdo<'i, 'o, I, O>(&mut self, fftgrain: I, output: O) -> Status
97    where
98        I: Into<CVec<'i>>,
99        O: Into<FVecMut<'o>>,
100    {
101        let fftgrain = fftgrain.into();
102        let mut output = output.into();
103
104        fftgrain.check_size(self.get_win())?;
105        output.check_size(self.get_hop())?;
106
107        // It seems the second arg have missing const qualifier so we need 'as *mut _' here
108        unsafe {
109            ffi::aubio_pvoc_rdo(self.pvoc, fftgrain.as_ptr() as *mut _, output.as_mut_ptr());
110        }
111        Ok(())
112    }
113
114    /**
115     * Set window type
116     */
117    pub fn set_window(&mut self, window_type: WindowType) -> Status {
118        if 0 == unsafe { ffi::aubio_pvoc_set_window(self.pvoc, window_type.as_native_cstr()) } {
119            Ok(())
120        } else {
121            Err(Error::InvalidArg)
122        }
123    }
124}
125
126#[cfg(test)]
127mod test {
128    use crate::*;
129
130    #[test]
131    fn test() {
132        const WIN_S: usize = 32; // window size
133        const HOP_S: usize = WIN_S / 4; // hop size
134        let in_ = [1.; HOP_S]; // input buffer
135        let mut fftgrain = carr!(WIN_S); // fft norm and phase
136        let mut out = farr!(HOP_S); // output buffer
137                                    // allocate fft and other memory space
138        let mut pv = PVoc::new(WIN_S, HOP_S).unwrap();
139
140        assert!(PVoc::new(WIN_S, 0).is_err());
141        assert_eq!(pv.get_win(), WIN_S);
142        assert_eq!(pv.get_hop(), HOP_S);
143
144        pv.set_window(WindowType::Hanningz).unwrap();
145
146        // compute 6 times
147        for _i in 0..6 {
148            // get some fresh input data
149            // ..
150            // execute phase vocoder
151            pv.do_(in_.as_ref(), fftgrain.as_mut()).unwrap();
152            // do something with fftgrain
153            // ...
154            println!("fftgrain: {:?}", fftgrain.as_ref());
155
156            // optionally rebuild the signal
157            pv.rdo(fftgrain.as_ref(), out.as_mut()).unwrap();
158            // and do something with the result
159            // ...
160            println!("out: {:?}", out);
161        }
162    }
163}