miniaudio/
resampling.rs

1use crate::base::{Error, Format};
2use crate::frames::{Frames, FramesMut};
3use miniaudio_sys as sys;
4
5#[repr(C)]
6#[derive(Clone, Copy, PartialEq, Eq)]
7pub enum ResampleAlgorithmType {
8    Linear = sys::ma_resample_algorithm_linear as _,
9    Speex = sys::ma_resample_algorithm_speex as _,
10}
11impl_from_c!(ResampleAlgorithmType, sys::ma_resample_algorithm);
12
13/// The choice of resampling algorithm depends on your situation and requirements.
14/// The linear resampler is the most efficient and has the least amount of latency,
15/// but at the expense of poorer quality. The Speex resampler is higher quality,
16/// but slower with more latency. It also performs several heap allocations internally
17/// for memory management.
18#[derive(Clone, Copy, PartialEq)]
19pub enum ResampleAlgorithm {
20    Linear {
21        lpf_order: u32,
22        lpf_nyquist_factor: f64,
23    },
24
25    Speex {
26        quality: u32,
27    },
28}
29
30impl ResampleAlgorithm {
31    pub fn algorithm_type(&self) -> ResampleAlgorithmType {
32        match *self {
33            ResampleAlgorithm::Linear { .. } => ResampleAlgorithmType::Linear,
34            ResampleAlgorithm::Speex { .. } => ResampleAlgorithmType::Speex,
35        }
36    }
37}
38
39#[repr(transparent)]
40#[derive(Clone)]
41pub struct LinearResamplerConfig(sys::ma_linear_resampler_config);
42
43impl LinearResamplerConfig {
44    #[inline]
45    pub fn new(
46        format: Format,
47        channels: u32,
48        sample_rate_in: u32,
49        sample_rate_out: u32,
50    ) -> LinearResamplerConfig {
51        LinearResamplerConfig(unsafe {
52            sys::ma_linear_resampler_config_init(
53                format as _,
54                channels,
55                sample_rate_in,
56                sample_rate_out,
57            )
58        })
59    }
60
61    #[inline]
62    pub fn format(&self) -> Format {
63        Format::from_c(self.0.format)
64    }
65
66    pub fn channels(&self) -> u32 {
67        self.0.channels
68    }
69
70    #[inline]
71    pub fn sample_rate_in(&self) -> u32 {
72        self.0.sampleRateIn
73    }
74
75    #[inline]
76    pub fn set_sample_rate_in(&mut self, sample_rate: u32) {
77        self.0.sampleRateIn = sample_rate;
78    }
79
80    #[inline]
81    pub fn sample_rate_out(&self) -> u32 {
82        self.0.sampleRateOut
83    }
84
85    #[inline]
86    pub fn set_sample_rate_out(&mut self, sample_rate: u32) {
87        self.0.sampleRateOut = sample_rate;
88    }
89
90    #[inline]
91    pub fn lpf_nyquist_factor(&self) -> f64 {
92        self.0.lpfNyquistFactor
93    }
94
95    #[inline]
96    pub fn set_lpf_nyquist_factor(&mut self, factor: f64) {
97        self.0.lpfNyquistFactor = factor;
98    }
99
100    #[inline]
101    pub fn lpf_order(&self) -> u32 {
102        self.0.lpfOrder
103    }
104
105    #[inline]
106    pub fn set_lpf_order(&mut self, order: u32) {
107        self.0.lpfOrder = order;
108    }
109}
110
111#[repr(transparent)]
112pub struct LinearResampler(sys::ma_linear_resampler);
113
114impl LinearResampler {
115    #[inline]
116    pub fn new(config: &LinearResamplerConfig) -> Result<LinearResampler, Error> {
117        let mut lr = std::mem::MaybeUninit::<LinearResampler>::uninit();
118        unsafe {
119            Error::from_c_result(sys::ma_linear_resampler_init(
120                config as *const LinearResamplerConfig as *const _,
121                lr.as_mut_ptr() as *mut _,
122            ))?;
123            Ok(lr.assume_init())
124        }
125    }
126
127    #[inline]
128    pub fn config(&self) -> &LinearResamplerConfig {
129        unsafe {
130            &*(&self.0.config as *const sys::ma_linear_resampler_config
131                as *const LinearResamplerConfig)
132        }
133    }
134
135    // FIXME this API actually allows passing null for input or output and does this:
136    //
137    //      You can pass in NULL for the input buffer in which case it will be treated
138    //      as an infinitely large buffer of zeros. The output buffer can also be NULL,
139    //      in which case the processing will be treated as seek.
140    //
141    // I don't have a really good way to represent this right now, so I don't support it :P.
142    //
143    /// Converts the given input data.
144    ///
145    /// Returns the number of input frames that were consumed during processing and the number of
146    /// output frames that were written to the output buffer respectively.
147    #[inline]
148    pub fn process_pcm_frames(
149        &mut self,
150        output: &mut FramesMut,
151        input: &Frames,
152    ) -> Result<(u64, u64), Error> {
153        let mut output_frames = output.frame_count() as u64;
154        let mut input_frames = input.frame_count() as u64;
155
156        Error::from_c_result(unsafe {
157            sys::ma_linear_resampler_process_pcm_frames(
158                &mut self.0,
159                input.as_ptr() as *const _,
160                &mut input_frames,
161                output.as_mut_ptr() as *mut _,
162                &mut output_frames,
163            )
164        })?;
165
166        Ok((output_frames, input_frames))
167    }
168
169    /// Sets the input and output sample rate.
170    #[inline]
171    pub fn set_rate(&mut self, sample_rate_in: u32, sample_rate_out: u32) -> Result<(), Error> {
172        Error::from_c_result(unsafe {
173            sys::ma_linear_resampler_set_rate(&mut self.0, sample_rate_in, sample_rate_out)
174        })
175    }
176
177    /// Sets the input and output sample rate as a ratio.
178    ///
179    /// The ratio is in/out.
180    #[inline]
181    pub fn set_rate_ratio(&mut self, ratio_in_out: f32) -> Result<(), Error> {
182        Error::from_c_result(unsafe {
183            sys::ma_linear_resampler_set_rate_ratio(&mut self.0, ratio_in_out)
184        })
185    }
186
187    /// Calculates the number of whole input frames that would need to be read from the client in
188    /// order to output the specified number of output frames.
189    ///
190    /// The returned value does not include cached input frames. It only returns the number of
191    /// extra frames that would need to be read from the input buffer in order to output the
192    /// specified number of output frames.
193    #[inline]
194    pub fn required_input_frame_count(&self, output_frame_count: u64) -> u64 {
195        unsafe {
196            sys::ma_linear_resampler_get_required_input_frame_count(
197                &self.0 as *const _ as *mut _,
198                output_frame_count,
199            )
200        }
201    }
202
203    /// Calculates the number of whole output frames that would be output after fully reading and
204    /// consuming the specified number of input frames.
205    #[inline]
206    pub fn expected_output_frame_count(&self, input_frame_count: u64) -> u64 {
207        unsafe {
208            sys::ma_linear_resampler_get_expected_output_frame_count(
209                &self.0 as *const _ as *mut _,
210                input_frame_count,
211            )
212        }
213    }
214    #[inline]
215
216    /// Retrieves the latency introduced by the resampler in input frames.
217    pub fn input_latency(&mut self) -> u64 {
218        unsafe { sys::ma_linear_resampler_get_input_latency(&self.0 as *const _ as *mut _) }
219    }
220
221    /// Retrieves the latency introduced by the resampler in output frames.
222    #[inline]
223    pub fn output_latency(&mut self) -> u64 {
224        unsafe { sys::ma_linear_resampler_get_output_latency(&self.0 as *const _ as *mut _) }
225    }
226
227    #[inline]
228    pub fn in_advance_int(&self) -> u32 {
229        self.0.inAdvanceInt
230    }
231
232    #[inline]
233    pub fn in_advance_frac(&self) -> u32 {
234        self.0.inAdvanceFrac
235    }
236
237    #[inline]
238    pub fn in_time_int(&self) -> u32 {
239        self.0.inTimeInt
240    }
241
242    #[inline]
243    pub fn in_time_frac(&self) -> u32 {
244        self.0.inTimeFrac
245    }
246}
247
248impl Drop for LinearResampler {
249    fn drop(&mut self) {
250        unsafe { sys::ma_linear_resampler_uninit(self as *mut LinearResampler as *mut _) };
251    }
252}
253
254impl Clone for LinearResampler {
255    fn clone(&self) -> Self {
256        // This shouldn't fail assuming this was initialized properly to start with.
257        Self::new(self.config()).expect("failed to clone linear resampler")
258    }
259}
260
261#[repr(transparent)]
262#[derive(Clone)]
263pub struct ResamplerConfig(sys::ma_resampler_config);
264
265impl ResamplerConfig {
266    pub fn new(
267        format: Format,
268        channels: u32,
269        sample_rate_in: u32,
270        sample_rate_out: u32,
271        algorithm: ResampleAlgorithmType,
272    ) -> ResamplerConfig {
273        ResamplerConfig(unsafe {
274            sys::ma_resampler_config_init(
275                format as _,
276                channels,
277                sample_rate_in,
278                sample_rate_out,
279                algorithm as _,
280            )
281        })
282    }
283
284    #[inline]
285    pub fn format(&self) -> Format {
286        Format::from_c(self.0.format)
287    }
288
289    #[inline]
290    pub fn channels(&self) -> u32 {
291        self.0.channels
292    }
293
294    #[inline]
295    pub fn sample_rate_in(&self) -> u32 {
296        self.0.sampleRateIn
297    }
298
299    #[inline]
300    pub fn set_sample_rate_in(&mut self, sample_rate: u32) {
301        self.0.sampleRateIn = sample_rate;
302    }
303
304    #[inline]
305    pub fn sample_rate_out(&self) -> u32 {
306        self.0.sampleRateOut
307    }
308
309    #[inline]
310    pub fn set_sample_rate_out(&mut self, sample_rate: u32) {
311        self.0.sampleRateOut = sample_rate;
312    }
313
314    pub fn set_algorithm(&mut self, algo: ResampleAlgorithm) {
315        match algo {
316            ResampleAlgorithm::Linear {
317                lpf_order,
318                lpf_nyquist_factor,
319            } => {
320                self.0.algorithm = sys::ma_resample_algorithm_linear;
321                self.0.linear.lpfOrder = lpf_order;
322                self.0.linear.lpfNyquistFactor = lpf_nyquist_factor;
323            }
324
325            ResampleAlgorithm::Speex { quality } => {
326                self.0.algorithm = sys::ma_resample_algorithm_speex;
327                self.0.speex.quality = quality as _;
328            }
329        }
330    }
331
332    pub fn algorithm(&self) -> ResampleAlgorithm {
333        match self.0.algorithm {
334            sys::ma_resample_algorithm_linear => ResampleAlgorithm::Linear {
335                lpf_order: self.0.linear.lpfOrder,
336                lpf_nyquist_factor: self.0.linear.lpfNyquistFactor,
337            },
338
339            sys::ma_resample_algorithm_speex => ResampleAlgorithm::Speex {
340                quality: self.0.speex.quality as _,
341            },
342
343            _ => unreachable!(),
344        }
345    }
346}
347
348#[repr(transparent)]
349pub struct Resampler(sys::ma_resampler);
350
351impl Resampler {
352    pub fn new(config: &ResamplerConfig) -> Result<Resampler, Error> {
353        let mut resampler = std::mem::MaybeUninit::<Resampler>::uninit();
354        unsafe {
355            sys::ma_resampler_init(&config.0, resampler.as_mut_ptr() as *mut _);
356            Ok(resampler.assume_init())
357        }
358    }
359
360    #[inline]
361    pub fn config(&self) -> &ResamplerConfig {
362        unsafe { &*(&self.0.config as *const sys::ma_resampler_config as *const ResamplerConfig) }
363    }
364
365    // FIXME this API actually allows passing null for input or output and does this:
366    //
367    //      You can pass in NULL for the input buffer in which case it will be treated
368    //      as an infinitely large buffer of zeros. The output buffer can also be NULL,
369    //      in which case the processing will be treated as seek.
370    //
371    // I don't have a really good way to represent this right now, so I don't support it :P.
372    //
373    /// Converts the given input data.
374    ///
375    /// Returns the number of input frames that were consumed during processing and the number of
376    /// output frames that were written to the output buffer respectively.
377    #[inline]
378    pub fn process_pcm_frames(
379        &mut self,
380        output: &mut FramesMut,
381        input: &Frames,
382    ) -> Result<(u64, u64), Error> {
383        if output.format() != input.format() {
384            ma_debug_panic!(
385                "output and input format did not match (output: {:?}, input: {:?}",
386                output.format(),
387                input.format()
388            );
389            return Err(Error::InvalidArgs);
390        }
391
392        let mut output_frames = output.frame_count() as u64;
393        let mut input_frames = input.frame_count() as u64;
394
395        Error::from_c_result(unsafe {
396            sys::ma_resampler_process_pcm_frames(
397                &mut self.0,
398                input.as_ptr() as *const _,
399                &mut input_frames,
400                output.as_mut_ptr() as *mut _,
401                &mut output_frames,
402            )
403        })?;
404
405        Ok((input_frames, output_frames))
406    }
407
408    /// Sets the input and output sample rate.
409    #[inline]
410    pub fn set_rate(&mut self, sample_rate_in: u32, sample_rate_out: u32) -> Result<(), Error> {
411        Error::from_c_result(unsafe {
412            sys::ma_resampler_set_rate(&mut self.0, sample_rate_in, sample_rate_out)
413        })
414    }
415
416    /// Sets the input and output sample rate as a ratio.
417    ///
418    /// The ratio is in/out.
419    #[inline]
420    pub fn set_rate_ratio(&mut self, ratio_in_out: f32) -> Result<(), Error> {
421        Error::from_c_result(unsafe { sys::ma_resampler_set_rate_ratio(&mut self.0, ratio_in_out) })
422    }
423
424    /// Calculates the number of whole input frames that would need to be read from the client in
425    /// order to output the specified number of output frames.
426    ///
427    /// The returned value does not include cached input frames. It only returns the number of
428    /// extra frames that would need to be read from the input buffer in order to output the
429    /// specified number of output frames.
430    #[inline]
431    pub fn required_input_frame_count(&self, output_frame_count: u64) -> u64 {
432        unsafe {
433            sys::ma_resampler_get_required_input_frame_count(
434                &self.0 as *const _ as *mut _,
435                output_frame_count,
436            )
437        }
438    }
439
440    /// Calculates the number of whole output frames that would be output after fully reading and
441    /// consuming the specified number of input frames.
442    #[inline]
443    pub fn expected_output_frame_count(&self, input_frame_count: u64) -> u64 {
444        unsafe {
445            sys::ma_linear_resampler_get_expected_output_frame_count(
446                &self.0 as *const _ as *mut _,
447                input_frame_count,
448            )
449        }
450    }
451    #[inline]
452
453    /// Retrieves the latency introduced by the resampler in input frames.
454    pub fn input_latency(&mut self) -> u64 {
455        unsafe { sys::ma_linear_resampler_get_input_latency(&self.0 as *const _ as *mut _) }
456    }
457
458    /// Retrieves the latency introduced by the resampler in output frames.
459    #[inline]
460    pub fn output_latency(&mut self) -> u64 {
461        unsafe { sys::ma_linear_resampler_get_output_latency(&self.0 as *const _ as *mut _) }
462    }
463}
464
465impl Clone for Resampler {
466    fn clone(&self) -> Self {
467        // This should not fail if the resampler was properly initialized.
468        Self::new(self.config()).expect("failed to clone resampler")
469    }
470}
471
472impl Drop for Resampler {
473    fn drop(&mut self) {
474        unsafe { sys::ma_resampler_uninit(&mut self.0) };
475    }
476}