Skip to main content

rodio/conversions/
sample_rate.rs

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