clarify naming for temporal resolution traits

This commit is contained in:
🪞👃🪞 2024-10-26 16:09:22 +03:00
parent 3a199e8030
commit ccc74fd743

View file

@ -7,7 +7,7 @@ impl<T> TimeUnit for T where T: Mul<Self, Output=Self> + Div<Self, Output=Self>
+ Rem<Self, Output=Self> + From<f64> + Copy {}
/// Trait for struct that defines a sample rate in hertz (samples per second)
pub trait TimeSR<T: TimeUnit> {
pub trait SampleRate<T: TimeUnit> {
/// Get the sample rate
fn sr (&self) -> T;
/// Set the sample rate
@ -19,7 +19,7 @@ pub trait TimeSR<T: TimeUnit> {
}
/// Trait for struct that defines a tempo in beats per minute
pub trait TimeBPM<T: TimeUnit> {
pub trait BeatsPerMinute<T: TimeUnit> {
/// Get the tempo
fn bpm (&self) -> T;
/// Set the tempo
@ -28,65 +28,81 @@ pub trait TimeBPM<T: TimeUnit> {
#[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<T> {
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<T> {
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 <E: Iterator<Item=(T, T)> + Sized, U> (
#[inline] fn quantize_into <E: Iterator<Item=(T, U)> + 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<T> {
self.usec_to_frame(self.note_to_usec(note))
}
#[inline] fn usec_to_frame (&self, usec: T) -> T where Self: TimeSR<T> {
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<T: TimeUnit> {
pub trait PulsesPerQuaver<T: TimeUnit> {
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<T> {
#[inline] fn usec_per_pulse (&self) -> T where Self: BeatsPerMinute<T> {
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<T> {
#[inline] fn pulses_per_second (&self) -> T where Self: BeatsPerMinute<T> {
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<T> + TimeBPM<T> {
#[inline] fn pulses_per_sample (&self) -> T where Self: SampleRate<T> + BeatsPerMinute<T> {
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<T> + TimeBPM<T> {
self.pulses_per_sample() * pulses
#[inline] fn pulses_to_sample (&self, p: T) -> T where Self: SampleRate<T> + BeatsPerMinute<T> {
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<T> + TimeBPM<T> {
samples / self.pulses_per_sample()
#[inline] fn samples_to_pulse (&self, s: T) -> T where Self: SampleRate<T> + BeatsPerMinute<T> {
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<T> + TimeBPM<T> {
#[inline] fn samples_per_pulse (&self) -> T where Self: SampleRate<T> + BeatsPerMinute<T> {
self.sr() / self.pulses_per_second()
}
}
pub trait FramePosition<T> {
fn frame (&self) -> T;
fn set_frame (&self, frame: T);
}
pub trait PulsePosition<T> {
fn pulse (&self) -> T;
fn set_pulse (&self, pulse: T);
}
pub trait UsecPosition<T> {
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<f64> 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<f64> 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<f64> 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<f64> 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<f64> for TransportTime {
#[inline] fn sr (&self) -> f64 { self.timebase.sr() }
impl SampleRate<f64> for TransportTime {
#[inline] fn sr (&self) -> f64 { self.timebase.sr() }
#[inline] fn set_sr (&self, sr: f64) { self.timebase.set_sr(sr); }
}
impl TimeBPM<f64> 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<f64> for TransportTime {
#[inline] fn bpm (&self) -> f64 { self.timebase.bpm() }
impl BeatsPerMinute<f64> for TransportTime {
#[inline] fn bpm (&self) -> f64 { self.timebase.bpm() }
#[inline] fn set_bpm (&self, bpm: f64) { self.timebase.set_bpm(bpm); }
}
impl TimePPQ<f64> 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<f64> for TransportTime {
impl PulsesPerQuaver<f64> 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<T: TimeUnit>: TimeSR<T> + TimeBPM<T> + TimePPQ<T> {}
pub trait LaunchSync<T> {
fn sync (&self) -> T;
fn set_sync (&self, sync: T) -> T;
}
pub trait TimeFrame<T> { fn frame (&self) -> T; fn set_frame (&self, frame: T); }
pub trait TimePulse<T> { fn pulse (&self) -> T; fn set_pulse (&self, pulse: T); }
pub trait TimeUsec<T> { fn usec (&self) -> T; fn set_usec (&self, usec: T); }
/// Trait defining a moment in time in different modes.
pub trait TimePoint<T>: TimeFrame<T> + TimePulse<T> + TimeUsec<T> {}
pub trait TimeSync<T> { fn sync (&self) -> T; fn set_sync (&self, sync: T) -> T; }
pub trait TimeQuant<T> { fn quant (&self) -> T; fn set_quant (&self, quant: T); }
pub trait Quantize<T> {
fn quant (&self) -> T;
fn set_quant (&self, quant: T);
}
/// (pulses, name)
pub const NOTE_DURATIONS: [(usize, &str);26] = [