mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-09 13:16:44 +01:00
wip: f64 timebase (sloooo)
This commit is contained in:
parent
c4d8692b71
commit
4055662bbd
12 changed files with 206 additions and 142 deletions
119
src/core/time.rs
119
src/core/time.rs
|
|
@ -2,101 +2,96 @@ use crate::core::*;
|
|||
|
||||
pub struct Timebase {
|
||||
/// Frames per second
|
||||
pub rate: AtomicUsize,
|
||||
pub rate: ::atomic_float::AtomicF64,
|
||||
/// Beats per minute
|
||||
pub bpm: AtomicUsize,
|
||||
pub bpm: ::atomic_float::AtomicF64,
|
||||
/// Ticks per beat
|
||||
pub ppq: AtomicUsize,
|
||||
}
|
||||
|
||||
/// NoteDuration in musical terms. Has definite usec value
|
||||
/// for given bpm and sample rate.
|
||||
pub enum NoteDuration {
|
||||
Nth(usize, usize),
|
||||
Dotted(Box<Self>),
|
||||
Tuplet(usize, Box<Self>),
|
||||
pub ppq: ::atomic_float::AtomicF64,
|
||||
}
|
||||
|
||||
impl Timebase {
|
||||
#[inline] fn rate (&self) -> usize {
|
||||
pub fn new (rate: f64, bpm: f64, ppq: f64) -> Self {
|
||||
Self { rate: rate.into(), bpm: bpm.into(), ppq: ppq.into() }
|
||||
}
|
||||
#[inline] fn rate (&self) -> f64 {
|
||||
self.rate.load(Ordering::Relaxed)
|
||||
}
|
||||
#[inline] fn frame_usec (&self) -> usize {
|
||||
1_000_000 / self.rate()
|
||||
#[inline] fn frame_usec (&self) -> f64 {
|
||||
1_000_000 as f64 / self.rate() as f64
|
||||
}
|
||||
#[inline] pub fn frame_to_usec (&self, frame: usize) -> usize {
|
||||
frame * 1000000 / self.rate()
|
||||
#[inline] pub fn frames_usecs (&self, frame: f64) -> f64 {
|
||||
frame * self.frame_usec()
|
||||
}
|
||||
|
||||
#[inline] pub fn bpm (&self) -> usize {
|
||||
#[inline] pub fn bpm (&self) -> f64 {
|
||||
self.bpm.load(Ordering::Relaxed)
|
||||
}
|
||||
#[inline] fn beat_usec (&self) -> usize {
|
||||
60_000_000_000_000 / self.bpm()
|
||||
}
|
||||
#[inline] fn beats_per_second (&self) -> f64 {
|
||||
self.bpm() as f64 / 60000000.0
|
||||
#[inline] fn beat_usec (&self) -> f64 {
|
||||
60_000_000_000_000f64 / self.bpm() as f64
|
||||
}
|
||||
|
||||
#[inline] pub fn ppq (&self) -> usize {
|
||||
#[inline] pub fn ppq (&self) -> f64 {
|
||||
self.ppq.load(Ordering::Relaxed)
|
||||
}
|
||||
#[inline] fn pulse_usec (&self) -> usize {
|
||||
self.beat_usec() / self.ppq()
|
||||
#[inline] fn pulse_usec (&self) -> f64 {
|
||||
self.beat_usec() / self.ppq() as f64
|
||||
}
|
||||
#[inline] fn pulse_frame (&self) -> usize {
|
||||
self.pulse_usec() / self.frame_usec()
|
||||
#[inline] fn pulse_frame (&self) -> f64 {
|
||||
self.pulse_usec() / self.frame_usec() as f64
|
||||
}
|
||||
#[inline] pub fn pulses_frames (&self, pulses: usize) -> usize {
|
||||
#[inline] pub fn pulses_frames (&self, pulses: f64) -> f64 {
|
||||
self.pulse_frame() * pulses
|
||||
}
|
||||
#[inline] pub fn frames_pulses (&self, frames: usize) -> usize {
|
||||
#[inline] pub fn frames_pulses (&self, frames: f64) -> f64 {
|
||||
frames / self.pulse_frame()
|
||||
}
|
||||
#[inline] pub fn frames_per_tick (&self) -> f64 {
|
||||
self.rate() as f64 / self.ticks_per_second()
|
||||
}
|
||||
#[inline] fn ticks_per_second (&self) -> f64 {
|
||||
self.beats_per_second() * self.ppq() as f64
|
||||
}
|
||||
#[inline] fn usec_to_frame (&self, usec: usize) -> usize {
|
||||
usec * self.rate() / 1000
|
||||
}
|
||||
#[inline] pub fn usec_per_step (&self, divisor: usize) -> usize {
|
||||
#[inline] pub fn usec_per_step (&self, divisor: f64) -> f64 {
|
||||
self.beat_usec() / divisor
|
||||
}
|
||||
|
||||
#[inline] pub fn note_to_usec (&self, note: &NoteDuration) -> usize {
|
||||
match note {
|
||||
NoteDuration::Nth(time, flies) =>
|
||||
self.beat_usec() * *time / *flies,
|
||||
NoteDuration::Dotted(note) =>
|
||||
self.note_to_usec(note) * 3 / 2,
|
||||
NoteDuration::Tuplet(n, note) =>
|
||||
self.note_to_usec(note) * 2 / *n,
|
||||
}
|
||||
#[inline] pub fn note_to_usec (&self, (num, den): (f64, f64)) -> f64 {
|
||||
4.0 * self.beat_usec() * num / den
|
||||
}
|
||||
|
||||
#[inline] pub fn note_to_frame (&self, note: &NoteDuration) -> usize {
|
||||
#[inline] fn usec_to_frame (&self, usec: f64) -> f64 {
|
||||
usec * self.rate() / 1000.0
|
||||
}
|
||||
#[inline] pub fn note_to_frame (&self, note: (f64, f64)) -> f64 {
|
||||
self.usec_to_frame(self.note_to_usec(note))
|
||||
}
|
||||
|
||||
#[inline] pub fn quantize (&self, step: &NoteDuration, time: usize) -> (usize, usize) {
|
||||
#[inline] pub fn quantize (
|
||||
&self, step: (f64, f64), time: f64
|
||||
) -> (f64, f64) {
|
||||
let step = self.note_to_usec(step);
|
||||
let time = time / step;
|
||||
let offset = time % step;
|
||||
(time, offset)
|
||||
(time / step, time % step)
|
||||
}
|
||||
|
||||
#[inline] pub fn quantize_into <T, U> (&self, step: &NoteDuration, events: U) -> Vec<(usize, T)>
|
||||
where U: std::iter::Iterator<Item=(usize, T)> + Sized
|
||||
#[inline] pub fn quantize_into <E, T> (
|
||||
&self, step: (f64, f64), events: E
|
||||
) -> Vec<(f64, T)>
|
||||
where E: std::iter::Iterator<Item=(f64, T)> + Sized
|
||||
{
|
||||
let step = (step.0.into(), step.1.into());
|
||||
events
|
||||
.map(|(time, event)|(self.quantize(step, time).0, event))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn frames_to_ticks (&self, start: usize, end: usize, quant: usize) -> Vec<(usize, usize)> {
|
||||
#[inline] fn beats_per_second (&self) -> f64 {
|
||||
self.bpm() as f64 / 60000000.0
|
||||
}
|
||||
#[inline] fn ticks_per_second (&self) -> f64 {
|
||||
self.beats_per_second() * self.ppq() as f64
|
||||
}
|
||||
#[inline] pub fn frames_per_tick (&self) -> f64 {
|
||||
self.rate() as f64 / self.ticks_per_second()
|
||||
}
|
||||
pub fn frames_to_ticks (
|
||||
&self,
|
||||
start: f64,
|
||||
end: f64,
|
||||
quant: f64,
|
||||
) -> Vec<(usize, usize)> {
|
||||
let start_frame = start % quant;
|
||||
let end_frame = end % quant;
|
||||
let fpt = self.frames_per_tick();
|
||||
|
|
@ -106,24 +101,24 @@ impl Timebase {
|
|||
let last_jitter = (frame - 1.0).max(0.0) % fpt;
|
||||
let next_jitter = frame + 1.0 % fpt;
|
||||
if jitter <= last_jitter && jitter <= next_jitter {
|
||||
ticks.push((frame as usize % (end-start), (frame / fpt) as usize));
|
||||
ticks.push((frame as usize % (end as usize-start as usize), (frame / fpt) as usize));
|
||||
};
|
||||
};
|
||||
if start_frame < end_frame {
|
||||
for frame in start_frame..end_frame {
|
||||
for frame in start_frame as usize..end_frame as usize {
|
||||
add_frame(frame as f64);
|
||||
}
|
||||
} else {
|
||||
let mut frame = start_frame;
|
||||
let mut frame = start_frame as usize;
|
||||
loop {
|
||||
add_frame(frame as f64);
|
||||
frame = frame + 1;
|
||||
if frame >= quant {
|
||||
if frame >= quant as usize {
|
||||
frame = 0;
|
||||
loop {
|
||||
add_frame(frame as f64);
|
||||
frame = frame + 1;
|
||||
if frame >= end_frame.saturating_sub(1) {
|
||||
if frame >= (end_frame as usize).saturating_sub(1) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue