move formatting onto time traits

This commit is contained in:
🪞👃🪞 2024-10-26 20:46:07 +03:00
parent f26609ed62
commit 8fb5417c22
4 changed files with 44 additions and 27 deletions

View file

@ -2,10 +2,10 @@ use crate::*;
use std::iter::Iterator;
/// Any numeric type that represents time
pub trait TimeUnit: PartialEq + Copy + Display
pub trait TimeUnit: Copy + Display + PartialOrd + PartialEq
+ Add<Self, Output=Self> + Mul<Self, Output=Self>
+ Div<Self, Output=Self> + Rem<Self, Output=Self> {}
impl<T> TimeUnit for T where T: PartialEq + Copy + Display
impl<T> TimeUnit for T where T: Copy + Display + PartialOrd + PartialEq
+ Add<Self, Output=Self> + Mul<Self, Output=Self>
+ Div<Self, Output=Self> + Rem<Self, Output=Self> {}
@ -121,6 +121,18 @@ pub trait PulsesPerQuaver<U: TimeUnit> {
{
self.sr() / self.pulses_per_second()
}
#[inline] fn format_beats (&self, pulse: U) -> String where U: TimeInteger {
let ppq = self.ppq();
let (beats, pulses) = if ppq > U::from(0) {
(pulse / ppq, pulse % ppq)
} else {
(U::from(0), U::from(0))
};
let bars = (beats / U::from(4)) + U::from(1);
let beats = (beats % U::from(4)) + U::from(1);
format!("{bars}.{beats}.{pulses:02}")
}
}
pub trait FramePosition<U: TimeUnit> {
@ -131,11 +143,22 @@ pub trait FramePosition<U: TimeUnit> {
pub trait PulsePosition<U: TimeUnit> {
fn pulse (&self) -> U;
fn set_pulse (&self, pulse: U);
#[inline] fn format_current_pulse (&self) -> String
where Self: PulsesPerQuaver<U>, U: TimeInteger
{
self.format_beats(self.pulse())
}
}
pub trait UsecPosition<U: TimeUnit> {
fn usec (&self) -> U;
fn set_usec (&self, usec: U);
#[inline] fn format_current_usec (&self) -> String where U: From<usize> {
let usecs = self.usec();
let (seconds, msecs) = (usecs / U::from(1000000), usecs / U::from(1000) % U::from(1000));
let (minutes, seconds) = (seconds / U::from(60), seconds % U::from(60));
format!("{minutes}:{seconds:02}:{msecs:03}")
}
}
pub trait LaunchSync<U: TimeUnit> {

View file

@ -165,18 +165,20 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
// track titles
let track_titles = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0))=>{
let name = track.name.read().unwrap();
let max_w = w.saturating_sub(1).min(name.len()).max(2);
let name = format!("{}", &name[0..max_w]);
let time1 = track.player.phrase.as_ref()
.map(|_|track.player.frames_since_start())
let name = track.name.read().unwrap();
let max_w = w.saturating_sub(1).min(name.len()).max(2);
let name = format!("{}", &name[0..max_w]);
let player = &track.player;
let clock = &player.clock;
let time1 = player.phrase.as_ref()
.map(|_|player.frames_since_start())
.flatten()
.map(|t|format!("{t:>}"))
.unwrap_or(String::from(""));
let time2 = track.player.next_phrase.as_ref()
.map(|(t, _)|format!("{:>}",
track.player.clock.samples_to_pulse(t.load(Ordering::Relaxed) as f64)
))
let time2 = player.next_phrase.as_ref()
.map(|(t, _)|format!("{:>}", clock.format_beats(
clock.samples_to_pulse(t.load(Ordering::Relaxed) as f64) as usize
)))
.unwrap_or(String::from(""));
col!(name, time1, time2)
.min_xy(w as u16, title_h)

View file

@ -51,6 +51,11 @@ impl PulsesPerQuaver<f64> for TransportTime {
#[inline] fn ppq (&self) -> f64 { self.timebase.ppq() }
#[inline] fn set_ppq (&self, ppq: f64) { self.timebase.set_ppq(ppq); }
}
impl PulsesPerQuaver<usize> for TransportTime {
const DEFAULT_PPQ: usize = Timebase::DEFAULT_PPQ as usize;
#[inline] fn ppq (&self) -> usize { self.timebase.ppq() as usize }
#[inline] fn set_ppq (&self, ppq: usize) { self.timebase.set_ppq(ppq as f64); }
}
impl FramePosition<usize> for TransportTime {
#[inline] fn sample (&self) -> usize { self.sample.load(Ordering::Relaxed) }
#[inline] fn set_sample (&self, sample: usize) { self.sample.store(sample, Ordering::Relaxed); }
@ -100,12 +105,6 @@ impl<E: Engine> TransportToolbar<E> {
}
}
}
pub fn bpm (&self) -> usize { self.clock.bpm() as usize }
pub fn ppq (&self) -> usize { self.clock.ppq() as usize }
pub fn pulse (&self) -> usize { self.clock.samples_to_pulse(self.clock.sample()as f64) as usize }
pub fn usecs (&self) -> usize { self.clock.samples_to_usec(self.clock.sample() as f64) as usize }
pub fn quant (&self) -> usize { self.clock.quant() }
pub fn sync (&self) -> usize { self.clock.sync() }
pub fn toggle_play (&mut self) -> Usually<()> {
let transport = self.transport.as_ref().unwrap();
let playing = self.clock.playing.read().unwrap().expect("1st sample has not been processed yet");

View file

@ -29,20 +29,13 @@ impl Content for TransportToolbar<Tui> {
//"QUANT ", ppq_to_name(self.quant as usize)
//})),
self.focus.wrap(self.focused, TransportToolbarFocus::Sync, &Outset::X(1u16, row! {
"SYNC ", pulses_to_name(self.sync() as usize)
"SYNC ", pulses_to_name(self.clock.sync() as usize)
}))
).align_w().fill_x(),
self.focus.wrap(self.focused, TransportToolbarFocus::Clock, &{
let pulse = self.clock.pulse();
let ppq = self.clock.ppq() as usize;
let usecs = self.clock.usec();
let (beats, pulses) = if ppq > 0 { (pulse / ppq, pulse % ppq) } else { (0, 0) };
let (bars, beats) = ((beats / 4) + 1, (beats % 4) + 1);
let (seconds, msecs) = (usecs / 1000000, usecs / 1000 % 1000);
let (minutes, seconds) = (seconds / 60, seconds % 60);
let time1 = format!("{bars}.{beats}.{pulses:02}");
let time2 = format!("{minutes}:{seconds:02}:{msecs:03}");
let time1 = self.clock.format_current_pulse();
let time2 = self.clock.format_current_usec();
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
}).align_e().fill_x(),