use std::fs::File; use std::path::{Path, PathBuf}; use audio_visualizer::spectrum::plotters_png_file::spectrum_static_plotters_png_visualize; use audio_visualizer::waveform::png_file::waveform_static_png_visualize; use audio_visualizer::{ChannelInterleavement, Channels}; use lowpass_filter::lowpass_filter; use minimp3::{Decoder as Mp3Decoder, Error as Mp3Error, Frame as Mp3Frame}; use spectrum_analyzer::scaling::scale_to_zero_to_one; use spectrum_analyzer::windows::hann_window; use spectrum_analyzer::{samples_fft_to_spectrum, FrequencyLimit}; use wav::{BitDepth, Header}; /// Takes a path to an mp3 as first argument, /// applies a low pass filter n times (second argument) /// and stores the file with suffix "_lowpassed" as wav file /// (because yet there is no mp3 encoding crate). fn main() { let env = std::env::args().collect::>(); let path = env.get(1).map(PathBuf::from).expect("Must provide path!"); let times = env .get(2) .map(|s| s.parse().expect("Must be valid number")) .unwrap_or(1); // READ MP3 and split into left and right channel let (lrlr_mp3_samples, mp3_sample_rate) = mp3_to_lrlr_audio(path.as_path()); let (left, right) = Channels::Stereo(ChannelInterleavement::LRLR) .stereo_interleavement() .to_channel_data(&lrlr_mp3_samples); let mut left = left.into_iter().map(|x| x as f32).collect::>(); let mut right = right.into_iter().map(|x| x as f32).collect::>(); // STORE SPECTRUM AS FILE BEFORE LPF samples_to_spectrum_and_plot(&left, mp3_sample_rate, "mp3-original-spectrum.png"); waveform_static_png_visualize( &left.iter().map(|x| *x as i16).collect::>(), Channels::Mono, "test/out", "mp3-original-waveform--left.png", ); waveform_static_png_visualize( &right.iter().map(|x| *x as i16).collect::>(), Channels::Mono, "test/out", "mp3-original-waveform--right.png", ); // APPLY LPF n TIMES for _ in 0..times { // left lowpass_filter(&mut left, mp3_sample_rate, 120.0); // right lowpass_filter(&mut right, mp3_sample_rate, 120.0); } // STORE DATA AS WAV store_data_as_wav(&left, &right, path.as_path(), mp3_sample_rate); // STORE SPECTRUM AS FILE AFTER LPF samples_to_spectrum_and_plot(&left, mp3_sample_rate, "mp3-lowpassed-spectrum.png"); waveform_static_png_visualize( &left.iter().map(|x| *x as i16).collect::>(), Channels::Mono, "test/out", "mp3-lowpassed-waveform--left.png", ); waveform_static_png_visualize( &right.iter().map(|x| *x as i16).collect::>(), Channels::Mono, "test/out", "mp3-lowpassed-waveform--right.png", ); } /// Reads the mp3 to a vector of the decoded LRLR (left, right, left, right) /// data. Second return value is the sampling rate. fn mp3_to_lrlr_audio(path: &Path) -> (Vec, f32) { let mut decoder = Mp3Decoder::new(File::open(&path).unwrap()); let mut lrlr_mp3_samples = vec![]; let mut mp3_sample_rate = None; loop { match decoder.next_frame() { Ok(Mp3Frame { data: samples_of_frame, sample_rate, .. }) => { if mp3_sample_rate.is_none() { mp3_sample_rate.replace(sample_rate as f32); } for sample in samples_of_frame { lrlr_mp3_samples.push(sample); } } Err(Mp3Error::Eof) => break, Err(e) => panic!("{:?}", e), } } (lrlr_mp3_samples, mp3_sample_rate.unwrap()) } fn samples_to_spectrum_and_plot(audio_data: &[f32], sampling_rate: f32, filename: &str) { let exponent = (audio_data.len() as f32).log2().floor(); let fft_len = 2.0_f32.powf(exponent) as usize; let samples_for_spectrum = hann_window(&audio_data[0..fft_len]); let original_spectrum = samples_fft_to_spectrum( &samples_for_spectrum, sampling_rate as u32, FrequencyLimit::Max(5000.0), Some(&scale_to_zero_to_one), ) .unwrap(); spectrum_static_plotters_png_visualize(&original_spectrum.to_map(None), "test/out", filename); } fn store_data_as_wav(left_audio: &[f32], right_audio: &[f32], path: &Path, sample_rate: f32) { let mut stereo_lrlr_data = Vec::with_capacity(left_audio.len() * 2); for i in 0..left_audio.len() { stereo_lrlr_data.push(left_audio[i] as i16); stereo_lrlr_data.push(right_audio[i] as i16); } let original_filename = path.file_name().unwrap().to_str().unwrap(); let new_path = path.with_file_name(&format!("{}--lowpassed.wav", original_filename)); let mut out_file = File::create(Path::new(&new_path)).unwrap(); wav::write( Header::new(0x01, 2, sample_rate as u32, 16), &BitDepth::Sixteen(stereo_lrlr_data), &mut out_file, ) .unwrap(); }