fixed_resample/
resampler_type.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
use rubato::{FastFixedIn, ResampleResult, Resampler as RubatoResampler, Sample};

use crate::ResampleQuality;

/// The type of resampling algorithm used in `fixed_resample`.
pub enum ResamplerType<T: Sample> {
    /// Low quality, fast performance
    Fast(FastFixedIn<T>),
    #[cfg(feature = "fft-resampler")]
    /// Great quality, medium performance
    Fft(rubato::FftFixedIn<T>),
}

impl<T: Sample> ResamplerType<T> {
    pub fn from_quality(
        in_sample_rate: u32,
        out_sample_rate: u32,
        num_channels: usize,
        quality: ResampleQuality,
    ) -> Self {
        assert_ne!(in_sample_rate, 0);
        assert_ne!(out_sample_rate, 0);
        assert_ne!(num_channels, 0);

        #[cfg(feature = "fft-resampler")]
        {
            match quality {
                ResampleQuality::Low => {
                    return Self::Fast(
                        FastFixedIn::new(
                            out_sample_rate as f64 / in_sample_rate as f64,
                            1.0,
                            rubato::PolynomialDegree::Linear,
                            1024,
                            num_channels,
                        )
                        .unwrap(),
                    )
                }
                ResampleQuality::Normal => {
                    return Self::Fft(
                        rubato::FftFixedIn::new(
                            in_sample_rate as usize,
                            out_sample_rate as usize,
                            1024,
                            2,
                            num_channels,
                        )
                        .unwrap(),
                    )
                }
            }
        }

        #[cfg(not(feature = "fft-resampler"))]
        {
            let _ = quality;

            return Self::Fast(
                FastFixedIn::new(
                    out_sample_rate as f64 / in_sample_rate as f64,
                    1.0,
                    rubato::PolynomialDegree::Linear,
                    1024,
                    num_channels,
                )
                .unwrap(),
            );
        }
    }

    /// Get the number of channels this Resampler is configured for.
    pub fn num_channels(&self) -> usize {
        match self {
            Self::Fast(r) => r.nbr_channels(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.nbr_channels(),
        }
    }

    /// Reset the resampler state and clear all internal buffers.
    pub fn reset(&mut self) {
        match self {
            Self::Fast(r) => r.reset(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.reset(),
        }
    }

    /// Get the number of frames per channel needed for the next call to
    /// [`ResamplerRefMut::process_into_buffer`].
    pub fn input_frames_next(&mut self) -> usize {
        match self {
            Self::Fast(r) => r.input_frames_next(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.input_frames_next(),
        }
    }

    /// Get the maximum number of input frames per channel the resampler could require.
    pub fn input_frames_max(&mut self) -> usize {
        match self {
            Self::Fast(r) => r.input_frames_max(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.input_frames_max(),
        }
    }

    /// Get the delay for the resampler, reported as a number of output frames.
    pub fn output_delay(&mut self) -> usize {
        match self {
            Self::Fast(r) => r.output_delay(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.output_delay(),
        }
    }

    /// Get the max number of output frames per channel.
    pub fn output_frames_max(&mut self) -> usize {
        match self {
            Self::Fast(r) => r.output_frames_max(),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.output_frames_max(),
        }
    }

    /// Resample a buffer of audio to a pre-allocated output buffer.
    /// Use this in real-time applications where the unpredictable time required to allocate
    /// memory from the heap can cause glitches. If this is not a problem, you may use
    /// the [process](Resampler::process) method instead.
    ///
    /// The input and output buffers are used in a non-interleaved format.
    /// The input is a slice, where each element of the slice is itself referenceable
    /// as a slice ([AsRef<\[T\]>](AsRef)) which contains the samples for a single channel.
    /// Because `[Vec<T>]` implements [`AsRef<\[T\]>`](AsRef), the input may be [`Vec<Vec<T>>`](Vec).
    ///
    /// The output data is a slice, where each element of the slice is a `[T]` which contains
    /// the samples for a single channel. If the output channel slices do not have sufficient
    /// capacity for all output samples, the function will return an error with the expected
    /// size. You could allocate the required output buffer with
    /// [output_buffer_allocate](Resampler::output_buffer_allocate) before calling this function
    /// and reuse the same buffer for each call.
    ///
    /// The `active_channels_mask` is optional.
    /// Any channel marked as inactive by a false value will be skipped during processing
    /// and the corresponding output will be left unchanged.
    /// If `None` is given, all channels will be considered active.
    ///
    /// Before processing, it checks that the input and outputs are valid.
    /// If either has the wrong number of channels, or if the buffer for any channel is too short,
    /// a [ResampleError] is returned.
    /// Both input and output are allowed to be longer than required.
    /// The number of input samples consumed and the number output samples written
    /// per channel is returned in a tuple, `(input_frames, output_frames)`.
    pub fn process_into_buffer<Vin: AsRef<[T]>, Vout: AsMut<[T]>>(
        &mut self,
        wave_in: &[Vin],
        wave_out: &mut [Vout],
        active_channels_mask: Option<&[bool]>,
    ) -> ResampleResult<(usize, usize)> {
        match self {
            Self::Fast(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.process_into_buffer(wave_in, wave_out, active_channels_mask),
        }
    }

    /// This is a convenience method for processing the last frames at the end of a stream.
    /// Use this when there are fewer frames remaining than what the resampler requires as input.
    /// Calling this function is equivalent to padding the input buffer with zeros
    /// to make it the right input length, and then calling [process_into_buffer](Resampler::process_into_buffer).
    /// This method can also be called without any input frames, by providing `None` as input buffer.
    /// This can be utilized to push any remaining delayed frames out from the internal buffers.
    /// Note that this method allocates space for a temporary input buffer.
    /// Real-time applications should instead call `process_into_buffer` with a zero-padded pre-allocated input buffer.
    pub fn process_partial_into_buffer<Vin: AsRef<[T]>, Vout: AsMut<[T]>>(
        &mut self,
        wave_in: Option<&[Vin]>,
        wave_out: &mut [Vout],
        active_channels_mask: Option<&[bool]>,
    ) -> ResampleResult<(usize, usize)> {
        match self {
            Self::Fast(r) => r.process_partial_into_buffer(wave_in, wave_out, active_channels_mask),
            #[cfg(feature = "fft-resampler")]
            Self::Fft(r) => r.process_partial_into_buffer(wave_in, wave_out, active_channels_mask),
        }
    }
}

impl<T: Sample> From<FastFixedIn<T>> for ResamplerType<T> {
    fn from(r: FastFixedIn<T>) -> Self {
        Self::Fast(r)
    }
}

#[cfg(feature = "fft-resampler")]
impl<T: Sample> From<rubato::FftFixedIn<T>> for ResamplerType<T> {
    fn from(r: rubato::FftFixedIn<T>) -> Self {
        Self::Fft(r)
    }
}