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