firewheel_nodes/
sampler.rs

1// TODO: The logic in this has become increadibly complex and error-prone. I plan
2// on rewriting the sampler engine using a state machine.
3
4use firewheel_core::clock::{DurationSamples, DurationSeconds};
5use firewheel_core::node::{ProcBuffers, ProcExtra, ProcStreamCtx};
6#[cfg(not(feature = "std"))]
7use num_traits::Float;
8
9use bevy_platform::sync::atomic::{AtomicU64, Ordering};
10use bevy_platform::time::Instant;
11use core::sync::atomic::AtomicU32;
12use core::{
13    num::{NonZeroU32, NonZeroUsize},
14    ops::Range,
15};
16use firewheel_core::diff::{EventQueue, PatchError, PathBuilder, RealtimeClone};
17use smallvec::SmallVec;
18
19use firewheel_core::{
20    channel_config::{ChannelConfig, ChannelCount, NonZeroChannelCount},
21    clock::InstantSeconds,
22    collector::ArcGc,
23    diff::{Diff, Notify, ParamPath, Patch},
24    dsp::{
25        buffer::InstanceBuffer,
26        declick::{DeclickFadeCurve, Declicker},
27        volume::{Volume, DEFAULT_AMP_EPSILON},
28    },
29    event::{NodeEventType, ParamData, ProcEvents},
30    mask::{MaskType, SilenceMask},
31    node::{
32        AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, ProcInfo,
33        ProcessStatus,
34    },
35    sample_resource::SampleResource,
36    StreamInfo,
37};
38
39#[cfg(feature = "scheduled_events")]
40use firewheel_core::clock::EventInstant;
41
42pub const MAX_OUT_CHANNELS: usize = 8;
43pub const DEFAULT_NUM_DECLICKERS: usize = 2;
44pub const MIN_PLAYBACK_SPEED: f64 = 0.0000001;
45
46/// The configuration of a [`SamplerNode`]
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
49#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51pub struct SamplerConfig {
52    /// The number of channels in this node.
53    pub channels: NonZeroChannelCount,
54    /// The maximum number of "declickers" present on this node.
55    /// The more declickers there are, the more samples that can be declicked
56    /// when played in rapid succession. (Note more declickers will allocate
57    /// more memory).
58    ///
59    /// By default this is set to `2`.
60    pub num_declickers: u32,
61    /// The quality of the resampling algorithm used when changing the playback
62    /// speed.
63    pub speed_quality: PlaybackSpeedQuality,
64}
65
66impl Default for SamplerConfig {
67    fn default() -> Self {
68        Self {
69            channels: NonZeroChannelCount::STEREO,
70            num_declickers: DEFAULT_NUM_DECLICKERS as u32,
71            speed_quality: PlaybackSpeedQuality::default(),
72        }
73    }
74}
75
76/// The quality of the resampling algorithm used for changing the playback
77/// speed of a sampler node.
78#[non_exhaustive]
79#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
80#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub enum PlaybackSpeedQuality {
83    #[default]
84    /// Low quality, fast performance. Recommended for most use cases.
85    ///
86    /// More specifically, this uses a linear resampling algorithm with no
87    /// antialiasing filter.
88    LinearFast,
89    // TODO: more quality options
90}
91
92/// A node that plays samples
93///
94/// It supports pausing, resuming, looping, and changing the playback speed.
95#[derive(Clone, Diff, Patch, PartialEq)]
96#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
97#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99pub struct SamplerNode {
100    /// The sample resource to use.
101    #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
102    #[cfg_attr(feature = "serde", serde(skip))]
103    pub sample: Option<ArcGc<dyn SampleResource>>,
104
105    /// The volume to play the sample at.
106    ///
107    /// Note, this gain parameter is *NOT* smoothed! If you need the gain to be
108    /// smoothed, please use a [`VolumeNode`] or a [`VolumePanNode`].
109    ///
110    /// [`VolumeNode`]: crate::volume::VolumeNode
111    /// [`VolumePanNode`]: crate::volume_pan::VolumePanNode
112    pub volume: Volume,
113
114    /// Whether or not the current sample should start/restart playing (true), or be
115    /// paused/stopped (false).
116    #[cfg_attr(feature = "serde", serde(skip))]
117    pub play: Notify<bool>,
118
119    /// Defines where the sampler should start playing from when
120    /// [`SamplerNode::play`] is set to `true`.
121    pub play_from: PlayFrom,
122
123    /// How many times a sample should be repeated.
124    pub repeat_mode: RepeatMode,
125
126    /// The speed at which to play the sample at. `1.0` means to play the sound at
127    /// its original speed, `< 1.0` means to play the sound slower (which will make
128    /// it lower-pitched), and `> 1.0` means to play the sound faster (which will
129    /// make it higher-pitched).
130    pub speed: f64,
131
132    /// If `true`, then mono samples will be converted to stereo during playback.
133    ///
134    /// By default this is set to `true`.
135    pub mono_to_stereo: bool,
136    /// If true, then samples will be crossfaded when the playhead or sample is
137    /// changed (if a sample was currently playing when the event was sent).
138    ///
139    /// By default this is set to `true`.
140    pub crossfade_on_seek: bool,
141    /// If the resutling gain (in raw amplitude, not decibels) is less
142    /// than or equal to this value, then the gain will be clamped to
143    /// `0.0` (silence).
144    ///
145    /// By default this is set to `0.00001` (-100 decibels).
146    pub min_gain: f32,
147}
148
149impl Default for SamplerNode {
150    fn default() -> Self {
151        Self {
152            sample: None,
153            volume: Volume::default(),
154            play: Default::default(),
155            play_from: PlayFrom::default(),
156            repeat_mode: RepeatMode::default(),
157            speed: 1.0,
158            mono_to_stereo: true,
159            crossfade_on_seek: true,
160            min_gain: DEFAULT_AMP_EPSILON,
161        }
162    }
163}
164
165impl core::fmt::Debug for SamplerNode {
166    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167        let mut f = f.debug_struct("SamplerNode");
168        f.field("has_sample", &self.sample.is_some());
169        f.field("volume", &self.volume);
170        f.field("play", &self.play);
171        f.field("play_from", &self.play_from);
172        f.field("repeat_mode", &self.repeat_mode);
173        f.field("speed", &self.speed);
174        f.field("mono_to_stereo", &self.mono_to_stereo);
175        f.field("crossfade_on_seek", &self.crossfade_on_seek);
176        f.field("min_gain", &self.min_gain);
177        f.finish()
178    }
179}
180
181impl SamplerNode {
182    /// Set the parameters to a play a single sample.
183    pub fn set_sample(&mut self, sample: ArcGc<dyn SampleResource>) {
184        self.sample = Some(sample);
185    }
186
187    /// Returns an event type to sync the `sample` parameter.
188    pub fn sync_sample_event(&self) -> NodeEventType {
189        NodeEventType::Param {
190            data: ParamData::any(self.sample.clone()),
191            path: ParamPath::Single(0),
192        }
193    }
194
195    /// Returns an event type to sync the `volume` parameter.
196    pub fn sync_volume_event(&self) -> NodeEventType {
197        NodeEventType::Param {
198            data: ParamData::Volume(self.volume),
199            path: ParamPath::Single(1),
200        }
201    }
202
203    /// Returns an event type to sync the `play` parameter.
204    pub fn sync_play_event(&self) -> NodeEventType {
205        NodeEventType::Param {
206            data: ParamData::Bool(*self.play),
207            path: ParamPath::Single(2),
208        }
209    }
210
211    /// Returns an event type to sync the `play_from` parameter.
212    pub fn sync_play_from_event(&self) -> NodeEventType {
213        NodeEventType::Param {
214            data: self.play_from.as_param_data(),
215            path: ParamPath::Single(3),
216        }
217    }
218
219    /// Returns an event type to sync the `playhead` parameter.
220    pub fn sync_repeat_mode_event(&self) -> NodeEventType {
221        NodeEventType::Param {
222            data: ParamData::any(self.repeat_mode),
223            path: ParamPath::Single(4),
224        }
225    }
226
227    /// Returns an event type to sync the `speed` parameter.
228    pub fn sync_speed_event(&self) -> NodeEventType {
229        NodeEventType::Param {
230            data: ParamData::F64(self.speed),
231            path: ParamPath::Single(5),
232        }
233    }
234
235    /// Start/restart the sample in this node.
236    ///
237    /// If a sample is already playing, then it will restart from the beginning.
238    pub fn start_or_restart(&mut self) {
239        self.play_from = PlayFrom::BEGINNING;
240        *self.play = true;
241    }
242
243    /// Play the sample in this node from the given playhead.
244    pub fn start_from(&mut self, from: PlayFrom) {
245        self.play_from = from;
246        *self.play = true;
247    }
248
249    /// Pause sample playback.
250    pub fn pause(&mut self) {
251        self.play_from = PlayFrom::Resume;
252        *self.play = false;
253    }
254
255    /// Resume sample playback.
256    pub fn resume(&mut self) {
257        *self.play = true;
258    }
259
260    /// Stop sample playback.
261    ///
262    /// Calling [`SamplerNode::resume`] after this will restart the sample from
263    /// the beginning.
264    pub fn stop(&mut self) {
265        self.play_from = PlayFrom::BEGINNING;
266        *self.play = false;
267    }
268
269    /// Returns `true` if the current state is set to restart the sample.
270    pub fn start_or_restart_requested(&self) -> bool {
271        *self.play && self.play_from == PlayFrom::BEGINNING
272    }
273
274    /// Returns `true` if the current state is set to resume the sample.
275    pub fn resume_requested(&self) -> bool {
276        *self.play && self.play_from == PlayFrom::Resume
277    }
278
279    /// Returns `true` if the current state is set to pause the sample.
280    pub fn pause_requested(&self) -> bool {
281        !*self.play && self.play_from == PlayFrom::Resume
282    }
283
284    /// Returns `true` if the current state is set to stop the sample.
285    pub fn stop_requested(&self) -> bool {
286        !*self.play && self.play_from != PlayFrom::Resume
287    }
288}
289
290#[derive(Clone)]
291pub struct SamplerState {
292    shared_state: ArcGc<SharedState>,
293}
294
295impl SamplerState {
296    fn new() -> Self {
297        Self {
298            shared_state: ArcGc::new(SharedState::default()),
299        }
300    }
301
302    /// Get the current position of the playhead in units of frames (samples of
303    /// a single channel of audio).
304    pub fn playhead_frames(&self) -> DurationSamples {
305        DurationSamples(
306            self.shared_state
307                .sample_playhead_frames
308                .load(Ordering::Relaxed) as i64,
309        )
310    }
311
312    /// Get the current position of the sample playhead in seconds.
313    ///
314    /// * `sample_rate` - The sample rate of the current audio stream.
315    pub fn playhead_seconds(&self, sample_rate: NonZeroU32) -> DurationSeconds {
316        DurationSeconds(self.playhead_frames().0 as f64 / sample_rate.get() as f64)
317    }
318
319    /// Get the current position of the playhead in units of frames (samples of
320    /// a single channel of audio), corrected with the delay between when the audio clock
321    /// was last updated and now.
322    ///
323    /// Call `FirewheelCtx::audio_clock_instant()` right before calling this method to get
324    /// the latest update instant.
325    pub fn playhead_frames_corrected(
326        &self,
327        update_instant: Option<Instant>,
328        sample_rate: NonZeroU32,
329    ) -> DurationSamples {
330        let frames = self.playhead_frames();
331
332        let Some(update_instant) = update_instant else {
333            return frames;
334        };
335
336        if SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
337            == SharedPlaybackState::Playing
338        {
339            DurationSamples(
340                frames.0
341                    + InstantSeconds(update_instant.elapsed().as_secs_f64())
342                        .to_samples(sample_rate)
343                        .0 as i64,
344            )
345        } else {
346            frames
347        }
348    }
349
350    /// Get the current position of the playhead in units of seconds, corrected with the
351    /// delay between when the audio clock was last updated and now.
352    ///
353    /// Call `FirewheelCtx::audio_clock_instant()` right before calling this method to get
354    /// the latest update instant.
355    pub fn playhead_seconds_corrected(
356        &self,
357        update_instant: Option<Instant>,
358        sample_rate: NonZeroU32,
359    ) -> DurationSeconds {
360        DurationSeconds(
361            self.playhead_frames_corrected(update_instant, sample_rate)
362                .0 as f64
363                / sample_rate.get() as f64,
364        )
365    }
366
367    /// Returns `true` if the sample is currently playing.
368    pub fn playing(&self) -> bool {
369        SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
370            == SharedPlaybackState::Playing
371    }
372
373    /// Returns `true` if the sample is currently paused.
374    pub fn paused(&self) -> bool {
375        SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
376            == SharedPlaybackState::Paused
377    }
378
379    /// Returns `true` if the sample has either not started playing yet or has finished
380    /// playing.
381    pub fn stopped(&self) -> bool {
382        SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
383            == SharedPlaybackState::Stopped
384    }
385
386    /// Manually set the shared `playing` flag. This can be useful to account for the delay
387    /// between sending a play event and the node's processor receiving that event.
388    pub fn mark_playing(&self) {
389        self.shared_state
390            .playback_state
391            .store(SharedPlaybackState::Playing as u32, Ordering::Relaxed);
392    }
393
394    /// Manually set the shared `paused` flag. This can be useful to account for the delay
395    /// between sending a play event and the node's processor receiving that event.
396    pub fn mark_paused(&self) {
397        self.shared_state
398            .playback_state
399            .store(SharedPlaybackState::Paused as u32, Ordering::Relaxed);
400    }
401
402    /// Manually set the shared `stopped` flag. This can be useful to account for the delay
403    /// between sending a play event and the node's processor receiving that event.
404    pub fn mark_stopped(&self) {
405        self.shared_state
406            .playback_state
407            .store(SharedPlaybackState::Stopped as u32, Ordering::Relaxed);
408    }
409
410    /// Returns the ID stored in the "finished" flag.
411    pub fn finished(&self) -> u64 {
412        self.shared_state.finished.load(Ordering::Relaxed)
413    }
414
415    /// Clears the "finished" flag.
416    pub fn clear_finished(&self) {
417        self.shared_state.finished.store(0, Ordering::Relaxed);
418    }
419
420    /// A score of how suitable this node is to start new work (Play a new sample). The
421    /// higher the score, the better the candidate.
422    pub fn worker_score(&self, params: &SamplerNode) -> u64 {
423        if params.sample.is_some() {
424            let playback_state = SharedPlaybackState::from_u32(
425                self.shared_state.playback_state.load(Ordering::Relaxed),
426            );
427
428            if *params.play {
429                let playhead_frames = self.playhead_frames();
430
431                if playback_state == SharedPlaybackState::Stopped {
432                    if playhead_frames.0 > 0 {
433                        // Sequence has likely finished playing.
434                        u64::MAX - 4
435                    } else {
436                        // Sequence has likely not started playing yet.
437                        u64::MAX - 5
438                    }
439                } else {
440                    // The older the sample is, the better it is as a candidate to steal
441                    // work from.
442                    playhead_frames.0 as u64
443                }
444            } else {
445                match playback_state {
446                    SharedPlaybackState::Stopped => u64::MAX - 1,
447                    SharedPlaybackState::Paused => u64::MAX - 2,
448                    SharedPlaybackState::Playing => u64::MAX - 3,
449                }
450            }
451        } else {
452            u64::MAX
453        }
454    }
455}
456
457/// Defines where the sampler should start playing from when
458/// [`SamplerNode::play`] is set to `true`.
459#[derive(Debug, Clone, Copy, PartialEq, RealtimeClone)]
460#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
461#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
462pub enum PlayFrom {
463    /// When [`SamplerNode::play`] is set to `true`, the sampler will resume
464    /// playing from where it last left off.
465    Resume,
466    /// When [`SamplerNode::play`] is set to `true`, the sampler will begin
467    /// playing  from this position in the sample in units of seconds.
468    Seconds(f64),
469    /// When [`SamplerNode::play`] is set to `true`, the sampler will begin
470    /// playing from this position in the sample in units of frames (samples
471    /// in a single channel of audio).
472    Frames(u64),
473}
474
475impl PlayFrom {
476    pub const BEGINNING: Self = Self::Frames(0);
477
478    pub fn as_frames(&self, sample_rate: NonZeroU32) -> Option<u64> {
479        match *self {
480            Self::Resume => None,
481            Self::Seconds(seconds) => Some(if seconds <= 0.0 {
482                0
483            } else {
484                (seconds.floor() as u64 * sample_rate.get() as u64)
485                    + (seconds.fract() * sample_rate.get() as f64).round() as u64
486            }),
487            Self::Frames(frames) => Some(frames),
488        }
489    }
490
491    pub fn as_param_data(&self) -> ParamData {
492        match self {
493            Self::Resume => ParamData::None,
494            Self::Seconds(s) => ParamData::F64(*s),
495            Self::Frames(f) => ParamData::U64(*f),
496        }
497    }
498}
499
500impl Default for PlayFrom {
501    fn default() -> Self {
502        Self::BEGINNING
503    }
504}
505
506impl Diff for PlayFrom {
507    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
508        if self != baseline {
509            event_queue.push_param(self.as_param_data(), path);
510        }
511    }
512}
513
514impl Patch for PlayFrom {
515    type Patch = Self;
516
517    fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, PatchError> {
518        match data {
519            ParamData::None => Ok(PlayFrom::Resume),
520            ParamData::F64(s) => Ok(PlayFrom::Seconds(*s)),
521            ParamData::U64(f) => Ok(PlayFrom::Frames(*f)),
522            _ => Err(PatchError::InvalidData),
523        }
524    }
525
526    fn apply(&mut self, value: Self::Patch) {
527        *self = value;
528    }
529}
530
531/// How many times a sample should be repeated.
532#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Diff, Patch)]
533#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
534#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
535pub enum RepeatMode {
536    /// Play the sample once and then stop.
537    #[default]
538    PlayOnce,
539    /// Repeat the sample the given number of times.
540    RepeatMultiple { num_times_to_repeat: u32 },
541    /// Repeat the sample endlessly.
542    RepeatEndlessly,
543}
544
545impl RepeatMode {
546    pub fn do_loop(&self, num_times_looped_back: u64) -> bool {
547        match self {
548            Self::PlayOnce => false,
549            &Self::RepeatMultiple {
550                num_times_to_repeat,
551            } => num_times_looped_back < num_times_to_repeat as u64,
552            Self::RepeatEndlessly => true,
553        }
554    }
555}
556
557impl AudioNode for SamplerNode {
558    type Configuration = SamplerConfig;
559
560    fn info(&self, config: &Self::Configuration) -> AudioNodeInfo {
561        AudioNodeInfo::new()
562            .debug_name("sampler")
563            .channel_config(ChannelConfig {
564                num_inputs: ChannelCount::ZERO,
565                num_outputs: config.channels.get(),
566            })
567            .custom_state(SamplerState::new())
568    }
569
570    fn construct_processor(
571        &self,
572        config: &Self::Configuration,
573        cx: ConstructProcessorContext,
574    ) -> impl AudioNodeProcessor {
575        let stop_declicker_buffers = if config.num_declickers == 0 {
576            None
577        } else {
578            Some(InstanceBuffer::<f32, MAX_OUT_CHANNELS>::new(
579                config.num_declickers as usize,
580                NonZeroUsize::new(config.channels.get().get() as usize).unwrap(),
581                cx.stream_info.declick_frames.get() as usize,
582            ))
583        };
584
585        SamplerProcessor {
586            config: config.clone(),
587            params: self.clone(),
588            shared_state: ArcGc::clone(&cx.custom_state::<SamplerState>().unwrap().shared_state),
589            loaded_sample_state: None,
590            declicker: Declicker::SettledAt1,
591            stop_declicker_buffers,
592            stop_declickers: smallvec::smallvec![StopDeclickerState::default(); config.num_declickers as usize],
593            num_active_stop_declickers: 0,
594            resampler: Some(Resampler::new(config.speed_quality)),
595            speed: self.speed.max(MIN_PLAYBACK_SPEED),
596            playing: *self.play,
597            paused: !*self.play && self.play_from == PlayFrom::Resume,
598            #[cfg(feature = "scheduled_events")]
599            queued_playback_instant: None,
600            min_gain: self.min_gain.max(0.0),
601            is_first_process: true,
602            max_block_frames: cx.stream_info.max_block_frames.get() as usize,
603        }
604    }
605}
606
607struct SamplerProcessor {
608    config: SamplerConfig,
609    params: SamplerNode,
610    shared_state: ArcGc<SharedState>,
611
612    loaded_sample_state: Option<LoadedSampleState>,
613
614    declicker: Declicker,
615
616    playing: bool,
617    paused: bool,
618
619    stop_declicker_buffers: Option<InstanceBuffer<f32, MAX_OUT_CHANNELS>>,
620    stop_declickers: SmallVec<[StopDeclickerState; DEFAULT_NUM_DECLICKERS]>,
621    num_active_stop_declickers: usize,
622
623    resampler: Option<Resampler>,
624    speed: f64,
625
626    #[cfg(feature = "scheduled_events")]
627    queued_playback_instant: Option<EventInstant>,
628
629    min_gain: f32,
630
631    is_first_process: bool,
632    max_block_frames: usize,
633}
634
635impl SamplerProcessor {
636    /// Returns `true` if the sample has finished playing, and also
637    /// returns the number of channels that were filled.
638    fn process_internal(
639        &mut self,
640        buffers: &mut [&mut [f32]],
641        frames: usize,
642        looping: bool,
643        extra: &mut ProcExtra,
644    ) -> (bool, usize) {
645        let (finished_playing, mut channels_filled) = if self.speed != 1.0 {
646            // Get around borrow checker.
647            let mut resampler = self.resampler.take().unwrap();
648
649            let (finished_playing, channels_filled) =
650                resampler.resample_linear(buffers, 0..frames, extra, self, looping);
651
652            self.resampler = Some(resampler);
653
654            (finished_playing, channels_filled)
655        } else {
656            self.resampler.as_mut().unwrap().reset();
657
658            self.copy_from_sample(buffers, 0..frames, looping)
659        };
660
661        let Some(state) = self.loaded_sample_state.as_ref() else {
662            return (true, 0);
663        };
664
665        if !self.declicker.has_settled() {
666            self.declicker.process(
667                buffers,
668                0..frames,
669                &extra.declick_values,
670                state.gain,
671                DeclickFadeCurve::EqualPower3dB,
672            );
673        } else if state.gain != 1.0 {
674            for b in buffers[..channels_filled].iter_mut() {
675                for s in b[..frames].iter_mut() {
676                    *s *= state.gain;
677                }
678            }
679        }
680
681        if state.sample_mono_to_stereo {
682            let (b0, b1) = buffers.split_first_mut().unwrap();
683            b1[0][..frames].copy_from_slice(&b0[..frames]);
684
685            channels_filled = 2;
686        }
687
688        (finished_playing, channels_filled)
689    }
690
691    /// Fill the buffer with raw data from the sample, starting from the
692    /// current playhead. Then increment the playhead.
693    ///
694    /// Returns `true` if the sample has finished playing, and also
695    /// returns the number of channels that were filled.
696    fn copy_from_sample(
697        &mut self,
698        buffers: &mut [&mut [f32]],
699        range_in_buffer: Range<usize>,
700        looping: bool,
701    ) -> (bool, usize) {
702        let Some(state) = self.loaded_sample_state.as_mut() else {
703            return (true, 0);
704        };
705
706        assert!(state.playhead_frames <= state.sample_len_frames);
707
708        let block_frames = range_in_buffer.end - range_in_buffer.start;
709        let first_copy_frames =
710            if state.playhead_frames + block_frames as u64 > state.sample_len_frames {
711                (state.sample_len_frames - state.playhead_frames) as usize
712            } else {
713                block_frames
714            };
715
716        if first_copy_frames > 0 {
717            state.sample.fill_buffers(
718                buffers,
719                range_in_buffer.start..range_in_buffer.start + first_copy_frames,
720                state.playhead_frames,
721            );
722
723            state.playhead_frames += first_copy_frames as u64;
724        }
725
726        if first_copy_frames < block_frames {
727            if looping {
728                let mut frames_copied = first_copy_frames;
729
730                while frames_copied < block_frames {
731                    let copy_frames = ((block_frames - frames_copied) as u64)
732                        .min(state.sample_len_frames)
733                        as usize;
734
735                    state.sample.fill_buffers(
736                        buffers,
737                        range_in_buffer.start + frames_copied
738                            ..range_in_buffer.start + frames_copied + copy_frames,
739                        0,
740                    );
741
742                    state.playhead_frames = copy_frames as u64;
743                    state.num_times_looped_back += 1;
744
745                    frames_copied += copy_frames;
746                }
747            } else {
748                let n_channels = buffers.len().min(state.sample_num_channels.get());
749                for b in buffers[..n_channels].iter_mut() {
750                    b[range_in_buffer.start + first_copy_frames..range_in_buffer.end].fill(0.0);
751                }
752
753                return (true, n_channels);
754            }
755        }
756
757        (false, buffers.len().min(state.sample_num_channels.get()))
758    }
759
760    fn currently_processing_sample(&self) -> bool {
761        if self.params.sample.is_none() {
762            false
763        } else {
764            self.playing || (self.paused && !self.declicker.has_settled())
765        }
766    }
767
768    fn num_channels_filled(&self, num_out_channels: usize) -> usize {
769        if let Some(state) = &self.loaded_sample_state {
770            if state.sample_mono_to_stereo {
771                2
772            } else {
773                state.sample_num_channels.get().min(num_out_channels)
774            }
775        } else {
776            0
777        }
778    }
779
780    fn stop(&mut self, num_out_channels: usize, extra: &mut ProcExtra) {
781        if self.currently_processing_sample() {
782            // Fade out the sample into a temporary look-ahead
783            // buffer to declick.
784
785            self.declicker.fade_to_0(&extra.declick_values);
786
787            // Work around the borrow checker.
788            if let Some(mut stop_declicker_buffers) = self.stop_declicker_buffers.take() {
789                if self.num_active_stop_declickers < stop_declicker_buffers.num_instances() {
790                    let declicker_i = self
791                        .stop_declickers
792                        .iter()
793                        .enumerate()
794                        .find_map(|(i, d)| if d.frames_left == 0 { Some(i) } else { None })
795                        .unwrap();
796
797                    let n_channels = self.num_channels_filled(num_out_channels);
798
799                    let fade_out_frames = stop_declicker_buffers.frames();
800
801                    self.stop_declickers[declicker_i].frames_left = fade_out_frames;
802                    self.stop_declickers[declicker_i].channels = n_channels;
803
804                    let mut tmp_buffers = stop_declicker_buffers
805                        .instance_mut(declicker_i, n_channels, fade_out_frames)
806                        .unwrap();
807
808                    self.process_internal(&mut tmp_buffers, fade_out_frames, false, extra);
809
810                    self.num_active_stop_declickers += 1;
811                }
812
813                self.stop_declicker_buffers = Some(stop_declicker_buffers);
814            }
815        }
816
817        if let Some(state) = &mut self.loaded_sample_state {
818            state.playhead_frames = 0;
819            state.num_times_looped_back = 0;
820        }
821
822        self.declicker.reset_to_1();
823
824        if let Some(resampler) = &mut self.resampler {
825            resampler.reset();
826        }
827    }
828
829    fn load_sample(&mut self, sample: ArcGc<dyn SampleResource>, num_out_channels: usize) {
830        let mut gain = self.params.volume.amp_clamped(self.min_gain);
831        if gain > 0.99999 && gain < 1.00001 {
832            gain = 1.0;
833        }
834
835        let sample_len_frames = sample.len_frames();
836        let sample_num_channels = sample.num_channels();
837
838        let sample_mono_to_stereo =
839            self.params.mono_to_stereo && num_out_channels > 1 && sample_num_channels.get() == 1;
840
841        self.loaded_sample_state = Some(LoadedSampleState {
842            sample,
843            sample_len_frames,
844            sample_num_channels,
845            sample_mono_to_stereo,
846            gain,
847            playhead_frames: 0,
848            num_times_looped_back: 0,
849        });
850    }
851}
852
853impl AudioNodeProcessor for SamplerProcessor {
854    fn process(
855        &mut self,
856        info: &ProcInfo,
857        buffers: ProcBuffers,
858        events: &mut ProcEvents,
859        extra: &mut ProcExtra,
860    ) -> ProcessStatus {
861        let mut sample_changed = self.is_first_process;
862        let mut repeat_mode_changed = false;
863        let mut speed_changed = false;
864        let mut volume_changed = false;
865        let mut new_playing: Option<bool> = if self.is_first_process {
866            Some(self.playing)
867        } else {
868            None
869        };
870
871        #[cfg(feature = "scheduled_events")]
872        let mut playback_instant: Option<EventInstant> = None;
873
874        #[cfg(not(feature = "scheduled_events"))]
875        for patch in events.drain_patches::<SamplerNode>() {
876            match patch {
877                SamplerNodePatch::Sample(_) => sample_changed = true,
878                SamplerNodePatch::Volume(_) => volume_changed = true,
879                SamplerNodePatch::Play(play) => {
880                    new_playing = Some(*play);
881                }
882                SamplerNodePatch::RepeatMode(_) => repeat_mode_changed = true,
883                SamplerNodePatch::Speed(_) => speed_changed = true,
884                SamplerNodePatch::MinGain(min_gain) => {
885                    self.min_gain = min_gain.max(0.0);
886                }
887                _ => {}
888            }
889
890            self.params.apply(patch);
891        }
892
893        #[cfg(feature = "scheduled_events")]
894        for (patch, timestamp) in events.drain_patches_with_timestamps::<SamplerNode>() {
895            match patch {
896                SamplerNodePatch::Sample(_) => sample_changed = true,
897                SamplerNodePatch::Volume(_) => volume_changed = true,
898                SamplerNodePatch::Play(play) => {
899                    playback_instant = timestamp;
900                    new_playing = Some(*play);
901                }
902                SamplerNodePatch::RepeatMode(_) => repeat_mode_changed = true,
903                SamplerNodePatch::Speed(_) => speed_changed = true,
904                SamplerNodePatch::MinGain(min_gain) => {
905                    self.min_gain = min_gain.max(0.0);
906                }
907                _ => {}
908            }
909
910            self.params.apply(patch);
911        }
912
913        if speed_changed {
914            self.speed = self.params.speed.max(MIN_PLAYBACK_SPEED);
915
916            if self.speed > 0.99999 && self.speed < 1.00001 {
917                self.speed = 1.0;
918            }
919        }
920
921        if volume_changed {
922            if let Some(loaded_sample) = &mut self.loaded_sample_state {
923                loaded_sample.gain = self.params.volume.amp_clamped(self.min_gain);
924                if loaded_sample.gain > 0.99999 && loaded_sample.gain < 1.00001 {
925                    loaded_sample.gain = 1.0;
926                }
927            }
928        }
929
930        if repeat_mode_changed {
931            if let Some(loaded_sample) = &mut self.loaded_sample_state {
932                loaded_sample.num_times_looped_back = 0;
933            }
934        }
935
936        if sample_changed {
937            self.stop(buffers.outputs.len(), extra);
938
939            #[cfg(feature = "scheduled_events")]
940            if new_playing == Some(true) && playback_instant.is_none() {
941                if let Some(queued_playback_instant) = self.queued_playback_instant.take() {
942                    if queued_playback_instant.to_samples(info).is_some() {
943                        playback_instant = Some(queued_playback_instant);
944                    }
945                }
946            }
947
948            self.loaded_sample_state = None;
949
950            if let Some(sample) = &self.params.sample {
951                self.load_sample(ArcGc::clone(sample), buffers.outputs.len());
952            }
953        }
954
955        if let Some(mut new_playing) = new_playing {
956            self.paused = false;
957
958            if new_playing {
959                let mut playhead_frames_at_play_instant = None;
960
961                if self.params.play_from == PlayFrom::Resume {
962                    // Resume
963                    if self.playing && !self.is_first_process {
964                        // Sample is already playing, no need to do anything.
965                        #[cfg(feature = "scheduled_events")]
966                        {
967                            self.queued_playback_instant = None;
968                        }
969                    } else if let Some(loaded_sample_state) = &self.loaded_sample_state {
970                        playhead_frames_at_play_instant = Some(loaded_sample_state.playhead_frames);
971                    }
972                } else {
973                    // Play from the given playhead
974                    if let Some(loaded_sample_state) = &mut self.loaded_sample_state {
975                        loaded_sample_state.num_times_looped_back = 0;
976                        playhead_frames_at_play_instant =
977                            Some(self.params.play_from.as_frames(info.sample_rate).unwrap());
978                    } else {
979                        #[cfg(feature = "scheduled_events")]
980                        {
981                            self.queued_playback_instant = playback_instant;
982                        }
983                    }
984                }
985
986                if let Some(playhead_frames_at_play_instant) = playhead_frames_at_play_instant {
987                    let loaded_sample_state = self.loaded_sample_state.as_mut().unwrap();
988                    let prev_playhead_frames = loaded_sample_state.playhead_frames;
989
990                    #[cfg(feature = "scheduled_events")]
991                    let mut new_playhead_frames = if let Some(playback_instant) = playback_instant {
992                        let playback_instant_samples = playback_instant
993                            .to_samples(info)
994                            .unwrap_or(info.clock_samples);
995                        let delay = if playback_instant_samples < info.clock_samples {
996                            (info.clock_samples - playback_instant_samples).0 as u64
997                        } else {
998                            0
999                        };
1000
1001                        playhead_frames_at_play_instant + delay
1002                    } else {
1003                        playhead_frames_at_play_instant
1004                    };
1005
1006                    #[cfg(not(feature = "scheduled_events"))]
1007                    let mut new_playhead_frames = playhead_frames_at_play_instant;
1008
1009                    if new_playhead_frames >= loaded_sample_state.sample_len_frames {
1010                        match self.params.repeat_mode {
1011                            RepeatMode::PlayOnce => {
1012                                new_playhead_frames = loaded_sample_state.sample_len_frames
1013                            }
1014                            RepeatMode::RepeatEndlessly => {
1015                                while new_playhead_frames >= loaded_sample_state.sample_len_frames {
1016                                    new_playhead_frames -= loaded_sample_state.sample_len_frames;
1017                                    loaded_sample_state.num_times_looped_back += 1;
1018                                }
1019                            }
1020                            RepeatMode::RepeatMultiple {
1021                                num_times_to_repeat,
1022                            } => {
1023                                while new_playhead_frames >= loaded_sample_state.sample_len_frames {
1024                                    if loaded_sample_state.num_times_looped_back
1025                                        == num_times_to_repeat as u64
1026                                    {
1027                                        new_playhead_frames = loaded_sample_state.sample_len_frames;
1028                                        break;
1029                                    }
1030
1031                                    new_playhead_frames -= loaded_sample_state.sample_len_frames;
1032                                    loaded_sample_state.num_times_looped_back += 1;
1033                                }
1034                            }
1035                        }
1036                    }
1037
1038                    if prev_playhead_frames != new_playhead_frames {
1039                        self.stop(buffers.outputs.len(), extra);
1040
1041                        self.loaded_sample_state.as_mut().unwrap().playhead_frames =
1042                            new_playhead_frames;
1043
1044                        self.shared_state
1045                            .sample_playhead_frames
1046                            .store(new_playhead_frames, Ordering::Relaxed);
1047                    }
1048
1049                    if new_playhead_frames
1050                        == self.loaded_sample_state.as_ref().unwrap().sample_len_frames
1051                    {
1052                        self.shared_state
1053                            .finished
1054                            .store(self.params.play.id(), Ordering::Relaxed);
1055
1056                        new_playing = false;
1057                    } else if new_playhead_frames != 0
1058                        || (self.num_active_stop_declickers > 0 && self.params.crossfade_on_seek)
1059                    {
1060                        self.declicker.reset_to_0();
1061                        self.declicker.fade_to_1(&extra.declick_values);
1062                    } else {
1063                        self.declicker.reset_to_1();
1064                    }
1065
1066                    #[cfg(feature = "scheduled_events")]
1067                    {
1068                        self.queued_playback_instant = None;
1069                    }
1070                }
1071            } else {
1072                if self.params.play_from == PlayFrom::Resume {
1073                    // Pause
1074                    self.declicker.fade_to_0(&extra.declick_values);
1075                    self.paused = true;
1076                } else {
1077                    // Stop
1078                    self.stop(buffers.outputs.len(), extra);
1079                    self.shared_state
1080                        .finished
1081                        .store(self.params.play.id(), Ordering::Relaxed);
1082                }
1083            }
1084
1085            self.playing = new_playing;
1086        }
1087
1088        self.is_first_process = false;
1089
1090        self.shared_state.playback_state.store(
1091            if self.playing {
1092                SharedPlaybackState::Playing
1093            } else if self.paused {
1094                SharedPlaybackState::Paused
1095            } else {
1096                SharedPlaybackState::Stopped
1097            } as u32,
1098            Ordering::Relaxed,
1099        );
1100
1101        let currently_processing_sample = self.currently_processing_sample();
1102
1103        if !currently_processing_sample && self.num_active_stop_declickers == 0 {
1104            return ProcessStatus::ClearAllOutputs;
1105        }
1106
1107        let mut num_filled_channels = 0;
1108
1109        if currently_processing_sample && self.params.sample.is_some() {
1110            let sample_state = self.loaded_sample_state.as_ref().unwrap();
1111
1112            let looping = self
1113                .params
1114                .repeat_mode
1115                .do_loop(sample_state.num_times_looped_back);
1116
1117            let (finished, n_channels) =
1118                self.process_internal(buffers.outputs, info.frames, looping, extra);
1119
1120            num_filled_channels = n_channels;
1121
1122            self.shared_state.sample_playhead_frames.store(
1123                self.loaded_sample_state.as_ref().unwrap().playhead_frames,
1124                Ordering::Relaxed,
1125            );
1126
1127            if finished {
1128                self.playing = false;
1129
1130                self.shared_state
1131                    .playback_state
1132                    .store(SharedPlaybackState::Stopped as u32, Ordering::Relaxed);
1133                self.shared_state
1134                    .finished
1135                    .store(self.params.play.id(), Ordering::Relaxed);
1136            }
1137        }
1138
1139        for (i, out_buf) in buffers
1140            .outputs
1141            .iter_mut()
1142            .enumerate()
1143            .skip(num_filled_channels)
1144        {
1145            if !info.out_silence_mask.is_channel_silent(i) {
1146                out_buf[..info.frames].fill(0.0);
1147            }
1148        }
1149
1150        if self.num_active_stop_declickers > 0 {
1151            let tmp_buffers = self.stop_declicker_buffers.as_ref().unwrap();
1152            let fade_out_frames = tmp_buffers.frames();
1153
1154            for (declicker_i, declicker) in self.stop_declickers.iter_mut().enumerate() {
1155                if declicker.frames_left == 0 {
1156                    continue;
1157                }
1158
1159                let tmp_buffers = tmp_buffers
1160                    .instance(declicker_i, declicker.channels, fade_out_frames)
1161                    .unwrap();
1162
1163                let copy_frames = info.frames.min(declicker.frames_left);
1164                let start_frame = fade_out_frames - declicker.frames_left;
1165
1166                for (out_buf, tmp_buf) in buffers.outputs.iter_mut().zip(tmp_buffers.iter()) {
1167                    for (os, &ts) in out_buf[..copy_frames]
1168                        .iter_mut()
1169                        .zip(tmp_buf[start_frame..start_frame + copy_frames].iter())
1170                    {
1171                        *os += ts;
1172                    }
1173                }
1174
1175                declicker.frames_left -= copy_frames;
1176                if declicker.frames_left == 0 {
1177                    self.num_active_stop_declickers -= 1;
1178                }
1179
1180                num_filled_channels = num_filled_channels.max(declicker.channels);
1181            }
1182        }
1183
1184        let out_silence_mask = if num_filled_channels >= buffers.outputs.len() {
1185            SilenceMask::NONE_SILENT
1186        } else {
1187            let mut mask = SilenceMask::new_all_silent(buffers.outputs.len());
1188            for i in 0..num_filled_channels {
1189                mask.set_channel(i, false);
1190            }
1191            mask
1192        };
1193
1194        ProcessStatus::OutputsModifiedWithMask(MaskType::Silence(out_silence_mask))
1195    }
1196
1197    fn new_stream(&mut self, stream_info: &StreamInfo, _context: &mut ProcStreamCtx) {
1198        if stream_info.sample_rate != stream_info.prev_sample_rate {
1199            self.stop_declicker_buffers = if self.config.num_declickers == 0 {
1200                None
1201            } else {
1202                Some(InstanceBuffer::<f32, MAX_OUT_CHANNELS>::new(
1203                    self.config.num_declickers as usize,
1204                    NonZeroUsize::new(self.config.channels.get().get() as usize).unwrap(),
1205                    stream_info.declick_frames.get() as usize,
1206                ))
1207            };
1208
1209            // The sample rate has changed, meaning that the sample resources now have
1210            // the incorrect sample rate and the user must reload them.
1211            self.params.sample = None;
1212            self.loaded_sample_state = None;
1213            self.playing = false;
1214            self.paused = false;
1215            self.shared_state
1216                .playback_state
1217                .store(SharedPlaybackState::Stopped as u32, Ordering::Relaxed);
1218            self.shared_state.finished.store(0, Ordering::Relaxed);
1219        }
1220    }
1221}
1222
1223struct SharedState {
1224    sample_playhead_frames: AtomicU64,
1225    playback_state: AtomicU32,
1226    finished: AtomicU64,
1227}
1228
1229impl Default for SharedState {
1230    fn default() -> Self {
1231        Self {
1232            sample_playhead_frames: AtomicU64::new(0),
1233            playback_state: AtomicU32::new(SharedPlaybackState::Stopped as u32),
1234            finished: AtomicU64::new(0),
1235        }
1236    }
1237}
1238
1239#[repr(u32)]
1240#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1241enum SharedPlaybackState {
1242    Stopped = 0,
1243    Paused,
1244    Playing,
1245}
1246
1247impl SharedPlaybackState {
1248    fn from_u32(val: u32) -> Self {
1249        match val {
1250            1 => Self::Paused,
1251            2 => Self::Playing,
1252            _ => Self::Stopped,
1253        }
1254    }
1255}
1256
1257struct LoadedSampleState {
1258    sample: ArcGc<dyn SampleResource>,
1259    sample_len_frames: u64,
1260    sample_num_channels: NonZeroUsize,
1261    sample_mono_to_stereo: bool,
1262    gain: f32,
1263    playhead_frames: u64,
1264    num_times_looped_back: u64,
1265}
1266
1267#[derive(Default, Clone, Copy)]
1268struct StopDeclickerState {
1269    frames_left: usize,
1270    channels: usize,
1271}
1272
1273struct Resampler {
1274    fract_in_frame: f64,
1275    is_first_process: bool,
1276    prev_speed: f64,
1277    _quality: PlaybackSpeedQuality,
1278    wraparound_buffer: [[f32; 2]; MAX_OUT_CHANNELS],
1279}
1280
1281impl Resampler {
1282    pub fn new(quality: PlaybackSpeedQuality) -> Self {
1283        Self {
1284            fract_in_frame: 0.0,
1285            is_first_process: true,
1286            prev_speed: 1.0,
1287            _quality: quality,
1288            wraparound_buffer: [[0.0; 2]; MAX_OUT_CHANNELS],
1289        }
1290    }
1291
1292    pub fn resample_linear(
1293        &mut self,
1294        out_buffers: &mut [&mut [f32]],
1295        out_buffer_range: Range<usize>,
1296        extra: &mut ProcExtra,
1297        processor: &mut SamplerProcessor,
1298        looping: bool,
1299    ) -> (bool, usize) {
1300        let total_out_frames = out_buffer_range.end - out_buffer_range.start;
1301
1302        assert_ne!(total_out_frames, 0);
1303
1304        let in_frame_start = if self.is_first_process {
1305            self.prev_speed = processor.speed;
1306            self.fract_in_frame = 0.0;
1307
1308            0.0
1309        } else {
1310            self.fract_in_frame + processor.speed
1311        };
1312
1313        let out_frame_to_in_frame = |out_frame: f64, in_frame_start: f64, speed: f64| -> f64 {
1314            in_frame_start + (out_frame * speed)
1315        };
1316
1317        // The function which maps the output frame to the input frame is given by
1318        // the kinematic equation:
1319        //
1320        // in_frame = in_frame_start + (out_frame * start_speed) + (0.5 * accel * out_frame^2)
1321        //      where: accel = (end_speed - start_speed)
1322        let out_frame_to_in_frame_with_accel =
1323            |out_frame: f64, in_frame_start: f64, start_speed: f64, half_accel: f64| -> f64 {
1324                in_frame_start + (out_frame * start_speed) + (out_frame * out_frame * half_accel)
1325            };
1326
1327        let num_channels = processor.num_channels_filled(out_buffers.len());
1328        let copy_start = if self.is_first_process { 0 } else { 2 };
1329        let mut finished_playing = false;
1330
1331        if self.prev_speed == processor.speed {
1332            self.resample_linear_inner(
1333                out_frame_to_in_frame,
1334                in_frame_start,
1335                self.prev_speed,
1336                out_buffer_range.clone(),
1337                processor,
1338                extra,
1339                looping,
1340                copy_start,
1341                num_channels,
1342                out_buffers,
1343                out_buffer_range.start,
1344                &mut finished_playing,
1345            );
1346        } else {
1347            let half_accel = 0.5 * (processor.speed - self.prev_speed) / total_out_frames as f64;
1348
1349            self.resample_linear_inner(
1350                |out_frame: f64, in_frame_start: f64, speed: f64| {
1351                    out_frame_to_in_frame_with_accel(out_frame, in_frame_start, speed, half_accel)
1352                },
1353                in_frame_start,
1354                self.prev_speed,
1355                out_buffer_range.clone(),
1356                processor,
1357                extra,
1358                looping,
1359                copy_start,
1360                num_channels,
1361                out_buffers,
1362                out_buffer_range.start,
1363                &mut finished_playing,
1364            );
1365        }
1366
1367        self.prev_speed = processor.speed;
1368        self.is_first_process = false;
1369
1370        (finished_playing, num_channels)
1371    }
1372
1373    fn resample_linear_inner<OutToInFrame>(
1374        &mut self,
1375        out_to_in_frame: OutToInFrame,
1376        in_frame_start: f64,
1377        speed: f64,
1378        out_buffer_range: Range<usize>,
1379        processor: &mut SamplerProcessor,
1380        extra: &mut ProcExtra,
1381        looping: bool,
1382        mut copy_start: usize,
1383        num_channels: usize,
1384        out_buffers: &mut [&mut [f32]],
1385        out_buffer_start: usize,
1386        finished_playing: &mut bool,
1387    ) where
1388        OutToInFrame: Fn(f64, f64, f64) -> f64,
1389    {
1390        let mut scratch_buffers = extra.scratch_buffers.all_mut();
1391
1392        let total_out_frames = out_buffer_range.end - out_buffer_range.start;
1393        let output_frame_end = (total_out_frames - 1) as f64;
1394
1395        let input_frame_end = out_to_in_frame(output_frame_end, in_frame_start, speed);
1396        let input_frames_needed = input_frame_end.trunc() as usize + 2;
1397
1398        let mut input_frames_processed = 0;
1399        let mut output_frames_processed = 0;
1400        while output_frames_processed < total_out_frames {
1401            let input_frames =
1402                (input_frames_needed - input_frames_processed).min(processor.max_block_frames);
1403
1404            if input_frames > copy_start {
1405                let (finished, _) = processor.copy_from_sample(
1406                    &mut scratch_buffers[..num_channels],
1407                    copy_start..input_frames,
1408                    looping,
1409                );
1410                if finished {
1411                    *finished_playing = true;
1412                }
1413            }
1414
1415            let max_block_frames_minus_1 = processor.max_block_frames - 1;
1416            let out_ch_start = out_buffer_start + output_frames_processed;
1417
1418            let mut out_frames_count = 0;
1419
1420            // Have an optimized loop for stereo audio.
1421            if num_channels == 2 {
1422                let mut last_in_frame = 0;
1423                let mut last_fract_frame = 0.0;
1424
1425                let (out_ch_0, out_ch_1) = out_buffers.split_first_mut().unwrap();
1426                let (r_ch_0, r_ch_1) = scratch_buffers.split_first_mut().unwrap();
1427
1428                let out_ch_0 = &mut out_ch_0[out_ch_start..out_buffer_range.end];
1429                let out_ch_1 = &mut out_ch_1[0][out_ch_start..out_buffer_range.end];
1430
1431                let r_ch_0 = &mut r_ch_0[..processor.max_block_frames];
1432                let r_ch_1 = &mut r_ch_1[0][..processor.max_block_frames];
1433
1434                if copy_start > 0 {
1435                    r_ch_0[0] = self.wraparound_buffer[0][0];
1436                    r_ch_1[0] = self.wraparound_buffer[1][0];
1437
1438                    r_ch_0[1] = self.wraparound_buffer[0][1];
1439                    r_ch_1[1] = self.wraparound_buffer[1][1];
1440                }
1441
1442                for (i, (out_s_0, out_s_1)) in
1443                    out_ch_0.iter_mut().zip(out_ch_1.iter_mut()).enumerate()
1444                {
1445                    let out_frame = (i + output_frames_processed) as f64;
1446
1447                    let in_frame_f64 = out_to_in_frame(out_frame, in_frame_start, speed);
1448
1449                    let in_frame_usize = in_frame_f64.trunc() as usize - input_frames_processed;
1450                    let fract_frame = in_frame_f64.fract();
1451
1452                    if in_frame_usize >= max_block_frames_minus_1 {
1453                        break;
1454                    }
1455
1456                    let s0_0 = r_ch_0[in_frame_usize];
1457                    let s0_1 = r_ch_1[in_frame_usize];
1458
1459                    let s1_0 = r_ch_0[in_frame_usize + 1];
1460                    let s1_1 = r_ch_1[in_frame_usize + 1];
1461
1462                    *out_s_0 = s0_0 + ((s1_0 - s0_0) * fract_frame as f32);
1463                    *out_s_1 = s0_1 + ((s1_1 - s0_1) * fract_frame as f32);
1464
1465                    last_in_frame = in_frame_usize;
1466                    last_fract_frame = fract_frame;
1467
1468                    out_frames_count += 1;
1469                }
1470
1471                self.wraparound_buffer[0][0] = r_ch_0[last_in_frame];
1472                self.wraparound_buffer[1][0] = r_ch_1[last_in_frame];
1473
1474                self.wraparound_buffer[0][1] = r_ch_0[last_in_frame + 1];
1475                self.wraparound_buffer[1][1] = r_ch_1[last_in_frame + 1];
1476
1477                self.fract_in_frame = last_fract_frame;
1478            } else {
1479                for ((out_ch, r_ch), w_ch) in out_buffers[..num_channels]
1480                    .iter_mut()
1481                    .zip(scratch_buffers[..num_channels].iter_mut())
1482                    .zip(self.wraparound_buffer[..num_channels].iter_mut())
1483                {
1484                    // Hint to compiler to optimize loop.
1485                    assert_eq!(r_ch.len(), processor.max_block_frames);
1486
1487                    if copy_start > 0 {
1488                        r_ch[0] = w_ch[0];
1489                        r_ch[1] = w_ch[1];
1490                    }
1491
1492                    let mut last_in_frame = 0;
1493                    let mut last_fract_frame = 0.0;
1494                    let mut out_frames_ch_count = 0;
1495                    for (i, out_s) in out_ch[out_ch_start..out_buffer_range.end]
1496                        .iter_mut()
1497                        .enumerate()
1498                    {
1499                        let out_frame = (i + output_frames_processed) as f64;
1500
1501                        let in_frame_f64 = out_to_in_frame(out_frame, in_frame_start, speed);
1502
1503                        let in_frame_usize = in_frame_f64.trunc() as usize - input_frames_processed;
1504                        last_fract_frame = in_frame_f64.fract();
1505
1506                        if in_frame_usize >= max_block_frames_minus_1 {
1507                            break;
1508                        }
1509
1510                        let s0 = r_ch[in_frame_usize];
1511                        let s1 = r_ch[in_frame_usize + 1];
1512
1513                        *out_s = s0 + ((s1 - s0) * last_fract_frame as f32);
1514
1515                        last_in_frame = in_frame_usize;
1516                        out_frames_ch_count += 1;
1517                    }
1518
1519                    w_ch[0] = r_ch[last_in_frame];
1520                    w_ch[1] = r_ch[last_in_frame + 1];
1521
1522                    self.fract_in_frame = last_fract_frame;
1523                    out_frames_count = out_frames_ch_count;
1524                }
1525            }
1526
1527            output_frames_processed += out_frames_count;
1528            input_frames_processed += input_frames - 2;
1529
1530            copy_start = 2;
1531        }
1532    }
1533
1534    pub fn reset(&mut self) {
1535        self.fract_in_frame = 0.0;
1536        self.is_first_process = true;
1537    }
1538}