Add repeat_infinite to Source

This commit is contained in:
Pierre Krieger 2015-10-16 16:08:52 +02:00
parent 21900968b5
commit 1f3eefd863

View file

@ -1,5 +1,6 @@
use std::cmp;
use std::time::Duration;
use std::mem;
use cpal;
@ -28,6 +29,16 @@ pub trait Source: Iterator where Self::Item: Sample {
///
/// `None` indicates at the same time "infinite" or "unknown".
fn get_total_duration(&self) -> Option<Duration>;
/// Repeats this source forever.
///
/// Note that this works by storing the data in a buffer, so the amount of memory used is
/// proportional to the size of the sound.
#[inline]
fn repeat_infinite(self) -> Repeat<Self> where Self: Sized {
let buffer = vec![(Vec::new(), self.get_samples_rate(), self.get_channels())];
Repeat { inner: RepeatImpl::FirstPass(self, buffer) }
}
}
/// An iterator that reads from a `Source` and converts the samples to a specific rate and
@ -168,3 +179,102 @@ impl<I> Iterator for Take<I> where I: Iterator {
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {
}
/// A source that repeats the given source.
pub struct Repeat<I> where I: Source, I::Item: Sample {
inner: RepeatImpl<I>,
}
enum RepeatImpl<I> where I: Source, I::Item: Sample {
FirstPass(I, Vec<(Vec<I::Item>, u32, u16)>),
NextPasses(Vec<(Vec<I::Item>, u32, u16)>, usize, usize)
}
impl<I> Iterator for Repeat<I> where I: Source, I::Item: Sample {
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
match self.inner {
RepeatImpl::FirstPass(ref mut input, ref mut buffer) => {
match input.get_current_frame_len() {
Some(1) => {
if let Some(sample) = input.next() {
buffer.last_mut().unwrap().0.push(sample);
buffer.push((Vec::new(), input.get_samples_rate(), input.get_channels()));
return Some(sample);
}
},
Some(0) => {
},
_ => {
if let Some(sample) = input.next() {
buffer.last_mut().unwrap().0.push(sample);
return Some(sample);
}
},
}
},
RepeatImpl::NextPasses(ref buffer, ref mut off1, ref mut off2) => {
let sample = buffer[*off1].0[*off2];
*off2 += 1;
if *off2 >= buffer[*off1].0.len() {
*off1 += 1;
*off2 = 0;
}
if *off1 >= buffer.len() {
*off1 = 0;
}
return Some(sample);
},
}
// if we reach this, we need to switch from FirstPass to NextPasses
let buffer = if let RepeatImpl::FirstPass(_, ref mut buffer) = self.inner {
mem::replace(buffer, Vec::new())
} else {
unreachable!()
};
mem::replace(&mut self.inner, RepeatImpl::NextPasses(buffer, 0, 0));
self.next()
}
// TODO: size_hint
}
impl<I> Source for Repeat<I> where I: Iterator + Source, I::Item: Sample {
#[inline]
fn get_current_frame_len(&self) -> Option<usize> {
match self.inner {
RepeatImpl::FirstPass(ref input, _) => input.get_current_frame_len(),
RepeatImpl::NextPasses(ref buffers, off1, off2) => Some(buffers[off1].0.len() - off2),
}
}
#[inline]
fn get_channels(&self) -> u16 {
match self.inner {
RepeatImpl::FirstPass(ref input, _) => input.get_channels(),
RepeatImpl::NextPasses(ref buffers, off1, _) => buffers[off1].2,
}
}
#[inline]
fn get_samples_rate(&self) -> u32 {
match self.inner {
RepeatImpl::FirstPass(ref input, _) => input.get_samples_rate(),
RepeatImpl::NextPasses(ref buffers, off1, _) => buffers[off1].1,
}
}
#[inline]
fn get_total_duration(&self) -> Option<Duration> {
// TODO: ?
None
}
}