From 7f57465b3a2b3c4185364500bbd1dc71c63818dd Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 2 Jan 2025 11:55:36 +0100 Subject: [PATCH] new minimal transport bar --- src/arranger.rs | 3 +- src/groovebox.rs | 116 ++++++++--------- src/piano_h.rs | 68 +++++----- src/sequencer.rs | 5 +- src/transport.rs | 325 +++++++++-------------------------------------- 5 files changed, 141 insertions(+), 376 deletions(-) diff --git a/src/arranger.rs b/src/arranger.rs index d3dd38c7..803ae95a 100644 --- a/src/arranger.rs +++ b/src/arranger.rs @@ -101,7 +101,6 @@ impl ArrangerTui { } render!(Tui: (self: ArrangerTui) => { let play = PlayPause(self.clock.is_rolling()); - let transport = TransportView::new(self, Some(ItemPalette::from(TuiTheme::g(96))), true); let pool_size = if self.phrases.visible { self.splits[1] } else { 0 }; let with_pool = |x|Bsp::w(Fixed::x(pool_size, PoolView(&self.phrases)), x); let status = ArrangerStatus::from(self); @@ -117,7 +116,7 @@ render!(Tui: (self: ArrangerTui) => { ) }; with_size(with_status(with_editbar(with_pool(col!( - row!(play, transport), + TransportView(&self.clock), Fill::x(Fixed::y(20, arranger())), Fill::xy(&self.editor), ))))) diff --git a/src/groovebox.rs b/src/groovebox.rs index 35fe41f4..af42e397 100644 --- a/src/groovebox.rs +++ b/src/groovebox.rs @@ -28,34 +28,20 @@ impl Groovebox { audio_from: &[&[impl AsRef];2], audio_to: &[&[impl AsRef];2], ) -> Usually { - let sampler = crate::sampler::Sampler::new( - jack, &"sampler", midi_from, audio_from, audio_to - )?; - let mut player = crate::midi::MidiPlayer::new( - jack, &"sequencer", &midi_from, &midi_to - )?; + let sampler = crate::sampler::Sampler::new(jack, &"sampler", midi_from, audio_from, audio_to)?; + let mut player = crate::midi::MidiPlayer::new(jack, &"sequencer", &midi_from, &midi_to)?; jack.read().unwrap().client().connect_ports(&player.midi_outs[0], &sampler.midi_in)?; - //jack.connect_midi_from(&player.midi_ins[0], &midi_from)?; - //jack.connect_midi_from(&sampler.midi_in, &midi_from)?; - //jack.connect_midi_to(&player.midi_outs[0], &midi_to)?; - //jack.connect_audio_from(&sampler.audio_ins[0], &audio_from[0])?; - //jack.connect_audio_from(&sampler.audio_ins[1], &audio_from[1])?; - //jack.connect_audio_to(&sampler.audio_outs[0], &audio_to[0])?; - //jack.connect_audio_to(&sampler.audio_outs[1], &audio_to[1])?; - let phrase = Arc::new(RwLock::new(MidiClip::new( "New", true, 4 * player.clock.timebase.ppq.get() as usize, None, Some(ItemColor::random().into()) ))); player.play_phrase = Some((Moment::zero(&player.clock.timebase), Some(phrase.clone()))); - let pool = crate::pool::PoolModel::from(&phrase); - let editor = crate::midi::MidiEditor::from(&phrase); Ok(Self { - _jack: jack.clone(), player, - pool, - editor, sampler, + _jack: jack.clone(), + pool: crate::pool::PoolModel::from(&phrase), + editor: crate::midi::MidiEditor::from(&phrase), size: Measure::new(), midi_buf: vec![vec![];65536], note_buf: vec![], @@ -78,6 +64,7 @@ audio!(|self: Groovebox, client, scope|{ if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) { return Control::Quit } + // TODO move this to sampler: for RawMidi { time, bytes } in self.player.midi_ins[0].iter(scope) { if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() { match message { @@ -120,52 +107,51 @@ render!(Tui: (self: Groovebox) => { let color = self.player.play_phrase().as_ref() .and_then(|(_,p)|p.as_ref().map(|p|p.read().unwrap().color)) .clone(); - let transport = Fixed::y(3, Bsp::e( - PlayPause(self.clock().is_rolling()), - TransportView::new(self, color, true), - )); - let selector = Fixed::y(1, Bsp::e( - PhraseSelector::play_phrase(&self.player), - PhraseSelector::next_phrase(&self.player), - )); - let sampler = Tui::bg(TuiTheme::g(32), Align::w(Fixed::x(sampler_w, Fill::xy(col!( - Meters(self.sampler.input_meter.as_ref()), - GrooveboxSamples(self) - ))))); - let status = EditStatus(&self.sampler, &self.editor, note_pt, ()); - let pool = PoolView(&self.pool); - let with_pool = move|x|Bsp::w(Align::e(Fill::y(Fixed::x(pool_w, pool))), x); - Fill::xy(Bsp::a(&self.size, - Bsp::s(transport, - Bsp::n(status, - Bsp::n(selector, - with_pool(Fill::xy(sampler)))))))}); - -struct EditStatus<'a, T: Content>(&'a Sampler, &'a MidiEditor, usize, T); -impl<'a, T: Content> Content for EditStatus<'a, T> { - fn content (&self) -> impl Content { - Bsp::n(Fixed::y(9, col!( - row!( - self.0.mapped[self.2].as_ref().map(|sample|format!( - "Sample {}-{}", - sample.read().unwrap().start, - sample.read().unwrap().end, - )), - MidiEditStatus(&self.1), - ), - lay!( - Outer(Style::default().fg(TuiTheme::g(128))), - Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.0.recording { - SampleViewer(Some(sample.clone())) - } else if let Some(sample) = &self.0.mapped[self.2] { - SampleViewer(Some(sample.clone())) - } else { - SampleViewer(None) - })), - ), - )), &self.3) - } -} + Fill::xy(Bsp::b( + &self.size, + Bsp::s( + Fill::x(Fixed::y(3, Align::x(TransportView(&self.player.clock)))), + Bsp::s( + Fill::x(Fixed::y(1, Align::x(Bsp::e( + PhraseSelector::play_phrase(&self.player), + PhraseSelector::next_phrase(&self.player), + )))), + Bsp::n( + Fixed::y(9, col!( + Bsp::e( + self.sampler.mapped[note_pt].as_ref().map(|sample|format!( + "Sample {}-{}", + sample.read().unwrap().start, + sample.read().unwrap().end, + )), + MidiEditStatus(&self.editor), + ), + Bsp::a( + Outer(Style::default().fg(TuiTheme::g(128))), + Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.sampler.recording { + SampleViewer(Some(sample.clone())) + } else if let Some(sample) = &self.sampler.mapped[note_pt] { + SampleViewer(Some(sample.clone())) + } else { + SampleViewer(None) + })), + ), + )), + Bsp::w( + Align::e(Fill::y(Fixed::x(pool_w, PoolView(&self.pool)))), + Fill::xy(Bsp::e( + Align::w(Fixed::x(sampler_w, Tui::bg(TuiTheme::g(32), Fill::xy(col!( + Meters(self.sampler.input_meter.as_ref()), + GrooveboxSamples(self) + ))))), + Fill::xy(Align::c("kyp")) + )) + ) + ) + ) + ) + ) +)}); struct GrooveboxSamples<'a>(&'a Groovebox); render!(Tui: (self: GrooveboxSamples<'a>) => { diff --git a/src/piano_h.rs b/src/piano_h.rs index 157ecd6b..654ac785 100644 --- a/src/piano_h.rs +++ b/src/piano_h.rs @@ -1,14 +1,9 @@ use crate::*; use super::*; -mod piano_h_cursor; -use self::piano_h_cursor::*; - -mod piano_h_keys; -pub(crate) use self::piano_h_keys::*; - +mod piano_h_cursor; use self::piano_h_cursor::*; +mod piano_h_keys; pub(crate) use self::piano_h_keys::*; mod piano_h_notes; use self::piano_h_notes::*; - mod piano_h_time; use self::piano_h_time::*; pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator { @@ -59,41 +54,40 @@ render!(Tui: (self: PianoHorizontal) => { } else { (ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false) }; - let field = move|x, y|row!( - Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)), - Tui::fg_bg(color.lighter.rgb, color.dark.rgb, y), - ); + //let field = move|x, y|row!( + //Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)), + //Tui::fg_bg(color.lighter.rgb, color.dark.rgb, y), + //); let keys_width = 5; let keys = move||PianoHorizontalKeys(self); let timeline = move||PianoHorizontalTimeline(self); let notes = move||PianoHorizontalNotes(self); let cursor = move||PianoHorizontalCursor(self); - let border = Fill::xy(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb))); - let with_border = |x|lay!(border, Padding::xy(0, 0, x)); - with_border(lay!( - Push::x(0, row!( - //" ", - field("Edit:", name.to_string()), " ", - field("Length:", length.to_string()), " ", - field("Loop:", looped.to_string()) - )), - Padding::xy(0, 1, Fill::xy(Bsp::s( - Fixed::y(1, Bsp::e( - Fixed::x(self.keys_width, ""), - Fill::x(timeline()), - )), - Bsp::e( - Fixed::x(self.keys_width, keys()), - Fill::xy(lay!( - &self.size, - Fill::xy(lay!( - Fill::xy(notes()), - Fill::xy(cursor()), - )) - )), - ), - ))) - )) + Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)).enclose("kyp"); + //with_border(lay!( + //Push::x(0, row!( + ////" ", + //field("Edit:", name.to_string()), " ", + //field("Length:", length.to_string()), " ", + //field("Loop:", looped.to_string()) + //)), + //Padding::xy(0, 1, Fill::xy(Bsp::s( + //Fixed::y(1, Bsp::e( + //Fixed::x(self.keys_width, ""), + //Fill::x(timeline()), + //)), + //Bsp::e( + //Fixed::x(self.keys_width, keys()), + //Fill::xy(lay!( + //&self.size, + //Fill::xy(lay!( + //Fill::xy(notes()), + //Fill::xy(cursor()), + //)) + //)), + //), + //))) + //)) }); impl PianoHorizontal { diff --git a/src/sequencer.rs b/src/sequencer.rs index 8fbe0897..d70eea2a 100644 --- a/src/sequencer.rs +++ b/src/sequencer.rs @@ -56,10 +56,7 @@ render!(Tui: (self: SequencerTui) => { p.as_ref().map(|p|p.read().unwrap().color) ).flatten().clone(); - let toolbar = Tui::when(self.transport, row!( - PlayPause(self.clock.is_rolling()), - TransportView::new(self, color, true), - )); + let toolbar = Tui::when(self.transport, TransportView(&self.clock)); let play_queue = Tui::when(self.selectors, row!( PhraseSelector::play_phrase(&self.player), diff --git a/src/transport.rs b/src/transport.rs index 1055fe96..c91429e9 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -1,15 +1,14 @@ use crate::*; use ClockCommand::{Play, Pause, SetBpm, SetQuant, SetSync}; -use TransportCommand::{Focus, Clock}; use FocusCommand::{Next, Prev}; use KeyCode::{Enter, Left, Right, Char}; + /// Transport clock app. pub struct TransportTui { pub jack: Arc>, pub clock: ClockModel, pub size: Measure, pub cursor: (usize, usize), - pub focus: TransportFocus, pub color: ItemPalette, } from_jack!(|jack|TransportTui Self { @@ -17,16 +16,20 @@ from_jack!(|jack|TransportTui Self { clock: ClockModel::from(jack), size: Measure::new(), cursor: (0, 0), - focus: TransportFocus::PlayPause, color: ItemPalette::random(), }); has_clock!(|self: TransportTui|&self.clock); audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope)); handle!(|self: TransportTui, from|TransportCommand::execute_with_state(self, from)); -render!(Tui: (self: TransportTui) => Bsp::e( - PlayPause(self.clock.is_rolling()), - TransportView::new(self, Some(self.color), true) +render!(Tui: (self: TransportTui) => TransportView(&self.clock)); + +pub struct TransportView<'a>(pub &'a ClockModel); +render!(Tui: (self: TransportView<'a>) => row!( + BeatStats::new(self.0), " ", + PlayPause(self.0.is_rolling()), " ", + OutputStats::new(self.0), )); + pub struct PlayPause(pub bool); render!(Tui: (self: PlayPause) => Tui::bg( if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)}, @@ -42,127 +45,43 @@ impl std::fmt::Debug for TransportTui { .finish() } } -pub struct TransportView { - color: ItemPalette, - focused: bool, - sr: String, - chunk: String, - latency: String, - bpm: String, - ppq: String, - beat: String, - global_sample: String, - global_second: String, - started: bool, - current_sample: f64, - current_second: f64, + +pub struct BeatStats { bpm: String, beat: String, time: String, } +impl BeatStats { + fn new (clock: &ClockModel) -> Self { + let (beat, time) = clock.started.read().unwrap().as_ref().map(|started|{ + let current_usec = clock.global.usec.get() - started.usec.get(); + ( + clock.timebase.format_beats_1(clock.timebase.usecs_to_pulse(current_usec)), + format!("{:.3}s", current_usec/1000000.) + ) + }).unwrap_or_else(||("-.-.--".to_string(), "-.---s".to_string())); + Self { bpm: format!("{:.3}", clock.timebase.bpm.get()), beat, time } + } } -impl TransportView { - pub fn new (state: &impl HasClock, color: Option, focused: bool) -> Self { - let clock = state.clock(); - let rate = clock.timebase.sr.get(); - let chunk = clock.chunk.load(Relaxed); - let latency = chunk as f64 / rate * 1000.; - let sr = format!("{:.1}k", rate / 1000.0); - let bpm = format!("{:.3}", clock.timebase.bpm.get()); - let ppq = format!("{:.0}", clock.timebase.ppq.get()); - let chunk = format!("{chunk}"); - let latency = format!("{latency}"); - let color = color.unwrap_or(ItemPalette::from(TuiTheme::g(32))); - let ( - global_sample, global_second, current_sample, current_second, beat - ) = if let Some(started) = clock.started.read().unwrap().as_ref() { - let current_sample = (clock.global.sample.get() - started.sample.get())/1000.; - let current_usec = clock.global.usec.get() - started.usec.get(); - let current_second = current_usec/1000000.; - let global_sample = format!("{:.0}k", started.sample.get()/1000.); - let global_second = format!("{:.1}s", started.usec.get()/1000.); - let beat = clock.timebase.format_beats_1(clock.timebase.usecs_to_pulse(current_usec)); - (global_sample, global_second, current_sample, current_second, beat) - } else { - let global_sample = format!("{:.0}k", clock.global.sample.get()/1000.); - let global_second = format!("{:.1}s", clock.global.usec.get()/1000000.); - let current_sample = 0.0; - let current_second = 0.0; - let beat = format!("000.0.00"); - (global_sample, global_second, current_sample, current_second, beat) - }; +render!(Tui: (self: BeatStats) => col!( + Bsp::e(&self.bpm, " BPM"), Bsp::e("Beat ", &self.beat), Bsp::e("Time ", &self.time), +)); + +pub struct OutputStats { sample_rate: String, buffer_size: String, latency: String, } +impl OutputStats { + fn new (clock: &ClockModel) -> Self { + let rate = clock.timebase.sr.get(); + let chunk = clock.chunk.load(Relaxed); Self { - color, focused, sr, bpm, ppq, chunk, latency, started: false, - global_sample, global_second, current_sample, current_second, beat + sample_rate: format!("{:.1}Hz", rate), + buffer_size: format!("{chunk}"), + latency: format!("{}", chunk as f64 / rate * 1000.), } } } -render!(Tui: (self: TransportView) => { - let color = self.color; - let transport_field = move|label, value|row!( - Tui::fg_bg(color.lightest.rgb, color.base.rgb, Tui::bold(true, label)), - Tui::fg_bg(color.base.rgb, color.darkest.rgb, "▌"), - Tui::fg_bg(color.lightest.rgb, color.darkest.rgb, format!("{:>10}", value)), - Tui::fg_bg(color.darkest.rgb, color.base.rgb, "▌"), - ); - Fixed::x(40, Tui::bg(Color::Red, Bsp::e( - Tui::bg(Color::Green, Fixed::x(18, col!( - transport_field(" Beat", self.beat.clone()), - transport_field(" Time", format!("{:.1}s", self.current_second)), - transport_field(" BPM", self.bpm.clone()), - ))), - Tui::bg(Color::Blue, Fixed::x(18, col!( - transport_field(" Rate", format!("{}", self.sr)), - transport_field(" Chunk", format!("{}", self.chunk)), - transport_field(" Lag", format!("{:.3}ms", self.latency)), - ))), - ))) -}); -impl HasFocus for TransportTui { - type Item = TransportFocus; - fn focused (&self) -> Self::Item { - self.focus - } - fn set_focused (&mut self, to: Self::Item) { - self.focus = to - } -} -/// Which item of the transport toolbar is focused -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum TransportFocus { - Bpm, - Sync, - PlayPause, - Clock, - Quant, -} -impl FocusWrap for TransportFocus { - fn wrap <'a, W: Content> (self, focus: TransportFocus, content: &'a W) - -> impl Content + 'a - { - let focused = focus == self; - let corners = focused.then_some(CORNERS); - //let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50))); - lay!(corners, /*highlight,*/ content) - } -} -impl FocusWrap for Option { - fn wrap <'a, W: Content> (self, focus: TransportFocus, content: &'a W) - -> impl Content + 'a - { - let focused = Some(focus) == self; - let corners = focused.then_some(CORNERS); - //let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50))); - lay!(corners, /*highlight,*/ content) - } -} -pub trait TransportControl: HasClock + { - fn transport_focused (&self) -> Option; -} -impl TransportControl for TransportTui { - fn transport_focused (&self) -> Option { - Some(self.focus) - } -} +render!(Tui: (self: OutputStats) => col!( + Bsp::e(format!("{}", self.sample_rate), " sample rate"), + Bsp::e(format!("{}", self.buffer_size), " sample buffer"), + Bsp::e(format!("{:.3}ms", self.latency), " latency"), +)); #[derive(Clone, Debug, PartialEq)] pub enum TransportCommand { - Focus(FocusCommand), Clock(ClockCommand), } command!(|self:TransportCommand,state:TransportTui|match self { @@ -170,60 +89,26 @@ command!(|self:TransportCommand,state:TransportTui|match self { Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock), _ => unreachable!(), }); -//command!(|self:TransportFocus,state:TransportTui|{ - //if let FocusCommand::Set(to) = self { state.set_focused(to); } - //Ok(None) -//}); impl InputToCommand for TransportCommand { fn input_to_command (state: &TransportTui, input: &TuiIn) -> Option { - to_transport_command(state, input) - .or_else(||to_focus_command(input).map(TransportCommand::Focus)) + use TransportCommand::*; + Some(match input.event() { + key_pat!(Char(' ')) => Clock(if state.clock().is_stopped() { + Play(None) + } else { + Pause(None) + }), + key_pat!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() { + Play(Some(0)) + } else { + Pause(Some(0)) + }), + _ => return None + }) } } -pub fn to_transport_command (state: &T, input: &TuiIn) -> Option -where - T: TransportControl, - U: Into>, -{ - Some(match input.event() { - key_pat!(Left) => Focus(Prev), - key_pat!(Right) => Focus(Next), - key_pat!(Char(' ')) => Clock(if state.clock().is_stopped() { - Play(None) - } else { - Pause(None) - }), - key_pat!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() { - Play(Some(0)) - } else { - Pause(Some(0)) - }), - _ => match state.transport_focused().unwrap() { - TransportFocus::Bpm => to_bpm_command(input, state.clock().bpm().get())?, - TransportFocus::Quant => to_quant_command(input, &state.clock().quant)?, - TransportFocus::Sync => to_sync_command(input, &state.clock().sync)?, - TransportFocus::Clock => to_seek_command(input)?, - TransportFocus::PlayPause => match input.event() { - key_pat!(Enter) => Clock( - if state.clock().is_stopped() { - Play(None) - } else { - Pause(None) - } - ), - key_pat!(Shift-Enter) => Clock( - if state.clock().is_stopped() { - Play(Some(0)) - } else { - Pause(Some(0)) - } - ), - _ => return None, - }, - } - }) -} fn to_bpm_command (input: &TuiIn, bpm: f64) -> Option { + use TransportCommand::*; Some(match input.event() { key_pat!(Char(',')) => Clock(SetBpm(bpm - 1.0)), key_pat!(Char('.')) => Clock(SetBpm(bpm + 1.0)), @@ -233,6 +118,7 @@ fn to_bpm_command (input: &TuiIn, bpm: f64) -> Option { }) } fn to_quant_command (input: &TuiIn, quant: &Quantize) -> Option { + use TransportCommand::*; Some(match input.event() { key_pat!(Char(',')) => Clock(SetQuant(quant.prev())), key_pat!(Char('.')) => Clock(SetQuant(quant.next())), @@ -242,6 +128,7 @@ fn to_quant_command (input: &TuiIn, quant: &Quantize) -> Option Option { + use TransportCommand::*; Some(match input.event() { key_pat!(Char(',')) => Clock(SetSync(sync.prev())), key_pat!(Char('.')) => Clock(SetSync(sync.next())), @@ -251,6 +138,7 @@ fn to_sync_command (input: &TuiIn, sync: &LaunchSync) -> Option Option { + use TransportCommand::*; Some(match input.event() { key_pat!(Char(',')) => todo!("transport seek bar"), key_pat!(Char('.')) => todo!("transport seek bar"), @@ -259,102 +147,3 @@ fn to_seek_command (input: &TuiIn) -> Option { _ => return None, }) } - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//struct Field(&'static str, String); - -//render!(|self: Field|{ - //Tui::to_east("│", Tui::to_east( - //Tui::bold(true, self.0), - //Tui::bg(Color::Rgb(0, 0, 0), self.1.as_str()), - //)) -//}); - -//pub struct TransportView { - //pub(crate) state: Option, - //pub(crate) selected: Option, - //pub(crate) focused: bool, - //pub(crate) bpm: f64, - //pub(crate) sync: f64, - //pub(crate) quant: f64, - //pub(crate) beat: String, - //pub(crate) msu: String, -//} - ////)?; - ////match *state { - ////Some(TransportState::Rolling) => { - ////add(&row!( - ////"│", - ////TuiStyle::fg("▶ PLAYING", Color::Rgb(0, 255, 0)), - ////format!("│0 (0)"), - ////format!("│00m00s000u"), - ////format!("│00B 0b 00/00") - ////))?; - ////add(&row!("│Now ", row!( - ////format!("│0 (0)"), //sample(chunk) - ////format!("│00m00s000u"), //msu - ////format!("│00B 0b 00/00"), //bbt - ////)))?; - ////}, - ////_ => { - ////add(&row!("│", TuiStyle::fg("⏹ STOPPED", Color::Rgb(255, 128, 0))))?; - ////add(&"")?; - ////} - ////} - ////Ok(()) - ////}).fill_x().bg(Color::Rgb(40, 50, 30)) -////}); - -//impl<'a, T: HasClock> From<&'a T> for TransportView where Option: From<&'a T> { - //fn from (state: &'a T) -> Self { - //let selected = state.into(); - //Self { - //selected, - //focused: selected.is_some(), - //state: Some(state.clock().transport.query_state().unwrap()), - //bpm: state.clock().bpm().get(), - //sync: state.clock().sync.get(), - //quant: state.clock().quant.get(), - //beat: state.clock().playhead.format_beat(), - //msu: state.clock().playhead.usec.format_msu(), - //} - //} -//} - - //row!( - ////selected.wrap(TransportFocus::PlayPause, &play_pause.fixed_xy(10, 3)), - //row!( - //col!( - //Field("SR ", format!("192000")), - //Field("BUF ", format!("1024")), - //Field("LEN ", format!("21300")), - //Field("CPU ", format!("00.0%")) - //), - //col!( - //Field("PUL ", format!("000000000")), - //Field("PPQ ", format!("96")), - //Field("BBT ", format!("00B0b00p")) - //), - //col!( - //Field("SEC ", format!("000000.000")), - //Field("BPM ", format!("000.000")), - //Field("MSU ", format!("00m00s00u")) - //), - //), - //selected.wrap(TransportFocus::Bpm, &Margin::X(1u16, { - //row! { - //"BPM ", - //format!("{}.{:03}", *bpm as usize, (bpm * 1000.0) % 1000.0) - //} - //})), - //selected.wrap(TransportFocus::Sync, &Margin::X(1u16, row! { - //"SYNC ", pulses_to_name(*sync as usize) - //})), - //selected.wrap(TransportFocus::Quant, &Margin::X(1u16, row! { - //"QUANT ", pulses_to_name(*quant as usize) - //})), - //selected.wrap(TransportFocus::Clock, &{ - //row!("B" , beat.as_str(), " T", msu.as_str()).margin_x(1) - //}).align_e().fill_x(), - //).fill_x().bg(Color::Rgb(40, 50, 30))