diff --git a/src/main.rs b/src/main.rs index e5c75ea5..c93f47f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,9 +78,6 @@ fn run_one (command: &cli::Command) -> Result<(), Box> { fn run_all () -> Result<(), Box> { let mut actions = vec![]; - actions.extend_from_slice(&transport::ACTIONS); - actions.extend_from_slice(&mixer::ACTIONS); - actions.extend_from_slice(&looper::ACTIONS); main_loop( &mut App { exited: false, @@ -92,23 +89,38 @@ fn run_all () -> Result<(), Box> { sequencer: sequencer::Sequencer::new()?, }, |state, stdout, mut offset| { + actions.clear(); + actions.extend_from_slice(&transport::ACTIONS); + match state.mode { + Mode::Transport => {}, + Mode::Mixer => actions.extend_from_slice(&mixer::ACTIONS), + Mode::Looper => actions.extend_from_slice(&looper::ACTIONS), + Mode::Sampler => actions.extend_from_slice(&sampler::ACTIONS), + Mode::Sequencer => actions.extend_from_slice(&sequencer::ACTIONS), + } + let (w, h) = render::render_toolbar_vertical(stdout, (offset.0, offset.1 + 1), &actions)?; offset.0 = offset.0 + w + 1; transport::render(&mut state.transport, stdout, (offset.0 + 1, 1))?; - render::render_box(stdout, offset.0, 0, 64, 4, + render::render_box(stdout, Some("Transport"), offset.0, 0, 70, 4, state.mode == Mode::Transport)?; mixer::render(&mut state.mixer, stdout, (offset.0 + 1, 6))?; - render::render_box(stdout, offset.0, 5, 64, 9, + render::render_box(stdout, Some("Mixer"), offset.0, 5, 70, 9, state.mode == Mode::Mixer)?; looper::render(&mut state.looper, stdout, (offset.0 + 1, 16))?; - render::render_box(stdout, offset.0, 15, 64, 6, + render::render_box(stdout, Some("Looper"), offset.0, 15, 70, 6, state.mode == Mode::Looper)?; - //sampler::render(sampler, stdout, (1, 46))?; - //sequencer::render(sequencer, stdout, (1, 66))?; + sampler::render(&mut state.sampler, stdout, (offset.0 + 1, 20))?; + render::render_box(stdout, Some("Sampler"), offset.0, 22, 70, 4, + state.mode == Mode::Sampler)?; + + sequencer::render(&mut state.sequencer, stdout, (offset.0 + 1, 25))?; + render::render_box(stdout, Some("Sequencer"), offset.0, 27, 70, 6, + state.mode == Mode::Sequencer)?; Ok(()) }, |state, event| { @@ -122,11 +134,15 @@ fn run_all () -> Result<(), Box> { KeyCode::Tab => match state.mode { Mode::Transport => state.mode = Mode::Mixer, Mode::Mixer => state.mode = Mode::Looper, - Mode::Looper => state.mode = Mode::Transport, + Mode::Looper => state.mode = Mode::Sampler, + Mode::Sampler => state.mode = Mode::Sequencer, + Mode::Sequencer => state.mode = Mode::Transport, _ => {} }, KeyCode::BackTab => match state.mode { - Mode::Transport => state.mode = Mode::Looper, + Mode::Transport => state.mode = Mode::Sequencer, + Mode::Sequencer => state.mode = Mode::Sampler, + Mode::Sampler => state.mode = Mode::Looper, Mode::Looper => state.mode = Mode::Mixer, Mode::Mixer => state.mode = Mode::Transport, _ => {} @@ -141,7 +157,12 @@ fn run_all () -> Result<(), Box> { Mode::Looper => looper::handle( &mut state.looper, event )?, - _ => {}, + Mode::Sampler => sampler::handle( + &mut state.sampler, event + )?, + Mode::Sequencer => sequencer::handle( + &mut state.sequencer, event + )?, } } } @@ -205,6 +226,7 @@ pub fn main_loop ( }); stdout.queue(Clear(ClearType::All))?.queue(Hide)?.flush()?; loop { + stdout.queue(Clear(ClearType::All))?; render(state, &mut stdout, (0, 0))?; stdout.flush()?; handle(state, &input.recv()?)?; diff --git a/src/render.rs b/src/render.rs index f1cd53c0..8074b79a 100644 --- a/src/render.rs +++ b/src/render.rs @@ -22,28 +22,39 @@ pub fn render_toolbar_vertical ( pub fn render_box ( stdout: &mut std::io::Stdout, + title: Option<&str>, x: u16, y: u16, - w: u16, + mut w: u16, h: u16, active: bool ) -> Result<(), Box> { - let edge: String = std::iter::repeat("─").take(w.saturating_sub(2) as usize).collect(); + if let Some(title) = title { + w = u16::max(w, title.len() as u16 + 4); + } let back: String = std::iter::repeat(" ").take(w.saturating_sub(2) as usize).collect(); if active { - stdout.queue(MoveTo(x, y))?.queue(PrintStyledContent(format!("┌{edge}┐").bold().yellow()))?; - for row in y+1..y+h { - stdout.queue(MoveTo(x, row))?.queue(PrintStyledContent("│".bold().yellow()))?; - stdout.queue(MoveTo(x+w-1, row))?.queue(PrintStyledContent("│".bold().yellow()))?; + let edge: String = std::iter::repeat("━").take(w.saturating_sub(2) as usize).collect(); + stdout.queue(MoveTo(x, y))?.queue(PrintStyledContent(format!("┏{edge}┓").bold().yellow()))?; + if let Some(title) = title { + stdout.queue(MoveTo(x+1, y))?.queue(PrintStyledContent(format!(" {title} ").bold().yellow()))?; } - stdout.queue(MoveTo(x, y+h))?.queue(PrintStyledContent(format!("└{edge}┘").bold().yellow()))?; + for row in y+1..y+h { + stdout.queue(MoveTo(x, row))?.queue(PrintStyledContent("┃".bold().yellow()))?; + stdout.queue(MoveTo(x+w-1, row))?.queue(PrintStyledContent("┃".bold().yellow()))?; + } + stdout.queue(MoveTo(x, y+h))?.queue(PrintStyledContent(format!("┗{edge}┛").bold().yellow()))?; } else { - stdout.queue(MoveTo(x, y))?.queue(Print(&format!("┌{edge}┐")))?; - for row in y+1..y+h { - stdout.queue(MoveTo(x, row))?.queue(Print("│"))?; - stdout.queue(MoveTo(x+w-1, row))?.queue(Print("│"))?; + let edge: String = std::iter::repeat("─").take(w.saturating_sub(2) as usize).collect(); + stdout.queue(MoveTo(x, y))?.queue(PrintStyledContent(format!("┌{edge}┐").grey().dim()))?; + if let Some(title) = title { + stdout.queue(MoveTo(x+1, y))?.queue(Print(format!(" {title} ")))?; } - stdout.queue(MoveTo(x, y+h))?.queue(Print(&format!("└{edge}┘")))?; + for row in y+1..y+h { + stdout.queue(MoveTo(x, row))?.queue(PrintStyledContent("│".grey().dim()))?; + stdout.queue(MoveTo(x+w-1, row))?.queue(PrintStyledContent("│".grey().dim()))?; + } + stdout.queue(MoveTo(x, y+h))?.queue(PrintStyledContent(format!("└{edge}┘").grey().dim()))?; } Ok(()) } diff --git a/src/sampler.rs b/src/sampler.rs index 0c630e4f..d2d4a9e6 100644 --- a/src/sampler.rs +++ b/src/sampler.rs @@ -6,7 +6,10 @@ pub use self::jack::*; pub use self::render::*; use crate::prelude::*; -pub const ACTIONS: [(&'static str, &'static str);0] = []; +pub const ACTIONS: [(&'static str, &'static str);2] = [ + ("Enter", "Play sample"), + ("Ins/Del", "Add/remove sample"), +]; pub struct Sampler { exited: bool, diff --git a/src/sampler/handle.rs b/src/sampler/handle.rs index 33c1b5ae..8190156b 100644 --- a/src/sampler/handle.rs +++ b/src/sampler/handle.rs @@ -3,7 +3,7 @@ use super::Sampler; pub fn handle ( state: &mut Sampler, - event: crossterm::event::Event + event: &Event ) -> Result<(), Box> { use crossterm::event::{Event, KeyCode, KeyModifiers}; if let Event::Key(event) = event { diff --git a/src/sampler/render.rs b/src/sampler/render.rs index e5856d47..8832990d 100644 --- a/src/sampler/render.rs +++ b/src/sampler/render.rs @@ -6,45 +6,21 @@ pub fn render ( stdout: &mut Stdout, offset: (u16, u16), ) -> Result<(), Box> { - render_toolbar(state, stdout, offset)?; render_table(state, stdout, offset)?; render_meters(state, stdout, offset)?; stdout.flush()?; Ok(()) } -fn render_toolbar ( - state: &mut Sampler, - stdout: &mut Stdout, - offset: (u16, u16), -) -> Result<(), Box> { - stdout - .queue(cursor::MoveTo(1, 0))? - .queue(PrintStyledContent("Arrows".yellow().bold()))? - .queue(cursor::MoveTo(1, 1))? - .queue(PrintStyledContent("Navigate".yellow()))? - - .queue(cursor::MoveTo(11, 0))? - .queue(PrintStyledContent("Enter".yellow().bold()))? - .queue(cursor::MoveTo(11, 1))? - .queue(PrintStyledContent("Play sample".yellow()))? - - .queue(cursor::MoveTo(24, 0))? - .queue(PrintStyledContent("Ins/Del".yellow().bold()))? - .queue(cursor::MoveTo(24, 1))? - .queue(PrintStyledContent("Add/remove sample".yellow()))?; - Ok(()) -} - fn render_table ( state: &mut Sampler, stdout: &mut Stdout, offset: (u16, u16), ) -> Result<(), Box> { - stdout - .queue(cursor::MoveTo(0, 3))? - .queue(Print( - " Name Rate Trigger Route"))?; + let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row); + stdout.queue(move_to(0, 3))?.queue( + Print(" Name Rate Trigger Route") + )?; for (i, sample) in state.samples.iter().enumerate() { let row = 4 + i as u16; for (j, (column, field)) in [ @@ -53,7 +29,7 @@ fn render_table ( (18, format!(" MIDI C10 36 ")), (33, format!(" {:.1}dB -> Output ", sample.gain)), ].into_iter().enumerate() { - stdout.queue(cursor::MoveTo(column, row))?; + stdout.queue(move_to(column, row))?; if state.selected_sample == i && state.selected_column == j { stdout.queue(PrintStyledContent(field.to_string().bold().reverse()))?; } else { @@ -69,11 +45,12 @@ fn render_meters ( stdout: &mut Stdout, offset: (u16, u16), ) -> Result<(), Box> { + let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row); for (i, sample) in state.samples.iter().enumerate() { let row = 4 + i as u16; - stdout - .queue(cursor::MoveTo(32, row))? - .queue(PrintStyledContent("▁".green()))?; + stdout.queue(move_to(32, row))?.queue( + PrintStyledContent("▁".green()) + )?; } Ok(()) } diff --git a/src/sequencer.rs b/src/sequencer.rs index bd0b0248..45ff8cef 100644 --- a/src/sequencer.rs +++ b/src/sequencer.rs @@ -6,13 +6,18 @@ pub use self::jack::*; pub use self::render::*; use crate::prelude::*; -pub const ACTIONS: [(&'static str, &'static str);0] = []; +pub const ACTIONS: [(&'static str, &'static str);4] = [ + ("+/-", "Zoom"), + ("A/D", "Add/delete note"), + ("]/[", "Duration"), + ("CapsLock", "Auto advance"), +]; pub struct Sequencer { exited: bool, jack: Jack, - cursor: (u16, u16), - duration: u16, + cursor: (u16, u16, u16), + sequence: Vec<()>, } impl Sequencer { @@ -30,10 +35,10 @@ impl Sequencer { ) )?; Ok(Self { - exited: false, - cursor: (0, 0), - duration: 0, + exited: false, + cursor: (0, 0, 0), jack, + sequence: vec![], }) } } diff --git a/src/sequencer/handle.rs b/src/sequencer/handle.rs index 6f22be8f..6fe93fa6 100644 --- a/src/sequencer/handle.rs +++ b/src/sequencer/handle.rs @@ -1,12 +1,10 @@ use crate::prelude::*; use super::Sequencer; -fn handle ( - state: &mut Sequencer, - event: crossterm::event::Event -) -> Result<(), Box> { - use crossterm::event::{Event, KeyCode, KeyModifiers}; +pub fn handle (state: &mut Sequencer,event: &Event) -> Result<(), Box> { + if let Event::Key(event) = event { + match event.code { KeyCode::Char('c') => { if event.modifiers == KeyModifiers::CONTROL { @@ -14,12 +12,12 @@ fn handle ( } }, KeyCode::Char('[') => { - if state.duration > 0 { - state.duration = state.duration - 1 + if state.cursor.2 > 0 { + state.cursor.2 = state.cursor.2 - 1 } }, KeyCode::Char(']') => { - state.duration = state.duration + 1 + state.cursor.2 = state.cursor.2 + 1 }, KeyCode::Down => { state.cursor.1 = if state.cursor.1 >= 3 { @@ -49,10 +47,13 @@ fn handle ( state.cursor.0 + 1 } }, + KeyCode::Char('A') => { + }, _ => { println!("{event:?}"); } } + } Ok(()) } diff --git a/src/sequencer/render.rs b/src/sequencer/render.rs index 1ae22ca8..225ee87d 100644 --- a/src/sequencer/render.rs +++ b/src/sequencer/render.rs @@ -6,68 +6,36 @@ pub fn render ( stdout: &mut Stdout, offset: (u16, u16) ) -> Result<(), Box> { - render_toolbar(state, stdout, offset)?; + //render_toolbar(state, stdout, offset)?; render_grid(state, stdout, offset)?; render_events(state, stdout, offset)?; Ok(()) } -fn render_toolbar ( - state: &mut Sequencer, - stdout: &mut Stdout, - offset: (u16, u16) -) -> Result<(), Box> { - stdout - .queue(MoveTo(1, 0))? - .queue(PrintStyledContent("Arrows".yellow().bold()))? - .queue(MoveTo(1, 1))? - .queue(PrintStyledContent("Navigate".yellow()))? - - .queue(MoveTo(12, 0))? - .queue(PrintStyledContent("+/-".yellow().bold()))? - .queue(MoveTo(12, 1))? - .queue(PrintStyledContent("Zoom".yellow()))? - - .queue(MoveTo(20, 0))? - .queue(PrintStyledContent("a/d".yellow().bold()))? - .queue(MoveTo(20, 1))? - .queue(PrintStyledContent("Add/delete".yellow()))? - - .queue(MoveTo(33, 0))? - .queue(PrintStyledContent("[/]".yellow().bold()))? - .queue(MoveTo(33, 1))? - .queue(PrintStyledContent("Duration".yellow()))? - - .queue(MoveTo(45, 0))? - .queue(PrintStyledContent("CapsLock".yellow().bold()))? - .queue(MoveTo(45, 1))? - .queue(PrintStyledContent("Auto advance".yellow()))?; - Ok(()) -} - fn render_grid ( state: &mut Sequencer, stdout: &mut Stdout, offset: (u16, u16) ) -> Result<(), Box> { + let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row); let bg = "┊···············┊···············┊···············┊···············"; - let cursor: String = if state.duration == 0 { + let cursor: String = if state.cursor.2 == 0 { "X".into() } else { std::iter::repeat("·") - .take(state.duration as usize) + .take(state.cursor.2 as usize) .collect() }; stdout - .queue(MoveTo(1, 3))?.queue(Print("1.1"))? - .queue(MoveTo(17, 3))?.queue(Print("1.2"))? - .queue(MoveTo(33, 3))?.queue(Print("1.3"))? - .queue(MoveTo(49, 3))?.queue(Print("1.4"))? - .queue(MoveTo(1, 4))?.queue(PrintStyledContent(bg.grey()))? - .queue(MoveTo(1, 5))?.queue(PrintStyledContent(bg.grey()))? - .queue(MoveTo(1, 6))?.queue(PrintStyledContent(bg.grey()))? - .queue(MoveTo(1, 7))?.queue(PrintStyledContent(bg.grey()))? - .queue(MoveTo(1 + state.cursor.0, 4 + state.cursor.1))? + .queue(move_to(1, 3))?.queue(Print("1.1"))? + .queue(move_to(17, 3))?.queue(Print("1.2"))? + .queue(move_to(33, 3))?.queue(Print("1.3"))? + .queue(move_to(49, 3))?.queue(Print("1.4"))? + .queue(move_to(1, 4))?.queue(PrintStyledContent(bg.grey()))? + .queue(move_to(1, 5))?.queue(PrintStyledContent(bg.grey()))? + .queue(move_to(1, 6))?.queue(PrintStyledContent(bg.grey()))? + .queue(move_to(1, 7))?.queue(PrintStyledContent(bg.grey()))? + .queue(move_to(1 + state.cursor.0, 4 + state.cursor.1))? .queue(PrintStyledContent(cursor.reverse()))?; Ok(()) }