1#[cfg(not(feature = "std"))]
2use num_traits::Float;
3
4use bevy_platform::time::Instant;
5use core::num::NonZeroU32;
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
7
8#[cfg(feature = "scheduled_events")]
9use crate::diff::{Diff, Patch};
10#[cfg(feature = "scheduled_events")]
11use crate::event::ParamData;
12#[cfg(feature = "scheduled_events")]
13use crate::node::ProcInfo;
14
15#[cfg(feature = "musical_transport")]
16mod transport;
17#[cfg(feature = "musical_transport")]
18pub use transport::*;
19
20#[cfg(feature = "scheduled_events")]
23#[derive(Debug, Clone, Copy, PartialEq)]
24#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub enum EventInstant {
27 Seconds(InstantSeconds),
33
34 Samples(InstantSamples),
40
41 #[cfg(feature = "musical_transport")]
44 Musical(InstantMusical),
45}
46
47#[cfg(feature = "scheduled_events")]
48impl EventInstant {
49 pub fn is_musical(&self) -> bool {
50 #[cfg(feature = "musical_transport")]
51 if let EventInstant::Musical(_) = self {
52 return true;
53 } else {
54 return false;
55 }
56
57 #[cfg(not(feature = "musical_transport"))]
58 return false;
59 }
60
61 pub fn to_samples(&self, proc_info: &ProcInfo) -> Option<InstantSamples> {
67 match self {
68 EventInstant::Samples(samples) => Some(*samples),
69 EventInstant::Seconds(seconds) => Some(seconds.to_samples(proc_info.sample_rate)),
70 #[cfg(feature = "musical_transport")]
71 EventInstant::Musical(musical) => proc_info.musical_to_samples(*musical),
72 }
73 }
74}
75
76#[cfg(feature = "scheduled_events")]
77impl From<InstantSeconds> for EventInstant {
78 fn from(value: InstantSeconds) -> Self {
79 Self::Seconds(value)
80 }
81}
82
83#[cfg(feature = "scheduled_events")]
84impl From<InstantSamples> for EventInstant {
85 fn from(value: InstantSamples) -> Self {
86 Self::Samples(value)
87 }
88}
89
90#[cfg(feature = "musical_transport")]
91impl From<InstantMusical> for EventInstant {
92 fn from(value: InstantMusical) -> Self {
93 Self::Musical(value)
94 }
95}
96
97#[cfg(feature = "scheduled_events")]
98impl Diff for EventInstant {
99 fn diff<E: crate::diff::EventQueue>(
100 &self,
101 baseline: &Self,
102 path: crate::diff::PathBuilder,
103 event_queue: &mut E,
104 ) {
105 if self != baseline {
106 match self {
107 EventInstant::Seconds(s) => event_queue.push_param(*s, path),
108 EventInstant::Samples(s) => event_queue.push_param(*s, path),
109 #[cfg(feature = "musical_transport")]
110 EventInstant::Musical(m) => event_queue.push_param(*m, path),
111 }
112 }
113 }
114}
115
116#[cfg(feature = "scheduled_events")]
117impl Patch for EventInstant {
118 type Patch = Self;
119
120 fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, crate::diff::PatchError> {
121 match data {
122 ParamData::InstantSeconds(s) => Ok(EventInstant::Seconds(*s)),
123 ParamData::InstantSamples(s) => Ok(EventInstant::Samples(*s)),
124 #[cfg(feature = "musical_transport")]
125 ParamData::InstantMusical(s) => Ok(EventInstant::Musical(*s)),
126 _ => Err(crate::diff::PatchError::InvalidData),
127 }
128 }
129
130 fn apply(&mut self, patch: Self::Patch) {
131 *self = patch;
132 }
133}
134
135#[cfg(feature = "scheduled_events")]
136impl Diff for Option<EventInstant> {
137 fn diff<E: crate::diff::EventQueue>(
138 &self,
139 baseline: &Self,
140 path: crate::diff::PathBuilder,
141 event_queue: &mut E,
142 ) {
143 if self != baseline {
144 match self {
145 Some(EventInstant::Seconds(s)) => event_queue.push_param(*s, path),
146 Some(EventInstant::Samples(s)) => event_queue.push_param(*s, path),
147 #[cfg(feature = "musical_transport")]
148 Some(EventInstant::Musical(m)) => event_queue.push_param(*m, path),
149 None => event_queue.push_param(ParamData::None, path),
150 }
151 }
152 }
153}
154
155#[cfg(feature = "scheduled_events")]
156impl Patch for Option<EventInstant> {
157 type Patch = Self;
158
159 fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, crate::diff::PatchError> {
160 match data {
161 ParamData::InstantSeconds(s) => Ok(Some(EventInstant::Seconds(*s))),
162 ParamData::InstantSamples(s) => Ok(Some(EventInstant::Samples(*s))),
163 #[cfg(feature = "musical_transport")]
164 ParamData::InstantMusical(s) => Ok(Some(EventInstant::Musical(*s))),
165 _ => Err(crate::diff::PatchError::InvalidData),
166 }
167 }
168
169 fn apply(&mut self, patch: Self::Patch) {
170 *self = patch;
171 }
172}
173
174#[repr(transparent)]
176#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
177#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
178#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
179pub struct InstantSeconds(pub f64);
180
181impl InstantSeconds {
182 pub const ZERO: Self = Self(0.0);
183
184 pub const fn new(seconds: f64) -> Self {
185 Self(seconds)
186 }
187
188 pub fn to_samples(self, sample_rate: NonZeroU32) -> InstantSamples {
189 InstantSamples(seconds_to_samples(self.0, sample_rate))
190 }
191
192 #[cfg(feature = "musical_transport")]
194 pub fn to_musical(
195 self,
196 transport: &MusicalTransport,
197 transport_start: InstantSeconds,
198 speed_multiplier: f64,
199 ) -> InstantMusical {
200 transport.seconds_to_musical(self, transport_start, speed_multiplier)
201 }
202
203 pub const fn duration_since(&self, earlier: Self) -> DurationSeconds {
207 DurationSeconds(self.0 - earlier.0)
208 }
209
210 pub fn checked_duration_since(&self, earlier: Self) -> Option<DurationSeconds> {
213 (self.0 >= earlier.0).then(|| DurationSeconds(self.0 - earlier.0))
214 }
215
216 pub const fn saturating_duration_since(&self, earlier: Self) -> DurationSeconds {
219 DurationSeconds((self.0 - earlier.0).max(0.0))
220 }
221}
222
223#[repr(transparent)]
225#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
226#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
227#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
228pub struct DurationSeconds(pub f64);
229
230impl DurationSeconds {
231 pub const ZERO: Self = Self(0.0);
232
233 pub const fn new(seconds: f64) -> Self {
234 Self(seconds)
235 }
236
237 pub fn to_samples(self, sample_rate: NonZeroU32) -> DurationSamples {
238 DurationSamples(seconds_to_samples(self.0, sample_rate))
239 }
240}
241
242fn seconds_to_samples(seconds: f64, sample_rate: NonZeroU32) -> i64 {
243 let seconds_i64 = seconds.floor() as i64;
244 let fract_samples_i64 = (seconds.fract() * f64::from(sample_rate.get())).round() as i64;
245
246 (seconds_i64 * i64::from(sample_rate.get())) + fract_samples_i64
247}
248
249impl Add<DurationSeconds> for InstantSeconds {
250 type Output = InstantSeconds;
251 fn add(self, rhs: DurationSeconds) -> Self::Output {
252 Self(self.0 + rhs.0)
253 }
254}
255
256impl Sub<DurationSeconds> for InstantSeconds {
257 type Output = InstantSeconds;
258 fn sub(self, rhs: DurationSeconds) -> Self::Output {
259 Self(self.0 - rhs.0)
260 }
261}
262
263impl AddAssign<DurationSeconds> for InstantSeconds {
264 fn add_assign(&mut self, rhs: DurationSeconds) {
265 *self = *self + rhs;
266 }
267}
268
269impl SubAssign<DurationSeconds> for InstantSeconds {
270 fn sub_assign(&mut self, rhs: DurationSeconds) {
271 *self = *self - rhs;
272 }
273}
274
275impl Sub<InstantSeconds> for InstantSeconds {
276 type Output = DurationSeconds;
277 fn sub(self, rhs: Self) -> Self::Output {
278 DurationSeconds(self.0 - rhs.0)
279 }
280}
281
282impl Add for DurationSeconds {
283 type Output = Self;
284 fn add(self, rhs: Self) -> Self::Output {
285 Self(self.0 + rhs.0)
286 }
287}
288
289impl Sub for DurationSeconds {
290 type Output = Self;
291 fn sub(self, rhs: Self) -> Self::Output {
292 Self(self.0 - rhs.0)
293 }
294}
295
296impl AddAssign for DurationSeconds {
297 fn add_assign(&mut self, rhs: Self) {
298 self.0 += rhs.0;
299 }
300}
301
302impl SubAssign for DurationSeconds {
303 fn sub_assign(&mut self, rhs: Self) {
304 self.0 -= rhs.0;
305 }
306}
307
308impl Mul<f64> for DurationSeconds {
309 type Output = Self;
310 fn mul(self, rhs: f64) -> Self::Output {
311 Self(self.0 * rhs)
312 }
313}
314
315impl Div<f64> for DurationSeconds {
316 type Output = Self;
317 fn div(self, rhs: f64) -> Self::Output {
318 Self(self.0 / rhs)
319 }
320}
321
322impl MulAssign<f64> for DurationSeconds {
323 fn mul_assign(&mut self, rhs: f64) {
324 self.0 *= rhs;
325 }
326}
327
328impl DivAssign<f64> for DurationSeconds {
329 fn div_assign(&mut self, rhs: f64) {
330 self.0 /= rhs;
331 }
332}
333
334impl From<f64> for InstantSeconds {
335 fn from(value: f64) -> Self {
336 Self(value)
337 }
338}
339
340impl From<InstantSeconds> for f64 {
341 fn from(value: InstantSeconds) -> Self {
342 value.0
343 }
344}
345
346impl From<f64> for DurationSeconds {
347 fn from(value: f64) -> Self {
348 Self(value)
349 }
350}
351
352impl From<DurationSeconds> for f64 {
353 fn from(value: DurationSeconds) -> Self {
354 value.0
355 }
356}
357
358#[repr(transparent)]
360#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
361#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
362#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
363pub struct InstantSamples(pub i64);
364
365impl InstantSamples {
366 pub const ZERO: Self = Self(0);
367 pub const MAX: Self = Self(i64::MAX);
368
369 pub const fn new(samples: i64) -> Self {
370 Self(samples)
371 }
372
373 pub fn whole_seconds_and_fract(&self, sample_rate: NonZeroU32) -> (i64, u32) {
375 whole_seconds_and_fract(self.0, sample_rate)
376 }
377
378 pub fn fract_second_samples(&self, sample_rate: NonZeroU32) -> u32 {
379 fract_second_samples(self.0, sample_rate)
380 }
381
382 pub fn to_seconds(self, sample_rate: NonZeroU32, sample_rate_recip: f64) -> InstantSeconds {
383 InstantSeconds(samples_to_seconds(self.0, sample_rate, sample_rate_recip))
384 }
385
386 #[cfg(feature = "musical_transport")]
388 pub fn to_musical(
389 self,
390 transport: &MusicalTransport,
391 transport_start: InstantSamples,
392 speed_multiplier: f64,
393 sample_rate: NonZeroU32,
394 sample_rate_recip: f64,
395 ) -> InstantMusical {
396 transport.samples_to_musical(
397 self,
398 transport_start,
399 speed_multiplier,
400 sample_rate,
401 sample_rate_recip,
402 )
403 }
404
405 pub const fn duration_since(&self, earlier: Self) -> DurationSamples {
409 DurationSamples(self.0 - earlier.0)
410 }
411
412 pub fn checked_duration_since(&self, earlier: Self) -> Option<DurationSamples> {
415 (self.0 >= earlier.0).then(|| DurationSamples(self.0 - earlier.0))
416 }
417
418 pub fn saturating_duration_since(&self, earlier: Self) -> DurationSamples {
421 DurationSamples((self.0 - earlier.0).max(0))
422 }
423}
424
425#[repr(transparent)]
427#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
428#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
429#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
430pub struct DurationSamples(pub i64);
431
432impl DurationSamples {
433 pub const ZERO: Self = Self(0);
434
435 pub const fn new(samples: i64) -> Self {
436 Self(samples)
437 }
438
439 pub fn whole_seconds_and_fract(&self, sample_rate: NonZeroU32) -> (i64, u32) {
441 whole_seconds_and_fract(self.0, sample_rate)
442 }
443
444 pub fn fract_second_samples(&self, sample_rate: NonZeroU32) -> u32 {
445 fract_second_samples(self.0, sample_rate)
446 }
447
448 pub fn to_seconds(self, sample_rate: NonZeroU32, sample_rate_recip: f64) -> DurationSeconds {
449 DurationSeconds(samples_to_seconds(self.0, sample_rate, sample_rate_recip))
450 }
451}
452
453fn whole_seconds_and_fract(samples: i64, sample_rate: NonZeroU32) -> (i64, u32) {
455 let (whole_seconds, fract_samples) = match sample_rate.get() {
457 44100 => (samples / 44100, samples % 44100),
458 48000 => (samples / 48000, samples % 48000),
459 sample_rate => (
460 samples / i64::from(sample_rate),
461 samples % i64::from(sample_rate),
462 ),
463 };
464
465 if fract_samples < 0 {
466 (
467 whole_seconds - 1,
468 sample_rate.get() - (fract_samples.abs() as u32),
469 )
470 } else {
471 (whole_seconds, fract_samples as u32)
472 }
473}
474
475fn fract_second_samples(samples: i64, sample_rate: NonZeroU32) -> u32 {
476 match sample_rate.get() {
477 44100 => (samples % 44100) as u32,
478 48000 => (samples % 48000) as u32,
479 sample_rate => (samples % i64::from(sample_rate)) as u32,
480 }
481}
482
483fn samples_to_seconds(samples: i64, sample_rate: NonZeroU32, sample_rate_recip: f64) -> f64 {
484 let (whole_seconds, fract_samples) = whole_seconds_and_fract(samples, sample_rate);
485 whole_seconds as f64 + (fract_samples as f64 * sample_rate_recip)
486}
487
488impl Add<DurationSamples> for InstantSamples {
489 type Output = InstantSamples;
490 fn add(self, rhs: DurationSamples) -> Self::Output {
491 Self(self.0 + rhs.0)
492 }
493}
494
495impl Sub<DurationSamples> for InstantSamples {
496 type Output = InstantSamples;
497 fn sub(self, rhs: DurationSamples) -> Self::Output {
498 Self(self.0 - rhs.0)
499 }
500}
501
502impl AddAssign<DurationSamples> for InstantSamples {
503 fn add_assign(&mut self, rhs: DurationSamples) {
504 *self = *self + rhs;
505 }
506}
507
508impl SubAssign<DurationSamples> for InstantSamples {
509 fn sub_assign(&mut self, rhs: DurationSamples) {
510 *self = *self - rhs;
511 }
512}
513
514impl Sub<InstantSamples> for InstantSamples {
515 type Output = DurationSamples;
516 fn sub(self, rhs: Self) -> Self::Output {
517 DurationSamples(self.0 - rhs.0)
518 }
519}
520
521impl Add for DurationSamples {
522 type Output = Self;
523 fn add(self, rhs: Self) -> Self::Output {
524 Self(self.0 + rhs.0)
525 }
526}
527
528impl Sub for DurationSamples {
529 type Output = Self;
530 fn sub(self, rhs: Self) -> Self::Output {
531 Self(self.0 - rhs.0)
532 }
533}
534
535impl AddAssign for DurationSamples {
536 fn add_assign(&mut self, rhs: Self) {
537 self.0 += rhs.0;
538 }
539}
540
541impl SubAssign for DurationSamples {
542 fn sub_assign(&mut self, rhs: Self) {
543 self.0 -= rhs.0;
544 }
545}
546
547impl Mul<i64> for DurationSamples {
548 type Output = Self;
549 fn mul(self, rhs: i64) -> Self::Output {
550 Self(self.0 * rhs)
551 }
552}
553
554impl Div<i64> for DurationSamples {
555 type Output = Self;
556 fn div(self, rhs: i64) -> Self::Output {
557 Self(self.0 / rhs)
558 }
559}
560
561impl MulAssign<i64> for DurationSamples {
562 fn mul_assign(&mut self, rhs: i64) {
563 self.0 *= rhs;
564 }
565}
566
567impl DivAssign<i64> for DurationSamples {
568 fn div_assign(&mut self, rhs: i64) {
569 self.0 /= rhs;
570 }
571}
572
573impl From<i64> for InstantSamples {
574 fn from(value: i64) -> Self {
575 Self(value)
576 }
577}
578
579impl From<InstantSamples> for i64 {
580 fn from(value: InstantSamples) -> Self {
581 value.0
582 }
583}
584
585impl From<i64> for DurationSamples {
586 fn from(value: i64) -> Self {
587 Self(value)
588 }
589}
590
591impl From<DurationSamples> for i64 {
592 fn from(value: DurationSamples) -> Self {
593 value.0
594 }
595}
596
597#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
599#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
600#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
601#[cfg(feature = "musical_transport")]
602pub struct InstantMusical(pub f64);
603
604#[cfg(feature = "musical_transport")]
605impl InstantMusical {
606 pub const ZERO: Self = Self(0.0);
607
608 pub const fn new(beats: f64) -> Self {
609 Self(beats)
610 }
611
612 pub fn to_seconds(&self, beats_per_minute: f64) -> InstantSeconds {
614 InstantSeconds(self.0 * 60.0 / beats_per_minute)
615 }
616
617 pub fn to_sample_time(&self, beats_per_minute: f64, sample_rate: NonZeroU32) -> InstantSamples {
619 self.to_seconds(beats_per_minute).to_samples(sample_rate)
620 }
621
622 pub fn to_seconds_with_spb(&self, seconds_per_beat: f64) -> InstantSeconds {
624 InstantSeconds(self.0 * seconds_per_beat)
625 }
626
627 pub fn to_sample_time_with_spb(
629 &self,
630 seconds_per_beat: f64,
631 sample_rate: NonZeroU32,
632 ) -> InstantSamples {
633 self.to_seconds_with_spb(seconds_per_beat)
634 .to_samples(sample_rate)
635 }
636}
637
638#[repr(transparent)]
640#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
641#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
642#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
643#[cfg(feature = "musical_transport")]
644pub struct DurationMusical(pub f64);
645
646#[cfg(feature = "musical_transport")]
647impl DurationMusical {
648 pub const ZERO: Self = Self(0.0);
649
650 pub const fn new(beats: f64) -> Self {
651 Self(beats)
652 }
653}
654
655#[cfg(feature = "musical_transport")]
656impl Add<DurationMusical> for InstantMusical {
657 type Output = InstantMusical;
658 fn add(self, rhs: DurationMusical) -> Self::Output {
659 Self(self.0 + rhs.0)
660 }
661}
662
663#[cfg(feature = "musical_transport")]
664impl Sub<DurationMusical> for InstantMusical {
665 type Output = InstantMusical;
666 fn sub(self, rhs: DurationMusical) -> Self::Output {
667 Self(self.0 - rhs.0)
668 }
669}
670
671#[cfg(feature = "musical_transport")]
672impl AddAssign<DurationMusical> for InstantMusical {
673 fn add_assign(&mut self, rhs: DurationMusical) {
674 *self = *self + rhs;
675 }
676}
677
678#[cfg(feature = "musical_transport")]
679impl SubAssign<DurationMusical> for InstantMusical {
680 fn sub_assign(&mut self, rhs: DurationMusical) {
681 *self = *self - rhs;
682 }
683}
684
685#[cfg(feature = "musical_transport")]
686impl Sub<InstantMusical> for InstantMusical {
687 type Output = DurationMusical;
688 fn sub(self, rhs: Self) -> Self::Output {
689 DurationMusical(self.0 - rhs.0)
690 }
691}
692
693#[cfg(feature = "musical_transport")]
694impl Add for DurationMusical {
695 type Output = Self;
696 fn add(self, rhs: Self) -> Self::Output {
697 Self(self.0 + rhs.0)
698 }
699}
700
701#[cfg(feature = "musical_transport")]
702impl Sub for DurationMusical {
703 type Output = Self;
704 fn sub(self, rhs: Self) -> Self::Output {
705 Self(self.0 - rhs.0)
706 }
707}
708
709#[cfg(feature = "musical_transport")]
710impl AddAssign for DurationMusical {
711 fn add_assign(&mut self, rhs: Self) {
712 self.0 += rhs.0;
713 }
714}
715
716#[cfg(feature = "musical_transport")]
717impl SubAssign for DurationMusical {
718 fn sub_assign(&mut self, rhs: Self) {
719 self.0 -= rhs.0;
720 }
721}
722
723#[cfg(feature = "musical_transport")]
724impl Mul<f64> for DurationMusical {
725 type Output = Self;
726 fn mul(self, rhs: f64) -> Self::Output {
727 Self(self.0 * rhs)
728 }
729}
730
731#[cfg(feature = "musical_transport")]
732impl Div<f64> for DurationMusical {
733 type Output = Self;
734 fn div(self, rhs: f64) -> Self::Output {
735 Self(self.0 / rhs)
736 }
737}
738
739#[cfg(feature = "musical_transport")]
740impl MulAssign<f64> for DurationMusical {
741 fn mul_assign(&mut self, rhs: f64) {
742 self.0 *= rhs;
743 }
744}
745
746#[cfg(feature = "musical_transport")]
747impl DivAssign<f64> for DurationMusical {
748 fn div_assign(&mut self, rhs: f64) {
749 self.0 /= rhs;
750 }
751}
752
753#[cfg(feature = "musical_transport")]
754impl From<f64> for InstantMusical {
755 fn from(value: f64) -> Self {
756 Self(value)
757 }
758}
759
760#[cfg(feature = "musical_transport")]
761impl From<InstantMusical> for f64 {
762 fn from(value: InstantMusical) -> Self {
763 value.0
764 }
765}
766
767#[cfg(feature = "musical_transport")]
768impl From<f64> for DurationMusical {
769 fn from(value: f64) -> Self {
770 Self(value)
771 }
772}
773
774#[cfg(feature = "musical_transport")]
775impl From<DurationMusical> for f64 {
776 fn from(value: DurationMusical) -> Self {
777 value.0
778 }
779}
780
781#[derive(Debug, Clone, Copy, PartialEq)]
789pub struct AudioClock {
790 pub samples: InstantSamples,
803
804 pub seconds: InstantSeconds,
812
813 #[cfg(feature = "musical_transport")]
822 pub musical: Option<InstantMusical>,
823
824 #[cfg(feature = "musical_transport")]
827 pub transport_is_playing: bool,
828
829 pub update_instant: Option<Instant>,
837}