rubato/
lib.rs

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