mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 14:14:21 +00:00
Add LoopedDecoder
LoopedDecoder works like the normal Decoder, but when the decoder reaches the end of file it will restart playback from the beginning. This has the advantage over Decoder::new().repeat_infinite() that it will not buffer the entire uncompressed audio file into memory. Update minimp3 to version 0.5 to use the `into_iter()` method
This commit is contained in:
parent
a80a90bae5
commit
95317f9b88
6 changed files with 170 additions and 5 deletions
|
@ -14,7 +14,7 @@ cpal = "0.12"
|
|||
claxon = { version = "0.4.2", optional = true }
|
||||
hound = { version = "3.3.1", optional = true }
|
||||
lewton = { version = "0.10", optional = true }
|
||||
minimp3 = { version = "0.3.2", optional = true }
|
||||
minimp3 = { version = "0.5.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["flac", "vorbis", "wav", "mp3"]
|
||||
|
|
|
@ -47,6 +47,9 @@ where
|
|||
samples: spec.samples,
|
||||
})
|
||||
}
|
||||
pub fn into_inner(self) -> R {
|
||||
self.reader.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Source for FlacDecoder<R>
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::fmt;
|
|||
use std::io::{Read, Seek};
|
||||
#[allow(unused_imports)]
|
||||
use std::io::SeekFrom;
|
||||
use std::mem;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::Source;
|
||||
|
@ -25,6 +26,10 @@ pub struct Decoder<R>(DecoderImpl<R>)
|
|||
where
|
||||
R: Read + Seek;
|
||||
|
||||
pub struct LoopedDecoder<R>(DecoderImpl<R>)
|
||||
where
|
||||
R: Read + Seek;
|
||||
|
||||
enum DecoderImpl<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
@ -83,6 +88,18 @@ where
|
|||
|
||||
Err(DecoderError::UnrecognizedFormat)
|
||||
}
|
||||
pub fn new_looped(data: R) -> Result<LoopedDecoder<R>, DecoderError> {
|
||||
Self::new(data).map(LoopedDecoder::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> LoopedDecoder<R>
|
||||
where
|
||||
R: Read + Seek + Send + 'static,
|
||||
{
|
||||
fn new(decoder: Decoder<R>) -> LoopedDecoder<R> {
|
||||
Self(decoder.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Iterator for Decoder<R>
|
||||
|
@ -187,6 +204,140 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> Iterator for LoopedDecoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
type Item = i16;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<i16> {
|
||||
if let Some(sample) = match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref mut source) => source.next(),
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref mut source) => source.next(),
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref mut source) => source.next(),
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref mut source) => source.next(),
|
||||
DecoderImpl::None(_) => None,
|
||||
} {
|
||||
Some(sample)
|
||||
} else {
|
||||
let decoder = mem::replace(&mut self.0, DecoderImpl::None(Default::default()));
|
||||
let (decoder, sample) = match decoder {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(source) => {
|
||||
let mut reader = source.into_inner();
|
||||
reader.seek(SeekFrom::Start(0)).ok()?;
|
||||
let mut source = wav::WavDecoder::new(reader).ok()?;
|
||||
let sample = source.next();
|
||||
(DecoderImpl::Wav(source), sample)
|
||||
}
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(source) => {
|
||||
use lewton::inside_ogg::OggStreamReader;
|
||||
let mut reader = source.into_inner().into_inner();
|
||||
reader.seek_bytes(SeekFrom::Start(0)).ok()?;
|
||||
let mut source = vorbis::VorbisDecoder::from_stream_reader(OggStreamReader::from_ogg_reader(reader).ok()?);
|
||||
let sample = source.next();
|
||||
(DecoderImpl::Vorbis(source), sample)
|
||||
}
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(source) => {
|
||||
let mut reader = source.into_inner();
|
||||
reader.seek(SeekFrom::Start(0)).ok()?;
|
||||
let mut source = flac::FlacDecoder::new(reader).ok()?;
|
||||
let sample = source.next();
|
||||
(DecoderImpl::Flac(source), sample)
|
||||
}
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(source) => {
|
||||
let mut reader = source.into_inner();
|
||||
reader.seek(SeekFrom::Start(0)).ok()?;
|
||||
let mut source = mp3::Mp3Decoder::new(reader).ok()?;
|
||||
let sample = source.next();
|
||||
(DecoderImpl::Mp3(source), sample)
|
||||
}
|
||||
none @ DecoderImpl::None(_) => (none, None)
|
||||
};
|
||||
self.0 = decoder;
|
||||
sample
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref source) => (source.size_hint().0, None),
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref source) => (source.size_hint().0, None),
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref source) => (source.size_hint().0, None),
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref source) => (source.size_hint().0, None),
|
||||
DecoderImpl::None(_) => (0, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Source for LoopedDecoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
#[inline]
|
||||
fn current_frame_len(&self) -> Option<usize> {
|
||||
match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref source) => source.current_frame_len(),
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref source) => source.current_frame_len(),
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref source) => source.current_frame_len(),
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref source) => source.current_frame_len(),
|
||||
DecoderImpl::None(_) => Some(0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn channels(&self) -> u16 {
|
||||
match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref source) => source.channels(),
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref source) => source.channels(),
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref source) => source.channels(),
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref source) => source.channels(),
|
||||
DecoderImpl::None(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_rate(&self) -> u32 {
|
||||
match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref source) => source.sample_rate(),
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref source) => source.sample_rate(),
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref source) => source.sample_rate(),
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref source) => source.sample_rate(),
|
||||
DecoderImpl::None(_) => 1,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn total_duration(&self) -> Option<Duration> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when creating a decoder.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DecoderError {
|
||||
|
|
|
@ -28,6 +28,9 @@ where
|
|||
current_frame_offset: 0,
|
||||
})
|
||||
}
|
||||
pub fn into_inner(self) -> R {
|
||||
self.decoder.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Source for Mp3Decoder<R>
|
||||
|
|
|
@ -25,8 +25,10 @@ where
|
|||
return Err(data);
|
||||
}
|
||||
|
||||
let mut stream_reader = OggStreamReader::new(data).unwrap();
|
||||
|
||||
let stream_reader = OggStreamReader::new(data).unwrap();
|
||||
Ok(Self::from_stream_reader(stream_reader))
|
||||
}
|
||||
pub fn from_stream_reader(mut stream_reader: OggStreamReader<R>) -> Self {
|
||||
let mut data = match stream_reader.read_dec_packet_itl().ok().and_then(|v| v) {
|
||||
Some(d) => d,
|
||||
None => Vec::new(),
|
||||
|
@ -39,10 +41,13 @@ where
|
|||
None => (),
|
||||
};
|
||||
|
||||
Ok(VorbisDecoder {
|
||||
VorbisDecoder {
|
||||
stream_reader: stream_reader,
|
||||
current_data: data.into_iter(),
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn into_inner(self) -> OggStreamReader<R> {
|
||||
self.stream_reader
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ where
|
|||
channels: spec.channels,
|
||||
})
|
||||
}
|
||||
pub fn into_inner(self) -> R {
|
||||
self.reader.reader.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
struct SamplesIterator<R>
|
||||
|
|
Loading…
Reference in a new issue