use crate::{
check_init, ffi,
vec::{CVec, FVecMut},
AsNativeStr, Error, Result, Smpl, Status,
};
use std::{
fmt::{Display, Formatter, Result as FmtResult},
str::FromStr,
};
pub trait SpecMethod: AsNativeStr {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SpecShape {
Centroid,
Spread,
Skewness,
Kurtosis,
Slope,
Decrease,
Rolloff,
}
impl SpecMethod for SpecShape {}
impl AsNativeStr for SpecShape {
fn as_native_str(&self) -> &'static str {
use self::SpecShape::*;
match self {
Centroid => "centroid\0",
Spread => "spread\0",
Skewness => "skewness\0",
Kurtosis => "kurtosis\0",
Slope => "slope\0",
Decrease => "decrease\0",
Rolloff => "rolloff\0",
}
}
}
impl AsRef<str> for SpecShape {
fn as_ref(&self) -> &str {
self.as_rust_str()
}
}
impl Display for SpecShape {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
self.as_ref().fmt(f)
}
}
impl FromStr for SpecShape {
type Err = Error;
fn from_str(src: &str) -> Result<Self> {
use self::SpecShape::*;
Ok(match src {
"centroid" => Centroid,
"spread" => Spread,
"skewness" => Skewness,
"kurtosis" => Kurtosis,
"slope" => Slope,
"decrease" => Decrease,
"rolloff" => Rolloff,
_ => return Err(Error::InvalidArg),
})
}
}
pub struct SpecDesc {
specdesc: *mut ffi::aubio_specdesc_t,
}
impl Drop for SpecDesc {
fn drop(&mut self) {
unsafe { ffi::del_aubio_specdesc(self.specdesc) }
}
}
impl SpecDesc {
pub fn new(method: impl SpecMethod, buf_size: usize) -> Result<Self> {
let specdesc =
unsafe { ffi::new_aubio_specdesc(method.as_native_cstr(), buf_size as ffi::uint_t) };
check_init(specdesc)?;
Ok(Self { specdesc })
}
pub fn do_<'i, 'o, I, O>(&mut self, fftgrain: I, desc: O) -> Status
where
I: Into<CVec<'i>>,
O: Into<FVecMut<'o>>,
{
let fftgrain = fftgrain.into();
let mut desc = desc.into();
desc.check_size(1)?;
unsafe {
ffi::aubio_specdesc_do(self.specdesc, fftgrain.as_ptr(), desc.as_mut_ptr());
}
Ok(())
}
pub fn do_result<'i, I>(&mut self, fftgrain: I) -> Result<Smpl>
where
I: Into<CVec<'i>>,
{
let mut desc = [0.; 1];
self.do_(fftgrain, &mut desc)?;
Ok(desc[0])
}
}
#[cfg(test)]
mod test {
use crate::*;
#[test]
fn test() {
const WIN: usize = 1024;
let in_ = carr!(WIN); let mut out = farr!(1);
let mut o = SpecDesc::new(OnsetMode::Energy, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(OnsetMode::Hfc, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(OnsetMode::Complex, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(OnsetMode::Phase, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(OnsetMode::Kl, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(OnsetMode::Mkl, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Centroid, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Spread, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Skewness, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Kurtosis, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Slope, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Decrease, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
let mut o = SpecDesc::new(SpecShape::Rolloff, WIN).unwrap();
o.do_(in_.as_ref(), out.as_mut()).unwrap();
}
}