aubio_rs/
specdesc.rs

1use crate::{
2    check_init, ffi,
3    vec::{CVec, FVecMut},
4    AsNativeStr, Error, Result, Smpl, Status,
5};
6
7use std::{
8    fmt::{Display, Formatter, Result as FmtResult},
9    str::FromStr,
10};
11
12/**
13 * Spectral description function
14 */
15pub trait SpecMethod: AsNativeStr {}
16
17/**
18 * Spectral shape descriptor
19 *
20 * The following descriptors are described in:
21 *
22 * Geoffroy Peeters, A large set of audio features for sound description (similarity and classification) in the CUIDADO project, CUIDADO I.S.T. Project Report 2004 ([pdf](http://www.ircam.fr/anasyn/peeters/ARTICLES/Peeters_2003_cuidadoaudiofeatures.pdf))
23 */
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum SpecShape {
26    /**
27     * Spectral centroid
28     *
29     * The spectral centroid represents the barycenter of the spectrum.
30     *
31     * __Note__: This function returns the result in bin. To get the spectral centroid in Hz, `bintofreq()` should be used.
32     */
33    Centroid,
34
35    /**
36     * Spectral spread
37     *
38     * The spectral spread is the variance of the spectral distribution around its centroid.
39     *
40     * See also [Standard deviation](http://en.wikipedia.org/wiki/Standard_deviation) on Wikipedia.
41     */
42    Spread,
43
44    /**
45     *  Spectral skewness
46     *
47     * Similarly, the skewness is computed from the third order moment of the spectrum. A negative skewness indicates more energy on the lower part of the spectrum. A positive skewness indicates more energy on the high frequency of the spectrum.
48     *
49     * See also [Skewness](http://en.wikipedia.org/wiki/Skewness) on Wikipedia.
50     */
51    Skewness,
52
53    /**
54     * Spectral kurtosis
55     *
56     * The kurtosis is a measure of the flatness of the spectrum, computed from the fourth order moment.
57     *
58     * See also [Kurtosis](http://en.wikipedia.org/wiki/Kurtosis) on Wikipedia.
59     */
60    Kurtosis,
61
62    /**
63     * Spectral slope
64     *
65     * The spectral slope represents decreasing rate of the spectral amplitude, computed using a linear regression.
66     */
67    Slope,
68
69    /**
70     * Spectral decrease
71     *
72     * The spectral decrease is another representation of the decreasing rate, based on perceptual criteria.
73     */
74    Decrease,
75
76    /**
77     * Spectral roll-off
78     *
79     * This function returns the bin number below which 95% of the spectrum energy is found.
80     */
81    Rolloff,
82}
83
84impl SpecMethod for SpecShape {}
85
86impl AsNativeStr for SpecShape {
87    fn as_native_str(&self) -> &'static str {
88        use self::SpecShape::*;
89
90        match self {
91            Centroid => "centroid\0",
92            Spread => "spread\0",
93            Skewness => "skewness\0",
94            Kurtosis => "kurtosis\0",
95            Slope => "slope\0",
96            Decrease => "decrease\0",
97            Rolloff => "rolloff\0",
98        }
99    }
100}
101
102impl AsRef<str> for SpecShape {
103    fn as_ref(&self) -> &str {
104        self.as_rust_str()
105    }
106}
107
108impl Display for SpecShape {
109    fn fmt(&self, f: &mut Formatter) -> FmtResult {
110        self.as_ref().fmt(f)
111    }
112}
113
114impl FromStr for SpecShape {
115    type Err = Error;
116
117    fn from_str(src: &str) -> Result<Self> {
118        use self::SpecShape::*;
119
120        Ok(match src {
121            "centroid" => Centroid,
122            "spread" => Spread,
123            "skewness" => Skewness,
124            "kurtosis" => Kurtosis,
125            "slope" => Slope,
126            "decrease" => Decrease,
127            "rolloff" => Rolloff,
128            _ => return Err(Error::InvalidArg),
129        })
130    }
131}
132
133/**
134 * Spectral description object
135 */
136pub struct SpecDesc {
137    specdesc: *mut ffi::aubio_specdesc_t,
138}
139
140impl Drop for SpecDesc {
141    fn drop(&mut self) {
142        unsafe { ffi::del_aubio_specdesc(self.specdesc) }
143    }
144}
145
146impl SpecDesc {
147    /**
148     * Creation of a spectral description object
149     *
150     * - `method` Spectral description method
151     * - `buf_size` Length of the input spectrum frame
152     */
153    pub fn new(method: impl SpecMethod, buf_size: usize) -> Result<Self> {
154        let specdesc =
155            unsafe { ffi::new_aubio_specdesc(method.as_native_cstr(), buf_size as ffi::uint_t) };
156
157        check_init(specdesc)?;
158
159        Ok(Self { specdesc })
160    }
161
162    /**
163     * Execute spectral description function on a spectral frame
164     *
165     * Generic function to compute spectral description.
166     */
167    pub fn do_<'i, 'o, I, O>(&mut self, fftgrain: I, desc: O) -> Status
168    where
169        I: Into<CVec<'i>>,
170        O: Into<FVecMut<'o>>,
171    {
172        let fftgrain = fftgrain.into();
173        let mut desc = desc.into();
174
175        desc.check_size(1)?;
176
177        unsafe {
178            ffi::aubio_specdesc_do(self.specdesc, fftgrain.as_ptr(), desc.as_mut_ptr());
179        }
180        Ok(())
181    }
182
183    /**
184     * Execute spectral description function on a spectral frame
185     *
186     * Generic function to compute spectral description.
187     */
188    pub fn do_result<'i, I>(&mut self, fftgrain: I) -> Result<Smpl>
189    where
190        I: Into<CVec<'i>>,
191    {
192        let mut desc = [0.; 1];
193        self.do_(fftgrain, &mut desc)?;
194        Ok(desc[0])
195    }
196}
197
198#[cfg(test)]
199mod test {
200    use crate::*;
201
202    #[test]
203    fn test() {
204        const WIN: usize = 1024; // window size
205
206        let in_ = carr!(WIN); // input buffer
207        let mut out = farr!(1); // output spectral descriptor
208
209        let mut o = SpecDesc::new(OnsetMode::Energy, WIN).unwrap();
210        o.do_(in_.as_ref(), out.as_mut()).unwrap();
211
212        let mut o = SpecDesc::new(OnsetMode::Hfc, WIN).unwrap();
213        o.do_(in_.as_ref(), out.as_mut()).unwrap();
214
215        let mut o = SpecDesc::new(OnsetMode::Complex, WIN).unwrap();
216        o.do_(in_.as_ref(), out.as_mut()).unwrap();
217
218        let mut o = SpecDesc::new(OnsetMode::Phase, WIN).unwrap();
219        o.do_(in_.as_ref(), out.as_mut()).unwrap();
220
221        let mut o = SpecDesc::new(OnsetMode::Kl, WIN).unwrap();
222        o.do_(in_.as_ref(), out.as_mut()).unwrap();
223
224        let mut o = SpecDesc::new(OnsetMode::Mkl, WIN).unwrap();
225        o.do_(in_.as_ref(), out.as_mut()).unwrap();
226
227        let mut o = SpecDesc::new(SpecShape::Centroid, WIN).unwrap();
228        o.do_(in_.as_ref(), out.as_mut()).unwrap();
229
230        let mut o = SpecDesc::new(SpecShape::Spread, WIN).unwrap();
231        o.do_(in_.as_ref(), out.as_mut()).unwrap();
232
233        let mut o = SpecDesc::new(SpecShape::Skewness, WIN).unwrap();
234        o.do_(in_.as_ref(), out.as_mut()).unwrap();
235
236        let mut o = SpecDesc::new(SpecShape::Kurtosis, WIN).unwrap();
237        o.do_(in_.as_ref(), out.as_mut()).unwrap();
238
239        let mut o = SpecDesc::new(SpecShape::Slope, WIN).unwrap();
240        o.do_(in_.as_ref(), out.as_mut()).unwrap();
241
242        let mut o = SpecDesc::new(SpecShape::Decrease, WIN).unwrap();
243        o.do_(in_.as_ref(), out.as_mut()).unwrap();
244
245        let mut o = SpecDesc::new(SpecShape::Rolloff, WIN).unwrap();
246        o.do_(in_.as_ref(), out.as_mut()).unwrap();
247    }
248}