fixed_resample/
resampler_type.rs

1use std::num::NonZeroUsize;
2
3use rubato::{
4    FastFixedIn, ResampleResult, Resampler as RubatoResampler, Sample, SincFixedIn,
5    SincInterpolationParameters, SincInterpolationType, WindowFunction,
6};
7
8use crate::ResampleQuality;
9
10/// The resampling algorithm used in `fixed_resample`.
11pub enum ResamplerType<T: Sample> {
12    /// Ok quality, fast performance
13    Fast(FastFixedIn<T>),
14    #[cfg(feature = "fft-resampler")]
15    /// Great quality, medium performance
16    Fft(rubato::FftFixedIn<T>),
17    /// Similar quality to [`ResamplerType::Fft`], low performance.
18    ///
19    /// Use this if you need a non-integer ratio (i.e. repitching a
20    /// sample).
21    ArbitraryRatioSinc(rubato::SincFixedIn<T>),
22}
23
24impl<T: Sample> ResamplerType<T> {
25    pub fn from_quality(
26        in_sample_rate: u32,
27        out_sample_rate: u32,
28        num_channels: NonZeroUsize,
29        quality: ResampleQuality,
30    ) -> Self {
31        assert_ne!(in_sample_rate, 0);
32        assert_ne!(out_sample_rate, 0);
33
34        #[cfg(feature = "fft-resampler")]
35        if let ResampleQuality::High = quality {
36            return Self::Fft(
37                rubato::FftFixedIn::new(
38                    in_sample_rate as usize,
39                    out_sample_rate as usize,
40                    1024,
41                    2,
42                    num_channels.get(),
43                )
44                .unwrap(),
45            );
46        }
47
48        #[cfg(not(feature = "fft-resampler"))]
49        let _ = quality;
50
51        Self::Fast(
52            FastFixedIn::new(
53                out_sample_rate as f64 / in_sample_rate as f64,
54                1.0,
55                rubato::PolynomialDegree::Linear,
56                1024,
57                num_channels.get(),
58            )
59            .unwrap(),
60        )
61    }
62
63    /// Create a new resampler that uses the `SincFixedIn` resampler from rubato.
64    ///
65    /// This has similar quality to the [`rubato::FftFixedIn`] resampler used
66    /// for [`ResampleQuality::High`], but with much lower performance. Use
67    /// this if you need a non-integer ratio (i.e. repitching a sample).
68    ///
69    /// * `ratio` - The resampling ratio (`output / input`)
70    /// * `num_channels` - The number of channels
71    ///
72    /// More specifically, this creates a resampler with the following parameters:
73    /// ```rust,ignore
74    /// SincInterpolationParameters {
75    ///     sinc_len: 128,
76    ///     f_cutoff: rubato::calculate_cutoff(128, WindowFunction::Blackman2),
77    ///     interpolation: SincInterpolationType::Cubic,
78    ///     oversampling_factor: 512,
79    ///     window: WindowFunction::Blackman2,
80    /// }
81    /// ```
82    ///
83    /// ## Panics
84    ///
85    /// Panics if:
86    /// * `ratio <= 0.0`
87    /// * `num_channels > MAX_CHANNELS`
88    pub fn arbitrary_ratio_sinc(ratio: f64, num_channels: NonZeroUsize) -> Self {
89        assert!(ratio > 0.0);
90
91        Self::ArbitraryRatioSinc(
92            SincFixedIn::new(
93                ratio,
94                1.0,
95                SincInterpolationParameters {
96                    sinc_len: 128,
97                    f_cutoff: rubato::calculate_cutoff(128, WindowFunction::Blackman2),
98                    interpolation: SincInterpolationType::Cubic,
99                    oversampling_factor: 512,
100                    window: WindowFunction::Blackman2,
101                },
102                1024,
103                num_channels.get(),
104            )
105            .unwrap(),
106        )
107    }
108
109    /// Get the number of channels this Resampler is configured for.
110    pub fn num_channels(&self) -> usize {
111        match self {
112            Self::Fast(r) => r.nbr_channels(),
113            #[cfg(feature = "fft-resampler")]
114            Self::Fft(r) => r.nbr_channels(),
115            Self::ArbitraryRatioSinc(r) => r.nbr_channels(),
116        }
117    }
118
119    /// Reset the resampler state and clear all internal buffers.
120    pub fn reset(&mut self) {
121        match self {
122            Self::Fast(r) => r.reset(),
123            #[cfg(feature = "fft-resampler")]
124            Self::Fft(r) => r.reset(),
125            Self::ArbitraryRatioSinc(r) => r.reset(),
126        }
127    }
128
129    /// Get the number of frames per channel needed for the next call to
130    /// [`ResamplerRefMut::process_into_buffer`].
131    pub fn input_frames_next(&mut self) -> usize {
132        match self {
133            Self::Fast(r) => r.input_frames_next(),
134            #[cfg(feature = "fft-resampler")]
135            Self::Fft(r) => r.input_frames_next(),
136            Self::ArbitraryRatioSinc(r) => r.input_frames_next(),
137        }
138    }
139
140    /// Get the maximum number of input frames per channel the resampler could require.
141    pub fn input_frames_max(&mut self) -> usize {
142        match self {
143            Self::Fast(r) => r.input_frames_max(),
144            #[cfg(feature = "fft-resampler")]
145            Self::Fft(r) => r.input_frames_max(),
146            Self::ArbitraryRatioSinc(r) => r.input_frames_max(),
147        }
148    }
149
150    /// Get the delay for the resampler, reported as a number of output frames.
151    pub fn output_delay(&mut self) -> usize {
152        match self {
153            Self::Fast(r) => r.output_delay(),
154            #[cfg(feature = "fft-resampler")]
155            Self::Fft(r) => r.output_delay(),
156            Self::ArbitraryRatioSinc(r) => r.output_delay(),
157        }
158    }
159
160    /// Get the max number of output frames per channel.
161    pub fn output_frames_max(&mut self) -> usize {
162        match self {
163            Self::Fast(r) => r.output_frames_max(),
164            #[cfg(feature = "fft-resampler")]
165            Self::Fft(r) => r.output_frames_max(),
166            Self::ArbitraryRatioSinc(r) => r.output_frames_max(),
167        }
168    }
169
170    /// Resample a buffer of audio to a pre-allocated output buffer.
171    /// Use this in real-time applications where the unpredictable time required to allocate
172    /// memory from the heap can cause glitches. If this is not a problem, you may use
173    /// the [process](Resampler::process) method instead.
174    ///
175    /// The input and output buffers are used in a non-interleaved format.
176    /// The input is a slice, where each element of the slice is itself referenceable
177    /// as a slice ([AsRef<\[T\]>](AsRef)) which contains the samples for a single channel.
178    /// Because `[Vec<T>]` implements [`AsRef<\[T\]>`](AsRef), the input may be [`Vec<Vec<T>>`](Vec).
179    ///
180    /// The output data is a slice, where each element of the slice is a `[T]` which contains
181    /// the samples for a single channel. If the output channel slices do not have sufficient
182    /// capacity for all output samples, the function will return an error with the expected
183    /// size. You could allocate the required output buffer with
184    /// [output_buffer_allocate](Resampler::output_buffer_allocate) before calling this function
185    /// and reuse the same buffer for each call.
186    ///
187    /// The `active_channels_mask` is optional.
188    /// Any channel marked as inactive by a false value will be skipped during processing
189    /// and the corresponding output will be left unchanged.
190    /// If `None` is given, all channels will be considered active.
191    ///
192    /// Before processing, it checks that the input and outputs are valid.
193    /// If either has the wrong number of channels, or if the buffer for any channel is too short,
194    /// a [ResampleError] is returned.
195    /// Both input and output are allowed to be longer than required.
196    /// The number of input samples consumed and the number output samples written
197    /// per channel is returned in a tuple, `(input_frames, output_frames)`.
198    pub fn process_into_buffer<Vin: AsRef<[T]>, Vout: AsMut<[T]>>(
199        &mut self,
200        wave_in: &[Vin],
201        wave_out: &mut [Vout],
202        active_channels_mask: Option<&[bool]>,
203    ) -> ResampleResult<(usize, usize)> {
204        match self {
205            Self::Fast(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
206            #[cfg(feature = "fft-resampler")]
207            Self::Fft(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
208            Self::ArbitraryRatioSinc(r) => {
209                r.process_into_buffer(wave_in, wave_out, active_channels_mask)
210            }
211        }
212    }
213}
214
215impl<T: Sample> From<FastFixedIn<T>> for ResamplerType<T> {
216    fn from(r: FastFixedIn<T>) -> Self {
217        Self::Fast(r)
218    }
219}
220
221#[cfg(feature = "fft-resampler")]
222impl<T: Sample> From<rubato::FftFixedIn<T>> for ResamplerType<T> {
223    fn from(r: rubato::FftFixedIn<T>) -> Self {
224        Self::Fft(r)
225    }
226}
227
228impl<T: Sample> From<SincFixedIn<T>> for ResamplerType<T> {
229    fn from(r: SincFixedIn<T>) -> Self {
230        Self::ArbitraryRatioSinc(r)
231    }
232}