rodio/conversions/
sample_rate.rs

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