From 4065e875969698b796a71f2986f462322ca7adf5 Mon Sep 17 00:00:00 2001 From: Bastian Hentschel Date: Thu, 7 Sep 2023 13:13:25 +0200 Subject: [PATCH 1/4] added elapsed duration to (looped)decoder --- src/decoder/mod.rs | 170 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 30 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index ae5f4311..5cddd1b9 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -7,9 +7,11 @@ use std::io::{Read, Seek, SeekFrom}; use std::marker::Sync; use std::mem; use std::str::FromStr; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; use std::time::Duration; -use crate::Source; +use crate::{Sample, Source}; #[cfg(feature = "symphonia")] use self::read_seek_source::ReadSeekSource; @@ -32,13 +34,21 @@ mod wav; /// Source of audio samples from decoding a file. /// /// Supports MP3, WAV, Vorbis and Flac. -pub struct Decoder(DecoderImpl) +pub struct Decoder where - R: Read + Seek; + R: Read + Seek, +{ + decoder: DecoderImpl, + info: Arc, +} -pub struct LoopedDecoder(DecoderImpl) +pub struct LoopedDecoder where - R: Read + Seek; + R: Read + Seek, +{ + decoder: DecoderImpl, + info: Arc, +} enum DecoderImpl where @@ -54,7 +64,50 @@ where Mp3(mp3::Mp3Decoder), #[cfg(feature = "symphonia")] Symphonia(symphonia::SymphoniaDecoder), - None(::std::marker::PhantomData), + None(std::marker::PhantomData), +} + +pub struct DecoderInfo { + channels: u16, + sample_rate: u32, + pub(crate) samples_elapsed: AtomicUsize, +} + +impl DecoderInfo { + fn from_source(source: &S) -> Self + where + S: Source, + S::Item: Sample, + { + Self { + channels: source.channels(), + sample_rate: source.sample_rate(), + samples_elapsed: AtomicUsize::default(), + } + } + + #[inline] + pub fn channels(&self) -> u16 { + self.channels + } + + #[inline] + pub fn sample_rate(&self) -> u32 { + self.sample_rate + } + + #[inline] + pub fn elapsed_samples(&self) -> usize { + self.samples_elapsed.load(Ordering::Relaxed) + } + + #[inline] + pub fn elapsed_duration(&self) -> Option { + Duration::try_from_secs_f64( + self.elapsed_samples() as f64 / self.sample_rate() as f64 / self.channels() as f64, + ) + .ok() + } } impl Decoder @@ -70,7 +123,11 @@ where let data = match wav::WavDecoder::new(data) { Err(data) => data, Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Wav(decoder))); + let info = Arc::new(DecoderInfo::from_source(&decoder)); + return Ok(Decoder { + decoder: DecoderImpl::Wav(decoder), + info, + }); } }; @@ -78,7 +135,11 @@ where let data = match flac::FlacDecoder::new(data) { Err(data) => data, Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Flac(decoder))); + let info = Arc::new(DecoderInfo::from_source(&decoder)); + return Ok(Decoder { + decoder: DecoderImpl::Flac(decoder), + info, + }); } }; @@ -86,7 +147,11 @@ where let data = match vorbis::VorbisDecoder::new(data) { Err(data) => data, Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Vorbis(decoder))); + let info = Arc::new(DecoderInfo::from_source(&decoder)); + return Ok(Decoder { + decoder: DecoderImpl::Vorbis(decoder), + info, + }); } }; @@ -94,7 +159,10 @@ where let data = match mp3::Mp3Decoder::new(data) { Err(data) => data, Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Mp3(decoder))); + return Ok(Decoder { + decoder: DecoderImpl::Mp3(decoder), + info: Arc::new(DecoderInfo::from_source(&decoder)), + }); } }; @@ -108,7 +176,11 @@ where match symphonia::SymphoniaDecoder::new(mss, None) { Err(e) => Err(e), Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Symphonia(decoder))); + let info = Arc::new(DecoderInfo::from_source(&decoder)); + Ok(Decoder { + decoder: DecoderImpl::Symphonia(decoder), + info, + }) } } } @@ -124,7 +196,13 @@ where pub fn new_wav(data: R) -> Result, DecoderError> { match wav::WavDecoder::new(data) { Err(_) => Err(DecoderError::UnrecognizedFormat), - Ok(decoder) => Ok(Decoder(DecoderImpl::Wav(decoder))), + Ok(decoder) => { + let info = Arc::new(DecoderInfo::from_source(&decoder)); + Ok(Decoder { + decoder: DecoderImpl::Wav(decoder), + info, + }) + } } } @@ -139,7 +217,13 @@ where pub fn new_flac(data: R) -> Result, DecoderError> { match flac::FlacDecoder::new(data) { Err(_) => Err(DecoderError::UnrecognizedFormat), - Ok(decoder) => Ok(Decoder(DecoderImpl::Flac(decoder))), + Ok(decoder) => { + let info = Arc::new(DecoderInfo::from_source(&decoder)); + Ok(Decoder { + decoder: DecoderImpl::Flac(decoder), + info, + }) + } } } @@ -154,7 +238,13 @@ where pub fn new_vorbis(data: R) -> Result, DecoderError> { match vorbis::VorbisDecoder::new(data) { Err(_) => Err(DecoderError::UnrecognizedFormat), - Ok(decoder) => Ok(Decoder(DecoderImpl::Vorbis(decoder))), + Ok(decoder) => { + let info = Arc::new(DecoderInfo::from_source(&decoder)); + Ok(Decoder { + decoder: DecoderImpl::Vorbis(decoder), + info, + }) + } } } @@ -163,7 +253,10 @@ where pub fn new_mp3(data: R) -> Result, DecoderError> { match mp3::Mp3Decoder::new(data) { Err(_) => Err(DecoderError::UnrecognizedFormat), - Ok(decoder) => Ok(Decoder(DecoderImpl::Mp3(decoder))), + Ok(decoder) => Ok(Decoder { + decoder: DecoderImpl::Mp3(decoder), + info: Arc::new(DecoderInfo::from_source(&decoder)), + }), } } @@ -195,10 +288,18 @@ where match symphonia::SymphoniaDecoder::new(mss, Some(hint)) { Err(e) => Err(e), Ok(decoder) => { - return Ok(Decoder(DecoderImpl::Symphonia(decoder))); + let info = Arc::new(DecoderInfo::from_source(&decoder)); + Ok(Decoder { + decoder: DecoderImpl::Symphonia(decoder), + info, + }) } } } + + pub fn get_info(&self) -> Arc { + self.info.clone() + } } #[derive(Debug)] @@ -249,7 +350,10 @@ where R: Read + Seek, { fn new(decoder: Decoder) -> LoopedDecoder { - Self(decoder.0) + Self { + decoder: decoder.decoder, + info: decoder.info, + } } } @@ -261,7 +365,7 @@ where #[inline] fn next(&mut self) -> Option { - match &mut self.0 { + if let Some(sample) = match &mut self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.next(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -273,12 +377,17 @@ where #[cfg(feature = "symphonia")] DecoderImpl::Symphonia(source) => source.next(), DecoderImpl::None(_) => None, + } { + self.info.samples_elapsed.fetch_add(1, Ordering::Relaxed); + Some(sample) + } else { + None } } #[inline] fn size_hint(&self) -> (usize, Option) { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.size_hint(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -300,7 +409,7 @@ where { #[inline] fn current_frame_len(&self) -> Option { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.current_frame_len(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -317,7 +426,7 @@ where #[inline] fn channels(&self) -> u16 { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.channels(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -334,7 +443,7 @@ where #[inline] fn sample_rate(&self) -> u32 { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.sample_rate(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -351,7 +460,7 @@ where #[inline] fn total_duration(&self) -> Option { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.total_duration(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -375,7 +484,7 @@ where #[inline] fn next(&mut self) -> Option { - if let Some(sample) = match &mut self.0 { + if let Some(sample) = match &mut self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.next(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -388,9 +497,10 @@ where DecoderImpl::Symphonia(source) => source.next(), DecoderImpl::None(_) => None, } { + self.info.samples_elapsed.fetch_add(1, Ordering::Relaxed); Some(sample) } else { - let decoder = mem::replace(&mut self.0, DecoderImpl::None(Default::default())); + let decoder = mem::replace(&mut self.decoder, DecoderImpl::None(Default::default())); let (decoder, sample) = match decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => { @@ -437,14 +547,14 @@ where } none @ DecoderImpl::None(_) => (none, None), }; - self.0 = decoder; + self.decoder = decoder; sample } } #[inline] fn size_hint(&self) -> (usize, Option) { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => (source.size_hint().0, None), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -466,7 +576,7 @@ where { #[inline] fn current_frame_len(&self) -> Option { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.current_frame_len(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -483,7 +593,7 @@ where #[inline] fn channels(&self) -> u16 { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.channels(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] @@ -500,7 +610,7 @@ where #[inline] fn sample_rate(&self) -> u32 { - match &self.0 { + match &self.decoder { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.sample_rate(), #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))] From 2d3b41fc846b842b6c8fd2decd5df30446ad7027 Mon Sep 17 00:00:00 2001 From: Bastian Hentschel Date: Thu, 7 Sep 2023 13:13:53 +0200 Subject: [PATCH 2/4] added example for elapsed duration usage --- examples/sample_count.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 examples/sample_count.rs diff --git a/examples/sample_count.rs b/examples/sample_count.rs new file mode 100644 index 00000000..5503ddc0 --- /dev/null +++ b/examples/sample_count.rs @@ -0,0 +1,16 @@ +use std::fs::File; +use std::io::BufReader; +use rodio::Decoder; + +fn main() { + let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap(); + + let file = BufReader::new(File::open("assets/music.flac").unwrap()); + let decoder = Decoder::new(file).unwrap(); + let info = decoder.get_info(); + let sink = rodio::Sink::try_new(&stream_handle).unwrap(); + sink.append(decoder); + while sink.len() > 0 { + println!("Elapsed Duration: {:?}", info.elapsed_duration().unwrap()); + } +} From 48510081ce4403b756830390dd135e4f59385b27 Mon Sep 17 00:00:00 2001 From: Bastian Hentschel Date: Thu, 7 Sep 2023 13:22:26 +0200 Subject: [PATCH 3/4] removed unneeded pub(crate) from previous commits --- src/decoder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 5cddd1b9..50d0e53d 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -70,7 +70,7 @@ where pub struct DecoderInfo { channels: u16, sample_rate: u32, - pub(crate) samples_elapsed: AtomicUsize, + samples_elapsed: AtomicUsize, } impl DecoderInfo { From f2fa025eaf7240ee74221789737b2f10ef9307b1 Mon Sep 17 00:00:00 2001 From: Bastian Hentschel Date: Thu, 7 Sep 2023 13:33:02 +0200 Subject: [PATCH 4/4] rustfmt --- examples/sample_count.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sample_count.rs b/examples/sample_count.rs index 5503ddc0..e98470a5 100644 --- a/examples/sample_count.rs +++ b/examples/sample_count.rs @@ -1,6 +1,6 @@ +use rodio::Decoder; use std::fs::File; use std::io::BufReader; -use rodio::Decoder; fn main() { let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();