1use 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#[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 pub channels: NonZeroChannelCount,
54 pub num_declickers: u32,
61 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#[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 LinearFast,
89 }
91
92#[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 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
102 #[cfg_attr(feature = "serde", serde(skip))]
103 pub sample: Option<ArcGc<dyn SampleResource>>,
104
105 pub volume: Volume,
113
114 #[cfg_attr(feature = "serde", serde(skip))]
117 pub play: Notify<bool>,
118
119 pub play_from: PlayFrom,
122
123 pub repeat_mode: RepeatMode,
125
126 pub speed: f64,
131
132 pub mono_to_stereo: bool,
136 pub crossfade_on_seek: bool,
141 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 pub fn set_sample(&mut self, sample: ArcGc<dyn SampleResource>) {
184 self.sample = Some(sample);
185 }
186
187 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 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 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 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 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 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 pub fn start_or_restart(&mut self) {
239 self.play_from = PlayFrom::BEGINNING;
240 *self.play = true;
241 }
242
243 pub fn start_from(&mut self, from: PlayFrom) {
245 self.play_from = from;
246 *self.play = true;
247 }
248
249 pub fn pause(&mut self) {
251 self.play_from = PlayFrom::Resume;
252 *self.play = false;
253 }
254
255 pub fn resume(&mut self) {
257 *self.play = true;
258 }
259
260 pub fn stop(&mut self) {
265 self.play_from = PlayFrom::BEGINNING;
266 *self.play = false;
267 }
268
269 pub fn start_or_restart_requested(&self) -> bool {
271 *self.play && self.play_from == PlayFrom::BEGINNING
272 }
273
274 pub fn resume_requested(&self) -> bool {
276 *self.play && self.play_from == PlayFrom::Resume
277 }
278
279 pub fn pause_requested(&self) -> bool {
281 !*self.play && self.play_from == PlayFrom::Resume
282 }
283
284 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 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 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 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 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 pub fn playing(&self) -> bool {
369 SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
370 == SharedPlaybackState::Playing
371 }
372
373 pub fn paused(&self) -> bool {
375 SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
376 == SharedPlaybackState::Paused
377 }
378
379 pub fn stopped(&self) -> bool {
382 SharedPlaybackState::from_u32(self.shared_state.playback_state.load(Ordering::Relaxed))
383 == SharedPlaybackState::Stopped
384 }
385
386 pub fn mark_playing(&self) {
389 self.shared_state
390 .playback_state
391 .store(SharedPlaybackState::Playing as u32, Ordering::Relaxed);
392 }
393
394 pub fn mark_paused(&self) {
397 self.shared_state
398 .playback_state
399 .store(SharedPlaybackState::Paused as u32, Ordering::Relaxed);
400 }
401
402 pub fn mark_stopped(&self) {
405 self.shared_state
406 .playback_state
407 .store(SharedPlaybackState::Stopped as u32, Ordering::Relaxed);
408 }
409
410 pub fn finished(&self) -> u64 {
412 self.shared_state.finished.load(Ordering::Relaxed)
413 }
414
415 pub fn clear_finished(&self) {
417 self.shared_state.finished.store(0, Ordering::Relaxed);
418 }
419
420 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 u64::MAX - 4
435 } else {
436 u64::MAX - 5
438 }
439 } else {
440 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#[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 Resume,
466 Seconds(f64),
469 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#[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 #[default]
538 PlayOnce,
539 RepeatMultiple { num_times_to_repeat: u32 },
541 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 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 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 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 self.declicker.fade_to_0(&extra.declick_values);
786
787 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 if self.playing && !self.is_first_process {
964 #[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 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 self.declicker.fade_to_0(&extra.declick_values);
1075 self.paused = true;
1076 } else {
1077 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 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 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 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 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}