audio_visualizer/waveform/
png_file.rs1use crate::util::png::write_png_file_rgb_tuples;
27use crate::Channels;
28use std::path::PathBuf;
29
30pub fn waveform_static_png_visualize(
34 samples: &[i16],
35 channels: Channels,
36 directory: &str,
37 filename: &str,
38) {
39 let image_width = 1500;
40 let image_height = 200;
41 if channels.is_stereo() {
42 assert_eq!(
43 0,
44 samples.len() % 2,
45 "If stereo is provided, the length of the audio data must be even!"
46 );
47 let (left, right) = channels.stereo_interleavement().to_channel_data(samples);
48 waveform_static_png_visualize(
49 &left,
50 Channels::Mono,
51 directory,
52 &format!("left_{}", filename),
53 );
54 waveform_static_png_visualize(
55 &right,
56 Channels::Mono,
57 directory,
58 &format!("right_{}", filename),
59 );
60 return;
61 }
62
63 let width_per_sample = image_width as f64 / samples.len() as f64;
65 let height_per_max_amplitude = image_height as f64 / 2_f64 / i16::max_value() as f64;
67
68 let mut image = vec![vec![(255, 255, 255); image_width]; image_height];
70 for (sample_index, sample_value) in samples.iter().enumerate() {
71 let x = (sample_index as f64 * width_per_sample) as usize;
73 let sample_value = *sample_value as f64 * -1.0; let mut y = ((image_height / 2) as f64 + sample_value * height_per_max_amplitude) as usize;
77
78 if y == image_height {
80 y -= 1;
81 }
82
83 image[y][x] = (0, 0, 0);
84 }
85
86 let mut path = PathBuf::new();
87 path.push(directory);
88 path.push(filename);
89 write_png_file_rgb_tuples(&path, &image);
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::tests::testutil::{TEST_OUT_DIR, TEST_SAMPLES_DIR};
96 use crate::ChannelInterleavement;
97 use minimp3::{Decoder as Mp3Decoder, Error as Mp3Error, Frame as Mp3Frame};
98 use std::fs::File;
99
100 #[test]
102 fn test_no_out_of_bounds_panic() {
103 let audio_data = vec![i16::MAX, i16::MIN];
104 waveform_static_png_visualize(
105 &audio_data,
106 Channels::Mono,
107 TEST_OUT_DIR,
108 "sample_1_waveform-test-out-of-bounds-check.png",
109 );
110 }
111
112 #[test]
113 fn test_visualize_png_output() {
114 let mut path = PathBuf::new();
115 path.push(TEST_SAMPLES_DIR);
116 path.push("sample_1.mp3");
117 let mut decoder = Mp3Decoder::new(File::open(path).unwrap());
118
119 let mut lrlr_mp3_samples = vec![];
120 loop {
121 match decoder.next_frame() {
122 Ok(Mp3Frame {
123 data: samples_of_frame,
124 ..
125 }) => {
126 for sample in samples_of_frame {
127 lrlr_mp3_samples.push(sample);
128 }
129 }
130 Err(Mp3Error::Eof) => break,
131 Err(e) => panic!("{:?}", e),
132 }
133 }
134
135 waveform_static_png_visualize(
136 &lrlr_mp3_samples,
137 Channels::Stereo(ChannelInterleavement::LRLR),
138 TEST_OUT_DIR,
139 "waveform_static_png_visualize_example.png",
140 );
141 }
142}