sva_samples/measure/
envelope.rs1#[derive(Clone, Copy, Debug, PartialEq)]
4pub struct EnvelopeFrame {
5 pub t_secs: f64,
6 pub rms: f64,
7 pub peak: f64,
8}
9
10pub fn trace(
11 samples: &[f64],
12 sample_rate: f64,
13 start_secs: f64,
14 frame_secs: f64,
15) -> Vec<EnvelopeFrame> {
16 let stride = ((frame_secs * sample_rate).round() as usize).max(1);
17 samples
18 .chunks(stride)
19 .enumerate()
20 .map(|(n, chunk)| EnvelopeFrame {
21 t_secs: start_secs + (n * stride) as f64 / sample_rate,
22 rms: rms(chunk),
23 peak: chunk.iter().fold(0f64, |a, &x| a.max(x.abs())),
24 })
25 .collect()
26}
27
28pub fn rms(samples: &[f64]) -> f64 {
29 if samples.is_empty() {
30 return 0.0;
31 }
32 let sum_sq: f64 = samples.iter().map(|&x| x * x).sum();
33 (sum_sq / samples.len() as f64).sqrt()
34}