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 { 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)) } } } }