From ccc74fd74329395f8834c53692c297510662571f Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 26 Oct 2024 16:09:22 +0300 Subject: [PATCH] clarify naming for temporal resolution traits --- crates/tek_core/src/time.rs | 120 +++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/crates/tek_core/src/time.rs b/crates/tek_core/src/time.rs index 3251559e..97dd2694 100644 --- a/crates/tek_core/src/time.rs +++ b/crates/tek_core/src/time.rs @@ -7,7 +7,7 @@ impl TimeUnit for T where T: Mul + Div + Rem + From + Copy {} /// Trait for struct that defines a sample rate in hertz (samples per second) -pub trait TimeSR { +pub trait SampleRate { /// Get the sample rate fn sr (&self) -> T; /// Set the sample rate @@ -19,7 +19,7 @@ pub trait TimeSR { } /// Trait for struct that defines a tempo in beats per minute -pub trait TimeBPM { +pub trait BeatsPerMinute { /// Get the tempo fn bpm (&self) -> T; /// Set the tempo @@ -28,65 +28,81 @@ pub trait TimeBPM { #[inline] fn usec_per_beat (&self) -> T { T::from(60_000_000f64) / self.bpm() } /// Return the number of beats in a second #[inline] fn beat_per_second (&self) -> T { self.bpm() / T::from(60_000_000f64) } - /// Return the duration of a note in microseconds + /// Return the number of microseconds corresponding to a note of the given duration #[inline] fn note_to_usec (&self, (num, den): (T, T)) -> T { T::from(4.0) * self.usec_per_beat() * num / den } + /// Return the number of frames corresponding to a note of the given duration + #[inline] fn note_to_frame (&self, note: (T, T)) -> T where Self: SampleRate { + self.usec_to_frame(self.note_to_usec(note)) + } + /// Return the number of frames corresponding to the given number of microseconds + #[inline] fn usec_to_frame (&self, usec: T) -> T where Self: SampleRate { + usec * self.sr() / T::from(1000f64) + } /// Return the quantized position of a moment in time given a step #[inline] fn quantize (&self, step: (T, T), time: T) -> (T, T) { let step = self.note_to_usec(step); (time / step, time % step) } /// Quantize a collection of events - #[inline] fn quantize_into + Sized, U> ( + #[inline] fn quantize_into + Sized, U> ( &self, step: (T, T), events: E ) -> Vec<(T, U)> { let step = (step.0.into(), step.1.into()); - events - .map(|(time, event)|(self.quantize(step, time).0, event)) - .collect() - } - #[inline] fn note_to_frame (&self, note: (T, T)) -> T where Self: TimeSR { - self.usec_to_frame(self.note_to_usec(note)) - } - #[inline] fn usec_to_frame (&self, usec: T) -> T where Self: TimeSR { - usec * self.sr() / T::from(1000f64) + let quantize = |(time, event)|(self.quantize(step, time).0, event); + events.map(quantize).collect() } } /// Trait for struct that defines a MIDI resolution in pulses per quaver (beat) -pub trait TimePPQ { +pub trait PulsesPerQuaver { const DEFAULT_PPQ: T; /// Get the PPQ fn ppq (&self) -> T; /// Set the PPQ fn set_ppq (&self, ppq: T); /// Return duration of a pulse in microseconds (BPM-dependent) - #[inline] fn usec_per_pulse (&self) -> T where Self: TimeBPM { + #[inline] fn usec_per_pulse (&self) -> T where Self: BeatsPerMinute { self.usec_per_beat() / self.ppq() } /// Return number of pulses in a second (BPM-dependent) - #[inline] fn pulses_per_second (&self) -> T where Self: TimeBPM { + #[inline] fn pulses_per_second (&self) -> T where Self: BeatsPerMinute { self.beat_per_second() * self.ppq() } /// Return fraction of a pulse to which a sample corresponds (SR- and BPM-dependent) - #[inline] fn pulses_per_sample (&self) -> T where Self: TimeSR + TimeBPM { + #[inline] fn pulses_per_sample (&self) -> T where Self: SampleRate + BeatsPerMinute { self.usec_per_pulse() / self.usec_per_sample() } /// Convert a number of pulses to a sample number (SR- and BPM-dependent) - #[inline] fn pulses_to_sample (&self, pulses: T) -> T where Self: TimeSR + TimeBPM { - self.pulses_per_sample() * pulses + #[inline] fn pulses_to_sample (&self, p: T) -> T where Self: SampleRate + BeatsPerMinute { + self.pulses_per_sample() * p } /// Convert a number of samples to a pulse number (SR- and BPM-dependent) - #[inline] fn samples_to_pulse (&self, samples: T) -> T where Self: TimeSR + TimeBPM { - samples / self.pulses_per_sample() + #[inline] fn samples_to_pulse (&self, s: T) -> T where Self: SampleRate + BeatsPerMinute { + s / self.pulses_per_sample() } /// Return number of samples in a pulse (SR- and BPM-dependent) - #[inline] fn samples_per_pulse (&self) -> T where Self: TimeSR + TimeBPM { + #[inline] fn samples_per_pulse (&self) -> T where Self: SampleRate + BeatsPerMinute { self.sr() / self.pulses_per_second() } } +pub trait FramePosition { + fn frame (&self) -> T; + fn set_frame (&self, frame: T); +} + +pub trait PulsePosition { + fn pulse (&self) -> T; + fn set_pulse (&self, pulse: T); +} + +pub trait UsecPosition { + fn usec (&self) -> T; + fn set_usec (&self, usec: T); +} + #[derive(Debug)] /// Keeps track of global time units. pub struct Timebase { @@ -103,6 +119,19 @@ impl Timebase { Self { sr: s.into(), bpm: b.into(), ppq: p.into() } } } +impl SampleRate for Timebase { + #[inline] fn sr (&self) -> f64 { self.sr.load(Ordering::Relaxed) } + #[inline] fn set_sr (&self, sr: f64) { self.sr.store(sr, Ordering::Relaxed); } +} +impl BeatsPerMinute for Timebase { + #[inline] fn bpm (&self) -> f64 { self.bpm.load(Ordering::Relaxed) } + #[inline] fn set_bpm (&self, bpm: f64) { self.bpm.store(bpm, Ordering::Relaxed); } +} +impl PulsesPerQuaver for Timebase { + const DEFAULT_PPQ: f64 = 96f64; + #[inline] fn ppq (&self) -> f64 { self.ppq.load(Ordering::Relaxed) } + #[inline] fn set_ppq (&self, ppq: f64) { self.ppq.store(ppq, Ordering::Relaxed); } +} #[derive(Debug)] pub struct TransportTime { @@ -121,48 +150,29 @@ pub struct TransportTime { /// Pulses per quarter note pub ppq: usize, } - -impl TimeSR for Timebase { - #[inline] fn sr (&self) -> f64 { self.sr.load(Ordering::Relaxed) } - #[inline] fn set_sr (&self, sr: f64) { self.sr.store(sr, Ordering::Relaxed); } -} -impl TimeSR for TransportTime { - #[inline] fn sr (&self) -> f64 { self.timebase.sr() } +impl SampleRate for TransportTime { + #[inline] fn sr (&self) -> f64 { self.timebase.sr() } #[inline] fn set_sr (&self, sr: f64) { self.timebase.set_sr(sr); } } - -impl TimeBPM for Timebase { - #[inline] fn bpm (&self) -> f64 { self.bpm.load(Ordering::Relaxed) } - #[inline] fn set_bpm (&self, bpm: f64) { self.bpm.store(bpm, Ordering::Relaxed); } -} -impl TimeBPM for TransportTime { - #[inline] fn bpm (&self) -> f64 { self.timebase.bpm() } +impl BeatsPerMinute for TransportTime { + #[inline] fn bpm (&self) -> f64 { self.timebase.bpm() } #[inline] fn set_bpm (&self, bpm: f64) { self.timebase.set_bpm(bpm); } } - -impl TimePPQ for Timebase { - const DEFAULT_PPQ: f64 = 96f64; - #[inline] fn ppq (&self) -> f64 { self.ppq.load(Ordering::Relaxed) } - #[inline] fn set_ppq (&self, ppq: f64) { self.ppq.store(ppq, Ordering::Relaxed); } -} -impl TimePPQ for TransportTime { +impl PulsesPerQuaver for TransportTime { const DEFAULT_PPQ: f64 = Timebase::DEFAULT_PPQ; - #[inline] fn ppq (&self) -> f64 { self.timebase.ppq() } + #[inline] fn ppq (&self) -> f64 { self.timebase.ppq() } #[inline] fn set_ppq (&self, ppq: f64) { self.timebase.set_ppq(ppq); } } -/// Trait defining temporal resolution in different modes. -pub trait TimeBase: TimeSR + TimeBPM + TimePPQ {} +pub trait LaunchSync { + fn sync (&self) -> T; + fn set_sync (&self, sync: T) -> T; +} -pub trait TimeFrame { fn frame (&self) -> T; fn set_frame (&self, frame: T); } -pub trait TimePulse { fn pulse (&self) -> T; fn set_pulse (&self, pulse: T); } -pub trait TimeUsec { fn usec (&self) -> T; fn set_usec (&self, usec: T); } - -/// Trait defining a moment in time in different modes. -pub trait TimePoint: TimeFrame + TimePulse + TimeUsec {} - -pub trait TimeSync { fn sync (&self) -> T; fn set_sync (&self, sync: T) -> T; } -pub trait TimeQuant { fn quant (&self) -> T; fn set_quant (&self, quant: T); } +pub trait Quantize { + fn quant (&self) -> T; + fn set_quant (&self, quant: T); +} /// (pulses, name) pub const NOTE_DURATIONS: [(usize, &str);26] = [