use std::{fs::File, path::PathBuf}; use clap::{Parser, Subcommand, ValueEnum}; use symphonia::core::{audio::SampleBuffer, codecs::DecoderOptions, formats::FormatOptions, io::MediaSourceStream, meta::MetadataOptions, probe::Hint}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] enum Backend { Jack, Alsa, Pulseaudio, Coreaudio, } #[derive(Parser)] #[command(version, about, long_about = None)] struct Cli { name: Option, #[arg(short, long, value_enum)] backend: Option, #[arg(short, long)] track: Option>, } fn main() { let cli = Cli::parse(); // You can check the value provided by positional arguments, or option arguments // Read the track from the tracks into the buffer if let Some(files) = cli.track { for file in files { read_audio_file(file); } } if let Some(backend) = cli.backend { match backend { Backend::Jack => println!("jack"), Backend::Alsa => println!("alsa"), Backend::Pulseaudio => println!("pulse"), Backend::Coreaudio => println!("coreaudio"), } } } fn read_audio_file(file: String) { let file = Box::new(File::open(file).unwrap()); let mss = MediaSourceStream::new(file, Default::default()); let mut hint = Hint::new(); hint.with_extension("mp3"); let format_opts: FormatOptions = Default::default(); let metadata_opts: MetadataOptions = Default::default(); let decoder_opts: DecoderOptions = Default::default(); let probed = symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts).unwrap(); // Get the format reader yielded by the probe operation. let mut format = probed.format; // Get the default track. let track = format.default_track().unwrap(); // Create a decoder for the track. let mut decoder = symphonia::default::get_codecs().make(&track.codec_params, &decoder_opts).unwrap(); // Store the track identifier, we'll use it to filter packets. let track_id = track.id; let mut sample_count = 0; let mut sample_buf = None; loop { // Get the next packet from the format reader. let packet = format.next_packet().unwrap(); // If the packet does not belong to the selected track, skip it. if packet.track_id() != track_id { continue; } // Decode the packet into audio samples, ignoring any decode errors. match decoder.decode(&packet) { Ok(audio_buf) => { // The decoded audio samples may now be accessed via the audio buffer if per-channel // slices of samples in their native decoded format is desired. Use-cases where // the samples need to be accessed in an interleaved order or converted into // another sample format, or a byte buffer is required, are covered by copying the // audio buffer into a sample buffer or raw sample buffer, respectively. In the // example below, we will copy the audio buffer into a sample buffer in an // interleaved order while also converting to a f32 sample format. // If this is the *first* decoded packet, create a sample buffer matching the // decoded audio buffer format. if sample_buf.is_none() { // Get the audio buffer specification. let spec = *audio_buf.spec(); // Get the capacity of the decoded buffer. Note: This is capacity, not length! let duration = audio_buf.capacity() as u64; // Create the f32 sample buffer. sample_buf = Some(SampleBuffer::::new(duration, spec)); } // Copy the decoded audio buffer into the sample buffer in an interleaved format. if let Some(buf) = &mut sample_buf { buf.copy_interleaved_ref(audio_buf); // The samples may now be access via the `samples()` function. sample_count += buf.samples().len(); print!("\rDecoded {} samples", sample_count); } } Err(symphonia::core::errors::Error::DecodeError(_)) => (), Err(_) => break, } } } pub struct DecodedAudio { pub samples: Vec, // interleaved pub sample_rate: u32, pub channels: u16, }