1use core::ops::{Add, AddAssign, Sub, SubAssign};
2
3use crate::node::ProcInfo;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub enum EventDelay {
8 DelayUntilSeconds(ClockSeconds),
17
18 DelayUntilSamples(ClockSamples),
28
29 DelayUntilMusical(MusicalTime),
35}
36
37impl EventDelay {
38 pub fn elapsed_or_get(&self, proc_info: &ProcInfo) -> Option<Self> {
39 match self {
40 EventDelay::DelayUntilSeconds(seconds) => {
41 if *seconds <= proc_info.clock_seconds.start {
42 None
43 } else {
44 Some(*self)
45 }
46 }
47 EventDelay::DelayUntilSamples(samples) => {
48 if *samples <= proc_info.clock_samples {
49 None
50 } else {
51 Some(*self)
52 }
53 }
54 EventDelay::DelayUntilMusical(musical) => {
55 if let Some(transport) = &proc_info.transport_info {
56 if transport.paused || *musical <= transport.musical_clock.start {
57 None
58 } else {
59 Some(*self)
60 }
61 } else {
62 None
63 }
64 }
65 }
66 }
67
68 pub fn elapsed_on_frame(&self, proc_info: &ProcInfo, sample_rate: u32) -> Option<usize> {
69 match self {
70 EventDelay::DelayUntilSeconds(seconds) => {
71 if *seconds <= proc_info.clock_seconds.start {
72 Some(0)
73 } else if *seconds >= proc_info.clock_seconds.end {
74 None
75 } else {
76 let frame = ((seconds.0 - proc_info.clock_seconds.start.0)
77 * f64::from(sample_rate))
78 .round() as usize;
79
80 if frame >= proc_info.frames {
81 None
82 } else {
83 Some(frame)
84 }
85 }
86 }
87 EventDelay::DelayUntilSamples(samples) => {
88 if *samples <= proc_info.clock_samples {
89 Some(0)
90 } else {
91 let frame = samples.0 - proc_info.clock_samples.0;
92
93 if frame >= proc_info.frames as i64 {
94 None
95 } else {
96 Some(frame as usize)
97 }
98 }
99 }
100 EventDelay::DelayUntilMusical(musical) => {
101 if let Some(transport) = &proc_info.transport_info {
102 if transport.paused || *musical >= transport.musical_clock.end {
103 None
104 } else if *musical <= transport.musical_clock.start {
105 Some(0)
106 } else {
107 let frame = transport.transport.musical_to_sample(*musical, sample_rate)
108 - proc_info.clock_samples;
109
110 if frame.0 >= proc_info.frames as i64 {
111 None
112 } else {
113 Some(frame.0 as usize)
114 }
115 }
116 } else {
117 None
118 }
119 }
120 }
121 }
122}
123
124#[repr(transparent)]
126#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
127pub struct ClockSeconds(pub f64);
128
129impl Add for ClockSeconds {
130 type Output = Self;
131 fn add(self, rhs: Self) -> Self::Output {
132 Self(self.0 + rhs.0)
133 }
134}
135
136impl Sub for ClockSeconds {
137 type Output = Self;
138 fn sub(self, rhs: Self) -> Self::Output {
139 Self(self.0 - rhs.0)
140 }
141}
142
143impl AddAssign for ClockSeconds {
144 fn add_assign(&mut self, rhs: Self) {
145 self.0 += rhs.0;
146 }
147}
148
149impl SubAssign for ClockSeconds {
150 fn sub_assign(&mut self, rhs: Self) {
151 self.0 -= rhs.0;
152 }
153}
154
155impl From<f64> for ClockSeconds {
156 fn from(value: f64) -> Self {
157 Self(value)
158 }
159}
160
161impl Into<f64> for ClockSeconds {
162 fn into(self) -> f64 {
163 self.0
164 }
165}
166
167#[repr(transparent)]
169#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
170pub struct ClockSamples(pub i64);
171
172impl ClockSamples {
173 pub const fn new(samples: i64) -> Self {
174 Self(samples)
175 }
176
177 pub fn from_secs_f64(seconds: f64, sample_rate: u32) -> Self {
178 let seconds_i64 = seconds.floor() as i64;
179 let fract_samples_i64 = (seconds.fract() * f64::from(sample_rate)).round() as i64;
180
181 Self((seconds_i64 * i64::from(sample_rate)) + fract_samples_i64)
182 }
183
184 pub fn whole_seconds_and_fract(&self, sample_rate: u32) -> (i64, u32) {
186 let whole_seconds = self.0 / i64::from(sample_rate);
187 let fract_samples = self.0 % i64::from(sample_rate);
188
189 if fract_samples < 0 {
190 (
191 whole_seconds - 1,
192 sample_rate - (fract_samples.abs() as u32),
193 )
194 } else {
195 (whole_seconds, fract_samples as u32)
196 }
197 }
198
199 #[inline]
200 pub fn fract_second_samples(&self, sample_rate: u32) -> u32 {
201 (self.0 % i64::from(sample_rate)) as u32
202 }
203
204 pub fn as_secs_f64(&self, sample_rate: u32, sample_rate_recip: f64) -> f64 {
205 let whole_seconds = self.0 / i64::from(sample_rate);
206 let fract_samples = self.0 % i64::from(sample_rate);
207
208 whole_seconds as f64 + (fract_samples as f64 * sample_rate_recip)
209 }
210}
211
212impl Add for ClockSamples {
213 type Output = Self;
214 fn add(self, rhs: Self) -> Self::Output {
215 Self(self.0 + rhs.0)
216 }
217}
218
219impl Sub for ClockSamples {
220 type Output = Self;
221 fn sub(self, rhs: Self) -> Self::Output {
222 Self(self.0 - rhs.0)
223 }
224}
225
226impl AddAssign for ClockSamples {
227 fn add_assign(&mut self, rhs: Self) {
228 self.0 += rhs.0;
229 }
230}
231
232impl SubAssign for ClockSamples {
233 fn sub_assign(&mut self, rhs: Self) {
234 self.0 -= rhs.0;
235 }
236}
237
238impl From<i64> for ClockSamples {
239 fn from(value: i64) -> Self {
240 Self(value)
241 }
242}
243
244impl Into<i64> for ClockSamples {
245 fn into(self) -> i64 {
246 self.0
247 }
248}
249
250#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
252pub struct MusicalTime(pub f64);
253
254impl MusicalTime {
255 pub const fn new(beats: f64) -> Self {
256 Self(beats)
257 }
258
259 pub fn to_sample_time(&self, seconds_per_beat: f64, sample_rate: u32) -> ClockSamples {
261 let secs_f64 = self.0 * seconds_per_beat;
262 ClockSamples::from_secs_f64(secs_f64, sample_rate)
263 }
264
265 pub fn from_sample_time(
267 sample_time: ClockSamples,
268 beats_per_second: f64,
269 sample_rate: u32,
270 sample_rate_recip: f64,
271 ) -> Self {
272 let secs_f64 = sample_time.as_secs_f64(sample_rate, sample_rate_recip);
273 MusicalTime(secs_f64 * beats_per_second)
274 }
275}
276
277pub fn seconds_per_beat(beats_per_minute: f64) -> f64 {
278 60.0 / beats_per_minute
279}
280
281pub fn beats_per_second(beats_per_minute: f64) -> f64 {
282 beats_per_minute * (1.0 / 60.0)
283}
284
285impl Add for MusicalTime {
286 type Output = Self;
287 fn add(self, rhs: Self) -> Self::Output {
288 Self(self.0 + rhs.0)
289 }
290}
291
292impl Sub for MusicalTime {
293 type Output = Self;
294 fn sub(self, rhs: Self) -> Self::Output {
295 Self(self.0 - rhs.0)
296 }
297}
298
299impl AddAssign for MusicalTime {
300 fn add_assign(&mut self, rhs: Self) {
301 self.0 += rhs.0;
302 }
303}
304
305impl SubAssign for MusicalTime {
306 fn sub_assign(&mut self, rhs: Self) {
307 self.0 -= rhs.0;
308 }
309}
310
311#[derive(Debug, Clone, Copy, PartialEq)]
312pub struct MusicalTransport {
313 beats_per_minute: f64,
314 seconds_per_beat: f64,
315 }
317
318impl MusicalTransport {
319 pub fn new(beats_per_minute: f64) -> Self {
320 Self {
321 beats_per_minute,
322 seconds_per_beat: seconds_per_beat(beats_per_minute),
323 }
324 }
325
326 pub fn beats_per_minute(&self) -> f64 {
327 self.beats_per_minute
328 }
329
330 pub fn seconds_per_beat(&self) -> f64 {
331 self.seconds_per_beat
332 }
333}
334
335impl MusicalTransport {
336 pub fn musical_to_sample(&self, musical: MusicalTime, sample_rate: u32) -> ClockSamples {
338 musical.to_sample_time(self.seconds_per_beat, sample_rate)
339 }
340
341 pub fn sample_to_musical(
343 &self,
344 sample_time: ClockSamples,
345 sample_rate: u32,
346 sample_rate_recip: f64,
347 ) -> MusicalTime {
348 MusicalTime::from_sample_time(
349 sample_time,
350 self.beats_per_minute * (1.0 / 60.0),
351 sample_rate,
352 sample_rate_recip,
353 )
354 }
355}