mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
clarify naming for temporal resolution traits
This commit is contained in:
parent
3a199e8030
commit
ccc74fd743
1 changed files with 65 additions and 55 deletions
|
|
@ -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] = [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue