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.get();
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 == 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,
410                            frames,
411                        );
412
413                        (on_output_packet)(&tmp_intlv_buf[..frames * num_channels]);
414                    }
415                };
416
417            let total_input_frames = input.len() / self.num_channels;
418
419            let mut tmp_deintlv_in_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
420                .tmp_deintlv_in_buf
421                .chunks_exact_mut(self.input_block_frames)
422                .collect();
423            let mut tmp_deintlv_out_buf_slices: ArrayVec<&mut [T], MAX_CHANNELS> = self
424                .tmp_deintlv_out_buf
425                .chunks_exact_mut(self.max_output_block_frames)
426                .collect();
427
428            let mut input_frames_processed = 0;
429            let mut output_frames_processed = 0;
430
431            let desired_output_frames = last_packet.and_then(|info| info.desired_output_frames);
432
433            while input_frames_processed < total_input_frames {
434                let copy_frames = (self.input_block_frames - self.tmp_deintlv_in_buf_len)
435                    .min(total_input_frames - input_frames_processed);
436
437                crate::interleave::deinterleave(
438                    &input[input_frames_processed * self.num_channels.get()
439                        ..(input_frames_processed + copy_frames) * self.num_channels.get()],
440                    &mut tmp_deintlv_in_buf_slices,
441                    self.num_channels.get(),
442                    self.tmp_deintlv_in_buf_len,
443                    copy_frames,
444                );
445
446                self.tmp_deintlv_in_buf_len += copy_frames;
447                input_frames_processed += copy_frames;
448
449                if self.tmp_deintlv_in_buf_len < self.input_block_frames {
450                    // Must wait for more data before resampling the next packet.
451                    break;
452                }
453
454                resample_inner(
455                    &mut self.resampler,
456                    &tmp_deintlv_in_buf_slices,
457                    &mut tmp_deintlv_out_buf_slices,
458                    &mut on_output_packet_inner,
459                    &mut output_frames_processed,
460                    desired_output_frames,
461                    &mut self.delay_frames_left,
462                    trim_delay,
463                    &mut self.tmp_intlv_buf,
464                );
465
466                self.tmp_deintlv_in_buf_len = 0;
467            }
468
469            if last_packet.is_some() {
470                process_last_packet(
471                    &mut tmp_deintlv_in_buf_slices,
472                    &mut tmp_deintlv_out_buf_slices,
473                    &mut self.resampler,
474                    &mut on_output_packet_inner,
475                    &mut output_frames_processed,
476                    desired_output_frames,
477                    &mut self.delay_frames_left,
478                    trim_delay,
479                    &mut self.tmp_intlv_buf,
480                    self.tmp_deintlv_in_buf_len,
481                );
482            }
483        }
484
485        if last_packet.is_some() {
486            self.reset();
487        }
488    }
489
490    /// Reset the state of the resampler.
491    ///
492    /// This method is realtime-safe.
493    pub fn reset(&mut self) {
494        self.resampler.reset();
495        self.tmp_deintlv_in_buf_len = 0;
496        self.delay_frames_left = self.output_delay;
497    }
498}
499
500impl<T: Sample, const MAX_CHANNELS: usize> Into<ResamplerType<T>>
501    for FixedResampler<T, MAX_CHANNELS>
502{
503    fn into(self) -> ResamplerType<T> {
504        self.resampler
505    }
506}
507
508fn process_last_packet<T: Sample, const MAX_CHANNELS: usize>(
509    tmp_deintlv_in_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
510    tmp_deintlv_out_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
511    resampler: &mut ResamplerType<T>,
512    on_output_packet: &mut impl FnMut(ArrayVec<&[T], MAX_CHANNELS>, &mut Vec<T>),
513    output_frames_processed: &mut u64,
514    desired_output_frames: Option<u64>,
515    delay_frames_left: &mut usize,
516    trim_delay: bool,
517    tmp_intlv_buf: &mut Vec<T>,
518    tmp_deintlv_in_buf_len: usize,
519) {
520    if tmp_deintlv_in_buf_len > 0 {
521        for ch in tmp_deintlv_in_buf_slices.iter_mut() {
522            ch[tmp_deintlv_in_buf_len..].fill(T::zero());
523        }
524
525        resample_inner(
526            resampler,
527            &tmp_deintlv_in_buf_slices,
528            tmp_deintlv_out_buf_slices,
529            on_output_packet,
530            output_frames_processed,
531            desired_output_frames,
532            delay_frames_left,
533            trim_delay,
534            tmp_intlv_buf,
535        );
536    }
537
538    for ch in tmp_deintlv_in_buf_slices.iter_mut() {
539        ch.fill(T::zero());
540    }
541
542    if let Some(desired_output_frames) = desired_output_frames {
543        if *output_frames_processed >= desired_output_frames {
544            return;
545        }
546
547        while *output_frames_processed < desired_output_frames {
548            resample_inner(
549                resampler,
550                &tmp_deintlv_in_buf_slices,
551                tmp_deintlv_out_buf_slices,
552                on_output_packet,
553                output_frames_processed,
554                Some(desired_output_frames),
555                delay_frames_left,
556                trim_delay,
557                tmp_intlv_buf,
558            );
559        }
560    } else {
561        resample_inner(
562            resampler,
563            &tmp_deintlv_in_buf_slices,
564            tmp_deintlv_out_buf_slices,
565            on_output_packet,
566            output_frames_processed,
567            desired_output_frames,
568            delay_frames_left,
569            trim_delay,
570            tmp_intlv_buf,
571        );
572    }
573}
574
575fn resample_inner<T: Sample, Vin: AsRef<[T]>, const MAX_CHANNELS: usize>(
576    resampler: &mut ResamplerType<T>,
577    input: &[Vin],
578    tmp_deintlv_out_buf_slices: &mut ArrayVec<&mut [T], MAX_CHANNELS>,
579    on_output_packet: &mut impl FnMut(ArrayVec<&[T], MAX_CHANNELS>, &mut Vec<T>),
580    output_frames_processed: &mut u64,
581    desired_output_frames: Option<u64>,
582    delay_frames_left: &mut usize,
583    trim_delay: bool,
584    tmp_intlv_buf: &mut Vec<T>,
585) {
586    let (_, output_frames) = resampler
587        .process_into_buffer(input, tmp_deintlv_out_buf_slices, None)
588        .unwrap();
589
590    let (output_packet_start, mut packet_output_frames) = if trim_delay && *delay_frames_left > 0 {
591        let delay_frames = output_frames.min(*delay_frames_left);
592        *delay_frames_left -= delay_frames;
593        (delay_frames, output_frames - delay_frames)
594    } else {
595        (0, output_frames)
596    };
597
598    if let Some(desired_output_frames) = desired_output_frames {
599        if desired_output_frames <= *output_frames_processed {
600            packet_output_frames = 0;
601        } else if (desired_output_frames - *output_frames_processed) < packet_output_frames as u64 {
602            packet_output_frames = (desired_output_frames - *output_frames_processed) as usize
603        }
604    }
605
606    if packet_output_frames > 0 {
607        let out_packet_slices: ArrayVec<&[T], MAX_CHANNELS> = tmp_deintlv_out_buf_slices
608            .iter()
609            .map(|s| &s[output_packet_start..output_packet_start + packet_output_frames])
610            .collect();
611
612        (on_output_packet)(out_packet_slices, tmp_intlv_buf);
613    }
614
615    *output_frames_processed += packet_output_frames as u64;
616}