rodio/conversions/
sample_rate.rs

1use crate::conversions::Sample;
2
3use std::mem;
4
5/// Iterator that converts from a certain sample rate to another.
6#[derive(Clone, Debug)]
7pub struct SampleRateConverter<I>
8where
9    I: Iterator,
10{
11    /// The iterator that gives us samples.
12    input: I,
13    /// We convert chunks of `from` samples into chunks of `to` samples.
14    from: u32,
15    /// We convert chunks of `from` samples into chunks of `to` samples.
16    to: u32,
17    /// Number of channels in the stream
18    channels: cpal::ChannelCount,
19    /// One sample per channel, extracted from `input`.
20    current_frame: Vec<I::Item>,
21    /// Position of `current_sample` modulo `from`.
22    current_frame_pos_in_chunk: u32,
23    /// The samples right after `current_sample` (one per channel), extracted from `input`.
24    next_frame: Vec<I::Item>,
25    /// The position of the next sample that the iterator should return, modulo `to`.
26    /// This counter is incremented (modulo `to`) every time the iterator is called.
27    next_output_frame_pos_in_chunk: u32,
28    /// The buffer containing the samples waiting to be output.
29    output_buffer: Vec<I::Item>,
30}
31
32impl<I> SampleRateConverter<I>
33where
34    I: Iterator,
35    I::Item: Sample,
36{
37    ///
38    ///
39    /// # Panic
40    ///
41    /// Panics if `from` or `to` are equal to 0.
42    ///
43    #[inline]
44    pub fn new(
45        mut input: I,
46        from: cpal::SampleRate,
47        to: cpal::SampleRate,
48        num_channels: cpal::ChannelCount,
49    ) -> SampleRateConverter<I> {
50        let from = from.0;
51        let to = to.0;
52
53        assert!(from >= 1);
54        assert!(to >= 1);
55
56        // finding greatest common divisor
57        let gcd = {
58            #[inline]
59            fn gcd(a: u32, b: u32) -> u32 {
60                if b == 0 {
61                    a
62                } else {
63                    gcd(b, a % b)
64                }
65            }
66
67            gcd(from, to)
68        };
69
70        let (first_samples, next_samples) = if from == to {
71            // if `from` == `to` == 1, then we just pass through
72            debug_assert_eq!(from, gcd);
73            (Vec::new(), Vec::new())
74        } else {
75            let first = input
76                .by_ref()
77                .take(num_channels as usize)
78                .collect::<Vec<_>>();
79            let next = input
80                .by_ref()
81                .take(num_channels as usize)
82                .collect::<Vec<_>>();
83            (first, next)
84        };
85
86        SampleRateConverter {
87            input,
88            from: from / gcd,
89            to: to / gcd,
90            channels: num_channels,
91            current_frame_pos_in_chunk: 0,
92            next_output_frame_pos_in_chunk: 0,
93            current_frame: first_samples,
94            next_frame: next_samples,
95            output_buffer: Vec::with_capacity(num_channels as usize - 1),
96        }
97    }
98
99    /// Destroys this iterator and returns the underlying iterator.
100    #[inline]
101    pub fn into_inner(self) -> I {
102        self.input
103    }
104
105    /// get mutable access to the iterator
106    #[inline]
107    pub fn inner_mut(&mut self) -> &mut I {
108        &mut self.input
109    }
110
111    fn next_input_frame(&mut self) {
112        self.current_frame_pos_in_chunk += 1;
113
114        mem::swap(&mut self.current_frame, &mut self.next_frame);
115        self.next_frame.clear();
116        for _ in 0..self.channels {
117            if let Some(i) = self.input.next() {
118                self.next_frame.push(i);
119            } else {
120                break;
121            }
122        }
123    }
124}
125
126impl<I> Iterator for SampleRateConverter<I>
127where
128    I: Iterator,
129    I::Item: Sample + Clone,
130{
131    type Item = I::Item;
132
133    fn next(&mut self) -> Option<I::Item> {
134        // the algorithm below doesn't work if `self.from == self.to`
135        if self.from == self.to {
136            debug_assert_eq!(self.from, 1);
137            return self.input.next();
138        }
139
140        // Short circuit if there are some samples waiting.
141        if !self.output_buffer.is_empty() {
142            return Some(self.output_buffer.remove(0));
143        }
144
145        // The frame we are going to return from this function will be a linear interpolation
146        // between `self.current_frame` and `self.next_frame`.
147
148        if self.next_output_frame_pos_in_chunk == self.to {
149            // If we jump to the next frame, we reset the whole state.
150            self.next_output_frame_pos_in_chunk = 0;
151
152            self.next_input_frame();
153            while self.current_frame_pos_in_chunk != self.from {
154                self.next_input_frame();
155            }
156            self.current_frame_pos_in_chunk = 0;
157        } else {
158            // Finding the position of the first sample of the linear interpolation.
159            let req_left_sample =
160                (self.from * self.next_output_frame_pos_in_chunk / self.to) % self.from;
161
162            // Advancing `self.current_frame`, `self.next_frame` and
163            // `self.current_frame_pos_in_chunk` until the latter variable
164            // matches `req_left_sample`.
165            while self.current_frame_pos_in_chunk != req_left_sample {
166                self.next_input_frame();
167                debug_assert!(self.current_frame_pos_in_chunk < self.from);
168            }
169        }
170
171        // Merging `self.current_frame` and `self.next_frame` into `self.output_buffer`.
172        // Note that `self.output_buffer` can be truncated if there is not enough data in
173        // `self.next_frame`.
174        let mut result = None;
175        let numerator = (self.from * self.next_output_frame_pos_in_chunk) % self.to;
176        for (off, (cur, next)) in self
177            .current_frame
178            .iter()
179            .zip(self.next_frame.iter())
180            .enumerate()
181        {
182            let sample = Sample::lerp(*cur, *next, numerator, self.to);
183
184            if off == 0 {
185                result = Some(sample);
186            } else {
187                self.output_buffer.push(sample);
188            }
189        }
190
191        // Incrementing the counter for the next iteration.
192        self.next_output_frame_pos_in_chunk += 1;
193
194        if result.is_some() {
195            result
196        } else {
197            // draining `self.current_frame`
198            if !self.current_frame.is_empty() {
199                let r = Some(self.current_frame.remove(0));
200                mem::swap(&mut self.output_buffer, &mut self.current_frame);
201                self.current_frame.clear();
202                r
203            } else {
204                None
205            }
206        }
207    }
208
209    #[inline]
210    fn size_hint(&self) -> (usize, Option<usize>) {
211        let apply = |samples: usize| {
212            // `samples_after_chunk` will contain the number of samples remaining after the chunk
213            // currently being processed
214            let samples_after_chunk = samples;
215            // adding the samples of the next chunk that may have already been read
216            let samples_after_chunk = if self.current_frame_pos_in_chunk == self.from - 1 {
217                samples_after_chunk + self.next_frame.len()
218            } else {
219                samples_after_chunk
220            };
221            // removing the samples of the current chunk that have not yet been read
222            let samples_after_chunk = samples_after_chunk.saturating_sub(
223                self.from
224                    .saturating_sub(self.current_frame_pos_in_chunk + 2) as usize
225                    * usize::from(self.channels),
226            );
227            // calculating the number of samples after the transformation
228            // TODO: this is wrong here \|/
229            let samples_after_chunk = samples_after_chunk * self.to as usize / self.from as usize;
230
231            // `samples_current_chunk` will contain the number of samples remaining to be output
232            // for the chunk currently being processed
233            let samples_current_chunk = (self.to - self.next_output_frame_pos_in_chunk) as usize
234                * usize::from(self.channels);
235
236            samples_current_chunk + samples_after_chunk + self.output_buffer.len()
237        };
238
239        if self.from == self.to {
240            self.input.size_hint()
241        } else {
242            let (min, max) = self.input.size_hint();
243            (apply(min), max.map(apply))
244        }
245    }
246}
247
248impl<I> ExactSizeIterator for SampleRateConverter<I>
249where
250    I: ExactSizeIterator,
251    I::Item: Sample + Clone,
252{
253}
254
255#[cfg(test)]
256mod test {
257    use super::SampleRateConverter;
258    use core::time::Duration;
259    use cpal::SampleRate;
260    use quickcheck::quickcheck;
261
262    // TODO: Remove once cpal 0.12.2 is released and the dependency is updated
263    //  (cpal#483 implemented ops::Mul on SampleRate)
264    const fn multiply_rate(r: SampleRate, k: u32) -> SampleRate {
265        SampleRate(k * r.0)
266    }
267
268    quickcheck! {
269        /// Check that resampling an empty input produces no output.
270        fn empty(from: u32, to: u32, n: u16) -> () {
271            let from = if from == 0 { return; } else { SampleRate(from) };
272            let to   = if   to == 0 { return; } else { SampleRate(to)   };
273            if n == 0 { return; }
274
275            let input: Vec<u16> = Vec::new();
276            let output =
277                SampleRateConverter::new(input.into_iter(), from, to, n)
278                  .collect::<Vec<_>>();
279
280            assert_eq!(output, []);
281        }
282
283        /// Check that resampling to the same rate does not change the signal.
284        fn identity(from: u32, n: u16, input: Vec<u16>) -> () {
285            let from = if from == 0 { return; } else { SampleRate(from) };
286            if n == 0 { return; }
287
288            let output =
289                SampleRateConverter::new(input.clone().into_iter(), from, from, n)
290                  .collect::<Vec<_>>();
291
292            assert_eq!(input, output);
293        }
294
295        /// Check that dividing the sample rate by k (integer) is the same as
296        ///   dropping a sample from each channel.
297        fn divide_sample_rate(to: u32, k: u32, input: Vec<u16>, n: u16) -> () {
298            let to = if to == 0 { return; } else { SampleRate(to) };
299            let from = multiply_rate(to, k);
300            if k == 0 || n == 0 { return; }
301
302            // Truncate the input, so it contains an integer number of frames.
303            let input = {
304                let ns = n as usize;
305                let mut i = input;
306                i.truncate(ns * (i.len() / ns));
307                i
308            };
309
310            let output =
311                SampleRateConverter::new(input.clone().into_iter(), from, to, n)
312                  .collect::<Vec<_>>();
313
314            assert_eq!(input.chunks_exact(n.into())
315                         .step_by(k as usize).collect::<Vec<_>>().concat(),
316                       output)
317        }
318
319        /// Check that, after multiplying the sample rate by k, every k-th
320        ///  sample in the output matches exactly with the input.
321        fn multiply_sample_rate(from: u32, k: u32, input: Vec<u16>, n: u16) -> () {
322            let from = if from == 0 { return; } else { SampleRate(from) };
323            let to = multiply_rate(from, k);
324            if k == 0 || n == 0 { return; }
325
326            // Truncate the input, so it contains an integer number of frames.
327            let input = {
328                let ns = n as usize;
329                let mut i = input;
330                i.truncate(ns * (i.len() / ns));
331                i
332            };
333
334            let output =
335                SampleRateConverter::new(input.clone().into_iter(), from, to, n)
336                  .collect::<Vec<_>>();
337
338            assert_eq!(input,
339                       output.chunks_exact(n.into())
340                         .step_by(k as usize).collect::<Vec<_>>().concat()
341            )
342        }
343
344        #[ignore]
345        /// Check that resampling does not change the audio duration,
346        ///  except by a negligible amount (± 1ms).  Reproduces #316.
347        /// Ignored, pending a bug fix.
348        fn preserve_durations(d: Duration, freq: f32, to: u32) -> () {
349            use crate::source::{SineWave, Source};
350
351            let to = if to == 0 { return; } else { SampleRate(to) };
352            let source = SineWave::new(freq).take_duration(d);
353            let from = SampleRate(source.sample_rate());
354
355            let resampled =
356                SampleRateConverter::new(source, from, to, 1);
357            let duration =
358                Duration::from_secs_f32(resampled.count() as f32 / to.0 as f32);
359
360            let delta = if d < duration { duration - d } else { d - duration };
361            assert!(delta < Duration::from_millis(1),
362                    "Resampled duration ({:?}) is not close to original ({:?}); Δ = {:?}",
363                    duration, d, delta);
364        }
365    }
366
367    #[test]
368    fn upsample() {
369        let input = vec![2u16, 16, 4, 18, 6, 20, 8, 22];
370        let output =
371            SampleRateConverter::new(input.into_iter(), SampleRate(2000), SampleRate(3000), 2);
372        assert_eq!(output.len(), 12);
373
374        let output = output.collect::<Vec<_>>();
375        assert_eq!(output, [2, 16, 3, 17, 4, 18, 6, 20, 7, 21, 8, 22]);
376    }
377}