fixed_resample/resampler_type.rs
1use rubato::{FastFixedIn, ResampleResult, Resampler as RubatoResampler, Sample};
2
3use crate::ResampleQuality;
4
5/// The type of resampling algorithm used in `fixed_resample`.
6pub enum ResamplerType<T: Sample> {
7 /// Low quality, fast performance
8 Fast(FastFixedIn<T>),
9 #[cfg(feature = "fft-resampler")]
10 /// Great quality, medium performance
11 Fft(rubato::FftFixedIn<T>),
12}
13
14impl<T: Sample> ResamplerType<T> {
15 pub fn from_quality(
16 in_sample_rate: u32,
17 out_sample_rate: u32,
18 num_channels: usize,
19 quality: ResampleQuality,
20 ) -> Self {
21 assert_ne!(in_sample_rate, 0);
22 assert_ne!(out_sample_rate, 0);
23 assert_ne!(num_channels, 0);
24
25 #[cfg(feature = "fft-resampler")]
26 {
27 match quality {
28 ResampleQuality::Low => {
29 return Self::Fast(
30 FastFixedIn::new(
31 out_sample_rate as f64 / in_sample_rate as f64,
32 1.0,
33 rubato::PolynomialDegree::Linear,
34 1024,
35 num_channels,
36 )
37 .unwrap(),
38 )
39 }
40 ResampleQuality::Normal => {
41 return Self::Fft(
42 rubato::FftFixedIn::new(
43 in_sample_rate as usize,
44 out_sample_rate as usize,
45 1024,
46 2,
47 num_channels,
48 )
49 .unwrap(),
50 )
51 }
52 }
53 }
54
55 #[cfg(not(feature = "fft-resampler"))]
56 {
57 let _ = quality;
58
59 return Self::Fast(
60 FastFixedIn::new(
61 out_sample_rate as f64 / in_sample_rate as f64,
62 1.0,
63 rubato::PolynomialDegree::Linear,
64 1024,
65 num_channels,
66 )
67 .unwrap(),
68 );
69 }
70 }
71
72 /// Get the number of channels this Resampler is configured for.
73 pub fn num_channels(&self) -> usize {
74 match self {
75 Self::Fast(r) => r.nbr_channels(),
76 #[cfg(feature = "fft-resampler")]
77 Self::Fft(r) => r.nbr_channels(),
78 }
79 }
80
81 /// Reset the resampler state and clear all internal buffers.
82 pub fn reset(&mut self) {
83 match self {
84 Self::Fast(r) => r.reset(),
85 #[cfg(feature = "fft-resampler")]
86 Self::Fft(r) => r.reset(),
87 }
88 }
89
90 /// Get the number of frames per channel needed for the next call to
91 /// [`ResamplerRefMut::process_into_buffer`].
92 pub fn input_frames_next(&mut self) -> usize {
93 match self {
94 Self::Fast(r) => r.input_frames_next(),
95 #[cfg(feature = "fft-resampler")]
96 Self::Fft(r) => r.input_frames_next(),
97 }
98 }
99
100 /// Get the maximum number of input frames per channel the resampler could require.
101 pub fn input_frames_max(&mut self) -> usize {
102 match self {
103 Self::Fast(r) => r.input_frames_max(),
104 #[cfg(feature = "fft-resampler")]
105 Self::Fft(r) => r.input_frames_max(),
106 }
107 }
108
109 /// Get the delay for the resampler, reported as a number of output frames.
110 pub fn output_delay(&mut self) -> usize {
111 match self {
112 Self::Fast(r) => r.output_delay(),
113 #[cfg(feature = "fft-resampler")]
114 Self::Fft(r) => r.output_delay(),
115 }
116 }
117
118 /// Get the max number of output frames per channel.
119 pub fn output_frames_max(&mut self) -> usize {
120 match self {
121 Self::Fast(r) => r.output_frames_max(),
122 #[cfg(feature = "fft-resampler")]
123 Self::Fft(r) => r.output_frames_max(),
124 }
125 }
126
127 /// Resample a buffer of audio to a pre-allocated output buffer.
128 /// Use this in real-time applications where the unpredictable time required to allocate
129 /// memory from the heap can cause glitches. If this is not a problem, you may use
130 /// the [process](Resampler::process) method instead.
131 ///
132 /// The input and output buffers are used in a non-interleaved format.
133 /// The input is a slice, where each element of the slice is itself referenceable
134 /// as a slice ([AsRef<\[T\]>](AsRef)) which contains the samples for a single channel.
135 /// Because `[Vec<T>]` implements [`AsRef<\[T\]>`](AsRef), the input may be [`Vec<Vec<T>>`](Vec).
136 ///
137 /// The output data is a slice, where each element of the slice is a `[T]` which contains
138 /// the samples for a single channel. If the output channel slices do not have sufficient
139 /// capacity for all output samples, the function will return an error with the expected
140 /// size. You could allocate the required output buffer with
141 /// [output_buffer_allocate](Resampler::output_buffer_allocate) before calling this function
142 /// and reuse the same buffer for each call.
143 ///
144 /// The `active_channels_mask` is optional.
145 /// Any channel marked as inactive by a false value will be skipped during processing
146 /// and the corresponding output will be left unchanged.
147 /// If `None` is given, all channels will be considered active.
148 ///
149 /// Before processing, it checks that the input and outputs are valid.
150 /// If either has the wrong number of channels, or if the buffer for any channel is too short,
151 /// a [ResampleError] is returned.
152 /// Both input and output are allowed to be longer than required.
153 /// The number of input samples consumed and the number output samples written
154 /// per channel is returned in a tuple, `(input_frames, output_frames)`.
155 pub fn process_into_buffer<Vin: AsRef<[T]>, Vout: AsMut<[T]>>(
156 &mut self,
157 wave_in: &[Vin],
158 wave_out: &mut [Vout],
159 active_channels_mask: Option<&[bool]>,
160 ) -> ResampleResult<(usize, usize)> {
161 match self {
162 Self::Fast(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
163 #[cfg(feature = "fft-resampler")]
164 Self::Fft(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
165 }
166 }
167
168 /// This is a convenience method for processing the last frames at the end of a stream.
169 /// Use this when there are fewer frames remaining than what the resampler requires as input.
170 /// Calling this function is equivalent to padding the input buffer with zeros
171 /// to make it the right input length, and then calling [process_into_buffer](Resampler::process_into_buffer).
172 /// This method can also be called without any input frames, by providing `None` as input buffer.
173 /// This can be utilized to push any remaining delayed frames out from the internal buffers.
174 /// Note that this method allocates space for a temporary input buffer.
175 /// Real-time applications should instead call `process_into_buffer` with a zero-padded pre-allocated input buffer.
176 pub fn process_partial_into_buffer<Vin: AsRef<[T]>, Vout: AsMut<[T]>>(
177 &mut self,
178 wave_in: Option<&[Vin]>,
179 wave_out: &mut [Vout],
180 active_channels_mask: Option<&[bool]>,
181 ) -> ResampleResult<(usize, usize)> {
182 match self {
183 Self::Fast(r) => r.process_partial_into_buffer(wave_in, wave_out, active_channels_mask),
184 #[cfg(feature = "fft-resampler")]
185 Self::Fft(r) => r.process_partial_into_buffer(wave_in, wave_out, active_channels_mask),
186 }
187 }
188}
189
190impl<T: Sample> From<FastFixedIn<T>> for ResamplerType<T> {
191 fn from(r: FastFixedIn<T>) -> Self {
192 Self::Fast(r)
193 }
194}
195
196#[cfg(feature = "fft-resampler")]
197impl<T: Sample> From<rubato::FftFixedIn<T>> for ResamplerType<T> {
198 fn from(r: rubato::FftFixedIn<T>) -> Self {
199 Self::Fft(r)
200 }
201}