Skip to main content

rubato/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "log")]
4extern crate log;
5
6pub use audioadapter;
7pub use audioadapter_buffers;
8
9use audioadapter::{Adapter, AdapterMut};
10use audioadapter_buffers::owned::InterleavedOwned;
11
12// Logging wrapper macros to avoid cluttering the code with conditionals.
13#[allow(unused)]
14macro_rules! trace { ($($x:tt)*) => (
15    #[cfg(feature = "log")] {
16        log::trace!($($x)*)
17    }
18) }
19#[allow(unused)]
20macro_rules! debug { ($($x:tt)*) => (
21    #[cfg(feature = "log")] {
22        log::debug!($($x)*)
23    }
24) }
25#[allow(unused)]
26macro_rules! info { ($($x:tt)*) => (
27    #[cfg(feature = "log")] {
28        log::info!($($x)*)
29    }
30) }
31#[allow(unused)]
32macro_rules! warn { ($($x:tt)*) => (
33    #[cfg(feature = "log")] {
34        log::warn!($($x)*)
35    }
36) }
37#[allow(unused)]
38macro_rules! error { ($($x:tt)*) => (
39    #[cfg(feature = "log")] {
40        log::error!($($x)*)
41    }
42) }
43
44mod asynchro;
45mod asynchro_fast;
46mod asynchro_sinc;
47mod error;
48mod interpolation;
49mod sample;
50mod sinc;
51#[cfg(feature = "fft_resampler")]
52mod synchro;
53mod windows;
54
55pub mod sinc_interpolator;
56
57pub use crate::asynchro::{Async, FixedAsync};
58pub use crate::asynchro_fast::PolynomialDegree;
59pub use crate::asynchro_sinc::{SincInterpolationParameters, SincInterpolationType};
60pub use crate::error::{
61    CpuFeature, MissingCpuFeature, ResampleError, ResampleResult, ResamplerConstructionError,
62};
63pub use crate::sample::Sample;
64#[cfg(feature = "fft_resampler")]
65pub use crate::synchro::{Fft, FixedSync};
66pub use crate::windows::{calculate_cutoff, WindowFunction};
67
68/// A struct for providing optional parameters when calling
69/// [process_into_buffer](Resampler::process_into_buffer).
70///
71/// All fields have sensible defaults: zero offsets, no partial length, and all channels active.
72/// Pass `None` as the `indexing` argument to use these defaults without constructing the struct.
73#[derive(Debug, Clone)]
74pub struct Indexing {
75    /// Number of frames to skip at the beginning of the input buffer before reading.
76    /// Use this to process a sub-region of a larger buffer without copying data.
77    /// Defaults to `0` (read from the start of the buffer).
78    pub input_offset: usize,
79
80    /// Number of frames to skip at the beginning of the output buffer before writing.
81    /// Use this to write results into a sub-region of a larger buffer.
82    /// Defaults to `0` (write from the start of the buffer).
83    pub output_offset: usize,
84
85    /// Set to `Some(n)` when the input buffer contains fewer valid frames than
86    /// [Resampler::input_frames_next] requires.
87    /// The resampler will read the first `n` frames from the input buffer and
88    /// treat the remaining frames as silence.
89    /// This is useful for processing the very last (partial) chunk of a stream or audio clip.
90    ///
91    /// **Important:** even with `partial_len` set, the output buffer must still be large enough
92    /// to hold at least [Resampler::output_frames_next] frames (plus `output_offset`),
93    /// because the resampler always produces a full output chunk.
94    ///
95    /// Set to `Some(0)` to process a chunk of pure silence (e.g. to flush the resampler delay).
96    ///
97    /// Defaults to `None`, meaning the full [Resampler::input_frames_next] frames are read.
98    pub partial_len: Option<usize>,
99
100    /// Optional per-channel processing mask.
101    /// When `Some(vec)`, each element corresponds to one channel:
102    /// `true` means the channel is processed normally,
103    /// `false` means the channel is skipped and its output is left unchanged.
104    /// When `None`, all channels are processed.
105    pub active_channels_mask: Option<Vec<bool>>,
106}
107
108pub(crate) fn get_offsets(indexing: &Option<&Indexing>) -> (usize, usize) {
109    indexing
110        .as_ref()
111        .map(|idx| (idx.input_offset, idx.output_offset))
112        .unwrap_or((0, 0))
113}
114
115pub(crate) fn get_partial_len(indexing: &Option<&Indexing>) -> Option<usize> {
116    indexing.as_ref().and_then(|idx| idx.partial_len)
117}
118
119/// Helper to update the mask from an optional Indexing struct
120pub(crate) fn update_mask(indexing: &Option<&Indexing>, mask: &mut [bool]) {
121    if let Some(idx) = indexing {
122        if let Some(new_mask) = &idx.active_channels_mask {
123            mask.copy_from_slice(new_mask);
124            return;
125        }
126    }
127    mask.iter_mut().for_each(|v| *v = true);
128}
129
130/// A resampler that is used to resample a chunk of audio to a new sample rate.
131/// For asynchronous resamplers, the rate can be adjusted as required.
132pub trait Resampler<T>: Send
133where
134    T: Sample,
135{
136    /// This is a convenience wrapper for [process_into_buffer](Resampler::process_into_buffer)
137    /// that allocates the output buffer with each call. For realtime applications, use
138    /// [process_into_buffer](Resampler::process_into_buffer) with a pre-allocated buffer
139    /// instead of this function.
140    ///
141    /// The output is returned as an [InterleavedOwned] struct that wraps a `Vec<T>`
142    /// of interleaved samples.
143    ///
144    /// The `input_offset` and `active_channels_mask` parameters have the same meaning as in
145    /// [process_into_buffer](Resampler::process_into_buffer).
146    fn process(
147        &mut self,
148        buffer_in: &dyn Adapter<'_, T>,
149        input_offset: usize,
150        active_channels_mask: Option<&[bool]>,
151    ) -> ResampleResult<InterleavedOwned<T>> {
152        let frames = self.output_frames_next();
153        let channels = self.nbr_channels();
154        let mut buffer_out = InterleavedOwned::<T>::new(T::coerce_from(0.0), channels, frames);
155
156        let indexing = Indexing {
157            input_offset,
158            output_offset: 0,
159            partial_len: None,
160            active_channels_mask: active_channels_mask.map(|m| m.to_vec()),
161        };
162        self.process_into_buffer(buffer_in, &mut buffer_out, Some(&indexing))?;
163        Ok(buffer_out)
164    }
165
166    /// Resample a buffer of audio to a pre-allocated output buffer.
167    /// Use this in real-time applications where the unpredictable time required to allocate
168    /// memory from the heap can cause glitches. If this is not a problem, you may use
169    /// the [process](Resampler::process) method instead.
170    ///
171    /// The input and output buffers are buffers from the [audioadapter] crate.
172    /// The input buffer must implement the [Adapter] trait,
173    /// and the output the corresponding [AdapterMut] trait.
174    /// This ensures that this method is able to both read and write
175    /// audio data from and to buffers with different layout, as well as different sample formats.
176    ///
177    /// The `indexing` parameter is optional. When left out, the default values are used.
178    ///  - `input_offset` and `output_offset`: these determine how many frames at the beginning
179    ///    of the input and output buffers will be skipped before reading or writing starts.
180    ///    See the `process_f64` example for how these may be used to process a longer sound clip.
181    ///  - `partial_len`: If the input buffer has fewer frames than the required input length,
182    ///    set `partial_len` to the available number.
183    ///    The resampler will then insert silence in place of the missing frames.
184    ///    This is useful for processing a longer buffer with repeated process calls,
185    ///    where at the last iteration there may be fewer frames left than what the resampler needs.
186    ///  - `active_channels_mask`: A vector of booleans determining what channels are to be processed.
187    ///    Any channel marked as inactive by a false value will be skipped during processing
188    ///    and the corresponding output will be left unchanged.
189    ///    If `None` is given, all channels will be considered active.
190    ///
191    /// Before processing, the input and output buffer sizes are checked.
192    /// If either has the wrong number of channels, or if the buffer can hold too few frames,
193    /// a [ResampleError] is returned.
194    /// Both input and output are allowed to be longer than required.
195    /// The number of input samples consumed and the number output samples written
196    /// per channel is returned in a tuple, `(input_frames, output_frames)`.
197    fn process_into_buffer<'a, 'b>(
198        &mut self,
199        buffer_in: &dyn Adapter<'a, T>,
200        buffer_out: &mut dyn AdapterMut<'b, T>,
201        indexing: Option<&Indexing>,
202    ) -> ResampleResult<(usize, usize)>;
203
204    /// Convenience method for processing audio clips of arbitrary length
205    /// from and to buffers in memory.
206    /// This method repeatedly calls [process_into_buffer](Resampler::process_into_buffer)
207    /// until all frames of the input buffer have been processed.
208    /// The processed frames are written to the output buffer,
209    /// with the initial silence (caused by the resampler delay) trimmed off.
210    ///
211    /// Use [process_all_needed_output_len](Resampler::process_all_needed_output_len)
212    /// to get the minimal length of the output buffer required
213    /// to resample a clip of a given length.
214    ///
215    /// The `active_channels_mask` parameter has the same meaning as in
216    /// [process_into_buffer](Resampler::process_into_buffer).
217    ///
218    /// Returns the lengths of the original input and the resampled output.
219    fn process_all_into_buffer<'a, 'b>(
220        &mut self,
221        buffer_in: &dyn Adapter<'a, T>,
222        buffer_out: &mut dyn AdapterMut<'b, T>,
223        input_len: usize,
224        active_channels_mask: Option<&[bool]>,
225    ) -> ResampleResult<(usize, usize)> {
226        let expected_output_len = (self.resample_ratio() * input_len as f64).ceil() as usize;
227
228        let mut indexing = Indexing {
229            input_offset: 0,
230            output_offset: 0,
231            active_channels_mask: active_channels_mask.map(|m| m.to_vec()),
232            partial_len: None,
233        };
234
235        let mut frames_left = input_len;
236        let mut output_len = 0;
237        let mut frames_to_trim = self.output_delay();
238        debug!(
239            "resamping {} input frames to {} output frames, delay to trim off {} frames",
240            input_len, expected_output_len, frames_to_trim
241        );
242
243        let next_nbr_input_frames = self.input_frames_next();
244        while frames_left > next_nbr_input_frames {
245            debug!("process, {} input frames left", frames_left);
246            let (nbr_in, nbr_out) =
247                self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
248            frames_left -= nbr_in;
249            output_len += nbr_out;
250            indexing.input_offset += nbr_in;
251            indexing.output_offset += nbr_out;
252            if frames_to_trim > 0 && output_len > frames_to_trim {
253                debug!(
254                    "output, {} is longer than delay to trim, {}, trimming..",
255                    output_len, frames_to_trim
256                );
257                // move useful output data to start of output buffer
258                buffer_out.copy_frames_within(frames_to_trim, 0, frames_to_trim);
259                // update counters
260                output_len -= frames_to_trim;
261                indexing.output_offset -= frames_to_trim;
262                frames_to_trim = 0;
263            }
264        }
265        if frames_left > 0 {
266            debug!("process the last partial chunk, len {}", frames_left);
267            indexing.partial_len = Some(frames_left);
268            let (_nbr_in, nbr_out) =
269                self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
270            output_len += nbr_out;
271            indexing.output_offset += nbr_out;
272        }
273        indexing.partial_len = Some(0);
274        while output_len < expected_output_len {
275            debug!(
276                "output is still too short, {} < {}, pump zeros..",
277                output_len, expected_output_len
278            );
279            let (_nbr_in, nbr_out) =
280                self.process_into_buffer(buffer_in, buffer_out, Some(&indexing))?;
281            output_len += nbr_out;
282            indexing.output_offset += nbr_out;
283        }
284        Ok((input_len, expected_output_len))
285    }
286
287    /// Calculate the minimal length of the output buffer
288    /// needed to process a clip of length `input_len` using the
289    /// [process_all_into_buffer](Resampler::process_all_into_buffer) method.
290    ///
291    /// Includes additional space needed by the resampler implementation. For
292    /// the length of resampled output, see the return value of
293    /// [process_all_into_buffer](Resampler::process_all_into_buffer).
294    fn process_all_needed_output_len(&mut self, input_len: usize) -> usize {
295        let delay_frames = self.output_delay();
296        let output_frames_max = self.output_frames_max();
297        let expected_output_len = (self.resample_ratio() * input_len as f64).ceil() as usize;
298        delay_frames + output_frames_max + expected_output_len
299    }
300
301    /// Get the maximum possible number of input frames per channel the resampler could require.
302    fn input_frames_max(&self) -> usize;
303
304    /// Get the number of frames per channel needed for the next call to
305    /// [process_into_buffer](Resampler::process_into_buffer) or [process](Resampler::process).
306    fn input_frames_next(&self) -> usize;
307
308    /// Get the number of channels this Resampler is configured for.
309    fn nbr_channels(&self) -> usize;
310
311    /// Get the maximum possible number of output frames per channel.
312    fn output_frames_max(&self) -> usize;
313
314    /// Get the number of frames per channel that will be output from the next call to
315    /// [process_into_buffer](Resampler::process_into_buffer) or [process](Resampler::process).
316    fn output_frames_next(&self) -> usize;
317
318    /// Get the delay for the resampler, reported as a number of output frames.
319    /// This gives how many frames any event in the input is delayed before it appears in the output.
320    fn output_delay(&self) -> usize;
321
322    /// Update the resample ratio.
323    ///
324    /// For asynchronous resamplers, the ratio must be within
325    /// `original / maximum` to `original * maximum`, where the original and maximum are the
326    /// resampling ratios that were provided to the constructor.
327    /// Trying to set the ratio
328    /// outside these bounds will return [ResampleError::RatioOutOfBounds].
329    ///
330    /// For synchronous resamplers, this will always return [ResampleError::SyncNotAdjustable].
331    ///
332    /// If the argument `ramp` is set to true, the ratio will be ramped from the old to the new value
333    /// during processing of the next chunk. This allows smooth transitions from one ratio to another.
334    /// If `ramp` is false, the new ratio will be applied from the start of the next chunk.
335    fn set_resample_ratio(&mut self, new_ratio: f64, ramp: bool) -> ResampleResult<()>;
336
337    /// Get the current resample ratio, defined as output sample rate divided by input sample rate.
338    fn resample_ratio(&self) -> f64;
339
340    /// Update the resample ratio as a factor relative to the original one.
341    ///
342    /// For asynchronous resamplers, the relative ratio must be within
343    /// `1 / maximum` to `maximum`, where `maximum` is the maximum
344    /// resampling ratio that was provided to the constructor.
345    /// Trying to set the ratio outside these bounds
346    /// will return [ResampleError::RatioOutOfBounds].
347    ///
348    /// Ratios above 1.0 slow down the output and lower the pitch, while ratios
349    /// below 1.0 speed up the output and raise the pitch.
350    ///
351    /// For synchronous resamplers, this will always return [ResampleError::SyncNotAdjustable].
352    fn set_resample_ratio_relative(&mut self, rel_ratio: f64, ramp: bool) -> ResampleResult<()>;
353
354    /// Reset the resampler state and clear all internal buffers.
355    fn reset(&mut self);
356
357    /// Change the chunk size for the resampler.
358    /// This is not supported by all resampler types.
359    /// The value must be equal to or smaller than the chunk size value
360    /// that the resampler was created with.
361    /// [ResampleError::InvalidChunkSize] is returned if the value is zero or too large.
362    ///
363    /// The meaning of chunk size depends on the resampler,
364    /// it refers to the input size for resamplers with fixed input size,
365    /// and output size for resamplers with fixed output size.
366    ///
367    /// Resamplers that do not support changing the chunk size
368    /// return [ResampleError::ChunkSizeNotAdjustable].
369    fn set_chunk_size(&mut self, _chunksize: usize) -> ResampleResult<()> {
370        Err(ResampleError::ChunkSizeNotAdjustable)
371    }
372}
373
374pub(crate) fn validate_buffers<'a, 'b, T: 'a + 'b>(
375    wave_in: &dyn Adapter<'a, T>,
376    wave_out: &dyn AdapterMut<'b, T>,
377    mask: &[bool],
378    channels: usize,
379    min_input_len: usize,
380    min_output_len: usize,
381) -> ResampleResult<()> {
382    if wave_in.channels() != channels {
383        return Err(ResampleError::WrongNumberOfInputChannels {
384            expected: channels,
385            actual: wave_in.channels(),
386        });
387    }
388    if mask.len() != channels {
389        return Err(ResampleError::WrongNumberOfMaskChannels {
390            expected: channels,
391            actual: mask.len(),
392        });
393    }
394    if wave_in.frames() < min_input_len {
395        return Err(ResampleError::InsufficientInputBufferSize {
396            expected: min_input_len,
397            actual: wave_in.frames(),
398        });
399    }
400    if wave_out.channels() != channels {
401        return Err(ResampleError::WrongNumberOfOutputChannels {
402            expected: channels,
403            actual: wave_out.channels(),
404        });
405    }
406    if wave_out.frames() < min_output_len {
407        return Err(ResampleError::InsufficientOutputBufferSize {
408            expected: min_output_len,
409            actual: wave_out.frames(),
410        });
411    }
412    Ok(())
413}
414
415#[cfg(test)]
416pub mod tests {
417    #[cfg(feature = "fft_resampler")]
418    use crate::Fft;
419    use crate::Resampler;
420    use crate::{
421        Async, FixedAsync, SincInterpolationParameters, SincInterpolationType, WindowFunction,
422    };
423    use audioadapter::Adapter;
424    use audioadapter_buffers::direct::SequentialSliceOfVecs;
425
426    #[test_log::test]
427    fn process_all() {
428        let mut resampler = Async::<f64>::new_sinc(
429            88200.0 / 44100.0,
430            1.1,
431            &SincInterpolationParameters {
432                sinc_len: 64,
433                f_cutoff: 0.95,
434                interpolation: SincInterpolationType::Cubic,
435                oversampling_factor: 16,
436                window: WindowFunction::BlackmanHarris2,
437            },
438            1024,
439            2,
440            FixedAsync::Input,
441        )
442        .unwrap();
443        let input_len = 12345;
444        let samples: Vec<f64> = (0..input_len).map(|v| v as f64 / 10.0).collect();
445        let input_data = vec![samples; 2];
446        // add a ramp to the input
447        let input = SequentialSliceOfVecs::new(&input_data, 2, input_len).unwrap();
448        let output_len = resampler.process_all_needed_output_len(input_len);
449        let mut output_data = vec![vec![0.0f64; output_len]; 2];
450        let mut output = SequentialSliceOfVecs::new_mut(&mut output_data, 2, output_len).unwrap();
451        let (nbr_in, nbr_out) = resampler
452            .process_all_into_buffer(&input, &mut output, input_len, None)
453            .unwrap();
454        assert_eq!(nbr_in, input_len);
455        // This is a simple ratio, output should be twice as long as input
456        assert_eq!(2 * nbr_in, nbr_out);
457
458        // check that the output follows the input ramp, within suitable margins
459        let increment = 0.1 / resampler.resample_ratio();
460        let delay = resampler.output_delay();
461        let margin = (delay as f64 * resampler.resample_ratio()) as usize;
462        let mut expected = margin as f64 * increment;
463        for frame in margin..(nbr_out - margin) {
464            for chan in 0..2 {
465                let val = output.read_sample(chan, frame).unwrap();
466                assert!(
467                    val - expected < 100.0 * increment,
468                    "frame: {}, value: {}, expected: {}",
469                    frame,
470                    val,
471                    expected
472                );
473                assert!(
474                    expected - val < 100.0 * increment,
475                    "frame: {}, value: {}, expected: {}",
476                    frame,
477                    val,
478                    expected
479                );
480            }
481            expected += increment;
482        }
483    }
484
485    // This tests that a Resampler can be boxed.
486    #[test_log::test]
487    fn boxed_resampler() {
488        let mut boxed: Box<dyn Resampler<f64>> = Box::new(
489            Async::<f64>::new_sinc(
490                88200.0 / 44100.0,
491                1.1,
492                &SincInterpolationParameters {
493                    sinc_len: 64,
494                    f_cutoff: 0.95,
495                    interpolation: SincInterpolationType::Cubic,
496                    oversampling_factor: 16,
497                    window: WindowFunction::BlackmanHarris2,
498                },
499                1024,
500                2,
501                FixedAsync::Input,
502            )
503            .unwrap(),
504        );
505        let max_frames_out = boxed.output_frames_max();
506        let nbr_frames_in_next = boxed.input_frames_next();
507        let waves = vec![vec![0.0f64; nbr_frames_in_next]; 2];
508        let mut waves_out = vec![vec![0.0f64; max_frames_out]; 2];
509        let input = SequentialSliceOfVecs::new(&waves, 2, nbr_frames_in_next).unwrap();
510        let mut output = SequentialSliceOfVecs::new_mut(&mut waves_out, 2, max_frames_out).unwrap();
511        process_with_boxed(&mut boxed, &input, &mut output);
512    }
513
514    fn process_with_boxed<'a>(
515        resampler: &mut Box<dyn Resampler<f64>>,
516        input: &SequentialSliceOfVecs<&'a [Vec<f64>]>,
517        output: &mut SequentialSliceOfVecs<&'a mut [Vec<f64>]>,
518    ) {
519        resampler.process_into_buffer(input, output, None).unwrap();
520    }
521
522    fn impl_send<T: Send>() {
523        fn is_send<T: Send>() {}
524        is_send::<Async<T>>();
525        #[cfg(feature = "fft_resampler")]
526        {
527            is_send::<Fft<T>>();
528        }
529    }
530
531    // This tests that all resamplers are Send.
532    #[test]
533    fn test_impl_send() {
534        impl_send::<f32>();
535        impl_send::<f64>();
536    }
537
538    pub fn expected_output_value(idx: usize, delay: usize, ratio: f64) -> f64 {
539        if idx <= delay {
540            return 0.0;
541        }
542        (idx - delay) as f64 * 0.1 / ratio
543    }
544
545    #[macro_export]
546    macro_rules! check_output {
547        ($resampler:ident, $fty:ty) => {
548            let mut ramp_value: $fty = 0.0;
549            let max_input_len = $resampler.input_frames_max();
550            let max_output_len = $resampler.output_frames_max();
551            let ratio = $resampler.resample_ratio() as $fty;
552            let delay = $resampler.output_delay();
553            let mut output_index = 0;
554
555            let out_incr = 0.1 / ratio;
556
557            let nbr_iterations =
558                100000 / ($resampler.output_frames_next() + $resampler.input_frames_next());
559            for _n in 0..nbr_iterations {
560                let expected_frames_in = $resampler.input_frames_next();
561                let expected_frames_out = $resampler.output_frames_next();
562                // Check that lengths are within the reported max values
563                assert!(expected_frames_in <= max_input_len);
564                assert!(expected_frames_out <= max_output_len);
565                let mut input_data = vec![vec![0.0 as $fty; expected_frames_in]; 2];
566                for m in 0..expected_frames_in {
567                    for ch in 0..2 {
568                        input_data[ch][m] = ramp_value;
569                    }
570                    ramp_value += 0.1;
571                }
572                let input = SequentialSliceOfVecs::new(&input_data, 2, expected_frames_in).unwrap();
573                let mut output_data = vec![vec![0.0 as $fty; expected_frames_out]; 2];
574                let mut output =
575                    SequentialSliceOfVecs::new_mut(&mut output_data, 2, expected_frames_out)
576                        .unwrap();
577
578                trace!("resample...");
579                let (input_frames, output_frames) = $resampler
580                    .process_into_buffer(&input, &mut output, None)
581                    .unwrap();
582                trace!("assert lengths");
583                assert_eq!(input_frames, expected_frames_in);
584                assert_eq!(output_frames, expected_frames_out);
585                trace!("check output");
586                for idx in 0..output_frames {
587                    let expected = expected_output_value(output_index + idx, delay, ratio) as $fty;
588                    for ch in 0..2 {
589                        let value = output_data[ch][idx];
590                        let margin = 3.0 * out_incr;
591                        assert!(
592                            value > expected - margin,
593                            "Value at frame {} is too small, {} < {} - {}",
594                            output_index + idx,
595                            value,
596                            expected,
597                            margin
598                        );
599                        assert!(
600                            value < expected + margin,
601                            "Value at frame {} is too large, {} > {} + {}",
602                            output_index + idx,
603                            value,
604                            expected,
605                            margin
606                        );
607                    }
608                }
609                output_index += output_frames;
610            }
611            assert!(output_index > 1000, "Too few frames checked!");
612        };
613    }
614
615    #[macro_export]
616    macro_rules! check_ratio {
617        ($resampler:ident, $repetitions:expr, $margin:expr, $fty:ty) => {
618            let ratio = $resampler.resample_ratio();
619            let max_input_len = $resampler.input_frames_max();
620            let max_output_len = $resampler.output_frames_max();
621            let waves_in = vec![vec![0.0 as $fty; max_input_len]; 2];
622            let input = SequentialSliceOfVecs::new(&waves_in, 2, max_input_len).unwrap();
623            let mut waves_out = vec![vec![0.0 as $fty; max_output_len]; 2];
624            let mut output =
625                SequentialSliceOfVecs::new_mut(&mut waves_out, 2, max_output_len).unwrap();
626            let mut total_in = 0;
627            let mut total_out = 0;
628            for _ in 0..$repetitions {
629                let out = $resampler
630                    .process_into_buffer(&input, &mut output, None)
631                    .unwrap();
632                total_in += out.0;
633                total_out += out.1
634            }
635            let measured_ratio = total_out as f64 / total_in as f64;
636            assert!(
637                measured_ratio / ratio > (1.0 - $margin),
638                "Measured ratio is too small, measured / expected = {}",
639                measured_ratio / ratio
640            );
641            assert!(
642                measured_ratio / ratio < (1.0 + $margin),
643                "Measured ratio is too large, measured / expected = {}",
644                measured_ratio / ratio
645            );
646        };
647    }
648
649    #[macro_export]
650    macro_rules! assert_fi_len {
651        ($resampler:ident, $chunksize:expr) => {
652            let nbr_frames_in_next = $resampler.input_frames_next();
653            let nbr_frames_in_max = $resampler.input_frames_max();
654            assert_eq!(
655                nbr_frames_in_next, $chunksize,
656                "expected {} for next input samples, got {}",
657                $chunksize, nbr_frames_in_next
658            );
659            assert_eq!(
660                nbr_frames_in_next, $chunksize,
661                "expected {} for max input samples, got {}",
662                $chunksize, nbr_frames_in_max
663            );
664        };
665    }
666
667    #[macro_export]
668    macro_rules! assert_fo_len {
669        ($resampler:ident, $chunksize:expr) => {
670            let nbr_frames_out_next = $resampler.output_frames_next();
671            let nbr_frames_out_max = $resampler.output_frames_max();
672            assert_eq!(
673                nbr_frames_out_next, $chunksize,
674                "expected {} for next output samples, got {}",
675                $chunksize, nbr_frames_out_next
676            );
677            assert_eq!(
678                nbr_frames_out_next, $chunksize,
679                "expected {} for max output samples, got {}",
680                $chunksize, nbr_frames_out_max
681            );
682        };
683    }
684
685    #[macro_export]
686    macro_rules! assert_fb_len {
687        ($resampler:ident) => {
688            let nbr_frames_out_next = $resampler.output_frames_next();
689            let nbr_frames_out_max = $resampler.output_frames_max();
690            let nbr_frames_in_next = $resampler.input_frames_next();
691            let nbr_frames_in_max = $resampler.input_frames_max();
692            let ratio = $resampler.resample_ratio();
693            assert_eq!(
694                nbr_frames_out_next, nbr_frames_out_max,
695                "next output frames, {}, is different than max, {}",
696                nbr_frames_out_next, nbr_frames_out_next
697            );
698            assert_eq!(
699                nbr_frames_in_next, nbr_frames_in_max,
700                "next input frames, {}, is different than max, {}",
701                nbr_frames_in_next, nbr_frames_in_max
702            );
703            let frames_ratio = nbr_frames_out_next as f64 / nbr_frames_in_next as f64;
704            assert_abs_diff_eq!(frames_ratio, ratio, epsilon = 0.000001);
705        };
706    }
707
708    #[macro_export]
709    macro_rules! check_reset {
710        ($resampler:ident) => {
711            let frames_in = $resampler.input_frames_next();
712
713            let mut input_data = vec![vec![0.0f64; frames_in]; 2];
714            input_data
715                .iter_mut()
716                .for_each(|ch| ch.iter_mut().for_each(|s| *s = rand::random()));
717
718            let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
719
720            let frames_out = $resampler.output_frames_next();
721            let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
722            let mut output_1 =
723                SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
724            $resampler
725                .process_into_buffer(&input, &mut output_1, None)
726                .unwrap();
727            $resampler.reset();
728            assert_eq!(
729                frames_in,
730                $resampler.input_frames_next(),
731                "Resampler requires different number of frames when new and after a reset."
732            );
733            let mut output_data_2 = vec![vec![0.0; frames_out]; 2];
734            let mut output_2 =
735                SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out).unwrap();
736            $resampler
737                .process_into_buffer(&input, &mut output_2, None)
738                .unwrap();
739            assert_eq!(
740                output_data_1, output_data_2,
741                "Resampler gives different output when new and after a reset."
742            );
743        };
744    }
745
746    #[macro_export]
747    macro_rules! check_input_offset {
748        ($resampler:ident) => {
749            let frames_in = $resampler.input_frames_next();
750
751            let mut input_data_1 = vec![vec![0.0f64; frames_in]; 2];
752            input_data_1
753                .iter_mut()
754                .for_each(|ch| ch.iter_mut().for_each(|s| *s = rand::random()));
755
756            let offset = 123;
757            let mut input_data_2 = vec![vec![0.0f64; frames_in + offset]; 2];
758            for (ch, data) in input_data_2.iter_mut().enumerate() {
759                data[offset..offset + frames_in].clone_from_slice(&input_data_1[ch][..])
760            }
761
762            let input_1 = SequentialSliceOfVecs::new(&input_data_1, 2, frames_in).unwrap();
763            let input_2 = SequentialSliceOfVecs::new(&input_data_2, 2, frames_in + offset).unwrap();
764
765            let frames_out = $resampler.output_frames_next();
766            let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
767            let mut output_1 =
768                SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
769            $resampler
770                .process_into_buffer(&input_1, &mut output_1, None)
771                .unwrap();
772            $resampler.reset();
773            assert_eq!(
774                frames_in,
775                $resampler.input_frames_next(),
776                "Resampler requires different number of frames when new and after a reset."
777            );
778            let mut output_data_2 = vec![vec![0.0; frames_out]; 2];
779            let mut output_2 =
780                SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out).unwrap();
781
782            let indexing = Indexing {
783                input_offset: offset,
784                output_offset: 0,
785                active_channels_mask: None,
786                partial_len: None,
787            };
788            $resampler
789                .process_into_buffer(&input_2, &mut output_2, Some(&indexing))
790                .unwrap();
791            assert_eq!(
792                output_data_1, output_data_2,
793                "Resampler gives different output when new and after a reset."
794            );
795        };
796    }
797
798    #[macro_export]
799    macro_rules! check_output_offset {
800        ($resampler:ident) => {
801            let frames_in = $resampler.input_frames_next();
802
803            let mut input_data = vec![vec![0.0f64; frames_in]; 2];
804            input_data
805                .iter_mut()
806                .for_each(|ch| ch.iter_mut().for_each(|s| *s = rand::random()));
807
808            let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
809
810            let frames_out = $resampler.output_frames_next();
811            let mut output_data_1 = vec![vec![0.0; frames_out]; 2];
812            let mut output_1 =
813                SequentialSliceOfVecs::new_mut(&mut output_data_1, 2, frames_out).unwrap();
814            $resampler
815                .process_into_buffer(&input, &mut output_1, None)
816                .unwrap();
817            $resampler.reset();
818            assert_eq!(
819                frames_in,
820                $resampler.input_frames_next(),
821                "Resampler requires different number of frames when new and after a reset."
822            );
823            let offset = 123;
824            let mut output_data_2 = vec![vec![0.0; frames_out + offset]; 2];
825            let mut output_2 =
826                SequentialSliceOfVecs::new_mut(&mut output_data_2, 2, frames_out + offset).unwrap();
827            let indexing = Indexing {
828                input_offset: 0,
829                output_offset: offset,
830                active_channels_mask: None,
831                partial_len: None,
832            };
833            $resampler
834                .process_into_buffer(&input, &mut output_2, Some(&indexing))
835                .unwrap();
836            assert_eq!(
837                output_data_1[0][..],
838                output_data_2[0][offset..],
839                "Resampler gives different output when new and after a reset."
840            );
841            assert_eq!(
842                output_data_1[1][..],
843                output_data_2[1][offset..],
844                "Resampler gives different output when new and after a reset."
845            );
846        };
847    }
848
849    #[macro_export]
850    macro_rules! check_masked {
851        ($resampler:ident) => {
852            let frames_in = $resampler.input_frames_next();
853
854            let mut input_data = vec![vec![0.0f64; frames_in]; 2];
855            input_data
856                .iter_mut()
857                .for_each(|ch| ch.iter_mut().for_each(|s| *s = rand::random()));
858
859            let input = SequentialSliceOfVecs::new(&input_data, 2, frames_in).unwrap();
860
861            let frames_out = $resampler.output_frames_next();
862            let mut output_data = vec![vec![0.0; frames_out]; 2];
863            let mut output =
864                SequentialSliceOfVecs::new_mut(&mut output_data, 2, frames_out).unwrap();
865
866            let indexing = Indexing {
867                input_offset: 0,
868                output_offset: 0,
869                active_channels_mask: Some(vec![false, true]),
870                partial_len: None,
871            };
872            $resampler
873                .process_into_buffer(&input, &mut output, Some(&indexing))
874                .unwrap();
875
876            let non_zero_chan_0 = output_data[0].iter().filter(|&v| *v != 0.0).count();
877            let non_zero_chan_1 = output_data[1].iter().filter(|&v| *v != 0.0).count();
878            // assert channel 0 is all zero
879            assert_eq!(
880                non_zero_chan_0, 0,
881                "Some sample in the non-active channel has a non-zero value"
882            );
883            // assert channel 1 has some values
884            assert!(
885                non_zero_chan_1 > 0,
886                "No sample in the active channel has a non-zero value"
887            );
888        };
889    }
890
891    #[macro_export]
892    macro_rules! check_resize {
893        ($resampler:ident) => {};
894    }
895}