audio_visualizer/spectrum/
plotters_png_file.rs

1//! Static spectrum analysis: print spectrum to PNG file.
2
3use plotters::prelude::*;
4use std::collections::BTreeMap;
5use std::fs;
6use std::path::PathBuf;
7
8pub fn spectrum_static_plotters_png_visualize(
9    frequency_spectrum: &BTreeMap<u32, f32>,
10    directory: &str,
11    filename: &str,
12) {
13    // assert no NAN
14    assert!(
15        !frequency_spectrum.iter().any(|(_, f)| f.is_nan()),
16        "There are NAN-values in the spectrum!"
17    );
18
19    // find maximum for graphics scaling
20    let mut max = 0.0;
21    for mag in frequency_spectrum.values() {
22        if *mag > max {
23            max = *mag;
24        }
25    }
26
27    let max_frequency = *frequency_spectrum
28        .iter()
29        .skip(frequency_spectrum.len() - 2)
30        .last()
31        .unwrap()
32        .0;
33
34    if !fs::exists(directory).unwrap() {
35        fs::create_dir(directory).unwrap();
36    }
37    let mut path = PathBuf::new();
38    path.push(directory);
39    path.push(filename);
40
41    let mut width = frequency_spectrum.len() as u32;
42    if width < 700 {
43        width = 700;
44    }
45
46    let height = if width < 700 {
47        (width as f32 / 0.8) as u32
48    } else {
49        700
50    };
51
52    let root = BitMapBackend::new(&path, (width, height)).into_drawing_area();
53    root.fill(&WHITE).unwrap();
54    let mut chart = ChartBuilder::on(&root)
55        .caption("y=f magnitudes of sample", ("sans-serif", 20).into_font())
56        .margin(5)
57        .x_label_area_size(60)
58        .y_label_area_size(60)
59        .build_cartesian_2d(0.0..(max_frequency as f32) /*.log10()*/, 0.0..max)
60        .unwrap();
61
62    chart.configure_mesh().draw().unwrap();
63
64    chart
65        .draw_series(LineSeries::new(
66            // (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
67            frequency_spectrum
68                .iter()
69                .map(|(frequency, magnitude)| ((*frequency as f32) /*.log10()*/, *magnitude)),
70            &RED,
71        ))
72        .unwrap()
73        .label("frequency magnitude")
74        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));
75
76    chart
77        .configure_series_labels()
78        .background_style(WHITE.mix(0.8))
79        .border_style(BLACK)
80        .draw()
81        .unwrap();
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::tests::testutil::TEST_OUT_DIR;
88
89    #[test]
90    fn test_visualize_sine_waves_spectrum_plotters() {
91        let mut spectrum = BTreeMap::new();
92        spectrum.insert(0, 0.0);
93        spectrum.insert(10, 5.0);
94        spectrum.insert(20, 20.0);
95        spectrum.insert(30, 40.0);
96        spectrum.insert(40, 80.0);
97        spectrum.insert(50, 120.0);
98        spectrum.insert(55, 130.0);
99        spectrum.insert(60, 140.0);
100        spectrum.insert(65, 130.0);
101        spectrum.insert(70, 120.0);
102        spectrum.insert(80, 80.0);
103        spectrum.insert(90, 40.0);
104        spectrum.insert(100, 20.0);
105        spectrum.insert(110, 5.0);
106        spectrum.insert(120, 0.0);
107        spectrum.insert(130, 0.0);
108
109        spectrum_static_plotters_png_visualize(
110            &spectrum,
111            TEST_OUT_DIR,
112            "spectrum_60hz_peak_plotters_visualization.png",
113        );
114    }
115
116    #[allow(non_snake_case)]
117    #[test]
118    #[should_panic]
119    fn test_panic_on_NAN() {
120        let mut spectrum = BTreeMap::new();
121        spectrum.insert(0, f32::NAN);
122
123        spectrum_static_plotters_png_visualize(
124            &spectrum,
125            TEST_OUT_DIR,
126            "spectrum_60hz_peak_plotters_visualization_NAN.png",
127        );
128    }
129}