wip: modularize once again

This commit is contained in:
🪞👃🪞 2025-01-08 18:50:15 +01:00
parent e08c9d1790
commit 3b6ff81dad
44 changed files with 984 additions and 913 deletions

View file

@ -1,137 +0,0 @@
use crate::*;
use ClockCommand::{Play, Pause, SetBpm, SetQuant, SetSync};
use FocusCommand::{Next, Prev};
use KeyCode::{Enter, Left, Right, Char};
/// Transport clock app.
pub struct TransportTui {
pub jack: Arc<RwLock<JackConnection>>,
pub clock: Clock,
}
has_clock!(|self: TransportTui|&self.clock);
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
render!(TuiOut: (self: TransportTui) => TransportView {
compact: false,
clock: &self.clock
});
impl TransportTui {
pub fn new (jack: &Arc<RwLock<JackConnection>>) -> Usually<Self> {
Ok(Self { jack: jack.clone(), clock: Clock::from(jack) })
}
}
pub struct TransportView<'a> { pub compact: bool, pub clock: &'a Clock }
impl<'a> TransportView<'a> {
pub fn new (compact: bool, clock: &'a Clock) -> Self {
Self { compact, clock }
}
}
render!(TuiOut: (self: TransportView<'a>) => Outer(
Style::default().fg(TuiTheme::g(255))
).enclose(row!(
OutputStats::new(self.compact, self.clock),
" ",
PlayPause { compact: false, playing: self.clock.is_rolling() },
" ",
BeatStats::new(self.compact, self.clock),
)));
pub struct PlayPause { pub compact: bool, pub playing: bool }
render!(TuiOut: (self: PlayPause) => Tui::bg(
if self.playing{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
Either(self.compact,
Thunk::new(||Fixed::x(9, Either(self.playing,
Tui::fg(Color::Rgb(0, 255, 0), " PLAYING "),
Tui::fg(Color::Rgb(255, 128, 0), " STOPPED ")))),
Thunk::new(||Fixed::x(5, Either(self.playing,
Tui::fg(Color::Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
Tui::fg(Color::Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))))));
pub struct BeatStats { compact: bool, bpm: Arc<str>, beat: Arc<str>, time: Arc<str>, }
impl BeatStats {
fn new (compact: bool, clock: &Clock) -> Self {
let bpm = format!("{:.3}", clock.timebase.bpm.get()).into();
let (beat, time) = if let Some(started) = clock.started.read().unwrap().as_ref() {
let now = clock.global.usec.get() - started.usec.get();
(
clock.timebase.format_beats_1(clock.timebase.usecs_to_pulse(now)).into(),
format!("{:.3}s", now/1000000.).into()
)
} else {
("-.-.--".to_string().into(), "-.---s".to_string().into())
};
Self { compact, bpm, beat, time }
}
}
render!(TuiOut: (self: BeatStats) => Either(self.compact,
row!(
FieldV(TuiTheme::g(128).into(), "BPM", &self.bpm),
FieldV(TuiTheme::g(128).into(), "Beat", &self.beat),
FieldV(TuiTheme::g(128).into(), "Time", &self.time),
),
col!(
Bsp::e(Tui::fg(TuiTheme::g(255), &self.bpm), " BPM"),
Bsp::e("Beat ", Tui::fg(TuiTheme::g(255), &self.beat)),
Bsp::e("Time ", Tui::fg(TuiTheme::g(255), &self.time)),
)));
pub struct OutputStats { compact: bool, sample_rate: Arc<str>, buffer_size: Arc<str>, latency: Arc<str>, }
impl OutputStats {
fn new (compact: bool, clock: &Clock) -> Self {
let rate = clock.timebase.sr.get();
let chunk = clock.chunk.load(Relaxed);
Self {
compact,
sample_rate: if compact {
format!("{:.1}kHz", rate / 1000.)
} else {
format!("{:.0}Hz", rate)
}.into(),
buffer_size: format!("{chunk}").into(),
latency: format!("{:.1}ms", chunk as f64 / rate * 1000.).into(),
}
}
}
render!(TuiOut: (self: OutputStats) => Either(self.compact,
row!(
FieldV(TuiTheme::g(128).into(), "SR", &self.sample_rate),
FieldV(TuiTheme::g(128).into(), "Buf", &self.buffer_size),
FieldV(TuiTheme::g(128).into(), "Lat", &self.latency),
),
col!(
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", self.sample_rate)), " sample rate"),
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", self.buffer_size)), " sample buffer"),
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{:.3}ms", self.latency)), " latency"),
)));
handle!(TuiIn: |self: TransportTui, input|ClockCommand::execute_with_state(self, input.event()));
keymap!(TRANSPORT_KEYS = |state: TransportTui, input: Event| ClockCommand {
key(Char(' ')) =>
if state.clock().is_stopped() { Play(None) } else { Pause(None) },
shift(key(Char(' '))) =>
if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
});
// TODO:
//keymap!(TRANSPORT_BPM_KEYS = |state: Clock, input: Event| ClockCommand {
//key(Char(',')) => SetBpm(state.bpm().get() - 1.0),
//key(Char('.')) => SetBpm(state.bpm().get() + 1.0),
//key(Char('<')) => SetBpm(state.bpm().get() - 0.001),
//key(Char('>')) => SetBpm(state.bpm().get() + 0.001),
//});
//keymap!(TRANSPORT_QUANT_KEYS = |state: Clock, input: Event| ClockCommand {
//key(Char(',')) => SetQuant(state.quant.prev()),
//key(Char('.')) => SetQuant(state.quant.next()),
//key(Char('<')) => SetQuant(state.quant.prev()),
//key(Char('>')) => SetQuant(state.quant.next()),
//});
//keymap!(TRANSPORT_SYNC_KEYS = |sync: Clock, input: Event | ClockCommand {
//key(Char(',')) => SetSync(state.sync.prev()),
//key(Char('.')) => SetSync(state.sync.next()),
//key(Char('<')) => SetSync(state.sync.prev()),
//key(Char('>')) => SetSync(state.sync.next()),
//});
//keymap!(TRANSPORT_SEEK_KEYS = |state: Clock, input: Event| ClockCommand {
//key(Char(',')) => todo!("transport seek bar"),
//key(Char('.')) => todo!("transport seek bar"),
//key(Char('<')) => todo!("transport seek beat"),
//key(Char('>')) => todo!("transport seek beat"),
//});