geng_rodio/source/
from_iter.rs

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