use crate::spectral::SpectralAnalyzer;
use crate::{AnalysisConfig, Result};
pub struct NoiseProfiler {
spectral_analyzer: SpectralAnalyzer,
}
impl NoiseProfiler {
#[must_use]
pub fn new(config: AnalysisConfig) -> Self {
Self {
spectral_analyzer: SpectralAnalyzer::new(config),
}
}
pub fn profile(&self, samples: &[f32], sample_rate: f32) -> Result<NoiseProfile> {
let spectral = self.spectral_analyzer.analyze(samples, sample_rate)?;
let noise_type = super::classify::classify_noise(&spectral);
let noise_level = crate::compute_rms(samples);
let noise_floor = self.estimate_noise_floor(samples);
Ok(NoiseProfile {
noise_type,
noise_level,
noise_floor,
spectral_flatness: spectral.flatness,
spectral_centroid: spectral.centroid,
})
}
#[allow(clippy::unused_self)]
fn estimate_noise_floor(&self, samples: &[f32]) -> f32 {
if samples.is_empty() {
return 0.0;
}
let mut amplitudes: Vec<f32> = samples.iter().map(|&x| x.abs()).collect();
amplitudes.sort_by(|a, b| a.partial_cmp(b).unwrap());
let idx = (amplitudes.len() as f32 * 0.1) as usize;
amplitudes[idx]
}
}
#[derive(Debug, Clone)]
pub struct NoiseProfile {
pub noise_type: super::classify::NoiseType,
pub noise_level: f32,
pub noise_floor: f32,
pub spectral_flatness: f32,
pub spectral_centroid: f32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_noise_profiler() {
let config = AnalysisConfig::default();
let profiler = NoiseProfiler::new(config);
let samples = vec![0.1; 8192];
let profile = profiler.profile(&samples, 44100.0);
assert!(profile.is_ok());
}
}