Skip to main content

rodio/source/
from_iter.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::math::nz;
6use crate::Source;
7
8/// Builds a source that chains sources provided by an iterator.
9///
10/// The `iterator` parameter is an iterator that produces a source. The source is then played.
11/// Whenever the source ends, the `iterator` is used again in order to produce the source that is
12/// played next.
13///
14/// If the `iterator` produces `None`, then the sound ends.
15pub fn from_iter<I>(iterator: I) -> FromIter<I::IntoIter>
16where
17    I: IntoIterator,
18{
19    let mut iterator = iterator.into_iter();
20    let first_source = iterator.next();
21
22    FromIter {
23        iterator,
24        current_source: first_source,
25    }
26}
27
28/// A source that chains sources provided by an iterator.
29#[derive(Clone)]
30pub struct FromIter<I>
31where
32    I: Iterator,
33{
34    // The iterator that provides sources.
35    iterator: I,
36    // Is only ever `None` if the first element of the iterator is `None`.
37    current_source: Option<I::Item>,
38}
39
40impl<I> Iterator for FromIter<I>
41where
42    I: Iterator,
43    I::Item: Iterator + Source,
44{
45    type Item = <I::Item as Iterator>::Item;
46
47    #[inline]
48    fn next(&mut self) -> Option<Self::Item> {
49        loop {
50            if let Some(src) = &mut self.current_source {
51                if let Some(value) = src.next() {
52                    return Some(value);
53                }
54            }
55
56            if let Some(src) = self.iterator.next() {
57                self.current_source = Some(src);
58            } else {
59                return None;
60            }
61        }
62    }
63
64    #[inline]
65    fn size_hint(&self) -> (usize, Option<usize>) {
66        if let Some(cur) = &self.current_source {
67            (cur.size_hint().0, None)
68        } else {
69            (0, None)
70        }
71    }
72}
73
74impl<I> Source for FromIter<I>
75where
76    I: Iterator,
77    I::Item: Iterator + Source,
78{
79    #[inline]
80    fn current_span_len(&self) -> Option<usize> {
81        // This function is non-trivial because the boundary between the current source and the
82        // next must be a span boundary as well.
83        //
84        // The current sound is free to return `None` for `current_span_len()`, in which case
85        // we *should* return the number of samples remaining the current sound.
86        // This can be estimated with `size_hint()`.
87        //
88        // If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this
89        // situation we force a span to have a maximum number of samples indicate by this
90        // constant.
91        const THRESHOLD: usize = 10240;
92
93        // Try the current `current_span_len`.
94        if let Some(src) = &self.current_source {
95            if !src.is_exhausted() {
96                return src.current_span_len();
97            }
98        }
99
100        // Try the size hint.
101        if let Some(src) = &self.current_source {
102            if let Some(val) = src.size_hint().1 {
103                if val < THRESHOLD && val != 0 {
104                    return Some(val);
105                }
106            }
107        }
108
109        // Otherwise we use the constant value.
110        Some(THRESHOLD)
111    }
112
113    #[inline]
114    fn channels(&self) -> ChannelCount {
115        if let Some(src) = &self.current_source {
116            src.channels()
117        } else {
118            // Dummy value that only happens if the iterator was empty.
119            nz!(2)
120        }
121    }
122
123    #[inline]
124    fn sample_rate(&self) -> SampleRate {
125        if let Some(src) = &self.current_source {
126            src.sample_rate()
127        } else {
128            // Dummy value that only happens if the iterator was empty.
129            nz!(44100)
130        }
131    }
132
133    #[inline]
134    fn total_duration(&self) -> Option<Duration> {
135        None
136    }
137
138    #[inline]
139    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
140        if let Some(source) = self.current_source.as_mut() {
141            source.try_seek(pos)
142        } else {
143            Ok(())
144        }
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use crate::buffer::SamplesBuffer;
151    use crate::math::nz;
152    use crate::source::{from_iter, Source};
153
154    #[test]
155    fn basic() {
156        let mut rx = from_iter((0..2).map(|n| {
157            if n == 0 {
158                SamplesBuffer::new(nz!(1), nz!(48000), vec![10.0, -10.0, 10.0, -10.0])
159            } else if n == 1 {
160                SamplesBuffer::new(nz!(2), nz!(96000), vec![5.0, 5.0, 5.0, 5.0])
161            } else {
162                unreachable!()
163            }
164        }));
165
166        assert_eq!(rx.channels(), nz!(1));
167        assert_eq!(rx.sample_rate().get(), 48000);
168        assert_eq!(rx.next(), Some(10.0));
169        assert_eq!(rx.next(), Some(-10.0));
170        assert_eq!(rx.next(), Some(10.0));
171        assert_eq!(rx.next(), Some(-10.0));
172        /*assert_eq!(rx.channels(), 2);
173        assert_eq!(rx.sample_rate().get(), 96000);*/
174        // FIXME: not working
175        assert_eq!(rx.next(), Some(5.0));
176        assert_eq!(rx.next(), Some(5.0));
177        assert_eq!(rx.next(), Some(5.0));
178        assert_eq!(rx.next(), Some(5.0));
179        assert_eq!(rx.next(), None);
180    }
181}