tek/engine/time/time_pulse.rs
unspeaker ef81b085a0
Some checks failed
/ build (push) Has been cancelled
break up into crates again
2025-09-10 01:58:32 +03:00

71 lines
2.1 KiB
Rust

use crate::*;
pub const DEFAULT_PPQ: f64 = 96.0;
/// FIXME: remove this and use PPQ from timebase everywhere:
pub const PPQ: usize = 96;
/// MIDI resolution in PPQ (pulses per quarter note)
#[derive(Debug, Default)] pub struct PulsesPerQuaver(AtomicF64);
impl_time_unit!(PulsesPerQuaver);
/// Timestamp in MIDI pulses
#[derive(Debug, Default)] pub struct Pulse(AtomicF64);
impl_time_unit!(Pulse);
/// Tempo in beats per minute
#[derive(Debug, Default)] pub struct BeatsPerMinute(AtomicF64);
impl_time_unit!(BeatsPerMinute);
/// Quantization setting for launching clips
#[derive(Debug, Default)] pub struct LaunchSync(AtomicF64);
impl_time_unit!(LaunchSync);
impl LaunchSync {
pub fn next (&self) -> f64 {
NoteDuration::next(self.get() as usize) as f64
}
pub fn prev (&self) -> f64 {
NoteDuration::prev(self.get() as usize) as f64
}
}
/// Quantization setting for notes
#[derive(Debug, Default)] pub struct Quantize(AtomicF64);
impl_time_unit!(Quantize);
impl Quantize {
pub fn next (&self) -> f64 {
NoteDuration::next(self.get() as usize) as f64
}
pub fn prev (&self) -> f64 {
NoteDuration::prev(self.get() as usize) as f64
}
}
/// Iterator that emits subsequent ticks within a range.
pub struct TicksIterator {
pub spp: f64,
pub sample: usize,
pub start: usize,
pub end: usize,
}
impl Iterator for TicksIterator {
type Item = (usize, usize);
fn next (&mut self) -> Option<Self::Item> {
loop {
if self.sample > self.end { return None }
let spp = self.spp;
let sample = self.sample as f64;
let start = self.start;
let end = self.end;
self.sample += 1;
//println!("{spp} {sample} {start} {end}");
let jitter = sample.rem_euclid(spp); // ramps
let next_jitter = (sample + 1.0).rem_euclid(spp);
if jitter > next_jitter { // at crossing:
let time = (sample as usize) % (end as usize-start as usize);
let tick = (sample / spp) as usize;
return Some((time, tick))
}
}
}
}