firewheel_nodes/
sampler.rs

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