geng_rodio/source/
uniform.rs

1use std::cmp;
2use std::time::Duration;
3
4use cpal::FromSample;
5
6use crate::conversions::{ChannelCountConverter, DataConverter, SampleRateConverter};
7use crate::{Sample, Source};
8
9/// An iterator that reads from a `Source` and converts the samples to a specific rate and
10/// channels count.
11///
12/// It implements `Source` as well, but all the data is guaranteed to be in a single frame whose
13/// channels and samples rate have been passed to `new`.
14#[derive(Clone)]
15pub struct UniformSourceIterator<I, D>
16where
17    I: Source,
18    I::Item: Sample,
19    D: Sample,
20{
21    inner: Option<DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D>>,
22    target_channels: u16,
23    target_sample_rate: u32,
24    total_duration: Option<Duration>,
25}
26
27impl<I, D> UniformSourceIterator<I, D>
28where
29    I: Source,
30    I::Item: Sample,
31    D: Sample,
32{
33    #[inline]
34    pub fn new(
35        input: I,
36        target_channels: u16,
37        target_sample_rate: u32,
38    ) -> UniformSourceIterator<I, D> {
39        let total_duration = input.total_duration();
40        let input = UniformSourceIterator::bootstrap(input, target_channels, target_sample_rate);
41
42        UniformSourceIterator {
43            inner: Some(input),
44            target_channels,
45            target_sample_rate,
46            total_duration,
47        }
48    }
49
50    #[inline]
51    fn bootstrap(
52        input: I,
53        target_channels: u16,
54        target_sample_rate: u32,
55    ) -> DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D> {
56        // Limit the frame length to something reasonable
57        let frame_len = input.current_frame_len().map(|x| x.min(32768));
58
59        let from_channels = input.channels();
60        let from_sample_rate = input.sample_rate();
61
62        let input = Take {
63            iter: input,
64            n: frame_len,
65        };
66        let input = SampleRateConverter::new(
67            input,
68            cpal::SampleRate(from_sample_rate),
69            cpal::SampleRate(target_sample_rate),
70            from_channels,
71        );
72        let input = ChannelCountConverter::new(input, from_channels, target_channels);
73
74        DataConverter::new(input)
75    }
76}
77
78impl<I, D> Iterator for UniformSourceIterator<I, D>
79where
80    I: Source,
81    I::Item: Sample,
82    D: FromSample<I::Item> + Sample,
83{
84    type Item = D;
85
86    #[inline]
87    fn next(&mut self) -> Option<D> {
88        if let Some(value) = self.inner.as_mut().unwrap().next() {
89            return Some(value);
90        }
91
92        let input = self
93            .inner
94            .take()
95            .unwrap()
96            .into_inner()
97            .into_inner()
98            .into_inner()
99            .iter;
100
101        let mut input =
102            UniformSourceIterator::bootstrap(input, self.target_channels, self.target_sample_rate);
103
104        let value = input.next();
105        self.inner = Some(input);
106        value
107    }
108
109    #[inline]
110    fn size_hint(&self) -> (usize, Option<usize>) {
111        (self.inner.as_ref().unwrap().size_hint().0, None)
112    }
113}
114
115impl<I, D> Source for UniformSourceIterator<I, D>
116where
117    I: Iterator + Source,
118    I::Item: Sample,
119    D: FromSample<I::Item> + Sample,
120{
121    #[inline]
122    fn current_frame_len(&self) -> Option<usize> {
123        None
124    }
125
126    #[inline]
127    fn channels(&self) -> u16 {
128        self.target_channels
129    }
130
131    #[inline]
132    fn sample_rate(&self) -> u32 {
133        self.target_sample_rate
134    }
135
136    #[inline]
137    fn total_duration(&self) -> Option<Duration> {
138        self.total_duration
139    }
140}
141
142#[derive(Clone, Debug)]
143struct Take<I> {
144    iter: I,
145    n: Option<usize>,
146}
147
148impl<I> Iterator for Take<I>
149where
150    I: Iterator,
151{
152    type Item = <I as Iterator>::Item;
153
154    #[inline]
155    fn next(&mut self) -> Option<<I as Iterator>::Item> {
156        if let Some(n) = &mut self.n {
157            if *n != 0 {
158                *n -= 1;
159                self.iter.next()
160            } else {
161                None
162            }
163        } else {
164            self.iter.next()
165        }
166    }
167
168    #[inline]
169    fn size_hint(&self) -> (usize, Option<usize>) {
170        if let Some(n) = self.n {
171            let (lower, upper) = self.iter.size_hint();
172
173            let lower = cmp::min(lower, n);
174
175            let upper = match upper {
176                Some(x) if x < n => Some(x),
177                _ => Some(n),
178            };
179
180            (lower, upper)
181        } else {
182            self.iter.size_hint()
183        }
184    }
185}
186
187impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}