1use crate::conversions::Sample;
2
3use std::mem;
4
5#[derive(Clone, Debug)]
7pub struct SampleRateConverter<I>
8where
9 I: Iterator,
10{
11 input: I,
13 from: u32,
15 to: u32,
17 channels: cpal::ChannelCount,
19 current_frame: Vec<I::Item>,
21 current_frame_pos_in_chunk: u32,
23 next_frame: Vec<I::Item>,
25 next_output_frame_pos_in_chunk: u32,
28 output_buffer: Vec<I::Item>,
30}
31
32impl<I> SampleRateConverter<I>
33where
34 I: Iterator,
35 I::Item: Sample,
36{
37 #[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 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 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 #[inline]
101 pub fn into_inner(self) -> I {
102 self.input
103 }
104
105 #[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 if self.from == self.to {
136 debug_assert_eq!(self.from, 1);
137 return self.input.next();
138 }
139
140 if !self.output_buffer.is_empty() {
142 return Some(self.output_buffer.remove(0));
143 }
144
145 if self.next_output_frame_pos_in_chunk == self.to {
149 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 let req_left_sample =
160 (self.from * self.next_output_frame_pos_in_chunk / self.to) % self.from;
161
162 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 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 self.next_output_frame_pos_in_chunk += 1;
193
194 if result.is_some() {
195 result
196 } else {
197 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 let samples_after_chunk = samples;
215 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 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 let samples_after_chunk = samples_after_chunk * self.to as usize / self.from as usize;
230
231 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 const fn multiply_rate(r: SampleRate, k: u32) -> SampleRate {
265 SampleRate(k * r.0)
266 }
267
268 quickcheck! {
269 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 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 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 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 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 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 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}