fixed_resample/
resampler.rs

1use std::{num::NonZeroUsize, ops::Range};
2
3use arrayvec::ArrayVec;
4use rubato::Sample;
5
6use crate::resampler_type::ResamplerType;
7
8/// The quality of the resampling algorithm used for a [`FixedResampler`].
9#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ResampleQuality {
11    /// Decent quality, fast performance, low latency
12    ///
13    /// This is recommended for most realtime applications where low latency
14    /// is desired.
15    ///
16    /// Internally this uses the [`FastFixedIn`] resampler from rubato with
17    /// linear interpolation.
18    Low,
19    #[default]
20    /// Great quality, medium performance, high latency
21    ///
22    /// This is recommended for most non-realtime applications where higher
23    /// latency is not an issue.
24    ///
25    /// Note, this resampler type adds a significant amount of latency (in
26    /// the hundreds of frames), so prefer to use the "Low" option if low
27    /// latency is desired.
28    ///
29    /// If the `fft-resampler` feature is not enabled, then this will fall
30    /// back to "Low".
31    ///
32    /// Internally this uses the [`FftFixedIn`] resampler from rubato with
33    /// a chunk size of `1024` and `2` sub-chunks.
34    High,
35}
36
37/// Options for processes the last packet in a resampler.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub struct LastPacketInfo {
40    /// The desired number of output frames that should be sent via the
41    /// `on_output_packet` closure.
42    ///
43    /// If this is `None`, then the last packet sent may contain extra
44    /// padded zeros on the end.
45    pub desired_output_frames: Option<u64>,
46}
47
48/// An easy-to-use resampler with a fixed ratio.
49///
50/// Internally this uses the `rubato` crate.
51pub struct FixedResampler<T: Sample, const MAX_CHANNELS: usize> {
52    resampler: ResamplerType<T>,
53    tmp_deintlv_in_buf: Vec<T>,
54    tmp_deintlv_out_buf: Vec<T>,
55    tmp_intlv_buf: Vec<T>,
56    tmp_deintlv_in_buf_len: usize,
57    num_channels: NonZeroUsize,
58    input_block_frames: usize,
59    max_output_block_frames: usize,
60    output_delay: usize,
61    delay_frames_left: usize,
62    in_sample_rate: u32,
63    out_sample_rate: u32,
64    interleaved: bool,
65}
66
67impl<T: Sample, const MAX_CHANNELS: usize> FixedResampler<T, MAX_CHANNELS> {
68    /// Create a new [`FixedResampler`].
69    ///
70    /// * `num_channels` - The number of audio channels.
71    /// * `in_sample_rate` - The sample rate of the input data.
72    /// * `out_sample_rate` - The sample rate of the output data.
73    /// * `quality` - The quality of the resampling algorithm to use.
74    /// * `interleaved` - If you plan on using [`FixedResampler::process_interleaved`],
75    /// then set this to `true`. Otherwise, you can set this to `false` to
76    /// save a bit of memory.
77    ///
78    /// # Panics
79    /// Panics if:
80    /// * `num_channels == 0`
81    /// * `num_channels > MAX_CHANNELS`
82    /// * `in_sample_rate == 0`
83    /// * `out_sample_rate == 0`
84    pub fn new(
85        num_channels: NonZeroUsize,
86        in_sample_rate: u32,
87        out_sample_rate: u32,
88        quality: ResampleQuality,
89        interleaved: bool,
90    ) -> Self {
91        Self::from_custom(
92            ResamplerType::from_quality(
93                in_sample_rate,
94                out_sample_rate,
95                num_channels,
96                quality.into(),
97            ),
98            in_sample_rate,
99            out_sample_rate,
100            interleaved,
101        )
102    }
103
104    /// Create a new [`FixedResampler`] using the custom resampler.
105    ///
106    /// * `resampler` - The resampler to use.
107    /// * `in_sample_rate` - The sample rate of the input data.
108    /// * `out_sample_rate` - The sample rate of the output data.
109    /// * `interleaved` - If you plan on using [`FixedResampler::process_interleaved`],
110    /// then set this to `true`. Otherwise, you can set this to `false` to
111    /// save a bit of memory.
112    ///
113    /// # Panics
114    /// Panics if:
115    /// * `resampler.num_channels() == 0`
116    /// * `resampler.num_channels() == 0 > MAX_CHANNELS`
117    /// * `in_sample_rate == 0`
118    /// * `out_sample_rate == 0`
119    pub fn from_custom(
120        resampler: impl Into<ResamplerType<T>>,
121        in_sample_rate: u32,
122        out_sample_rate: u32,
123        interleaved: bool,
124    ) -> Self {
125        assert_ne!(in_sample_rate, 0);
126        assert_ne!(out_sample_rate, 0);
127
128        let mut resampler: ResamplerType<T> = resampler.into();
129
130        let num_channels = NonZeroUsize::new(resampler.num_channels()).unwrap();
131
132        assert!(num_channels.get() <= MAX_CHANNELS);
133
134        let input_block_frames = resampler.input_frames_max();
135        let max_output_block_frames = resampler.output_frames_max();
136        let output_delay = resampler.output_delay();
137
138        let tmp_in_buf_len = input_block_frames * num_channels.get();
139        let tmp_out_buf_len = max_output_block_frames * num_channels.get();
140
141        let mut tmp_deintlv_in_buf = Vec::new();
142        tmp_deintlv_in_buf.reserve_exact(tmp_in_buf_len);
143        tmp_deintlv_in_buf.resize(tmp_in_buf_len, T::zero());
144
145        let mut tmp_deintlv_out_buf = Vec::new();
146        tmp_deintlv_out_buf.reserve_exact(tmp_out_buf_len);
147        tmp_deintlv_out_buf.resize(tmp_out_buf_len, T::zero());
148
149        let tmp_intlv_buf = if interleaved && num_channels.get() > 1 {
150            let intlv_buf_len =
151                input_block_frames.max(max_output_block_frames) * num_channels.get();
152            let mut v = Vec::new();
153            v.reserve_exact(intlv_buf_len);
154            v.resize(intlv_buf_len, T::zero());
155            v
156        } else {
157            Vec::new()
158        };
159
160        Self {
161            resampler,
162            tmp_deintlv_in_buf,
163            tmp_deintlv_out_buf,
164            tmp_intlv_buf,
165            tmp_deintlv_in_buf_len: 0,
166            num_channels,
167            input_block_frames,
168            max_output_block_frames,
169            output_delay,
170            delay_frames_left: output_delay,
171            in_sample_rate,
172            out_sample_rate,
173            interleaved,
174        }
175    }
176
177    /// The number of channels configured for this resampler.
178    pub fn num_channels(&self) -> NonZeroUsize {
179        self.num_channels
180    }
181
182    /// The input sample rate configured for this resampler.
183    pub fn in_sample_rate(&self) -> u32 {
184        self.in_sample_rate
185    }
186
187    /// The output sample rate configured for this resampler.
188    pub fn out_sample_rate(&self) -> u32 {
189        self.out_sample_rate
190    }
191
192    /// The number of frames (samples in a single channel of audio) that appear in
193    /// a single packet of input data in the internal resampler.
194    pub fn input_block_frames(&self) -> usize {
195        self.input_block_frames
196    }
197
198    /// The maximum number of frames (samples in a single channel of audio) that can
199    /// appear in a single call to the `on_output_packet` closure in
200    /// [`FixedResampler::process`] and [`FixedResampler::process_interleaved`].
201    pub fn max_output_block_frames(&self) -> usize {
202        self.max_output_block_frames
203    }
204
205    /// The delay introduced by the internal resampler in number of output frames (
206    /// samples in a single channel of audio).
207    pub fn output_delay(&self) -> usize {
208        self.output_delay
209    }
210
211    /// Whether or not the `interleaved` argument was set to `true` in the constructor.
212    pub fn is_interleaved(&self) -> bool {
213        self.interleaved
214    }
215
216    /// The number of frames (samples in a single channel of audio) that are needed
217    /// for an output buffer given the number of input frames.
218    pub fn out_alloc_frames(&self, input_frames: u64) -> u64 {
219        ((input_frames * self.out_sample_rate as u64) / self.in_sample_rate as u64) + 1
220    }
221
222    #[allow(unused)]
223    pub(crate) fn tmp_input_frames(&self) -> usize {
224        self.tmp_deintlv_in_buf_len
225    }
226
227    /// Process the given de-interleaved input data and return packets of de-interleaved
228    /// resampled output data.
229    ///
230    /// * `input` - The de-interleaved channels of input data.
231    /// * `input_range` - The range in each input channel to read from.
232    /// * `on_output_packet` - Gets called whenever there is a new packet of resampled
233    /// output data. The output data is in de-interleaved format.
234    /// * `last_packet` - If this is `Some`, then any leftover input samples in the
235    /// buffer will be flushed out and the resampler reset. Use this if this is the
236    /// last/only packet of input data when used in a non-realtime context.
237    /// * `trim_delay` - If `true`, then the initial padded zeros introduced by the
238    /// internal resampler will be trimmed off. If this is being used in a realtime
239    /// context, then prefer to set this to `false`.
240    ///
241    /// This method is realtime-safe.
242    ///
243    /// # Panics
244    /// Panics if:
245    /// * `input.len() < self.num_channels()`
246    /// * The `input_range` is out of bounds for any of the input channels.
247    pub fn process<Vin: AsRef<[T]>>(
248        &mut self,
249        input: &[Vin],
250        input_range: Range<usize>,
251        mut on_output_packet: impl FnMut(ArrayVec<&[T], MAX_CHANNELS>),
252        last_packet: Option<LastPacketInfo>,
253        trim_delay: bool,
254    ) {
255        assert!(input.len() >= self.num_channels.get());
256
257        {
258            let mut on_output_packet_inner =
259                move |output_packet: ArrayVec<&[T], MAX_CHANNELS>, _tmp_intlv_buf: &mut Vec<T>| {
260                    (on_output_packet)(output_packet);
261                };
262
263            let total_input_frames = input_range.end - input_range.start;
264
265            let mut tmp_deintlv_in_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
266                .tmp_deintlv_in_buf
267                .chunks_exact_mut(self.input_block_frames)
268                .collect();
269            let mut tmp_deintlv_out_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
270                .tmp_deintlv_out_buf
271                .chunks_exact_mut(self.max_output_block_frames)
272                .collect();
273
274            let mut input_frames_processed = 0;
275            let mut output_frames_processed = 0;
276
277            let desired_output_frames = last_packet.and_then(|info| info.desired_output_frames);
278
279            while input_frames_processed < total_input_frames {
280                if self.tmp_deintlv_in_buf_len == 0
281                    && (total_input_frames - input_frames_processed) >= self.input_block_frames
282                {
283                    // We can use the input data directly to avoid an extra copy.
284
285                    let input_slices: ArrayVec<&[T], MAX_CHANNELS> = input
286                        [..self.num_channels.get()]
287                        .iter()
288                        .map(|s| {
289                            &s.as_ref()[input_range.start + input_frames_processed
290                                ..input_range.start
291                                    + input_frames_processed
292                                    + self.input_block_frames]
293                        })
294                        .collect();
295
296                    resample_inner(
297                        &mut self.resampler,
298                        &input_slices,
299                        &mut tmp_deintlv_out_buf_slices,
300                        &mut on_output_packet_inner,
301                        &mut output_frames_processed,
302                        desired_output_frames,
303                        &mut self.delay_frames_left,
304                        trim_delay,
305                        &mut self.tmp_intlv_buf,
306                    );
307
308                    input_frames_processed += self.input_block_frames;
309                } else {
310                    let copy_frames = (self.input_block_frames - self.tmp_deintlv_in_buf_len)
311                        .min(total_input_frames - input_frames_processed);
312
313                    for (in_slice_ch, input_ch) in
314                        tmp_deintlv_in_buf_slices.iter_mut().zip(input.iter())
315                    {
316                        in_slice_ch[self.tmp_deintlv_in_buf_len
317                            ..self.tmp_deintlv_in_buf_len + copy_frames]
318                            .copy_from_slice(
319                                &input_ch.as_ref()[input_range.start + input_frames_processed
320                                    ..input_range.start + input_frames_processed + copy_frames],
321                            );
322                    }
323
324                    self.tmp_deintlv_in_buf_len += copy_frames;
325                    input_frames_processed += copy_frames;
326
327                    if self.tmp_deintlv_in_buf_len < self.input_block_frames {
328                        // Must wait for more data before resampling the next packet.
329                        break;
330                    }
331
332                    resample_inner(
333                        &mut self.resampler,
334                        &tmp_deintlv_in_buf_slices,
335                        &mut tmp_deintlv_out_buf_slices,
336                        &mut on_output_packet_inner,
337                        &mut output_frames_processed,
338                        desired_output_frames,
339                        &mut self.delay_frames_left,
340                        trim_delay,
341                        &mut self.tmp_intlv_buf,
342                    );
343
344                    self.tmp_deintlv_in_buf_len = 0;
345                }
346            }
347
348            if last_packet.is_some() {
349                process_last_packet(
350                    &mut tmp_deintlv_in_buf_slices,
351                    &mut tmp_deintlv_out_buf_slices,
352                    &mut self.resampler,
353                    &mut on_output_packet_inner,
354                    &mut output_frames_processed,
355                    desired_output_frames,
356                    &mut self.delay_frames_left,
357                    trim_delay,
358                    &mut self.tmp_intlv_buf,
359                    self.tmp_deintlv_in_buf_len,
360                );
361            }
362        }
363
364        if last_packet.is_some() {
365            self.reset();
366        }
367    }
368
369    /// Process the given interleaved input data and return packets of interleaved
370    /// resampled output data.
371    ///
372    /// * `input` - The interleaved input data.
373    /// * `on_output_packet` - Gets called whenever there is a new packet of resampled
374    /// output data. The output data is in interleaved format.
375    /// * `last_packet` - If this is `Some`, then any leftover input samples in the
376    /// buffer will be flushed out and the resampler reset. Use this if this is the
377    /// last/only packet of input data when used in a non-realtime context.
378    /// * `trim_delay` - If `true`, then the initial padded zeros introduced by the
379    /// internal resampler will be trimmed off. If this is being used in a realtime
380    /// context, then prefer to set this to `false`.
381    ///
382    /// This method is realtime-safe.
383    ///
384    /// # Panics
385    /// Panics if the `interleaved` argument in the constructor was `false`.
386    pub fn process_interleaved(
387        &mut self,
388        input: &[T],
389        mut on_output_packet: impl FnMut(&[T]),
390        last_packet: Option<LastPacketInfo>,
391        trim_delay: bool,
392    ) {
393        assert!(self.interleaved, "The constructor argument \"interleaved\" must be set to \"true\" in order to call FixedResampler::process_interleaved");
394
395        {
396            let num_channels = self.num_channels;
397
398            let mut on_output_packet_inner =
399                move |output_packet: ArrayVec<&[T], MAX_CHANNELS>, tmp_intlv_buf: &mut Vec<T>| {
400                    let frames = output_packet[0].len();
401
402                    if num_channels.get() == 1 {
403                        (on_output_packet)(&output_packet[0]);
404                    } else {
405                        crate::interleave::interleave(
406                            &output_packet,
407                            tmp_intlv_buf.as_mut_slice(),
408                            num_channels,
409                            0..frames,
410                        );
411
412                        (on_output_packet)(&tmp_intlv_buf[..frames * num_channels.get()]);
413                    }
414                };
415
416            let total_input_frames = input.len() / self.num_channels;
417
418            let mut tmp_deintlv_in_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
419                .tmp_deintlv_in_buf
420                .chunks_exact_mut(self.input_block_frames)
421                .collect();
422            let mut tmp_deintlv_out_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
423                .tmp_deintlv_out_buf
424                .chunks_exact_mut(self.max_output_block_frames)
425                .collect();
426
427            let mut input_frames_processed = 0;
428            let mut output_frames_processed = 0;
429
430            let desired_output_frames = last_packet.and_then(|info| info.desired_output_frames);
431
432            while input_frames_processed < total_input_frames {
433                let copy_frames = (self.input_block_frames - self.tmp_deintlv_in_buf_len)
434                    .min(total_input_frames - input_frames_processed);
435
436                crate::interleave::deinterleave(
437                    &input[input_frames_processed * self.num_channels.get()
438                        ..(input_frames_processed + copy_frames) * self.num_channels.get()],
439                    &mut tmp_deintlv_in_buf_slices,
440                    self.num_channels,
441                    self.tmp_deintlv_in_buf_len..self.tmp_deintlv_in_buf_len + copy_frames,
442                );
443
444                self.tmp_deintlv_in_buf_len += copy_frames;
445                input_frames_processed += copy_frames;
446
447                if self.tmp_deintlv_in_buf_len < self.input_block_frames {
448                    // Must wait for more data before resampling the next packet.
449                    break;
450                }
451
452                resample_inner(
453                    &mut self.resampler,
454                    &tmp_deintlv_in_buf_slices,
455                    &mut tmp_deintlv_out_buf_slices,
456                    &mut on_output_packet_inner,
457                    &mut output_frames_processed,
458                    desired_output_frames,
459                    &mut self.delay_frames_left,
460                    trim_delay,
461                    &mut self.tmp_intlv_buf,
462                );
463
464                self.tmp_deintlv_in_buf_len = 0;
465            }
466
467            if last_packet.is_some() {
468                process_last_packet(
469                    &mut tmp_deintlv_in_buf_slices,
470                    &mut tmp_deintlv_out_buf_slices,
471                    &mut self.resampler,
472                    &mut on_output_packet_inner,
473                    &mut output_frames_processed,
474                    desired_output_frames,
475                    &mut self.delay_frames_left,
476                    trim_delay,
477                    &mut self.tmp_intlv_buf,
478                    self.tmp_deintlv_in_buf_len,
479                );
480            }
481        }
482
483        if last_packet.is_some() {
484            self.reset();
485        }
486    }
487
488    /// Reset the state of the resampler.
489    ///
490    /// This method is realtime-safe.
491    pub fn reset(&mut self) {
492        self.resampler.reset();
493        self.tmp_deintlv_in_buf_len = 0;
494        self.delay_frames_left = self.output_delay;
495    }
496}
497
498impl<T: Sample, const MAX_CHANNELS: usize> Into<ResamplerType<T>>
499    for FixedResampler<T, MAX_CHANNELS>
500{
501    fn into(self) -> ResamplerType<T> {
502        self.resampler
503    }
504}
505
506fn process_last_packet<T: Sample, const MAX_CHANNELS: usize>(
507    tmp_deintlv_in_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
508    tmp_deintlv_out_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
509    resampler: &mut ResamplerType<T>,
510    on_output_packet: &mut impl FnMut(ArrayVec<&[T], MAX_CHANNELS>, &mut Vec<T>),
511    output_frames_processed: &mut u64,
512    desired_output_frames: Option<u64>,
513    delay_frames_left: &mut usize,
514    trim_delay: bool,
515    tmp_intlv_buf: &mut Vec<T>,
516    tmp_deintlv_in_buf_len: usize,
517) {
518    if tmp_deintlv_in_buf_len > 0 {
519        for ch in tmp_deintlv_in_buf_slices.iter_mut() {
520            ch[tmp_deintlv_in_buf_len..].fill(T::zero());
521        }
522
523        resample_inner(
524            resampler,
525            &tmp_deintlv_in_buf_slices,
526            tmp_deintlv_out_buf_slices,
527            on_output_packet,
528            output_frames_processed,
529            desired_output_frames,
530            delay_frames_left,
531            trim_delay,
532            tmp_intlv_buf,
533        );
534    }
535
536    for ch in tmp_deintlv_in_buf_slices.iter_mut() {
537        ch.fill(T::zero());
538    }
539
540    if let Some(desired_output_frames) = desired_output_frames {
541        if *output_frames_processed >= desired_output_frames {
542            return;
543        }
544
545        while *output_frames_processed < desired_output_frames {
546            resample_inner(
547                resampler,
548                &tmp_deintlv_in_buf_slices,
549                tmp_deintlv_out_buf_slices,
550                on_output_packet,
551                output_frames_processed,
552                Some(desired_output_frames),
553                delay_frames_left,
554                trim_delay,
555                tmp_intlv_buf,
556            );
557        }
558    } else {
559        resample_inner(
560            resampler,
561            &tmp_deintlv_in_buf_slices,
562            tmp_deintlv_out_buf_slices,
563            on_output_packet,
564            output_frames_processed,
565            desired_output_frames,
566            delay_frames_left,
567            trim_delay,
568            tmp_intlv_buf,
569        );
570    }
571}
572
573fn resample_inner<T: Sample, Vin: AsRef<[T]>, const MAX_CHANNELS: usize>(
574    resampler: &mut ResamplerType<T>,
575    input: &[Vin],
576    tmp_deintlv_out_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
577    on_output_packet: &mut impl FnMut(ArrayVec<&[T], MAX_CHANNELS>, &mut Vec<T>),
578    output_frames_processed: &mut u64,
579    desired_output_frames: Option<u64>,
580    delay_frames_left: &mut usize,
581    trim_delay: bool,
582    tmp_intlv_buf: &mut Vec<T>,
583) {
584    let (_, output_frames) = resampler
585        .process_into_buffer(input, tmp_deintlv_out_buf_slices, None)
586        .unwrap();
587
588    let (output_packet_start, mut packet_output_frames) = if trim_delay && *delay_frames_left > 0 {
589        let delay_frames = output_frames.min(*delay_frames_left);
590        *delay_frames_left -= delay_frames;
591        (delay_frames, output_frames - delay_frames)
592    } else {
593        (0, output_frames)
594    };
595
596    if let Some(desired_output_frames) = desired_output_frames {
597        if desired_output_frames <= *output_frames_processed {
598            packet_output_frames = 0;
599        } else if (desired_output_frames - *output_frames_processed) < packet_output_frames as u64 {
600            packet_output_frames = (desired_output_frames - *output_frames_processed) as usize
601        }
602    }
603
604    if packet_output_frames > 0 {
605        let out_packet_slices: ArrayVec<&[T], MAX_CHANNELS> = tmp_deintlv_out_buf_slices
606            .iter()
607            .map(|s| &s[output_packet_start..output_packet_start + packet_output_frames])
608            .collect();
609
610        (on_output_packet)(out_packet_slices, tmp_intlv_buf);
611    }
612
613    *output_frames_processed += packet_output_frames as u64;
614}