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 pub channels: NonZeroChannelCount,
36 pub mono_to_stereo: bool,
40 pub num_declickers: u32,
47 pub crossfade_on_restart: bool,
52 pub amp_epsilon: f32,
55 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#[non_exhaustive]
76#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
77pub enum PlaybackSpeedQuality {
78 #[default]
79 LinearFast,
84 }
86
87#[derive(Clone, Diff, Patch)]
88#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
89pub struct SamplerNode {
90 pub sequence: Notify<Option<SequenceType>>,
92
93 pub playback: Notify<PlaybackState>,
95
96 pub playhead: Notify<Playhead>,
98
99 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 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 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 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 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 pub fn start_or_restart(&mut self, delay: Option<EventDelay>) {
167 *self.playhead = Playhead::default();
168 *self.playback = PlaybackState::Play { delay };
169 }
170
171 pub fn pause(&mut self) {
173 *self.playback = PlaybackState::Pause;
174 }
175
176 pub fn resume(&mut self, delay: Option<EventDelay>) {
178 *self.playback = PlaybackState::Play { delay };
179 }
180
181 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 pub fn playhead_frames(&self) -> u64 {
206 self.shared_state
207 .sequence_playhead_frames
208 .load(Ordering::Relaxed)
209 }
210
211 pub fn playhead_seconds(&self, sample_rate: NonZeroU32) -> f64 {
215 self.playhead_frames() as f64 / sample_rate.get() as f64
216 }
217
218 pub fn stopped(&self) -> bool {
221 self.shared_state.stopped.load(Ordering::Relaxed)
222 }
223
224 pub fn mark_stopped(&self, stopped: bool) {
227 self.shared_state.stopped.store(stopped, Ordering::Release);
228 }
229
230 pub fn finished(&self) -> u64 {
232 self.shared_state.finished.load(Ordering::Relaxed)
233 }
234
235 pub fn clear_finished(&self) {
237 self.shared_state.finished.store(0, Ordering::Relaxed);
238 }
239
240 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 u64::MAX - 4
262 } else {
263 u64::MAX - 5
265 }
266 } else {
267 playhead_frames
270 }
271 }
272 }
273 } else {
274 u64::MAX
275 }
276 }
277}
278
279#[derive(Default, Debug, Clone, Copy, PartialEq)]
281pub enum PlaybackState {
282 #[default]
286 Stop,
287 Pause,
292 Play {
294 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#[derive(Debug, Clone, Copy, PartialEq)]
313pub enum Playhead {
314 Seconds(f64),
316 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#[derive(Clone, PartialEq)]
344pub enum SequenceType {
345 SingleSample {
346 sample: ArcGc<dyn SampleResource>,
348 volume: Volume,
353 repeat_mode: RepeatMode,
355 },
356 Sequence {
358 sequence: ArcGc<Vec<SequenceEvent>>,
359 timing: SequenceTiming,
360 },
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
365pub enum SequenceTiming {
366 Seconds,
368 Samples,
370}
371
372#[derive(Clone, PartialEq)]
373pub struct SequenceEvent {
374 pub event: SequenceEventType,
375 pub offset_from_start: f64,
381}
382
383#[derive(Clone, PartialEq)]
384pub enum SequenceEventType {
385 PlaySample {
386 sample: ArcGc<dyn SampleResource>,
388 normalized_volume: f32,
394 },
396 Stop,
398 SetPlayheadSeconds(f64),
400 SetPlayheadSamples(u64),
403}
404
405#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
407pub enum RepeatMode {
408 #[default]
410 PlayOnce,
411 RepeatMultiple { num_times_to_repeat: u32 },
413 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 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 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 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 self.declicker.fade_to_0(declick_values);
688
689 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 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 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 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 *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 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 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 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}