Skip to main content

fixed_resample/
resampler.rs

1use audioadapter_buffers::direct;
2use audioadapter_buffers::owned::{InterleavedOwned, SequentialOwned};
3use rubato::{
4    audioadapter::{Adapter, AdapterMut},
5    ResampleResult, Resampler, Sample,
6};
7use std::ops::Range;
8
9/// The quality of the resampling algorithm used for a [`PacketResampler`] or a
10/// [`Resampler`] created with [`resampler_from_quality`].
11#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum ResampleQuality {
13    /// Low quality, low CPU, low latency
14    ///
15    /// Internally this uses the [`Async`][rubato::Async] resampler from rubato
16    /// with linear polynomial interpolation.
17    VeryLow,
18    /// Slightly better quality than [`ResampleQuality::VeryLow`], slightly higher
19    /// CPU than [`ResampleQuality::VeryLow`], low latency
20    ///
21    /// Internally this uses the [`Async`][rubato::Async] resampler from rubato
22    /// with cubic polynomial interpolation.
23    Low,
24    #[default]
25    /// Great quality, medium CPU, high latency
26    ///
27    /// This is recommended for most non-realtime applications where higher
28    /// latency is not an issue.
29    ///
30    /// Note, this resampler type adds a significant amount of latency (in
31    /// the hundreds of frames), so prefer to use the "Low" option if low
32    /// latency is desired.
33    ///
34    /// If the `fft-resampler` feature is not enabled, then this will fall
35    /// back to [`ResampleQuality::Low`].
36    ///
37    /// Internally this uses the [`rubato::Fft`] resampler from rubato.
38    High,
39    /// Great quality, high CPU, low latency
40    ///
41    /// Internally this uses the [`Async`][rubato::Async] resampler from rubato
42    /// with [`Cubic`](rubato::SincInterpolationType::Cubic) sinc
43    /// interpolation, a [`BlackmanHarris2`](rubato::WindowFunction::BlackmanHarris2)
44    /// window function, a sinc length of `256`, and an oversampling factor
45    /// of `128`.
46    HighWithLowLatency,
47}
48
49impl From<usize> for ResampleQuality {
50    fn from(value: usize) -> Self {
51        match value {
52            0 => Self::VeryLow,
53            1 => Self::Low,
54            2 => Self::High,
55            _ => Self::HighWithLowLatency,
56        }
57    }
58}
59
60/// The configuration for a [`PacketResampler`] or a [`Resampler`] create with
61/// [`resampler_from_quality`].
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct ResamplerConfig {
64    /// The quality of the resampling algorithm.
65    ///
66    /// By default this is set to [`ResampleQuality::High`].
67    pub quality: ResampleQuality,
68
69    /// The chunk size of the resampler. Lower values may reduce latency, but may
70    /// use more CPU.
71    ///
72    /// By default this is set to `512`.
73    pub chunk_size: usize,
74}
75
76impl Default for ResamplerConfig {
77    fn default() -> Self {
78        Self {
79            quality: ResampleQuality::default(),
80            chunk_size: 512,
81        }
82    }
83}
84
85/// Create a new [`Resampler`] with the given settings.
86///
87/// * `num_channels` - The number of audio channels.
88/// * `in_sample_rate` - The sample rate of the input data.
89/// * `out_sample_rate` - The sample rate of the output data.
90/// * `config` - Extra configuration for the resampler.
91///
92/// # Panics
93/// Panics if:
94/// * `num_channels == 0`
95/// * `in_sample_rate == 0`
96/// * `out_sample_rate == 0`
97/// * `config.chunk_size == 0`
98/// * `config.sub_chunks == 0`
99pub fn resampler_from_quality<T: Sample>(
100    num_channels: usize,
101    in_sample_rate: u32,
102    out_sample_rate: u32,
103    config: ResamplerConfig,
104) -> Box<dyn Resampler<T>> {
105    assert_ne!(num_channels, 0);
106    assert_ne!(in_sample_rate, 0);
107    assert_ne!(out_sample_rate, 0);
108    assert_ne!(config.chunk_size, 0);
109
110    let low = || -> Box<dyn rubato::Resampler<T>> {
111        Box::new(
112            rubato::Async::new_poly(
113                out_sample_rate as f64 / in_sample_rate as f64,
114                1.0,
115                rubato::PolynomialDegree::Cubic,
116                config.chunk_size,
117                num_channels,
118                rubato::FixedAsync::Input,
119            )
120            .unwrap(),
121        )
122    };
123
124    match config.quality {
125        ResampleQuality::VeryLow => Box::new(
126            rubato::Async::new_poly(
127                out_sample_rate as f64 / in_sample_rate as f64,
128                1.0,
129                rubato::PolynomialDegree::Linear,
130                config.chunk_size,
131                num_channels,
132                rubato::FixedAsync::Input,
133            )
134            .unwrap(),
135        ),
136        ResampleQuality::Low => low(),
137        ResampleQuality::High => {
138            #[cfg(feature = "fft-resampler")]
139            return Box::new(
140                rubato::Fft::new(
141                    in_sample_rate as usize,
142                    out_sample_rate as usize,
143                    config.chunk_size,
144                    num_channels,
145                    rubato::FixedSync::Input,
146                )
147                .unwrap(),
148            );
149
150            #[cfg(not(feature = "fft-resampler"))]
151            return low();
152        }
153        ResampleQuality::HighWithLowLatency => Box::new(
154            rubato::Async::new_sinc(
155                out_sample_rate as f64 / in_sample_rate as f64,
156                1.0,
157                &rubato::SincInterpolationParameters::default(),
158                config.chunk_size,
159                num_channels,
160                rubato::FixedAsync::Input,
161            )
162            .unwrap(),
163        ),
164    }
165}
166
167/// The resampling ratio for [`PacketResampler::from_custom`].
168#[derive(Debug, Clone, Copy, PartialEq)]
169enum ResampleRatio {
170    IntegerSampleRate {
171        in_sample_rate: u32,
172        out_sample_rate: u32,
173    },
174    Float(f64),
175}
176
177/// A wrapper around rubato's [`Resampler`] that accepts inputs of any size and sends
178/// resampled output packets to a given closure.
179///
180/// When using the [`Sequential`] [`PacketResamplerBuffer`], the output packets will
181/// be in de-interleaved format (using &[`SequentialOwned`]). When using the
182/// [`Interleaved`] [`PacketResamplerBuffer`], the output packets be be in interleaved
183/// format (using `&[T]`).
184///
185/// This only supports synchronous resampling.
186pub struct PacketResampler<T: Sample, B: PacketResamplerBuffer<T>> {
187    resampler: Box<dyn Resampler<T>>,
188    ratio: ResampleRatio,
189    num_channels: usize,
190
191    buffer: B,
192    active_channels_mask: Option<Vec<bool>>,
193    in_buf_len: usize,
194    delay_frames_left: usize,
195}
196
197impl<T: Sample, B: PacketResamplerBuffer<T>> PacketResampler<T, B> {
198    /// Create a new [`PacketResampler`].
199    ///
200    /// * `num_channels` - The number of audio channels.
201    /// * `in_sample_rate` - The sample rate of the input data.
202    /// * `out_sample_rate` - The sample rate of the output data.
203    /// * `config` - Extra configuration for the resampler.
204    ///
205    /// # Panics
206    /// Panics if:
207    /// * `num_channels == 0`
208    /// * `in_sample_rate == 0`
209    /// * `out_sample_rate == 0`
210    /// * `config.chunk_size == 0`
211    /// * `config.sub_chunks == 0`
212    pub fn new(
213        num_channels: usize,
214        in_sample_rate: u32,
215        out_sample_rate: u32,
216        config: ResamplerConfig,
217    ) -> Self {
218        let resampler =
219            resampler_from_quality(num_channels, in_sample_rate, out_sample_rate, config);
220
221        Self::new_inner(resampler, Some((in_sample_rate, out_sample_rate)))
222    }
223
224    /// Create a new [`PacketResampler`] using a custom [`Resampler`].
225    ///
226    /// This can be used, for example, to create a PacketResampler with non-integer input
227    /// and/or output sample rates.
228    pub fn from_custom(resampler: Box<dyn Resampler<T>>) -> Self {
229        Self::new_inner(resampler, None)
230    }
231
232    fn new_inner(resampler: Box<dyn Resampler<T>>, sr: Option<(u32, u32)>) -> Self {
233        let ratio = if let Some((in_sample_rate, out_sample_rate)) = sr {
234            ResampleRatio::IntegerSampleRate {
235                in_sample_rate,
236                out_sample_rate,
237            }
238        } else {
239            ResampleRatio::Float(resampler.resample_ratio())
240        };
241
242        let num_channels = resampler.nbr_channels();
243        let input_frames_max = resampler.input_frames_max();
244        let output_frames_max = resampler.output_frames_max();
245
246        Self {
247            resampler,
248            ratio,
249            num_channels,
250            buffer: B::new(num_channels, input_frames_max, output_frames_max),
251            active_channels_mask: Some(vec![false; num_channels]),
252            in_buf_len: 0,
253            delay_frames_left: 0,
254        }
255    }
256
257    /// The number of channels configured for this resampler.
258    pub fn nbr_channels(&self) -> usize {
259        self.num_channels
260    }
261
262    /// The resampling ratio `output / input`.
263    pub fn ratio(&self) -> f64 {
264        self.resampler.resample_ratio()
265    }
266
267    /// The number of frames (samples in a single channel of audio) that appear in
268    /// a single packet of input data in the internal resampler.
269    pub fn max_input_block_frames(&self) -> usize {
270        self.resampler.input_frames_max()
271    }
272
273    /// The maximum number of frames (samples in a single channel of audio) that can
274    /// appear in a single call to the `on_output_packet` closure in
275    /// [`PacketResampler::process`].
276    pub fn max_output_block_frames(&self) -> usize {
277        self.resampler.output_frames_max()
278    }
279
280    /// The delay introduced by the internal resampler in number of output frames (
281    /// samples in a single channel of audio).
282    pub fn output_delay(&self) -> usize {
283        self.resampler.output_delay()
284    }
285
286    /// The number of frames (samples in a single channel of audio) that are needed
287    /// for an output buffer given the number of input frames.
288    pub fn out_alloc_frames(&self, input_frames: u64) -> u64 {
289        match self.ratio {
290            // Use integer math when possible for more accurate results.
291            ResampleRatio::IntegerSampleRate {
292                in_sample_rate,
293                out_sample_rate,
294            } => ((input_frames * out_sample_rate as u64) / in_sample_rate as u64) + 1,
295            ResampleRatio::Float(ratio) => (input_frames as f64 * ratio).ceil() as u64,
296        }
297    }
298
299    #[allow(unused)]
300    pub(crate) fn tmp_input_frames(&self) -> usize {
301        self.in_buf_len
302    }
303
304    /// Process the given input data and return packets of resampled output data.
305    ///
306    /// * `buffer_in` - The input data. You can use one of the types in the [`direct`]
307    ///   module to wrap your input data into a type that implements [`Adapter`].
308    /// * `input_range` - The range in each input channel to read from. If this is
309    ///   `None`, then the entire input buffer will be read.
310    /// * `active_channels_mask` - An optional mask that selects which channels in
311    ///   `buffer_in` to use. Channels marked with `false` will be skipped and the
312    ///   output channel filled with zeros. If `None`, then all of the channels will
313    ///   be active.
314    /// * `on_output_packet` - Gets called whenever there is a new packet of resampled
315    ///   output data. `(buffer, output_frames)`
316    ///     * When using [`Sequential`] output buffers, the output will be of type
317    ///       &[`SequentialOwned`]. Note, the length of this buffer may be less than
318    ///       `output_frames`. Only read up to `output_frames` data from the buffer.
319    ///     * When using [`Interleaved`] output buffers, the output will be of type
320    ///       `&[T]`. The number of frames in this slice will always be equal to
321    ///       `output_frames`.
322    /// * `last_packet` - If this is `Some`, then any leftover input samples in the
323    ///   buffer will be flushed out and the resampler reset. Use this if this is the
324    ///   last/only packet of input data.
325    /// * `trim_delay` - If `true`, then the initial padded zeros introduced by the
326    ///   internal resampler will be trimmed off.
327    ///
328    /// This method is realtime-safe.
329    ///
330    /// # Panics
331    /// Panics if:
332    /// * The `input_range` is out of bounds for any of the input channels.
333    pub fn process(
334        &mut self,
335        buffer_in: &dyn Adapter<T>,
336        input_range: Option<Range<usize>>,
337        active_channels_mask: Option<&[bool]>,
338        mut on_output_packet: impl FnMut(&B::Output, usize),
339        last_packet: Option<LastPacketInfo>,
340        trim_delay: bool,
341    ) {
342        let (input_start, total_frames) = if let Some(range) = input_range {
343            (range.start, range.end - range.start)
344        } else {
345            (0, buffer_in.frames())
346        };
347
348        let use_indexing =
349            active_channels_mask.is_some() || buffer_in.channels() < self.num_channels;
350
351        let indexing = if use_indexing {
352            let mut m = self.active_channels_mask.take().unwrap();
353
354            if let Some(in_mask) = active_channels_mask {
355                for (in_mask, out_mask) in in_mask.iter().zip(m.iter_mut()) {
356                    *out_mask = *in_mask;
357                }
358            } else {
359                for mask in m.iter_mut().take(buffer_in.channels()) {
360                    *mask = true;
361                }
362            }
363            for mask in m.iter_mut().skip(buffer_in.channels()) {
364                *mask = false;
365            }
366
367            Some(rubato::Indexing {
368                input_offset: 0,
369                output_offset: 0,
370                partial_len: None,
371                active_channels_mask: Some(m),
372            })
373        } else {
374            None
375        };
376
377        let mut output_frames_processed: u64 = 0;
378
379        let mut frames_left = total_frames;
380        while frames_left > 0 {
381            let needed_input_frames = self.resampler.input_frames_next();
382
383            if self.in_buf_len < needed_input_frames {
384                let block_frames_to_copy = frames_left.min(needed_input_frames - self.in_buf_len);
385
386                for ch_i in 0..self.num_channels {
387                    let channel_active = ch_i < buffer_in.channels()
388                        && active_channels_mask
389                            .as_ref()
390                            .map(|m| m.get(ch_i).copied().unwrap_or(false))
391                            .unwrap_or(true);
392
393                    if channel_active {
394                        self.buffer.copy_from_other_to_input_channel(
395                            buffer_in,
396                            ch_i,
397                            ch_i,
398                            input_start + (total_frames - frames_left),
399                            self.in_buf_len,
400                            block_frames_to_copy,
401                        );
402                    }
403                }
404
405                self.in_buf_len += block_frames_to_copy;
406                frames_left -= block_frames_to_copy;
407            }
408
409            if self.in_buf_len >= needed_input_frames {
410                self.in_buf_len = 0;
411
412                let (_, mut output_frames) = self
413                    .buffer
414                    .resample(indexing.as_ref(), &mut self.resampler)
415                    .unwrap();
416
417                if self.delay_frames_left > 0 {
418                    if self.delay_frames_left >= output_frames {
419                        self.delay_frames_left -= output_frames;
420
421                        if trim_delay {
422                            continue;
423                        }
424                    } else if trim_delay {
425                        self.buffer.output_copy_frames_within(
426                            self.delay_frames_left,
427                            0,
428                            output_frames,
429                        );
430
431                        output_frames -= self.delay_frames_left;
432                        self.delay_frames_left = 0;
433                    } else {
434                        self.delay_frames_left = 0;
435                    }
436                }
437
438                output_frames_processed += output_frames as u64;
439
440                (on_output_packet)(self.buffer.output(output_frames), output_frames);
441            }
442        }
443
444        if let Some(info) = &last_packet {
445            if self.in_buf_len > 0 {
446                self.buffer.input_fill_frames_with(
447                    self.in_buf_len,
448                    self.resampler.input_frames_max(),
449                    &T::zero(),
450                );
451            } else {
452                self.buffer.input_fill_with(&T::zero());
453            };
454
455            let desired_output_frames = info.desired_output_frames.unwrap_or_else(|| {
456                output_frames_processed + self.resampler.output_delay() as u64 + 1
457            });
458
459            while output_frames_processed < desired_output_frames {
460                let (_, mut output_frames) = self
461                    .buffer
462                    .resample(indexing.as_ref(), &mut self.resampler)
463                    .unwrap();
464
465                if self.in_buf_len > 0 {
466                    self.buffer.input_fill_with(&T::zero());
467                    self.in_buf_len = 0;
468                }
469
470                if self.delay_frames_left > 0 {
471                    if self.delay_frames_left >= output_frames {
472                        self.delay_frames_left -= output_frames;
473
474                        if trim_delay {
475                            continue;
476                        }
477                    } else if trim_delay {
478                        self.buffer.output_copy_frames_within(
479                            self.delay_frames_left,
480                            0,
481                            output_frames,
482                        );
483
484                        output_frames -= self.delay_frames_left;
485                        self.delay_frames_left = 0;
486                    } else {
487                        self.delay_frames_left = 0;
488                    }
489                }
490
491                output_frames =
492                    output_frames.min((desired_output_frames - output_frames_processed) as usize);
493                output_frames_processed += output_frames as u64;
494
495                (on_output_packet)(self.buffer.output(output_frames), output_frames);
496            }
497
498            self.reset();
499        }
500
501        if let Some(i) = indexing {
502            self.active_channels_mask = i.active_channels_mask;
503        }
504    }
505
506    pub fn output_delay_frames_left(&self) -> usize {
507        self.delay_frames_left
508    }
509
510    pub fn reset(&mut self) {
511        self.resampler.reset();
512        self.in_buf_len = 0;
513        self.delay_frames_left = self.resampler.output_delay();
514    }
515
516    pub fn into_inner(self) -> Box<dyn Resampler<T>> {
517        self.resampler
518    }
519}
520
521/// Options for processes the last packet in a resampler.
522#[derive(Debug, Clone, Copy, PartialEq, Eq)]
523pub struct LastPacketInfo {
524    /// The desired number of output frames that should be sent via the
525    /// `on_output_packet` closure.
526    ///
527    /// If this is `None`, then the last packet sent may contain extra
528    /// padded zeros on the end.
529    pub desired_output_frames: Option<u64>,
530}
531
532/// The type of output buffer to use for a [`PacketResampler`].
533///
534/// The provided options are [`Sequential`] and [`Interleaved`].
535pub trait PacketResamplerBuffer<T: Sample> {
536    type Output: ?Sized;
537
538    fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self;
539
540    fn output(&self, frames: usize) -> &Self::Output;
541
542    fn resample(
543        &mut self,
544        indexing: Option<&rubato::Indexing>,
545        resampler: &mut Box<dyn Resampler<T>>,
546    ) -> ResampleResult<(usize, usize)>;
547
548    /// Copy values from a channel of another Adapter.
549    /// The `self_skip` and `other_skip` arguments are the offsets
550    /// in frames for where copying starts in the two channels.
551    /// The method copies `take` values.
552    ///
553    /// Returns the the number of values that were clipped during conversion.
554    /// Implementations that do not perform any conversion
555    /// always return zero clipped samples.
556    ///
557    /// If an invalid channel number is given,
558    /// or if either of the channels is to short to copy `take` values,
559    /// no values will be copied and `None` is returned.
560    fn copy_from_other_to_input_channel(
561        &mut self,
562        other: &dyn Adapter<T>,
563        other_channel: usize,
564        self_channel: usize,
565        other_skip: usize,
566        self_skip: usize,
567        take: usize,
568    ) -> Option<usize>;
569
570    /// Write the provided value to every sample in a range of frames.
571    /// Can be used to clear a range of frames by writing zeroes,
572    /// or to initialize each sample to a certain value.
573    /// Returns `None` if called with a too large range.
574    fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize>;
575
576    /// Write the provided value to every sample in the entire buffer.
577    /// Can be used to clear a buffer by writing zeroes,
578    /// or to initialize each sample to a certain value.
579    fn input_fill_with(&mut self, value: &T);
580
581    /// Copy frames within the buffer.
582    /// Copying is performed for all channels.
583    /// Copies `count` frames, from the range `src..src+count`,
584    /// to the range `dest..dest+count`.
585    /// The two regions are allowed to overlap.
586    /// The default implementation copies by calling the read and write methods,
587    /// while type specific implementations can use more efficient methods.
588    fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize);
589}
590
591/// Use de-interleaved output packets for a [`PacketResampler`].
592pub struct Sequential<T: Sample> {
593    in_buffer: SequentialOwned<T>,
594    out_buffer: SequentialOwned<T>,
595}
596
597impl<T: Sample> PacketResamplerBuffer<T> for Sequential<T> {
598    type Output = SequentialOwned<T>;
599
600    fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self {
601        Self {
602            in_buffer: SequentialOwned::new(T::zero(), channels, input_frames),
603            out_buffer: SequentialOwned::new(T::zero(), channels, output_frames),
604        }
605    }
606
607    fn output(&self, _frames: usize) -> &Self::Output {
608        &self.out_buffer
609    }
610
611    fn resample(
612        &mut self,
613        indexing: Option<&rubato::Indexing>,
614        resampler: &mut Box<dyn Resampler<T>>,
615    ) -> ResampleResult<(usize, usize)> {
616        resampler.process_into_buffer(&self.in_buffer, &mut self.out_buffer, indexing)
617    }
618
619    fn copy_from_other_to_input_channel(
620        &mut self,
621        other: &dyn Adapter<T>,
622        other_channel: usize,
623        self_channel: usize,
624        other_skip: usize,
625        self_skip: usize,
626        take: usize,
627    ) -> Option<usize> {
628        self.in_buffer.copy_from_other_to_channel(
629            other,
630            other_channel,
631            self_channel,
632            other_skip,
633            self_skip,
634            take,
635        )
636    }
637
638    fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize> {
639        self.in_buffer.fill_frames_with(start, count, value)
640    }
641
642    fn input_fill_with(&mut self, value: &T) {
643        self.in_buffer.fill_with(value);
644    }
645
646    fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize) {
647        self.out_buffer.copy_frames_within(src, dest, count);
648    }
649}
650
651/// Use interleaved output packets for a [`PacketResampler`].
652pub struct Interleaved<T: Sample> {
653    in_buffer: InterleavedOwned<T>,
654    out_buffer: Vec<T>,
655    channels: usize,
656    output_frames: usize,
657}
658
659impl<T: Sample> PacketResamplerBuffer<T> for Interleaved<T> {
660    type Output = [T];
661
662    fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self {
663        let out_buffer_size = output_frames * channels;
664        let mut out_buffer = Vec::new();
665        out_buffer.reserve_exact(out_buffer_size);
666        out_buffer.resize(out_buffer_size, T::zero());
667
668        Self {
669            in_buffer: InterleavedOwned::new(T::zero(), channels, input_frames),
670            out_buffer,
671            channels,
672            output_frames,
673        }
674    }
675
676    fn output(&self, frames: usize) -> &Self::Output {
677        &self.out_buffer[0..frames * self.channels]
678    }
679
680    fn resample(
681        &mut self,
682        indexing: Option<&rubato::Indexing>,
683        resampler: &mut Box<dyn Resampler<T>>,
684    ) -> ResampleResult<(usize, usize)> {
685        let mut out_buffer_wrapper = direct::InterleavedSlice::new_mut(
686            &mut self.out_buffer,
687            self.channels,
688            self.output_frames,
689        )
690        .unwrap();
691
692        resampler.process_into_buffer(&self.in_buffer, &mut out_buffer_wrapper, indexing)
693    }
694
695    fn copy_from_other_to_input_channel(
696        &mut self,
697        other: &dyn Adapter<T>,
698        other_channel: usize,
699        self_channel: usize,
700        other_skip: usize,
701        self_skip: usize,
702        take: usize,
703    ) -> Option<usize> {
704        self.in_buffer.copy_from_other_to_channel(
705            other,
706            other_channel,
707            self_channel,
708            other_skip,
709            self_skip,
710            take,
711        )
712    }
713
714    fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize> {
715        self.in_buffer.fill_frames_with(start, count, value)
716    }
717
718    fn input_fill_with(&mut self, value: &T) {
719        self.in_buffer.fill_with(value);
720    }
721
722    fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize) {
723        self.out_buffer.copy_within(src..count, dest);
724    }
725}
726
727/// Extend the given Vec with the contents of a channel from the given [`Adapter`].
728///
729/// If the adapter does not contain enough frames, then only the available number of
730/// frames will be appended to the Vec.
731///
732/// Returns the number of frames that were appended to the Vec.
733///
734/// # Panics
735/// * Panics if `buffer_in_channel >= buffer_in.channels()`
736pub fn extend_from_adapter_channel<T: Sample>(
737    out_buffer: &mut Vec<T>,
738    buffer_in: &dyn Adapter<T>,
739    buffer_in_skip: usize,
740    buffer_in_channel: usize,
741    frames: usize,
742) -> usize {
743    assert!(buffer_in_channel < buffer_in.channels());
744
745    let out_buffer_len = out_buffer.len();
746    let available = out_buffer.capacity() - out_buffer_len;
747    if available < frames {
748        out_buffer.reserve(frames);
749    }
750
751    // Safety:
752    // * We ensured that the output buffer has enough capacity above.
753    // * All the new frames in the output buffer will be filled with data below, and
754    // we correctly truncate any frames which did not get filled with data.
755    unsafe {
756        out_buffer.set_len(out_buffer_len + frames);
757    }
758
759    let frames_copied = buffer_in.copy_from_channel_to_slice(
760        buffer_in_channel,
761        buffer_in_skip,
762        &mut out_buffer[out_buffer_len..],
763    );
764
765    // Truncate any unused data.
766    if frames_copied < frames {
767        // Safety:
768        // * The new length is less than the old length.
769        // * T requires `Copy`, so there is no need to call the destructor on each sample.
770        unsafe {
771            out_buffer.set_len(out_buffer_len + frames_copied);
772        }
773    }
774
775    frames_copied
776}