mirror of
https://github.com/RustAudio/rodio
synced 2024-12-14 06:02:31 +00:00
Add Source::from_iter
This commit is contained in:
parent
138b746d12
commit
a0ea1ce433
3 changed files with 183 additions and 123 deletions
|
@ -1,7 +1,5 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use Sample;
|
||||
use Source;
|
||||
use source::from_iter;
|
||||
use source::FromIter;
|
||||
|
||||
/// Builds a source that chains sources built from a factory.
|
||||
///
|
||||
|
@ -10,138 +8,31 @@ use Source;
|
|||
/// played next.
|
||||
///
|
||||
/// If the `factory` closure returns `None`, then the sound ends.
|
||||
pub fn from_factory<F, S>(mut factory: F) -> FromFactory<F, S>
|
||||
pub fn from_factory<F, S>(factory: F) -> FromIter<FromFactoryIter<F>>
|
||||
where F: FnMut() -> Option<S>
|
||||
{
|
||||
let first_source = factory().expect("The factory returned an empty source"); // TODO: meh
|
||||
|
||||
FromFactory {
|
||||
from_iter(FromFactoryIter {
|
||||
factory: factory,
|
||||
current_source: first_source,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A source that chains sources built from a factory.
|
||||
#[derive(Clone)]
|
||||
pub struct FromFactory<F, S> {
|
||||
/// Internal type used by `from_factory`.
|
||||
pub struct FromFactoryIter<F> {
|
||||
factory: F,
|
||||
current_source: S,
|
||||
}
|
||||
|
||||
impl<F, S> Iterator for FromFactory<F, S>
|
||||
where F: FnMut() -> Option<S>,
|
||||
S: Source,
|
||||
S::Item: Sample
|
||||
impl<F, S> Iterator for FromFactoryIter<F>
|
||||
where F: FnMut() -> Option<S>
|
||||
{
|
||||
type Item = <S as Iterator>::Item;
|
||||
type Item = S;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<<S as Iterator>::Item> {
|
||||
loop {
|
||||
if let Some(value) = self.current_source.next() {
|
||||
return Some(value);
|
||||
}
|
||||
|
||||
if let Some(src) = (self.factory)() {
|
||||
self.current_source = src;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
fn next(&mut self) -> Option<S> {
|
||||
(self.factory)()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.current_source.size_hint().0, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S> Source for FromFactory<F, S>
|
||||
where F: FnMut() -> Option<S>,
|
||||
S: Iterator + Source,
|
||||
S::Item: Sample
|
||||
{
|
||||
#[inline]
|
||||
fn current_frame_len(&self) -> Option<usize> {
|
||||
// This function is non-trivial because the boundary between the current source and the
|
||||
// next must be a frame boundary as well.
|
||||
//
|
||||
// The current sound is free to return `None` for `current_frame_len()`, in which case
|
||||
// we *should* return the number of samples remaining the current sound.
|
||||
// This can be estimated with `size_hint()`.
|
||||
//
|
||||
// If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this
|
||||
// situation we force a frame to have a maximum number of samples indicate by this
|
||||
// constant.
|
||||
const THRESHOLD: usize = 10240;
|
||||
|
||||
// Try the current `current_frame_len`.
|
||||
if let Some(val) = self.current_source.current_frame_len() {
|
||||
if val != 0 {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Try the size hint.
|
||||
if let Some(val) = self.current_source.size_hint().1 {
|
||||
if val < THRESHOLD && val != 0 {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we use the constant value.
|
||||
Some(THRESHOLD)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn channels(&self) -> u16 {
|
||||
self.current_source.channels()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn samples_rate(&self) -> u32 {
|
||||
self.current_source.samples_rate()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn total_duration(&self) -> Option<Duration> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use buffer::SamplesBuffer;
|
||||
use source::from_factory;
|
||||
use source::Source;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut n = 0;
|
||||
let mut rx = from_factory(move || {
|
||||
if n == 0 {
|
||||
n = 1;
|
||||
Some(SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10]))
|
||||
} else if n == 1 {
|
||||
n = 2;
|
||||
Some(SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(rx.channels(), 1);
|
||||
assert_eq!(rx.samples_rate(), 48000);
|
||||
assert_eq!(rx.next(), Some(10));
|
||||
assert_eq!(rx.next(), Some(-10));
|
||||
assert_eq!(rx.next(), Some(10));
|
||||
assert_eq!(rx.next(), Some(-10));
|
||||
/*assert_eq!(rx.channels(), 2);
|
||||
assert_eq!(rx.samples_rate(), 96000);*/ // FIXME: not working
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), None);
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
|
|
167
src/source/from_iter.rs
Normal file
167
src/source/from_iter.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use Sample;
|
||||
use Source;
|
||||
|
||||
/// Builds a source that chains sources provided by an iterator.
|
||||
///
|
||||
/// The `iterator` parameter is an iterator that produces a source. The source is then played.
|
||||
/// Whenever the source ends, the `iterator` is used again in order to produce the source that is
|
||||
/// played next.
|
||||
///
|
||||
/// If the `iterator` produces `None`, then the sound ends.
|
||||
pub fn from_iter<I>(iterator: I) -> FromIter<I::IntoIter>
|
||||
where I: IntoIterator
|
||||
{
|
||||
let mut iterator = iterator.into_iter();
|
||||
let first_source = iterator.next();
|
||||
|
||||
FromIter {
|
||||
iterator: iterator,
|
||||
current_source: first_source,
|
||||
}
|
||||
}
|
||||
|
||||
/// A source that chains sources provided by an iterator.
|
||||
#[derive(Clone)]
|
||||
pub struct FromIter<I> where I: Iterator {
|
||||
// The iterator that provides sources.
|
||||
iterator: I,
|
||||
// Is only ever `None` if the first element of the iterator is `None`.
|
||||
current_source: Option<I::Item>,
|
||||
}
|
||||
|
||||
impl<I> Iterator for FromIter<I>
|
||||
where I: Iterator,
|
||||
I::Item: Iterator + Source,
|
||||
<I::Item as Iterator>::Item: Sample
|
||||
{
|
||||
type Item = <I::Item as Iterator>::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<<I::Item as Iterator>::Item> {
|
||||
loop {
|
||||
if let Some(ref mut src) = self.current_source {
|
||||
if let Some(value) = src.next() {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(src) = self.iterator.next() {
|
||||
self.current_source = Some(src);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
if let Some(ref cur) = self.current_source {
|
||||
(cur.size_hint().0, None)
|
||||
} else {
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Source for FromIter<I>
|
||||
where I: Iterator,
|
||||
I::Item: Iterator + Source,
|
||||
<I::Item as Iterator>::Item: Sample
|
||||
{
|
||||
#[inline]
|
||||
fn current_frame_len(&self) -> Option<usize> {
|
||||
// This function is non-trivial because the boundary between the current source and the
|
||||
// next must be a frame boundary as well.
|
||||
//
|
||||
// The current sound is free to return `None` for `current_frame_len()`, in which case
|
||||
// we *should* return the number of samples remaining the current sound.
|
||||
// This can be estimated with `size_hint()`.
|
||||
//
|
||||
// If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this
|
||||
// situation we force a frame to have a maximum number of samples indicate by this
|
||||
// constant.
|
||||
const THRESHOLD: usize = 10240;
|
||||
|
||||
// Try the current `current_frame_len`.
|
||||
if let Some(ref src) = self.current_source {
|
||||
if let Some(val) = src.current_frame_len() {
|
||||
if val != 0 {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try the size hint.
|
||||
if let Some(ref src) = self.current_source {
|
||||
if let Some(val) = src.size_hint().1 {
|
||||
if val < THRESHOLD && val != 0 {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we use the constant value.
|
||||
Some(THRESHOLD)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn channels(&self) -> u16 {
|
||||
if let Some(ref src) = self.current_source {
|
||||
src.channels()
|
||||
} else {
|
||||
// Dummy value that only happens if the iterator was empty.
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn samples_rate(&self) -> u32 {
|
||||
if let Some(ref src) = self.current_source {
|
||||
src.samples_rate()
|
||||
} else {
|
||||
// Dummy value that only happens if the iterator was empty.
|
||||
44100
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn total_duration(&self) -> Option<Duration> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use buffer::SamplesBuffer;
|
||||
use source::from_iter;
|
||||
use source::Source;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut rx = from_iter((0..2).map(|n| {
|
||||
if n == 0 {
|
||||
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
|
||||
} else if n == 1 {
|
||||
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}));
|
||||
|
||||
assert_eq!(rx.channels(), 1);
|
||||
assert_eq!(rx.samples_rate(), 48000);
|
||||
assert_eq!(rx.next(), Some(10));
|
||||
assert_eq!(rx.next(), Some(-10));
|
||||
assert_eq!(rx.next(), Some(10));
|
||||
assert_eq!(rx.next(), Some(-10));
|
||||
/*assert_eq!(rx.channels(), 2);
|
||||
assert_eq!(rx.samples_rate(), 96000);*/ // FIXME: not working
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), Some(5));
|
||||
assert_eq!(rx.next(), None);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,8 @@ pub use self::buffered::Buffered;
|
|||
pub use self::delay::Delay;
|
||||
pub use self::empty::Empty;
|
||||
pub use self::fadein::FadeIn;
|
||||
pub use self::from_factory::{from_factory, FromFactory};
|
||||
pub use self::from_factory::{from_factory, FromFactoryIter};
|
||||
pub use self::from_iter::{from_iter, FromIter};
|
||||
pub use self::mix::Mix;
|
||||
pub use self::pausable::Pausable;
|
||||
pub use self::periodic::PeriodicAccess;
|
||||
|
@ -28,6 +29,7 @@ mod delay;
|
|||
mod empty;
|
||||
mod fadein;
|
||||
mod from_factory;
|
||||
mod from_iter;
|
||||
mod mix;
|
||||
mod pausable;
|
||||
mod periodic;
|
||||
|
|
Loading…
Reference in a new issue