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 planes: &[&[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 let len = planes.iter().map(|p| p.len()).min().unwrap_or(0);
18 (0..len)
19 .step_by(stride)
20 .map(|from| {
21 let to = (from + stride).min(len);
22 let frame: Vec<&[f64]> = planes.iter().map(|p| &p[from..to]).collect();
23 EnvelopeFrame {
24 t_secs: start_secs + from as f64 / sample_rate,
25 rms: level(&frame),
26 peak: frame
27 .iter()
28 .flat_map(|p| p.iter())
29 .fold(0f64, |a, &x| a.max(x.abs())),
30 }
31 })
32 .collect()
33}
34
35pub fn level(planes: &[&[f64]]) -> f64 {
37 let count: usize = planes.iter().map(|p| p.len()).sum();
38 if count == 0 {
39 return 0.0;
40 }
41 let sum_sq: f64 = planes.iter().flat_map(|p| p.iter()).map(|&x| x * x).sum();
42 (sum_sq / count as f64).sqrt()
43}
44
45pub fn rms(samples: &[f64]) -> f64 {
46 level(&[samples])
47}