1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "log")]
4extern crate log;
5use audioadapter::{Adapter, AdapterMut};
6use audioadapter_buffers::owned::InterleavedOwned;
7
8#[allow(unused)]
10macro_rules! trace { ($($x:tt)*) => (
11 #[cfg(feature = "log")] {
12 log::trace!($($x)*)
13 }
14) }
15#[allow(unused)]
16macro_rules! debug { ($($x:tt)*) => (
17 #[cfg(feature = "log")] {
18 log::debug!($($x)*)
19 }
20) }
21#[allow(unused)]
22macro_rules! info { ($($x:tt)*) => (
23 #[cfg(feature = "log")] {
24 log::info!($($x)*)
25 }
26) }
27#[allow(unused)]
28macro_rules! warn { ($($x:tt)*) => (
29 #[cfg(feature = "log")] {
30 log::warn!($($x)*)
31 }
32) }
33#[allow(unused)]
34macro_rules! error { ($($x:tt)*) => (
35 #[cfg(feature = "log")] {
36 log::error!($($x)*)
37 }
38) }
39
40mod asynchro;
41mod asynchro_fast;
42mod asynchro_sinc;
43mod error;
44mod interpolation;
45mod sample;
46mod sinc;
47#[cfg(feature = "fft_resampler")]
48mod synchro;
49mod windows;
50
51pub mod sinc_interpolator;
52
53pub use crate::asynchro::{Async, FixedAsync};
54pub use crate::asynchro_fast::PolynomialDegree;
55pub use crate::asynchro_sinc::{SincInterpolationParameters, SincInterpolationType};
56pub use crate::error::{
57 CpuFeature, MissingCpuFeature, ResampleError, ResampleResult, ResamplerConstructionError,
58};
59pub use crate::sample::Sample;
60#[cfg(feature = "fft_resampler")]
61pub use crate::synchro::{Fft, FixedSync};
62pub use crate::windows::{calculate_cutoff, WindowFunction};
63
64#[derive(Debug, Clone)]
67pub struct Indexing {
68 pub input_offset: usize,
69 pub output_offset: usize,
70 pub partial_len: Option<usize>,
71 pub active_channels_mask: Option<Vec<bool>>,
72}
73
74pub(crate) fn get_offsets(indexing: &Option<&Indexing>) -> (usize, usize) {
75 indexing
76 .as_ref()
77 .map(|idx| (idx.input_offset, idx.output_offset))
78 .unwrap_or((0, 0))
79}
80
81pub(crate) fn get_partial_len(indexing: &Option<&Indexing>) -> Option<usize> {
82 indexing.as_ref().and_then(|idx| idx.partial_len)
83}
84
85pub(crate) fn update_mask(indexing: &Option<&Indexing>, mask: &mut [bool]) {
87 if let Some(idx) = indexing {
88 if let Some(new_mask) = &idx.active_channels_mask {
89 mask.copy_from_slice(new_mask);
90 return;
91 }
92 }
93 mask.iter_mut().for_each(|v| *v = true);
94}
95
96pub trait Resampler<T>: Send
99where
100 T: Sample,
101{
102 fn process(
113 &mut self,
114 buffer_in: &dyn Adapter<'_, T>,
115 input_offset: usize,
116 active_channels_mask: Option<&[bool]>,
117 ) -> ResampleResult<InterleavedOwned<T>> {
118 let frames = self.output_frames_next();
119 let channels = self.nbr_channels();
120 let mut buffer_out = InterleavedOwned::<T>::new(T::coerce_from(0.0), channels, frames);
121
122 let indexing = Indexing {
123 input_offset,
124 output_offset: 0,
125 partial_len: None,
126 active_channels_mask: active_channels_mask.map(|m| m.to_vec()),
127 };
128 self.process_into_buffer(buffer_in, &mut buffer_out, Some(&indexing))?;
129 Ok(buffer_out)
130 }
131
132 fn process_into_buffer<'a>(
164 &mut self,
165 buffer_in: &dyn Adapter<'a, T>,
166 buffer_out: &mut dyn AdapterMut<'a, T>,
167 indexing: Option<&Indexing>,
168 ) -> ResampleResult<(usize, usize)>;
169
170 fn process_all_into_buffer<'a>(
184 &mut self,
185 buffer_in: &dyn Adapter<'a, T>,
186 buffer_out: &mut dyn AdapterMut<'a, T>,
187 input_len: usize,
188 active_channels_mask: Option<&[bool]>,
189 ) -> ResampleResult<(usize, usize)> {
190 let expected_output_len = (self.resample_ratio() * input_len as f64).ceil() as usize;
191
192 let mut indexing = Indexing {
193 input_offset: 0,
194 output_offset: 0,
195 active_channels_mask: active_channels_mask.map(|m| m.to_vec()),
196 partial_len: None,
197 };
198
199 let mut frames_left = input_len;
200 let mut output_len = 0;
201 let mut frames_to_trim = self.output_delay();
202 debug!(
203 "resamping {} input frames to {} output frames, delay to trim off {} frames",
204 input_len, expected_output_len, frames_to_trim
205 );
206
207 let next_nbr_input_frames = self.input_frames_next();
208 while frames_left > next_nbr_input_frames {
209 debug!("process, {} input frames left", frames_left);
210 let (nbr_in, nbr_out) =
211 self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
212 frames_left -= nbr_in;
213 output_len += nbr_out;
214 indexing.input_offset += nbr_in;
215 indexing.output_offset += nbr_out;
216 if frames_to_trim > 0 && output_len > frames_to_trim {
217 debug!(
218 "output, {} is longer than delay to trim, {}, trimming..",
219 output_len, frames_to_trim
220 );
221 buffer_out.copy_frames_within(frames_to_trim, 0, frames_to_trim);
223 output_len -= frames_to_trim;
225 indexing.output_offset -= frames_to_trim;
226 frames_to_trim = 0;
227 }
228 }
229 if frames_left > 0 {
230 debug!("process the last partial chunk, len {}", frames_left);
231 indexing.partial_len = Some(frames_left);
232 let (_nbr_in, nbr_out) =
233 self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
234 output_len += nbr_out;
235 indexing.output_offset += nbr_out;
236 }
237 indexing.partial_len = Some(0);
238 while output_len < expected_output_len {
239 debug!(
240 "output is still too short, {} < {}, pump zeros..",
241 output_len, expected_output_len
242 );
243 let (_nbr_in, nbr_out) =
244 self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
245 output_len += nbr_out;
246 indexing.output_offset += nbr_out;
247 }
248 Ok((input_len, expected_output_len))
249 }
250
251 fn process_all_needed_output_len(&mut self, input_len: usize) -> usize {
255 let delay_frames = self.output_delay();
256 let output_frames_next = self.output_frames_next();
257 let expected_output_len = (self.resample_ratio() * input_len as f64).ceil() as usize;
258 delay_frames + output_frames_next + expected_output_len
259 }
260
261 fn input_frames_max(&self) -> usize;
263
264 fn input_frames_next(&self) -> usize;
267
268 fn nbr_channels(&self) -> usize;
270
271 fn output_frames_max(&self) -> usize;
273
274 fn output_frames_next(&self) -> usize;
277
278 fn output_delay(&self) -> usize;
281
282 fn set_resample_ratio(&mut self, new_ratio: f64, ramp: bool) -> ResampleResult<()>;
296
297 fn resample_ratio(&self) -> f64;
299
300 fn set_resample_ratio_relative(&mut self, rel_ratio: f64, ramp: bool) -> ResampleResult<()>;
313
314 fn reset(&mut self);
316
317 fn set_chunk_size(&mut self, _chunksize: usize) -> ResampleResult<()> {
330 Err(ResampleError::ChunkSizeNotAdjustable)
331 }
332}
333
334pub(crate) fn validate_buffers<'a, T: 'a>(
335 wave_in: &dyn Adapter<'a, T>,
336 wave_out: &dyn AdapterMut<'a, T>,
337 mask: &[bool],
338 channels: usize,
339 min_input_len: usize,
340 min_output_len: usize,
341) -> ResampleResult<()> {
342 if wave_in.channels() != channels {
343 return Err(ResampleError::WrongNumberOfInputChannels {
344 expected: channels,
345 actual: wave_in.channels(),
346 });
347 }
348 if mask.len() != channels {
349 return Err(ResampleError::WrongNumberOfMaskChannels {
350 expected: channels,
351 actual: mask.len(),
352 });
353 }
354 if wave_in.frames() < min_input_len {
355 return Err(ResampleError::InsufficientInputBufferSize {
356 expected: min_input_len,
357 actual: wave_in.frames(),
358 });
359 }
360 if wave_out.channels() != channels {
361 return Err(ResampleError::WrongNumberOfOutputChannels {
362 expected: channels,
363 actual: wave_out.channels(),
364 });
365 }
366 if wave_out.frames() < min_output_len {
367 return Err(ResampleError::InsufficientOutputBufferSize {
368 expected: min_output_len,
369 actual: wave_out.frames(),
370 });
371 }
372 Ok(())
373}
374
375#[cfg(test)]
376pub mod tests {
377 #[cfg(feature = "fft_resampler")]
378 use crate::Fft;
379 use crate::Resampler;
380 use crate::{
381 Async, FixedAsync, SincInterpolationParameters, SincInterpolationType, WindowFunction,
382 };
383 use audioadapter::Adapter;
384 use audioadapter_buffers::direct::SequentialSliceOfVecs;
385
386 #[test_log::test]
387 fn process_all() {
388 let mut resampler = Async::<f64>::new_sinc(
389 88200 as f64 / 44100 as f64,
390 1.1,
391 &SincInterpolationParameters {
392 sinc_len: 64,
393 f_cutoff: 0.95,
394 interpolation: SincInterpolationType::Cubic,
395 oversampling_factor: 16,
396 window: WindowFunction::BlackmanHarris2,
397 },
398 1024,
399 2,
400 FixedAsync::Input,
401 )
402 .unwrap();
403 let input_len = 12345;
404 let samples: Vec<f64> = (0..input_len).map(|v| v as f64 / 10.0).collect();
405 let input_data = vec![samples; 2];
406 let input = SequentialSliceOfVecs::new(&input_data, 2, input_len).unwrap();
408 let output_len = resampler.process_all_needed_output_len(input_len);
409 let mut output_data = vec![vec![0.0f64; output_len]; 2];
410 let mut output = SequentialSliceOfVecs::new_mut(&mut output_data, 2, output_len).unwrap();
411 let (nbr_in, nbr_out) = resampler
412 .process_all_into_buffer(&input, &mut output, input_len, None)
413 .unwrap();
414 assert_eq!(nbr_in, input_len);
415 assert_eq!(2 * nbr_in, nbr_out);
417
418 let increment = 0.1 / resampler.resample_ratio();
420 let delay = resampler.output_delay();
421 let margin = (delay as f64 * resampler.resample_ratio()) as usize;
422 let mut expected = margin as f64 * increment;
423 for frame in margin..(nbr_out - margin) {
424 for chan in 0..2 {
425 let val = output.read_sample(chan, frame).unwrap();
426 assert!(
427 val - expected < 100.0 * increment,
428 "frame: {}, value: {}, expected: {}",
429 frame,
430 val,
431 expected
432 );
433 assert!(
434 expected - val < 100.0 * increment,
435 "frame: {}, value: {}, expected: {}",
436 frame,
437 val,
438 expected
439 );
440 }
441 expected += increment;
442 }
443 }
444
445 #[test_log::test]
447 fn boxed_resampler() {
448 let mut boxed: Box<dyn Resampler<f64>> = Box::new(
449 Async::<f64>::new_sinc(
450 88200 as f64 / 44100 as f64,
451 1.1,
452 &SincInterpolationParameters {
453 sinc_len: 64,
454 f_cutoff: 0.95,
455 interpolation: SincInterpolationType::Cubic,
456 oversampling_factor: 16,
457 window: WindowFunction::BlackmanHarris2,
458 },
459 1024,
460 2,
461 FixedAsync::Input,
462 )
463 .unwrap(),
464 );
465 let max_frames_out = boxed.output_frames_max();
466 let nbr_frames_in_next = boxed.input_frames_next();
467 let waves = vec![vec![0.0f64; nbr_frames_in_next]; 2];
468 let mut waves_out = vec![vec![0.0f64; max_frames_out]; 2];
469 let input = SequentialSliceOfVecs::new(&waves, 2, nbr_frames_in_next).unwrap();
470 let mut output = SequentialSliceOfVecs::new_mut(&mut waves_out, 2, max_frames_out).unwrap();
471 let _ = process_with_boxed(&mut boxed, &input, &mut output);
472 }
473
474 fn process_with_boxed<'a>(
475 resampler: &mut Box<dyn Resampler<f64>>,
476 input: &SequentialSliceOfVecs<&'a [Vec<f64>]>,
477 output: &mut SequentialSliceOfVecs<&'a mut [Vec<f64>]>,
478 ) {
479 resampler.process_into_buffer(input, output, None).unwrap();
480 }
481
482 fn impl_send<T: Send>() {
483 fn is_send<T: Send>() {}
484 is_send::<Async<T>>();
485 #[cfg(feature = "fft_resampler")]
486 {
487 is_send::<Fft<T>>();
488 }
489 }
490
491 #[test]
493 fn test_impl_send() {
494 impl_send::<f32>();
495 impl_send::<f64>();
496 }
497
498 pub fn expected_output_value(idx: usize, delay: usize, ratio: f64) -> f64 {
499 if idx <= delay {
500 return 0.0;
501 }
502 (idx - delay) as f64 * 0.1 / ratio
503 }
504
505 #[macro_export]
506 macro_rules! check_output {
507 ($resampler:ident, $fty:ty) => {
508 let mut ramp_value: $fty = 0.0;
509 let max_input_len = $resampler.input_frames_max();
510 let max_output_len = $resampler.output_frames_max();
511 let ratio = $resampler.resample_ratio() as $fty;
512 let delay = $resampler.output_delay();
513 let mut output_index = 0;
514
515 let out_incr = 0.1 / ratio;
516
517 let nbr_iterations =
518 100000 / ($resampler.output_frames_next() + $resampler.input_frames_next());
519 for _n in 0..nbr_iterations {
520 let expected_frames_in = $resampler.input_frames_next();
521 let expected_frames_out = $resampler.output_frames_next();
522 assert!(expected_frames_in <= max_input_len);
524 assert!(expected_frames_out <= max_output_len);
525 let mut input_data = vec![vec![0.0 as $fty; expected_frames_in]; 2];
526 for m in 0..expected_frames_in {
527 for ch in 0..2 {
528 input_data[ch][m] = ramp_value;
529 }
530 ramp_value = ramp_value + 0.1;
531 }
532 let input = SequentialSliceOfVecs::new(&input_data, 2, expected_frames_in).unwrap();
533 let mut output_data = vec![vec![0.0 as $fty; expected_frames_out]; 2];
534 let mut output =
535 SequentialSliceOfVecs::new_mut(&mut output_data, 2, expected_frames_out)
536 .unwrap();
537
538 trace!("resample...");
539 let (input_frames, output_frames) = $resampler
540 .process_into_buffer(&input, &mut output, None)
541 .unwrap();
542 trace!("assert lengths");
543 assert_eq!(input_frames, expected_frames_in);
544 assert_eq!(output_frames, expected_frames_out);
545 trace!("check output");
546 for idx in 0..output_frames {
547 let expected = expected_output_value(output_index + idx, delay, ratio) as $fty;
548 for ch in 0..2 {
549 let value = output_data[ch][idx];
550 let margin = 3.0 * out_incr;
551 assert!(
552 value > expected - margin,
553 "Value at frame {} is too small, {} < {} - {}",
554 output_index + idx,
555 value,
556 expected,
557 margin
558 );
559 assert!(
560 value < expected + margin,
561 "Value at frame {} is too large, {} > {} + {}",
562 output_index + idx,
563 value,
564 expected,
565 margin
566 );
567 }
568 }
569 output_index += output_frames;
570 }
571 assert!(output_index > 1000, "Too few frames checked!");
572 };
573 }
574
575 #[macro_export]
576 macro_rules! check_ratio {
577 ($resampler:ident, $repetitions:expr, $margin:expr, $fty:ty) => {
578 let ratio = $resampler.resample_ratio();
579 let max_input_len = $resampler.input_frames_max();
580 let max_output_len = $resampler.output_frames_max();
581 let waves_in = vec![vec![0.0 as $fty; max_input_len]; 2];
582 let input = SequentialSliceOfVecs::new(&waves_in, 2, max_input_len).unwrap();
583 let mut waves_out = vec![vec![0.0 as $fty; max_output_len]; 2];
584 let mut output =
585 SequentialSliceOfVecs::new_mut(&mut waves_out, 2, max_output_len).unwrap();
586 let mut total_in = 0;
587 let mut total_out = 0;
588 for _ in 0..$repetitions {
589 let out = $resampler
590 .process_into_buffer(&input, &mut output, None)
591 .unwrap();
592 total_in += out.0;
593 total_out += out.1
594 }
595 let measured_ratio = total_out as f64 / total_in as f64;
596 assert!(
597 measured_ratio / ratio > (1.0 - $margin),
598 "Measured ratio is too small, measured / expected = {}",
599 measured_ratio / ratio
600 );
601 assert!(
602 measured_ratio / ratio < (1.0 + $margin),
603 "Measured ratio is too large, measured / expected = {}",
604 measured_ratio / ratio
605 );
606 };
607 }
608
609 #[macro_export]
610 macro_rules! assert_fi_len {
611 ($resampler:ident, $chunksize:expr) => {
612 let nbr_frames_in_next = $resampler.input_frames_next();
613 let nbr_frames_in_max = $resampler.input_frames_max();
614 assert_eq!(
615 nbr_frames_in_next, $chunksize,
616 "expected {} for next input samples, got {}",
617 $chunksize, nbr_frames_in_next
618 );
619 assert_eq!(
620 nbr_frames_in_next, $chunksize,
621 "expected {} for max input samples, got {}",
622 $chunksize, nbr_frames_in_max
623 );
624 };
625 }
626
627 #[macro_export]
628 macro_rules! assert_fo_len {
629 ($resampler:ident, $chunksize:expr) => {
630 let nbr_frames_out_next = $resampler.output_frames_next();
631 let nbr_frames_out_max = $resampler.output_frames_max();
632 assert_eq!(
633 nbr_frames_out_next, $chunksize,
634 "expected {} for next output samples, got {}",
635 $chunksize, nbr_frames_out_next
636 );
637 assert_eq!(
638 nbr_frames_out_next, $chunksize,
639 "expected {} for max output samples, got {}",
640 $chunksize, nbr_frames_out_max
641 );
642 };
643 }
644
645 #[macro_export]
646 macro_rules! assert_fb_len {
647 ($resampler:ident) => {
648 let nbr_frames_out_next = $resampler.output_frames_next();
649 let nbr_frames_out_max = $resampler.output_frames_max();
650 let nbr_frames_in_next = $resampler.input_frames_next();
651 let nbr_frames_in_max = $resampler.input_frames_max();
652 let ratio = $resampler.resample_ratio();
653 assert_eq!(
654 nbr_frames_out_next, nbr_frames_out_max,
655 "next output frames, {}, is different than max, {}",
656 nbr_frames_out_next, nbr_frames_out_next
657 );
658 assert_eq!(
659 nbr_frames_in_next, nbr_frames_in_max,
660 "next input frames, {}, is different than max, {}",
661 nbr_frames_in_next, nbr_frames_in_max
662 );
663 let frames_ratio = nbr_frames_out_next as f64 / nbr_frames_in_next as f64;
664 assert_abs_diff_eq!(frames_ratio, ratio, epsilon = 0.000001);
665 };
666 }
667
668 #[macro_export]
669 macro_rules! check_reset {
670 ($resampler:ident) => {
671 let frames_in = $resampler.input_frames_next();
672
673 let mut rng = rand::thread_rng();
674 let mut input_data = vec![vec![0.0f64; frames_in]; 2];
675 input_data
676 .iter_mut()
677 .for_each(|ch| ch.iter_mut().for_each(|s| *s = rng.gen()));
678
679 let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
680
681 let frames_out = $resampler.output_frames_next();
682 let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
683 let mut output_1 =
684 SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
685 $resampler
686 .process_into_buffer(&input, &mut output_1, None)
687 .unwrap();
688 $resampler.reset();
689 assert_eq!(
690 frames_in,
691 $resampler.input_frames_next(),
692 "Resampler requires different number of frames when new and after a reset."
693 );
694 let mut output_data_2 = vec![vec![0.0; frames_out]; 2];
695 let mut output_2 =
696 SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out).unwrap();
697 $resampler
698 .process_into_buffer(&input, &mut output_2, None)
699 .unwrap();
700 assert_eq!(
701 output_data_1, output_data_2,
702 "Resampler gives different output when new and after a reset."
703 );
704 };
705 }
706
707 #[macro_export]
708 macro_rules! check_input_offset {
709 ($resampler:ident) => {
710 let frames_in = $resampler.input_frames_next();
711
712 let mut rng = rand::thread_rng();
713 let mut input_data_1 = vec![vec![0.0f64; frames_in]; 2];
714 input_data_1
715 .iter_mut()
716 .for_each(|ch| ch.iter_mut().for_each(|s| *s = rng.gen()));
717
718 let offset = 123;
719 let mut input_data_2 = vec![vec![0.0f64; frames_in + offset]; 2];
720 for (ch, data) in input_data_2.iter_mut().enumerate() {
721 data[offset..offset + frames_in].clone_from_slice(&input_data_1[ch][..])
722 }
723
724 let input_1 = SequentialSliceOfVecs::new(&input_data_1, 2, frames_in).unwrap();
725 let input_2 = SequentialSliceOfVecs::new(&input_data_2, 2, frames_in + offset).unwrap();
726
727 let frames_out = $resampler.output_frames_next();
728 let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
729 let mut output_1 =
730 SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
731 $resampler
732 .process_into_buffer(&input_1, &mut output_1, None)
733 .unwrap();
734 $resampler.reset();
735 assert_eq!(
736 frames_in,
737 $resampler.input_frames_next(),
738 "Resampler requires different number of frames when new and after a reset."
739 );
740 let mut output_data_2 = vec![vec![0.0; frames_out]; 2];
741 let mut output_2 =
742 SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out).unwrap();
743
744 let indexing = Indexing {
745 input_offset: offset,
746 output_offset: 0,
747 active_channels_mask: None,
748 partial_len: None,
749 };
750 $resampler
751 .process_into_buffer(&input_2, &mut output_2, Some(&indexing))
752 .unwrap();
753 assert_eq!(
754 output_data_1, output_data_2,
755 "Resampler gives different output when new and after a reset."
756 );
757 };
758 }
759
760 #[macro_export]
761 macro_rules! check_output_offset {
762 ($resampler:ident) => {
763 let frames_in = $resampler.input_frames_next();
764
765 let mut rng = rand::thread_rng();
766 let mut input_data = vec![vec![0.0f64; frames_in]; 2];
767 input_data
768 .iter_mut()
769 .for_each(|ch| ch.iter_mut().for_each(|s| *s = rng.gen()));
770
771 let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
772
773 let frames_out = $resampler.output_frames_next();
774 let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
775 let mut output_1 =
776 SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
777 $resampler
778 .process_into_buffer(&input, &mut output_1, None)
779 .unwrap();
780 $resampler.reset();
781 assert_eq!(
782 frames_in,
783 $resampler.input_frames_next(),
784 "Resampler requires different number of frames when new and after a reset."
785 );
786 let offset = 123;
787 let mut output_data_2 = vec![vec![0.0; frames_out + offset]; 2];
788 let mut output_2 =
789 SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out + offset).unwrap();
790 let indexing = Indexing {
791 input_offset: 0,
792 output_offset: offset,
793 active_channels_mask: None,
794 partial_len: None,
795 };
796 $resampler
797 .process_into_buffer(&input, &mut output_2, Some(&indexing))
798 .unwrap();
799 assert_eq!(
800 output_data_1[0][..],
801 output_data_2[0][offset..],
802 "Resampler gives different output when new and after a reset."
803 );
804 assert_eq!(
805 output_data_1[1][..],
806 output_data_2[1][offset..],
807 "Resampler gives different output when new and after a reset."
808 );
809 };
810 }
811
812 #[macro_export]
813 macro_rules! check_masked {
814 ($resampler:ident) => {
815 let frames_in = $resampler.input_frames_next();
816
817 let mut rng = rand::thread_rng();
818 let mut input_data = vec![vec![0.0f64; frames_in]; 2];
819 input_data
820 .iter_mut()
821 .for_each(|ch| ch.iter_mut().for_each(|s| *s = rng.gen()));
822
823 let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
824
825 let frames_out = $resampler.output_frames_next();
826 let mut output_data = vec![vec![0.0; frames_out]; 2];
827 let mut output =
828 SequentialSliceOfVecs::new_mut(&mut output_data, 2, frames_out).unwrap();
829
830 let indexing = Indexing {
831 input_offset: 0,
832 output_offset: 0,
833 active_channels_mask: Some(vec![false, true]),
834 partial_len: None,
835 };
836 $resampler
837 .process_into_buffer(&input, &mut output, Some(&indexing))
838 .unwrap();
839
840 let non_zero_chan_0 = output_data[0].iter().filter(|&v| *v != 0.0).count();
841 let non_zero_chan_1 = output_data[1].iter().filter(|&v| *v != 0.0).count();
842 assert_eq!(
844 non_zero_chan_0, 0,
845 "Some sample in the non-active channel has a non-zero value"
846 );
847 assert!(
849 non_zero_chan_1 > 0,
850 "No sample in the active channel has a non-zero value"
851 );
852 };
853 }
854
855 #[macro_export]
856 macro_rules! check_resize {
857 ($resampler:ident) => {};
858 }
859}