math_audio_dsp/
waveform.rs1pub const WAVEFORM_SAMPLES: usize = 128;
3
4pub fn compute_waveform(mono_samples: &[f32]) -> Vec<u8> {
11 if mono_samples.is_empty() {
12 log::warn!("[Waveform] No samples provided");
13 return vec![0u8; WAVEFORM_SAMPLES];
14 }
15
16 let samples_per_chunk = mono_samples.len() / WAVEFORM_SAMPLES;
17
18 if samples_per_chunk == 0 {
20 log::warn!(
21 "[Waveform] Input too short ({} samples), padding waveform",
22 mono_samples.len()
23 );
24 let mut waveform = Vec::with_capacity(WAVEFORM_SAMPLES);
25 for i in 0..WAVEFORM_SAMPLES {
26 if i < mono_samples.len() {
27 let amplitude = mono_samples[i].abs();
28 waveform.push((amplitude.min(1.0) * 255.0) as u8);
29 } else {
30 waveform.push(0);
31 }
32 }
33 return waveform;
34 }
35
36 let mut rms_values: Vec<f32> = Vec::with_capacity(WAVEFORM_SAMPLES);
38
39 for chunk_idx in 0..WAVEFORM_SAMPLES {
40 let start = chunk_idx * samples_per_chunk;
41 let end = if chunk_idx == WAVEFORM_SAMPLES - 1 {
42 mono_samples.len()
43 } else {
44 start + samples_per_chunk
45 };
46
47 let chunk = &mono_samples[start..end];
48 let sum_squares: f32 = chunk.iter().map(|s| s * s).sum();
49 let rms = (sum_squares / chunk.len() as f32).sqrt();
50 rms_values.push(rms);
51 }
52
53 let max_rms = rms_values
55 .iter()
56 .cloned()
57 .fold(0.0f32, |a, b| a.max(b))
58 .max(0.001);
59
60 let waveform: Vec<u8> = rms_values
61 .iter()
62 .map(|&rms| {
63 let normalized = rms / max_rms;
64 (normalized * 255.0) as u8
65 })
66 .collect();
67
68 log::debug!(
69 "[Waveform] Computed waveform with {} samples, max_rms={:.4}",
70 waveform.len(),
71 max_rms
72 );
73
74 waveform
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_empty_input() {
83 let waveform = compute_waveform(&[]);
84 assert_eq!(waveform.len(), WAVEFORM_SAMPLES);
85 assert!(waveform.iter().all(|&v| v == 0));
86 }
87
88 #[test]
89 fn test_short_input() {
90 let samples = vec![0.5; 10];
91 let waveform = compute_waveform(&samples);
92 assert_eq!(waveform.len(), WAVEFORM_SAMPLES);
93 }
94
95 #[test]
96 fn test_waveform_length_constant() {
97 assert_eq!(WAVEFORM_SAMPLES, 128);
98 }
99
100 #[test]
101 fn test_normal_input() {
102 let samples: Vec<f32> = (0..48000)
103 .map(|i| (i as f32 / 48000.0 * 440.0 * std::f32::consts::TAU).sin())
104 .collect();
105 let waveform = compute_waveform(&samples);
106 assert_eq!(waveform.len(), WAVEFORM_SAMPLES);
107 assert!(waveform.iter().any(|&v| v > 0));
108 }
109}