diff --git a/crates/tek_core/src/lib.rs b/crates/tek_core/src/lib.rs index d02aca7e..6a0191bb 100644 --- a/crates/tek_core/src/lib.rs +++ b/crates/tek_core/src/lib.rs @@ -16,7 +16,7 @@ pub(crate) use std::thread::{spawn, JoinHandle}; pub(crate) use std::time::Duration; pub(crate) use atomic_float::*; use better_panic::{Settings, Verbosity}; -use std::ops::{Add, Sub, Mul, Div}; +use std::ops::{Add, Sub, Mul, Div, Rem}; use std::cmp::{Ord, Eq, PartialEq}; use std::fmt::{Debug, Display}; diff --git a/crates/tek_core/src/time.rs b/crates/tek_core/src/time.rs index 713873b1..3251559e 100644 --- a/crates/tek_core/src/time.rs +++ b/crates/tek_core/src/time.rs @@ -1,9 +1,10 @@ use crate::*; +use std::iter::Iterator; -pub trait TimeUnit: Mul + Div + From + Sized {} - -impl TimeUnit for T - where T: Mul + Div + From + Sized {} +pub trait TimeUnit: Mul + Div + + Rem + From + Copy {} +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 { @@ -27,6 +28,30 @@ 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 + #[inline] fn note_to_usec (&self, (num, den): (T, T)) -> T { + T::from(4.0) * self.usec_per_beat() * num / den + } + /// 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> ( + &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) + } } /// Trait for struct that defines a MIDI resolution in pulses per quaver (beat) @@ -72,6 +97,12 @@ pub struct Timebase { /// Ticks per beat pub ppq: AtomicF64, } +impl Default for Timebase { fn default () -> Self { Self::new(48000f64, 150f64, 96f64) } } +impl Timebase { + pub fn new (s: impl Into, b: impl Into, p: impl Into) -> Self { + Self { sr: s.into(), bpm: b.into(), ppq: p.into() } + } +} #[derive(Debug)] pub struct TransportTime { @@ -133,48 +164,6 @@ 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); } -impl Default for Timebase { - fn default () -> Self { Self::new(48000f64, 150f64, 96f64) } -} - -impl Timebase { - pub fn new ( - sr: impl Into, bpm: impl Into, ppq: impl Into - ) -> Self { - Self { sr: sr.into(), bpm: bpm.into(), ppq: ppq.into() } - } - - #[inline] pub fn note_to_usec (&self, (num, den): (f64, f64)) -> f64 { - 4.0 * self.usec_per_beat() * num / den - } - - #[inline] pub fn note_to_frame (&self, note: (f64, f64)) -> f64 { - self.usec_to_frame(self.note_to_usec(note)) - } - #[inline] fn usec_to_frame (&self, usec: f64) -> f64 { - usec * self.sr() / 1000.0 - } - - #[inline] pub fn quantize ( - &self, step: (f64, f64), time: f64 - ) -> (f64, f64) { - let step = self.note_to_usec(step); - (time / step, time % step) - } - - #[inline] pub fn quantize_into ( - &self, step: (f64, f64), events: E - ) -> Vec<(f64, T)> - where E: std::iter::Iterator + Sized - { - let step = (step.0.into(), step.1.into()); - events - .map(|(time, event)|(self.quantize(step, time).0, event)) - .collect() - } - -} - /// (pulses, name) pub const NOTE_DURATIONS: [(usize, &str);26] = [ (1, "1/384"),