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