use std::collections::VecDeque;
pub struct WaveformBuffer {
samples: VecDeque<f32>,
max_samples: usize,
}
impl WaveformBuffer {
pub fn new(max_samples: usize) -> Self {
Self {
samples: VecDeque::with_capacity(max_samples),
max_samples,
}
}
pub fn push_samples(&mut self, new_samples: &[f32]) {
for &sample in new_samples {
self.samples.push_back(sample);
while self.samples.len() > self.max_samples {
self.samples.pop_front();
}
}
}
pub fn get_display_samples(&self, count: usize) -> Vec<f32> {
if self.samples.is_empty() {
return vec![0.0; count];
}
let step = self.samples.len() as f32 / count as f32;
(0..count)
.map(|i| {
let idx = (i as f32 * step) as usize;
self.samples.get(idx).copied().unwrap_or(0.0)
})
.collect()
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.samples.clear();
}
}
#[allow(dead_code)]
pub fn amplitude_to_blocks(amplitude: f32) -> &'static str {
let normalized = amplitude.abs().min(1.0);
let index = (normalized * 8.0) as usize;
match index {
0 => " ",
1 => "▁",
2 => "▂",
3 => "▃",
4 => "▄",
5 => "▅",
6 => "▆",
7 => "▇",
_ => "█",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_waveform_buffer_new() {
let buffer = WaveformBuffer::new(100);
assert_eq!(buffer.samples.len(), 0);
assert_eq!(buffer.max_samples, 100);
}
#[test]
fn test_push_samples() {
let mut buffer = WaveformBuffer::new(5);
buffer.push_samples(&[1.0, 2.0, 3.0]);
assert_eq!(buffer.samples.len(), 3);
buffer.push_samples(&[4.0, 5.0, 6.0]);
assert_eq!(buffer.samples.len(), 5);
let samples: Vec<f32> = buffer.samples.iter().copied().collect();
assert_eq!(samples, vec![2.0, 3.0, 4.0, 5.0, 6.0]);
}
#[test]
fn test_get_display_samples_empty() {
let buffer = WaveformBuffer::new(100);
let samples = buffer.get_display_samples(10);
assert_eq!(samples.len(), 10);
assert!(samples.iter().all(|&s| s == 0.0));
}
#[test]
fn test_get_display_samples_downsampling() {
let mut buffer = WaveformBuffer::new(10);
buffer.push_samples(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);
let samples = buffer.get_display_samples(5);
assert_eq!(samples.len(), 5);
assert_eq!(samples[0], 1.0);
assert_eq!(samples[2], 5.0);
assert_eq!(samples[4], 9.0);
}
#[test]
fn test_get_display_samples_upsampling() {
let mut buffer = WaveformBuffer::new(5);
buffer.push_samples(&[1.0, 2.0, 3.0]);
let samples = buffer.get_display_samples(6);
assert_eq!(samples.len(), 6);
}
#[test]
fn test_clear() {
let mut buffer = WaveformBuffer::new(10);
buffer.push_samples(&[1.0, 2.0, 3.0]);
assert_eq!(buffer.samples.len(), 3);
buffer.clear();
assert_eq!(buffer.samples.len(), 0);
}
#[test]
fn test_amplitude_to_blocks() {
assert_eq!(amplitude_to_blocks(0.0), " ");
assert_eq!(amplitude_to_blocks(0.12), " "); assert_eq!(amplitude_to_blocks(0.13), "▁"); assert_eq!(amplitude_to_blocks(0.25), "▂"); assert_eq!(amplitude_to_blocks(0.38), "▃"); assert_eq!(amplitude_to_blocks(0.5), "▄"); assert_eq!(amplitude_to_blocks(0.63), "▅"); assert_eq!(amplitude_to_blocks(0.75), "▆"); assert_eq!(amplitude_to_blocks(0.88), "▇"); assert_eq!(amplitude_to_blocks(1.0), "█"); assert_eq!(amplitude_to_blocks(1.5), "█"); assert_eq!(amplitude_to_blocks(-0.9), "▇"); }
}
#[allow(dead_code)]
pub fn generate_waveform_line(samples: &[f32], width: usize, height: usize) -> Vec<String> {
let mut lines = vec![String::new(); height];
if samples.is_empty() || width == 0 {
return lines;
}
let step = samples.len() as f32 / width as f32;
let display_samples: Vec<f32> = (0..width)
.map(|i| {
let start = (i as f32 * step) as usize;
let end = ((i + 1) as f32 * step) as usize;
let end = end.min(samples.len());
if start < end {
samples[start..end].iter().sum::<f32>() / (end - start) as f32
} else {
0.0
}
})
.collect();
for (x, &sample) in display_samples.iter().enumerate() {
let y = ((1.0 - sample) * 0.5 * (height - 1) as f32) as usize;
let y = y.min(height - 1);
if x < lines[y].len() {
lines[y].replace_range(x..=x, "█");
} else {
while lines[y].len() < x {
lines[y].push(' ');
}
lines[y].push('█');
}
}
lines
}