feat: draw bpm and bbt

This commit is contained in:
🪞👃🪞 2024-06-26 00:56:07 +03:00
parent c06b9d16e2
commit b1df7bf4e6
3 changed files with 100 additions and 90 deletions

View file

@ -7,6 +7,7 @@ pub struct Launcher {
monitoring: bool,
recording: bool,
overdub: bool,
position: usize,
cursor: (usize, usize),
tracks: Vec<DynamicDevice<Sequencer>>,
chains: Vec<DynamicDevice<Chain>>,
@ -14,6 +15,7 @@ pub struct Launcher {
show_help: bool,
view: LauncherView,
}
#[derive(PartialEq)]
pub enum LauncherView {
Tracks,
Sequencer,
@ -49,6 +51,7 @@ impl Launcher {
overdub: true,
transport,
cursor: (1, 2),
position: 0,
scenes: vec![
Scene::new(&"Scene#01", &[Some(0), None, None, None]),
Scene::new(&"Scene#02", &[None, None, None, None]),
@ -126,16 +129,19 @@ impl Launcher {
}
impl DevicePorts for Launcher {}
pub fn process (state: &mut Launcher, _: &Client, _: &ProcessScope) -> Control {
state.playing = state.transport.query_state().unwrap();
let transport = state.transport.query().unwrap();
state.playing = transport.state;
state.position = transport.pos.frame() as usize;
Control::Continue
}
pub fn render (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let Rect { x, y, width, height } = area;
crate::device::sequencer::draw_timer(buf, x + width - 1, y, 0, 0, 0, 0);
crate::device::sequencer::draw_play_stop(buf, x + 1, y, &state.playing);
crate::device::sequencer::draw_rec(buf, x + 12, y, state.recording);
crate::device::sequencer::draw_mon(buf, x + 19, y, state.monitoring);
crate::device::sequencer::draw_dub(buf, x + 26, y, state.overdub);
draw_bpm(buf, x + 33, y, state.timebase.tempo());
draw_timer(buf, x + width - 1, y, &state.timebase, state.position);
let track_area = Rect { x: x, y: y+1, width, height: 22 };
let seq_area = Rect { x: x, y: y+22, width, height: 20 };
let chain_area = Rect { x: x, y: y+41, width, height: 21 };
@ -154,20 +160,28 @@ pub fn render (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect>
let style = Some(Style::default().green().dim());
let chain = &*state.chains[0].state();
let (_, plugins) = crate::device::chain::draw_as_row(chain, buf, chain_area, style)?;
match state.view {
LauncherView::Tracks => draw_box_styled(buf, track_area, style),
LauncherView::Sequencer => draw_box_styled(buf, seq_area, style),
LauncherView::Chains => draw_box_styled(buf, Rect { height: 18, ..chain_area }, style),
};
if state.view == LauncherView::Tracks {
draw_box_styled(buf, track_area, style);
}
draw_highlight(state, buf, &track_highlight, match state.view {
LauncherView::Tracks => Style::default().green().not_dim(),
_ => Style::default().green().dim()
});
if state.view == LauncherView::Chains {
draw_box_styled(buf, Rect { height: 18, ..chain_area }, style);
}
draw_highlight(state, buf, &Some(plugins[chain.focus]), match state.view {
LauncherView::Chains => Style::default().green().not_dim(),
_ => Style::default().green().dim()
});
if state.view == LauncherView::Sequencer {
draw_box_styled(buf, seq_area, style);
}
draw_sequencer(state, buf, seq_area.x, seq_area.y + 1, seq_area.width, seq_area.height - 2)?;
if state.show_help {
let style = Some(Style::default().bold().white().not_dim().on_black().italic());
let hide = "[Left/Right] Track [Up/Down] Scene [,/.] Value [F1] Toggle help ";
@ -175,6 +189,20 @@ pub fn render (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect>
}
Ok(area)
}
fn draw_bpm (buf: &mut Buffer, x: u16, y: u16, tempo: usize) {
let style = Style::default().not_dim();
"BPM"
.blit(buf, x, y, Some(style));
format!("{:03}.{:03}", tempo / 1000, tempo % 1000)
.blit(buf, x + 4, y, Some(style.bold()));
}
fn draw_timer (buf: &mut Buffer, x: u16, y: u16, timebase: &Arc<Timebase>, frame: usize) {
let tick = (frame as f64 / timebase.frames_per_tick()) as usize;
let (beats, ticks) = (tick / timebase.ppq(), tick % timebase.ppq());
let (bars, beats) = (beats / 4, beats % 4);
let timer = format!("{}.{}.{ticks:02}", bars + 1, beats + 1);
timer.blit(buf, x - timer.len() as u16, y, Some(Style::default().not_dim()));
}
fn draw_scenes (
state: &Launcher, buf: &mut Buffer, x: u16, y: u16,
) -> Rect {

View file

@ -131,7 +131,7 @@ impl Sequencer {
// Read from sequence into output buffer
if self.playing == TransportState::Rolling {
let frame = transport.pos.frame() as usize;
let quant = self.timebase.fpb() as usize * self.steps / self.resolution;
let quant = self.timebase.frames_per_beat() as usize * self.steps / self.resolution;
let ticks = self.timebase.frames_to_ticks(frame, frame + frames, quant);
for (time, tick) in ticks.iter() {
if let Some(events) = sequence.get(&(*tick as u32)) {
@ -235,13 +235,13 @@ fn render (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<Rect> {
let Rect { x, y, width, .. } = area;
let (time0, time1) = s.time_axis;
let (note0, note1) = s.note_axis;
let pos = s.transport.query().unwrap().pos;
let frame = pos.frame();
let usecs = s.timebase.frame_to_usec(frame as usize);
let usec_per_step = s.timebase.usec_per_step(s.resolution as usize);
let steps = usecs / usec_per_step;
let pos = s.transport.query().unwrap().pos;
let frame = pos.frame();
let usecs = s.timebase.frame_to_usec(frame as usize);
let ustep = s.timebase.usec_per_step(s.resolution as usize);
let steps = usecs / ustep;
let header = draw_header(s, buf, area, steps)?;
let piano = match s.mode {
let piano = match s.mode {
SequencerView::Tiny =>
Rect { x, y, width, height: 0 },
SequencerView::Compact =>
@ -273,7 +273,7 @@ pub fn draw_header (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) ->
let step = beat % s.steps;
let reps = s.steps / s.resolution;
let steps = s.steps % s.resolution;
draw_timer(buf, x + width - 2, y + 1, rep, step, reps, steps);
draw_timer(buf, x + width - 2, y + 1, &format!("{rep}.{step:02} / {reps}.{steps}"));
let style = Style::default().gray();
draw_play_stop(buf, x + 2, y + 1, &s.playing);
let separator = format!("{}", "-".repeat((area.width - 2).into()));
@ -285,11 +285,10 @@ pub fn draw_header (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) ->
Ok(Rect { x, y, width: area.width, height: 3 })
}
pub fn draw_timer (
buf: &mut Buffer, x: u16, y: u16, rep: usize, step: usize, reps: usize, steps: usize
buf: &mut Buffer, x: u16, y: u16, timer: &str
) {
let style = Style::default().gray();
let timer = format!("{rep}.{step:02} / {reps}.{steps}");
timer.blit(buf, x - timer.len() as u16, y, Some(style.bold().not_dim()));
let style = Some(Style::default().gray().bold().not_dim());
timer.blit(buf, x - timer.len() as u16, y, style);
}
pub fn draw_play_stop (buf: &mut Buffer, x: u16, y: u16, state: &TransportState) {
let style = Style::default().gray();
@ -554,13 +553,13 @@ fn quantize_prev (s: &mut Sequencer) -> Usually<bool> {
let mut s = sequencer.state.lock().unwrap();
s.rate = Hz(48000);
s.tempo = Tempo(240_000);
println!("F/S = {:.03}", s.fps());
println!("B/S = {:.03}", s.bps());
println!("F/B = {:.03}", s.fpb());
println!("T/B = {:.03}", s.tpb());
println!("F/T = {:.03}", s.fpt());
println!("F/L = {:.03}", s.fpl());
println!("T/L = {:.03}", s.tpl());
println!("F/S = {:.03}", s.frames_per_second());
println!("B/S = {:.03}", s.beats_per_secon());
println!("F/B = {:.03}", s.frames_per_beat());
println!("T/B = {:.03}", s.ticks_per_beat());
println!("F/T = {:.03}", s.frames_per_tick());
println!("F/L = {:.03}", s.frames_per_loop());
println!("T/L = {:.03}", s.ticks_per_loop());
let fpt = s.fpt();
let frames_per_chunk = 240;
let chunk = |chunk: usize| s.frames_to_ticks(