audio-visualizer 0.5.0

Simple audio visualization library which is especially useful for developers to visually check audio samples, e.g. by waveform or spectrum. (So far) this library is not capable of doing nice visualizations for end users.
Documentation
//! Static spectrum analysis: print spectrum to PNG file.

use plotters::prelude::*;
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;

pub fn spectrum_static_plotters_png_visualize(
    frequency_spectrum: &BTreeMap<u32, f32>,
    directory: &str,
    filename: &str,
) {
    // assert no NAN
    assert!(
        !frequency_spectrum.iter().any(|(_, f)| f.is_nan()),
        "There are NAN-values in the spectrum!"
    );

    // find maximum for graphics scaling
    let mut max = 0.0;
    for mag in frequency_spectrum.values() {
        if *mag > max {
            max = *mag;
        }
    }

    let max_frequency = *frequency_spectrum
        .iter()
        .skip(frequency_spectrum.len() - 2)
        .last()
        .unwrap()
        .0;

    if !fs::exists(directory).unwrap() {
        fs::create_dir(directory).unwrap();
    }
    let mut path = PathBuf::new();
    path.push(directory);
    path.push(filename);

    let mut width = frequency_spectrum.len() as u32;
    if width < 700 {
        width = 700;
    }

    let height = if width < 700 {
        (width as f32 / 0.8) as u32
    } else {
        700
    };

    let root = BitMapBackend::new(&path, (width, height)).into_drawing_area();
    root.fill(&WHITE).unwrap();
    let mut chart = ChartBuilder::on(&root)
        .caption("y=f magnitudes of sample", ("sans-serif", 20).into_font())
        .margin(5)
        .x_label_area_size(60)
        .y_label_area_size(60)
        .build_cartesian_2d(0.0..(max_frequency as f32) /*.log10()*/, 0.0..max)
        .unwrap();

    chart.configure_mesh().draw().unwrap();

    chart
        .draw_series(LineSeries::new(
            // (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
            frequency_spectrum
                .iter()
                .map(|(frequency, magnitude)| ((*frequency as f32) /*.log10()*/, *magnitude)),
            &RED,
        ))
        .unwrap()
        .label("frequency magnitude")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));

    chart
        .configure_series_labels()
        .background_style(WHITE.mix(0.8))
        .border_style(BLACK)
        .draw()
        .unwrap();
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::testutil::TEST_OUT_DIR;

    #[test]
    fn test_visualize_sine_waves_spectrum_plotters() {
        let mut spectrum = BTreeMap::new();
        spectrum.insert(0, 0.0);
        spectrum.insert(10, 5.0);
        spectrum.insert(20, 20.0);
        spectrum.insert(30, 40.0);
        spectrum.insert(40, 80.0);
        spectrum.insert(50, 120.0);
        spectrum.insert(55, 130.0);
        spectrum.insert(60, 140.0);
        spectrum.insert(65, 130.0);
        spectrum.insert(70, 120.0);
        spectrum.insert(80, 80.0);
        spectrum.insert(90, 40.0);
        spectrum.insert(100, 20.0);
        spectrum.insert(110, 5.0);
        spectrum.insert(120, 0.0);
        spectrum.insert(130, 0.0);

        spectrum_static_plotters_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_plotters_visualization.png",
        );
    }

    #[allow(non_snake_case)]
    #[test]
    #[should_panic]
    fn test_panic_on_NAN() {
        let mut spectrum = BTreeMap::new();
        spectrum.insert(0, f32::NAN);

        spectrum_static_plotters_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_plotters_visualization_NAN.png",
        );
    }
}