show buffer size and latency

This commit is contained in:
🪞👃🪞 2024-11-27 01:30:40 +01:00
parent 763063f4ed
commit 51889d4b43
5 changed files with 33 additions and 14 deletions

View file

@ -47,17 +47,23 @@ pub struct ClockModel {
pub quant: Arc<Quantize>, pub quant: Arc<Quantize>,
/// Launch quantization factor /// Launch quantization factor
pub sync: Arc<LaunchSync>, pub sync: Arc<LaunchSync>,
/// Size of buffer in samples
pub chunk: Arc<AtomicUsize>,
} }
impl From<&Arc<Transport>> for ClockModel { impl From<&Arc<RwLock<JackClient>>> for ClockModel {
fn from (transport: &Arc<Transport>) -> Self { fn from (jack: &Arc<RwLock<JackClient>>) -> Self {
let jack = jack.read().unwrap();
let chunk = jack.client().buffer_size();
let transport = jack.client().transport();
Self { Self {
playing: RwLock::new(None).into(), playing: RwLock::new(None).into(),
started: RwLock::new(None).into(), started: RwLock::new(None).into(),
current: Instant::default().into(), current: Instant::default().into(),
quant: Arc::new(24.into()), quant: Arc::new(24.into()),
sync: Arc::new(384.into()), sync: Arc::new(384.into()),
transport: transport.clone(), transport: Arc::new(transport),
chunk: Arc::new((chunk as usize).into()),
} }
} }
} }
@ -137,11 +143,18 @@ pub struct ClockAudio<'a, T: HasClock>(pub &'a mut T);
impl<'a, T: HasClock> Audio for ClockAudio<'a, T> { impl<'a, T: HasClock> Audio for ClockAudio<'a, T> {
#[inline] fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { #[inline] fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let state = self.0.clock(); let state = self.0.clock();
let times = scope.cycle_times().unwrap();
let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times; // Update chunk size
let _chunk_size = scope.n_frames() as usize; state.chunk.store(scope.n_frames() as usize, Ordering::Relaxed);
// Query transport state
let transport = state.transport.query().unwrap(); let transport = state.transport.query().unwrap();
// FIXME duplicated
state.current.sample.set(transport.pos.frame() as f64); state.current.sample.set(transport.pos.frame() as f64);
// Update play/pause state and starting point
let CycleTimes { current_frames, current_usecs, .. } = scope.cycle_times().unwrap();
let mut playing = state.playing.write().unwrap(); let mut playing = state.playing.write().unwrap();
let mut started = state.started.write().unwrap(); let mut started = state.started.write().unwrap();
if *playing != Some(transport.state) { if *playing != Some(transport.state) {
@ -159,10 +172,13 @@ impl<'a, T: HasClock> Audio for ClockAudio<'a, T> {
if *playing == Some(TransportState::Stopped) { if *playing == Some(TransportState::Stopped) {
*started = None; *started = None;
} }
// FIXME duplicated
state.current.update_from_usec(match *started { state.current.update_from_usec(match *started {
Some((_, usecs)) => current_usecs as f64 - usecs as f64, Some((_, usecs)) => current_usecs as f64 - usecs as f64,
None => 0. None => 0.
}); });
Control::Continue Control::Continue
} }
} }

View file

@ -30,7 +30,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerTui {
fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> { fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
Ok(Self { Ok(Self {
jack: jack.clone(), jack: jack.clone(),
clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())), clock: ClockModel::from(jack),
phrases: PhraseListModel::default(), phrases: PhraseListModel::default(),
editor: PhraseEditorModel::default(), editor: PhraseEditorModel::default(),
selected: ArrangerSelection::Clip(0, 0), selected: ArrangerSelection::Clip(0, 0),

View file

@ -20,7 +20,7 @@ pub struct SequencerTui {
impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui { impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
type Error = Box<dyn std::error::Error>; type Error = Box<dyn std::error::Error>;
fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> { fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
let clock = ClockModel::from(&Arc::new(jack.read().unwrap().transport())); let clock = ClockModel::from(jack);
Ok(Self { Ok(Self {
jack: jack.clone(), jack: jack.clone(),
phrases: PhraseListModel::default(), phrases: PhraseListModel::default(),
@ -111,7 +111,7 @@ impl_focus!(SequencerTui SequencerFocus [
pub struct SequencerStatusBar { pub struct SequencerStatusBar {
pub(crate) cpu: Option<String>, pub(crate) cpu: Option<String>,
pub(crate) size: String, pub(crate) size: String,
pub(crate) sr: String, pub(crate) res: String,
pub(crate) mode: &'static str, pub(crate) mode: &'static str,
pub(crate) help: &'static [(&'static str, &'static str, &'static str)] pub(crate) help: &'static [(&'static str, &'static str, &'static str)]
} }
@ -130,10 +130,13 @@ impl From<&SequencerTui> for SequencerStatusBar {
fn from (state: &SequencerTui) -> Self { fn from (state: &SequencerTui) -> Self {
use SequencerFocus::*; use SequencerFocus::*;
use TransportFocus::*; use TransportFocus::*;
let samples = state.clock.chunk.load(Ordering::Relaxed);
let rate = state.clock.current.timebase.sr.get() as f64;
let buffer = samples as f64 / rate;
Self { Self {
cpu: state.perf.percentage().map(|cpu|format!(" {cpu:.01}% ")), cpu: state.perf.percentage().map(|cpu|format!("{cpu:.01}%")),
size: format!(" {}x{} ", state.size.w(), state.size.h()), size: format!("{}x{}│", state.size.w(), state.size.h()),
sr: format!(" {}Hz ", state.clock.current.timebase.sr.get()), res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.),
mode: match state.focused() { mode: match state.focused() {
Transport(focus) => match focus { Transport(focus) => match focus {
PlayPause => " PLAY/PAUSE ", PlayPause => " PLAY/PAUSE ",

View file

@ -25,7 +25,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for TransportTui {
fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> { fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
Ok(Self { Ok(Self {
jack: jack.clone(), jack: jack.clone(),
clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())), clock: ClockModel::from(jack),
size: Measure::new(), size: Measure::new(),
cursor: (0, 0), cursor: (0, 0),
focus: FocusState::Entered(TransportFocus::PlayPause) focus: FocusState::Entered(TransportFocus::PlayPause)

View file

@ -34,7 +34,7 @@ impl Content for SequencerStatusBar {
widget(&self.mode).bg(orange).fg(black).bold(true), widget(&self.mode).bg(orange).fg(black).bold(true),
row!( row!(
widget(&self.cpu).fg(orange), widget(&self.cpu).fg(orange),
widget(&self.sr).fg(orange), widget(&self.res).fg(orange),
widget(&self.size).fg(orange), widget(&self.size).fg(orange),
).align_se().fill_x() ).align_se().fill_x()
) )