#![deny(
clippy::all,
clippy::cargo,
clippy::nursery,
// clippy::restriction,
// clippy::pedantic
)]
#![allow(
clippy::suboptimal_flops,
clippy::redundant_pub_crate,
clippy::fallible_impl_from
)]
#![deny(missing_debug_implementations)]
#![deny(rustdoc::all)]
use audio_visualizer::spectrum::plotters_png_file::spectrum_static_plotters_png_visualize;
use minimp3::{Decoder as Mp3Decoder, Error as Mp3Error, Frame as Mp3Frame};
use spectrum_analyzer::scaling::scale_to_zero_to_one;
use spectrum_analyzer::windows::{blackman_harris_4term, hamming_window, hann_window};
use spectrum_analyzer::{samples_fft_to_spectrum, FrequencyLimit};
use std::fs::File;
use std::time::Instant;
const TEST_OUT_DIR: &str = "test/out";
fn main() {
println!("bass drum example:");
example__bass_drum_sample();
println!("============================");
println!("clap beat example:");
example__clap_beat_sample();
println!("============================");
println!("high hat example:");
example__high_hat_sample();
}
#[allow(non_snake_case)]
fn example__bass_drum_sample() {
let (samples, sampling_rate) =
read_mp3_to_mono("test/samples/bass_drum_with_high-hat_at_end-sample.mp3");
let samples = samples.into_iter().map(|x| x as f32).collect::<Vec<f32>>();
to_spectrum_and_plot(
&samples[0..4096],
sampling_rate,
"example__mp3-samples__bass_drum__spectrum",
FrequencyLimit::Max(5000.0),
)
}
#[allow(non_snake_case)]
fn example__clap_beat_sample() {
let (samples, sampling_rate) = read_mp3_to_mono("test/samples/clap-beat-sample.mp3");
let samples = samples.into_iter().map(|x| x as f32).collect::<Vec<f32>>();
to_spectrum_and_plot(
&samples[0..4096],
sampling_rate,
"example__mp3-samples__clap_beat__spectrum",
FrequencyLimit::Max(5000.0),
)
}
#[allow(non_snake_case)]
fn example__high_hat_sample() {
let (samples, sampling_rate) = read_mp3_to_mono("test/samples/high-hat-sample.mp3");
let samples = samples.into_iter().map(|x| x as f32).collect::<Vec<f32>>();
to_spectrum_and_plot(
&samples[0..4096],
sampling_rate,
"example__mp3-samples__high-hat__spectrum",
FrequencyLimit::All,
)
}
fn to_spectrum_and_plot(
samples: &[f32],
sampling_rate: u32,
filename: &str,
frequency_limit: FrequencyLimit,
) {
let no_window = samples;
let now = Instant::now();
let hann_window = hann_window(no_window);
println!(
"[Measurement]: Hann-Window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let now = Instant::now();
let hamming_window = hamming_window(no_window);
println!(
"[Measurement]: Hamming-Window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let blackman_harris_4term_window = blackman_harris_4term(no_window);
println!(
"[Measurement]: Blackmann-Harris-4-term-Window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let blackman_harris_7term_window = blackman_harris_4term(no_window);
println!(
"[Measurement]: Blackmann-Harris-7-term-Window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let now = Instant::now();
let spectrum_no_window = samples_fft_to_spectrum(
no_window,
sampling_rate,
frequency_limit,
Some(&scale_to_zero_to_one),
)
.unwrap();
println!(
"[Measurement]: FFT to Spectrum with no window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let now = Instant::now();
let spectrum_hamming_window = samples_fft_to_spectrum(
&hamming_window,
sampling_rate,
frequency_limit,
Some(&scale_to_zero_to_one),
)
.unwrap();
println!(
"[Measurement]: FFT to Spectrum with Hamming window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let now = Instant::now();
let spectrum_hann_window = samples_fft_to_spectrum(
&hann_window,
sampling_rate,
frequency_limit,
Some(&scale_to_zero_to_one),
)
.unwrap();
println!(
"[Measurement]: FFT to Spectrum with Hann window with {} samples took: {}µs",
samples.len(),
now.elapsed().as_micros()
);
let now = Instant::now();
let spectrum_blackman_harris_4term_window = samples_fft_to_spectrum(
&blackman_harris_4term_window,
sampling_rate,
frequency_limit,
Some(&scale_to_zero_to_one),
)
.unwrap();
println!("[Measurement]: FFT to Spectrum with Blackmann Harris 4-term window with {} samples took: {}µs", samples.len(), now.elapsed().as_micros());
let now = Instant::now();
let spectrum_blackman_harris_7term_window = samples_fft_to_spectrum(
&blackman_harris_7term_window,
sampling_rate,
frequency_limit,
Some(&scale_to_zero_to_one),
)
.unwrap();
println!("[Measurement]: FFT to Spectrum with Blackmann Harris 7-term window with {} samples took: {}µs", samples.len(), now.elapsed().as_micros());
spectrum_static_plotters_png_visualize(
&spectrum_no_window.to_map(None),
TEST_OUT_DIR,
&format!("{}--no-window.png", filename),
);
spectrum_static_plotters_png_visualize(
&spectrum_hamming_window.to_map(None),
TEST_OUT_DIR,
&format!("{}--hamming-window.png", filename),
);
spectrum_static_plotters_png_visualize(
&spectrum_hann_window.to_map(None),
TEST_OUT_DIR,
&format!("{}--hann-window.png", filename),
);
spectrum_static_plotters_png_visualize(
&spectrum_blackman_harris_4term_window.to_map(None),
TEST_OUT_DIR,
&format!("{}--blackman-harris-4-term-window.png", filename),
);
spectrum_static_plotters_png_visualize(
&spectrum_blackman_harris_7term_window.to_map(None),
TEST_OUT_DIR,
&format!("{}--blackman-harris-7-term-window.png", filename),
);
}
fn read_mp3_to_mono(file: &str) -> (Vec<i16>, u32) {
let mut decoder = Mp3Decoder::new(File::open(file).unwrap());
let mut sampling_rate = 0;
let mut mono_samples = vec![];
loop {
match decoder.next_frame() {
Ok(Mp3Frame {
data: samples_of_frame,
sample_rate,
channels,
..
}) => {
sampling_rate = sample_rate;
if channels == 2 {
for (i, sample) in samples_of_frame.iter().enumerate().step_by(2) {
let sample = *sample as i32;
let next_sample = samples_of_frame[i + 1] as i32;
mono_samples.push(((sample + next_sample) as f32 / 2.0) as i16);
}
} else if channels == 1 {
mono_samples.extend_from_slice(&samples_of_frame);
} else {
panic!("Unsupported number of channels={}", channels);
}
}
Err(Mp3Error::Eof) => break,
Err(e) => panic!("{:?}", e),
}
}
(mono_samples, sampling_rate as u32)
}