fix time trait usage

This commit is contained in:
🪞👃🪞 2024-11-01 15:27:06 +02:00
parent dc38fd3d52
commit 799228e366
7 changed files with 36 additions and 47 deletions

View file

@ -12,8 +12,8 @@ pub const DEFAULT_PPQ: f64 = 96.0;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TimeUnit(AtomicF64); pub struct TimeUnit(AtomicF64);
impl TimeUnit { impl TimeUnit {
fn get (&self) -> f64 { self.0.load(Ordering::Relaxed) } pub fn get (&self) -> f64 { self.0.load(Ordering::Relaxed) }
fn set (&self, value: f64) { self.0.store(value, Ordering::Relaxed) } pub fn set (&self, value: f64) { self.0.store(value, Ordering::Relaxed) }
} }
/// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat) /// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat)
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -274,7 +274,7 @@ pub trait LaunchSync {
} }
} }
/// Something that defines note quantization /// Something that defines note quantization
pub trait Quantize<T> { fn quant (&self) -> &TimeUnit; } pub trait Quantize { fn quant (&self) -> &TimeUnit; }
/// (pulses, name), assuming 96 PPQ /// (pulses, name), assuming 96 PPQ
pub const NOTE_DURATIONS: [(usize, &str);26] = [ pub const NOTE_DURATIONS: [(usize, &str);26] = [
(1, "1/384"), (1, "1/384"),

View file

@ -400,14 +400,14 @@ impl PhrasePlayer {
} }
pub fn samples_since_start (&self) -> Option<usize> { pub fn samples_since_start (&self) -> Option<usize> {
self.phrase.as_ref() self.phrase.as_ref()
.map(|(started,_)|started.sample()) .map(|(started,_)|started.sample().get())
.map(|started|started - self.clock.instant.sample()) .map(|started|(started - self.clock.instant.sample().get()) as usize)
} }
pub fn playing_phrase (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> { pub fn playing_phrase (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
if let ( if let (
Some(TransportState::Rolling), Some((started, Some(ref phrase))) Some(TransportState::Rolling), Some((started, Some(ref phrase)))
) = (*self.clock.playing.read().unwrap(), &self.phrase) { ) = (*self.clock.playing.read().unwrap(), &self.phrase) {
Some((started.sample(), phrase.clone())) Some((started.sample().get() as usize, phrase.clone()))
} else { } else {
None None
} }

View file

@ -18,7 +18,7 @@ impl Audio for PhrasePlayer {
self.reset_midi_out_buf(false /* FIXME where did force-reset come from? */); self.reset_midi_out_buf(false /* FIXME where did force-reset come from? */);
} }
let has_midi_inputs = self.has_midi_inputs(); let has_midi_inputs = self.has_midi_inputs();
let quant = self.clock.quant(); let quant = self.clock.quant().get();
if let Some((start_frame, phrase)) = self.playing_phrase() { if let Some((start_frame, phrase)) = self.playing_phrase() {
// Write chunk of phrase to output // Write chunk of phrase to output
phrase.read().map(|phrase|{ phrase.read().map(|phrase|{
@ -58,10 +58,8 @@ impl Audio for PhrasePlayer {
let pulse = self.clock.timebase.samples_to_pulse( let pulse = self.clock.timebase.samples_to_pulse(
(frame0 + frame - start_frame) as f64 (frame0 + frame - start_frame) as f64
); );
let quantized = ( let quantized = (pulse / quant).round() * quant;
pulse / quant as f64 let looped = quantized as usize % length;
).round() as usize * quant;
let looped = quantized % length;
looped looped
}, message); }, message);
} }

View file

@ -5,24 +5,21 @@ pub struct TransportTime {
pub timebase: Arc<Timebase>, pub timebase: Arc<Timebase>,
/// Current moment in time /// Current moment in time
pub instant: Instant, pub instant: Instant,
/// Note quantization factor
pub quant: TimeUnit,
/// Launch quantization factor
pub sync: TimeUnit,
/// Playback state /// Playback state
pub playing: RwLock<Option<TransportState>>, pub playing: RwLock<Option<TransportState>>,
/// Note quantization factor
pub quant: AtomicUsize,
/// Launch quantization factor
pub sync: AtomicUsize,
} }
impl PulsePosition<usize> for TransportTime { impl PulsePosition for TransportTime {
#[inline] fn pulse (&self) -> usize { self.instant.pulse() } #[inline] fn pulse (&self) -> &TimeUnit { self.instant.pulse() }
#[inline] fn set_pulse (&self, usec: usize) { self.instant.set_pulse(usec); }
} }
impl Quantize<usize> for TransportTime { impl Quantize for TransportTime {
#[inline] fn quant (&self) -> usize { self.quant.load(Ordering::Relaxed) } #[inline] fn quant (&self) -> &TimeUnit { &self.quant }
#[inline] fn set_quant (&self, quant: usize) { self.quant.store(quant, Ordering::Relaxed); }
} }
impl LaunchSync<usize> for TransportTime { impl LaunchSync for TransportTime {
#[inline] fn sync (&self) -> usize { self.sync.load(Ordering::Relaxed) } #[inline] fn sync (&self) -> &TimeUnit { &self.sync }
#[inline] fn set_sync (&self, sync: usize) { self.sync.store(sync, Ordering::Relaxed); }
} }
/// Stores and displays time-related state. /// Stores and displays time-related state.
pub struct TransportToolbar<E: Engine> { pub struct TransportToolbar<E: Engine> {
@ -65,7 +62,7 @@ impl<E: Engine> TransportToolbar<E> {
Arc::new(TransportTime { Arc::new(TransportTime {
playing: Some(TransportState::Stopped).into(), playing: Some(TransportState::Stopped).into(),
quant: 24.into(), quant: 24.into(),
sync: (timebase.ppq() as usize * 4).into(), sync: (timebase.ppq().get() * 4.).into(),
instant: Instant::default(), instant: Instant::default(),
timebase: timebase.into(), timebase: timebase.into(),
}) })

View file

@ -24,36 +24,30 @@ impl TransportToolbar<Tui> {
Ok(Some(true)) Ok(Some(true))
} }
fn handle_bpm (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle_bpm (&mut self, from: &TuiInput) -> Perhaps<bool> {
let bpm = self.clock.timebase.bpm(); let bpm = self.clock.timebase.bpm().get();
match from.event() { match from.event() {
key!(KeyCode::Char(',')) => { self.clock.timebase.set_bpm(bpm - 1.0); }, key!(KeyCode::Char(',')) => { self.clock.timebase.bpm.set(bpm - 1.0); },
key!(KeyCode::Char('.')) => { self.clock.timebase.set_bpm(bpm + 1.0); }, key!(KeyCode::Char('.')) => { self.clock.timebase.bpm.set(bpm + 1.0); },
key!(KeyCode::Char('<')) => { self.clock.timebase.set_bpm(bpm - 0.001); }, key!(KeyCode::Char('<')) => { self.clock.timebase.bpm.set(bpm - 0.001); },
key!(KeyCode::Char('>')) => { self.clock.timebase.set_bpm(bpm + 0.001); }, key!(KeyCode::Char('>')) => { self.clock.timebase.bpm.set(bpm + 0.001); },
_ => return Ok(None) _ => return Ok(None)
} }
Ok(Some(true)) Ok(Some(true))
} }
fn handle_quant (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle_quant (&mut self, from: &TuiInput) -> Perhaps<bool> {
let quant = self.clock.quant().get() as usize;
match from.event() { match from.event() {
key!(KeyCode::Char(',')) => { key!(KeyCode::Char(',')) => { self.clock.quant.set(prev_note_length(quant) as f64); },
self.clock.set_quant(prev_note_length(self.clock.quant())); key!(KeyCode::Char('.')) => { self.clock.quant.set(next_note_length(quant) as f64); },
},
key!(KeyCode::Char('.')) => {
self.clock.set_quant(next_note_length(self.clock.quant()));
},
_ => return Ok(None) _ => return Ok(None)
} }
return Ok(Some(true)) return Ok(Some(true))
} }
fn handle_sync (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle_sync (&mut self, from: &TuiInput) -> Perhaps<bool> {
let sync = self.clock.sync().get() as usize;
match from.event() { match from.event() {
key!(KeyCode::Char(',')) => { key!(KeyCode::Char(',')) => { self.clock.quant.set(prev_note_length(sync) as f64); },
self.clock.set_quant(prev_note_length(self.clock.sync())); key!(KeyCode::Char('.')) => { self.clock.quant.set(next_note_length(sync) as f64); },
},
key!(KeyCode::Char('.')) => {
self.clock.set_quant(next_note_length(self.clock.sync()));
},
_ => return Ok(None) _ => return Ok(None)
} }
return Ok(Some(true)) return Ok(Some(true))

View file

@ -5,7 +5,7 @@ impl<E: Engine> Audio for TransportToolbar<E> {
let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times; let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times;
let _chunk_size = scope.n_frames() as usize; let _chunk_size = scope.n_frames() as usize;
let transport = self.transport.as_ref().unwrap().query().unwrap(); let transport = self.transport.as_ref().unwrap().query().unwrap();
self.clock.instant.set_sample(transport.pos.frame() as usize); self.clock.instant.sample.set(transport.pos.frame() as f64);
if *self.clock.playing.read().unwrap() != Some(transport.state) { if *self.clock.playing.read().unwrap() != Some(transport.state) {
self.started = match transport.state { self.started = match transport.state {
TransportState::Rolling => Some((current_frames as usize, current_usecs as usize)), TransportState::Rolling => Some((current_frames as usize, current_usecs as usize)),
@ -18,8 +18,8 @@ impl<E: Engine> Audio for TransportToolbar<E> {
self.started = None; self.started = None;
} }
self.clock.instant.update_from_usec(match self.started { self.clock.instant.update_from_usec(match self.started {
Some((_, usecs)) => current_usecs as usize - usecs, Some((_, usecs)) => current_usecs as f64 - usecs as f64,
None => 0 None => 0.
}); });
Control::Continue Control::Continue
} }

View file

@ -20,14 +20,14 @@ impl Content for TransportToolbar<Tui> {
row!( row!(
self.focus.wrap(self.focused, TransportToolbarFocus::Bpm, &Outset::X(1u16, { self.focus.wrap(self.focused, TransportToolbarFocus::Bpm, &Outset::X(1u16, {
let bpm = self.clock.timebase.bpm(); let bpm = self.clock.timebase.bpm().get();
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) } row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
})), })),
//let quant = self.focus.wrap(self.focused, TransportToolbarFocus::Quant, &Outset::X(1u16, row! { //let quant = self.focus.wrap(self.focused, TransportToolbarFocus::Quant, &Outset::X(1u16, row! {
//"QUANT ", ppq_to_name(self.quant as usize) //"QUANT ", ppq_to_name(self.quant as usize)
//})), //})),
self.focus.wrap(self.focused, TransportToolbarFocus::Sync, &Outset::X(1u16, row! { self.focus.wrap(self.focused, TransportToolbarFocus::Sync, &Outset::X(1u16, row! {
"SYNC ", pulses_to_name(self.clock.sync() as usize) "SYNC ", pulses_to_name(self.clock.sync().get() as usize)
})) }))
).align_w().fill_x(), ).align_w().fill_x(),