use core::f64;
use super::spectral_analysis_tools::*;
use super::computation::*;
#[derive(Copy, Clone)]
pub struct Analysis {
pub alpha_ratio: f64,
pub hammarberg_index: f64,
pub spectral_centroid: f64,
pub spectral_difference: f64,
pub spectral_entropy: f64,
pub spectral_flatness: f64,
pub spectral_flux: f64,
pub spectral_kurtosis: f64,
pub spectral_roll_off_50: f64,
pub spectral_roll_off_75: f64,
pub spectral_roll_off_90: f64,
pub spectral_roll_off_95: f64,
pub spectral_skewness: f64,
pub spectral_slope: f64,
pub spectral_slope_0_1_khz: f64,
pub spectral_slope_1_5_khz: f64,
pub spectral_slope_0_5_khz: f64,
pub spectral_variance: f64,
}
pub fn analyzer(magnitude_spectrum_current: &[f64], magnitude_spectrum_prev: Option<&[f64]>, sample_rate: u32, rfft_freqs: &[f64]) -> Analysis {
let power_spectrum = make_power_spectrum(&magnitude_spectrum_current);
let magnitude_spectrum_sum = magnitude_spectrum_current.iter().sum();
let power_spectrum_sum = power_spectrum.iter().sum();
let spectrum_pmf = make_spectrum_pmf(&power_spectrum, power_spectrum_sum);
let analysis_spectral_centroid = compute_spectral_centroid(&magnitude_spectrum_current, &rfft_freqs, magnitude_spectrum_sum);
let analysis_spectral_variance = compute_spectral_variance(&spectrum_pmf, &rfft_freqs, analysis_spectral_centroid);
let analysis_spectral_skewness = compute_spectral_skewness(&spectrum_pmf, &rfft_freqs, analysis_spectral_centroid, analysis_spectral_variance);
let analysis_spectral_kurtosis = compute_spectral_kurtosis(&spectrum_pmf, &rfft_freqs, analysis_spectral_centroid, analysis_spectral_variance);
let analysis_spectral_entropy = compute_spectral_entropy(&spectrum_pmf);
let analysis_spectral_flatness = compute_spectral_flatness(&magnitude_spectrum_current, magnitude_spectrum_sum);
let analysis_spectral_roll_off_50 = compute_spectral_roll_off_point(&power_spectrum, &rfft_freqs, power_spectrum_sum, 0.5);
let analysis_spectral_roll_off_75 = compute_spectral_roll_off_point(&power_spectrum, &rfft_freqs, power_spectrum_sum, 0.75);
let analysis_spectral_roll_off_90 = compute_spectral_roll_off_point(&power_spectrum, &rfft_freqs, power_spectrum_sum, 0.9);
let analysis_spectral_roll_off_95 = compute_spectral_roll_off_point(&power_spectrum, &rfft_freqs, power_spectrum_sum, 0.95);
let analysis_spectral_slope = compute_spectral_slope(&power_spectrum, power_spectrum_sum);
let spec_difference = match magnitude_spectrum_prev {
Some(spec) => {
match spectral_difference(magnitude_spectrum_current, spec, true) {
Ok(diff) => diff,
Err(_) => f64::NAN
}},
None => f64::NAN
};
let spec_flux = match magnitude_spectrum_prev {
Some(spec) => {
match spectral_flux(magnitude_spectrum_current, spec, Some(crate::util::Norm::L2)) {
Ok(diff) => diff,
Err(_) => f64::NAN
}},
None => f64::NAN
};
let analysis_spectral_slope_0_1_khz = compute_spectral_slope_region(&power_spectrum, &rfft_freqs, 0.0, 1000.0, sample_rate);
let analysis_spectral_slope_1_5_khz = compute_spectral_slope_region(&power_spectrum, &rfft_freqs, 1000.0, 5000.0, sample_rate);
let analysis_spectral_slope_0_5_khz = compute_spectral_slope_region(&power_spectrum, &rfft_freqs, 0.0, 5000.0, sample_rate);
Analysis {
alpha_ratio: alpha_ratio(magnitude_spectrum_current, rfft_freqs),
hammarberg_index: hammarberg_index(magnitude_spectrum_current, rfft_freqs),
spectral_centroid: analysis_spectral_centroid,
spectral_difference: spec_difference,
spectral_entropy: analysis_spectral_entropy,
spectral_flatness: analysis_spectral_flatness,
spectral_flux: spec_flux,
spectral_kurtosis: analysis_spectral_kurtosis,
spectral_roll_off_50: analysis_spectral_roll_off_50,
spectral_roll_off_75: analysis_spectral_roll_off_75,
spectral_roll_off_90: analysis_spectral_roll_off_90,
spectral_roll_off_95: analysis_spectral_roll_off_95,
spectral_skewness: analysis_spectral_skewness,
spectral_slope: analysis_spectral_slope,
spectral_slope_0_1_khz: analysis_spectral_slope_0_1_khz,
spectral_slope_0_5_khz: analysis_spectral_slope_0_5_khz,
spectral_slope_1_5_khz: analysis_spectral_slope_1_5_khz,
spectral_variance: analysis_spectral_variance,
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::spectrum;
#[test]
pub fn basic_tests4() {
let fft_size: usize = 4096;
let hop_size: usize = fft_size / 2;
let window_type = crate::WindowType::Hamming;
let path = String::from("D:\\Recording\\grains.wav");
let mut audio = match crate::read(&path) {
Ok(x) => x,
Err(_) => panic!("could not read audio")
};
let stft_imaginary_spectrum: Vec<Vec<num::Complex<f64>>> = crate::spectrum::rstft(&mut audio.samples[0], fft_size, hop_size, window_type);
let (stft_magnitude_spectrum, _) = crate::spectrum::complex_to_polar_rstft(&stft_imaginary_spectrum);
let mut analyses: Vec<Analysis> = Vec::with_capacity(stft_magnitude_spectrum.len());
let rfft_freqs = spectrum::rfftfreq(fft_size, audio.sample_rate);
for i in 0..stft_magnitude_spectrum.len() {
analyses.push(analyzer(&stft_magnitude_spectrum[i], None, audio.sample_rate, &rfft_freqs));
}
}
}