1use crate::common::{ChannelCount, SampleRate};
2use crate::{math, Sample};
3use num_rational::Ratio;
4use std::mem;
5
6#[derive(Clone, Debug)]
8pub struct SampleRateConverter<I>
9where
10 I: Iterator,
11{
12 input: I,
14 from: u32,
16 to: u32,
18 channels: ChannelCount,
20 current_span: Vec<I::Item>,
22 current_span_pos_in_chunk: u32,
24 next_frame: Vec<I::Item>,
26 next_output_span_pos_in_chunk: u32,
29 output_buffer: Vec<I::Item>,
31}
32
33impl<I> SampleRateConverter<I>
34where
35 I: Iterator,
36{
37 #[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 (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 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 #[inline]
94 pub fn into_inner(self) -> I {
95 self.input
96 }
97
98 #[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 if self.from == self.to {
128 debug_assert_eq!(self.from, 1);
129 return self.input.next();
130 }
131
132 if !self.output_buffer.is_empty() {
134 return Some(self.output_buffer.remove(0));
135 }
136
137 if self.next_output_span_pos_in_chunk == self.to {
141 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 let req_left_sample =
152 (self.from * self.next_output_span_pos_in_chunk / self.to) % self.from;
153
154 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 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 self.next_output_span_pos_in_chunk += 1;
185
186 if result.is_some() {
187 result
188 } else {
189 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 let samples_after_chunk = samples;
207 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 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 let samples_after_chunk = samples_after_chunk * self.to as usize / self.from as usize;
221
222 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 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 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 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 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 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 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 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); 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}