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}