use crate::compute_rms;
#[must_use]
pub fn rms_level(samples: &[f32]) -> f32 {
compute_rms(samples)
}
#[must_use]
pub fn rms_over_time(samples: &[f32], hop_size: usize) -> Vec<f32> {
if hop_size == 0 || samples.is_empty() {
return vec![];
}
let window_size = hop_size * 2;
if samples.len() < window_size {
return vec![rms_level(samples)];
}
let num_frames = (samples.len() - window_size) / hop_size + 1;
let mut rms_values = Vec::with_capacity(num_frames);
for i in 0..num_frames {
let start = i * hop_size;
let end = (start + window_size).min(samples.len());
let rms = rms_level(&samples[start..end]);
rms_values.push(rms);
}
rms_values
}
#[must_use]
pub fn rms_db(samples: &[f32]) -> f32 {
let rms = rms_level(samples);
if rms > 0.0 {
20.0 * rms.log10()
} else {
-100.0
}
}
#[must_use]
pub fn short_long_term_rms(samples: &[f32], short_window: usize, long_window: usize) -> (f32, f32) {
let short_rms = if samples.len() >= short_window {
rms_level(&samples[samples.len() - short_window..])
} else {
rms_level(samples)
};
let long_rms = if samples.len() >= long_window {
rms_level(&samples[samples.len() - long_window..])
} else {
rms_level(samples)
};
(short_rms, long_rms)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rms_over_time() {
let mut samples = Vec::new();
for i in 0..10000 {
let amp = i as f32 / 10000.0;
samples.push(amp);
}
let rms_track = rms_over_time(&samples, 1000);
assert!(!rms_track.is_empty());
assert!(rms_track.last().unwrap() > rms_track.first().unwrap());
}
#[test]
fn test_rms_db() {
let samples = vec![1.0; 100];
let db = rms_db(&samples);
assert!((db - 0.0).abs() < 0.1); }
#[test]
fn test_short_long_term() {
let samples = vec![0.5; 10000];
let (short, long) = short_long_term_rms(&samples, 1000, 5000);
assert!((short - long).abs() < 0.01);
}
}