rubato/
lib.rs

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// Logging wrapper macros to avoid cluttering the code with conditionals.
12#[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/// A struct for providing optional parameters when calling
68/// [process_into_buffer](Resampler::process_into_buffer).
69#[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
88/// Helper to update the mask from an optional Indexing struct
89pub(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
99/// A resampler that is used to resample a chunk of audio to a new sample rate.
100/// For asynchronous resamplers, the rate can be adjusted as required.
101pub trait Resampler<T>: Send
102where
103    T: Sample,
104{
105    /// This is a convenience wrapper for [process_into_buffer](Resampler::process_into_buffer)
106    /// that allocates the output buffer with each call. For realtime applications, use
107    /// [process_into_buffer](Resampler::process_into_buffer) with a pre-allocated buffer
108    /// instead of this function.
109    ///
110    /// The output is returned as an [InterleavedOwned] struct that wraps a `Vec<T>`
111    /// of interleaved samples.
112    ///
113    /// The `input_offset` and `active_channels_mask` parameters have the same meaning as in
114    /// [process_into_buffer](Resampler::process_into_buffer).
115    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    /// Resample a buffer of audio to a pre-allocated output buffer.
136    /// Use this in real-time applications where the unpredictable time required to allocate
137    /// memory from the heap can cause glitches. If this is not a problem, you may use
138    /// the [process](Resampler::process) method instead.
139    ///
140    /// The input and output buffers are buffers from the [audioadapter] crate.
141    /// The input buffer must implement the [Adapter] trait,
142    /// and the output the corresponding [AdapterMut] trait.
143    /// This ensures that this method is able to both read and write
144    /// audio data from and to buffers with different layout, as well as different sample formats.
145    ///
146    /// The `indexing` parameter is optional. When left out, the default values are used.
147    ///  - `input_offset` and `output_offset`: these determine how many frames at the beginning
148    ///    of the input and output buffers will be skipped before reading or writing starts.
149    ///    See the `process_f64` example for how these may be used to process a longer sound clip.
150    ///  - `partial_len`: If the input buffer has fewer frames than the required input length,
151    ///    set `partial_len` to the available number.
152    ///    The resampler will then insert silence in place of the missing frames.
153    ///    This is useful for processing a longer buffer with repeated process calls,
154    ///    where at the last iteration there may be fewer frames left than what the resampler needs.
155    ///  - `active_channels_mask`: A vector of booleans determining what channels are to be processed.
156    ///    Any channel marked as inactive by a false value will be skipped during processing
157    ///    and the corresponding output will be left unchanged.
158    ///    If `None` is given, all channels will be considered active.
159    ///
160    /// Before processing, the input and output buffer sizes are checked.
161    /// If either has the wrong number of channels, or if the buffer can hold too few frames,
162    /// a [ResampleError] is returned.
163    /// Both input and output are allowed to be longer than required.
164    /// The number of input samples consumed and the number output samples written
165    /// per channel is returned in a tuple, `(input_frames, output_frames)`.
166    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    /// Convenience method for processing audio clips of arbitrary length
174    /// from and to buffers in memory.
175    /// This method repeatedly calls [process_into_buffer](Resampler::process_into_buffer)
176    /// until all frames of the input buffer have been processed.
177    /// The processed frames are written to the output buffer,
178    /// with the initial silence (caused by the resampler delay) trimmed off.
179    ///
180    /// Use [process_all_needed_output_len](Resampler::process_all_needed_output_len)
181    /// to get the minimal length of the output buffer required
182    /// to resample a clip of a given length.
183    ///
184    /// The `active_channels_mask` parameter has the same meaning as in
185    /// [process_into_buffer](Resampler::process_into_buffer).
186    ///
187    /// Returns the lengths of the original input and the resampled output.
188    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                // move useful output data to start of output buffer
227                buffer_out.copy_frames_within(frames_to_trim, 0, frames_to_trim);
228                // update counters
229                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    /// Calculate the minimal length of the output buffer
257    /// needed to process a clip of length `input_len` using the
258    /// [process_all_into_buffer](Resampler::process_all_into_buffer) method.
259    ///
260    /// Includes additional space needed by the resampler implementation. For
261    /// the length of resampled output, see the return value of
262    /// [process_all_into_buffer](Resampler::process_all_into_buffer).
263    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    /// Get the maximum possible number of input frames per channel the resampler could require.
271    fn input_frames_max(&self) -> usize;
272
273    /// Get the number of frames per channel needed for the next call to
274    /// [process_into_buffer](Resampler::process_into_buffer) or [process](Resampler::process).
275    fn input_frames_next(&self) -> usize;
276
277    /// Get the number of channels this Resampler is configured for.
278    fn nbr_channels(&self) -> usize;
279
280    /// Get the maximum possible number of output frames per channel.
281    fn output_frames_max(&self) -> usize;
282
283    /// Get the number of frames per channel that will be output from the next call to
284    /// [process_into_buffer](Resampler::process_into_buffer) or [process](Resampler::process).
285    fn output_frames_next(&self) -> usize;
286
287    /// Get the delay for the resampler, reported as a number of output frames.
288    /// This gives how many frames any event in the input is delayed before it appears in the output.
289    fn output_delay(&self) -> usize;
290
291    /// Update the resample ratio.
292    ///
293    /// For asynchronous resamplers, the ratio must be within
294    /// `original / maximum` to `original * maximum`, where the original and maximum are the
295    /// resampling ratios that were provided to the constructor.
296    /// Trying to set the ratio
297    /// outside these bounds will return [ResampleError::RatioOutOfBounds].
298    ///
299    /// For synchronous resamplers, this will always return [ResampleError::SyncNotAdjustable].
300    ///
301    /// If the argument `ramp` is set to true, the ratio will be ramped from the old to the new value
302    /// during processing of the next chunk. This allows smooth transitions from one ratio to another.
303    /// If `ramp` is false, the new ratio will be applied from the start of the next chunk.
304    fn set_resample_ratio(&mut self, new_ratio: f64, ramp: bool) -> ResampleResult<()>;
305
306    /// Get the current resample ratio, defined as output sample rate divided by input sample rate.
307    fn resample_ratio(&self) -> f64;
308
309    /// Update the resample ratio as a factor relative to the original one.
310    ///
311    /// For asynchronous resamplers, the relative ratio must be within
312    /// `1 / maximum` to `maximum`, where `maximum` is the maximum
313    /// resampling ratio that was provided to the constructor.
314    /// Trying to set the ratio outside these bounds
315    /// will return [ResampleError::RatioOutOfBounds].
316    ///
317    /// Ratios above 1.0 slow down the output and lower the pitch, while ratios
318    /// below 1.0 speed up the output and raise the pitch.
319    ///
320    /// For synchronous resamplers, this will always return [ResampleError::SyncNotAdjustable].
321    fn set_resample_ratio_relative(&mut self, rel_ratio: f64, ramp: bool) -> ResampleResult<()>;
322
323    /// Reset the resampler state and clear all internal buffers.
324    fn reset(&mut self);
325
326    /// Change the chunk size for the resampler.
327    /// This is not supported by all resampler types.
328    /// The value must be equal to or smaller than the chunk size value
329    /// that the resampler was created with.
330    /// [ResampleError::InvalidChunkSize] is returned if the value is zero or too large.
331    ///
332    /// The meaning of chunk size depends on the resampler,
333    /// it refers to the input size for resamplers with fixed input size,
334    /// and output size for resamplers with fixed output size.
335    ///
336    /// Resamplers that do not support changing the chunk size
337    /// return [ResampleError::ChunkSizeNotAdjustable].
338    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        // add a ramp to the input
416        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        // This is a simple ratio, output should be twice as long as input
425        assert_eq!(2 * nbr_in, nbr_out);
426
427        // check that the output follows the input ramp, within suitable margins
428        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    // This tests that a Resampler can be boxed.
455    #[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    // This tests that all resamplers are Send.
501    #[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                // Check that lengths are within the reported max values
532                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 channel 0 is all zero
852            assert_eq!(
853                non_zero_chan_0, 0,
854                "Some sample in the non-active channel has a non-zero value"
855            );
856            // assert channel 1 has some values
857            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}