advance play cursor in sequencer

This commit is contained in:
🪞👃🪞 2024-06-03 06:51:53 +03:00
parent 4fd208d53f
commit 7c1dc9ce9b
9 changed files with 53 additions and 37 deletions

View file

@ -101,7 +101,7 @@ impl Engine {
stdout
.queue(crossterm::terminal::EnterAlternateScreen)?
.flush()?;
let sleep = std::time::Duration::from_millis(16);
let sleep = std::time::Duration::from_millis(20);
loop {
stdout
.queue(crossterm::terminal::BeginSynchronizedUpdate)?
@ -122,7 +122,7 @@ impl Engine {
crossterm::terminal::disable_raw_mode()?;
break
}
std::thread::sleep(sleep);
//std::thread::sleep(sleep);
}
Ok(())
}

View file

@ -12,7 +12,6 @@ pub fn render (
.queue(move_to(0, 1))?.queue(PrintStyledContent(" Metronome [ ] ████ Track 1".bold()))?
.queue(move_to(0, 2))?.queue(PrintStyledContent(" Loop 1 [ ] ████ Track 1".bold()))?
.queue(move_to(0, 3))?.queue(PrintStyledContent(" Loop 2 [ ] ████████ Track 2".bold()))?
.queue(move_to(0, 4))?.queue(PrintStyledContent(" Loop 3 [ ] ████████ Track 3".bold()))?
.flush()?;
.queue(move_to(0, 4))?.queue(PrintStyledContent(" Loop 3 [ ] ████████ Track 3".bold()))?;
Ok(())
}

View file

@ -72,7 +72,7 @@ fn run_one (command: &cli::Command) -> Result<(), Box<dyn Error>> {
),
cli::Command::Sequencer => engine.run(
&mut sequencer::Sequencer::new()?,
&mut sequencer::Sequencer::new(engine.jack_client.as_client())?,
|state, stdout, mut offset| {
let (w, h) = render::render_toolbar_vertical(stdout, offset, &sequencer::ACTIONS)?;
offset.0 = offset.0 + w + 2;
@ -122,10 +122,10 @@ fn run_all () -> Result<(), Box<dyn Error>> {
exited: false,
mode: Mode::Sequencer,
transport: transport::Transport::new(engine.jack_client.as_client())?,
sequencer: sequencer::Sequencer::new(engine.jack_client.as_client())?,
mixer: mixer::Mixer::new()?,
looper: looper::Looper::new()?,
sampler: sampler::Sampler::new()?,
sequencer: sequencer::Sequencer::new()?,
};
let render = |state: &mut App, stdout: &mut Stdout, mut offset: (u16, u16)| {

View file

@ -8,7 +8,6 @@ pub fn render (
) -> Result<(), Box<dyn Error>> {
render_table(state, stdout, offset)?;
render_meters(state, stdout, offset)?;
stdout.flush()?;
Ok(())
}

View file

@ -8,7 +8,6 @@ pub fn render (
) -> Result<(), Box<dyn Error>> {
render_table(state, stdout, offset)?;
render_meters(state, stdout, offset)?;
stdout.flush()?;
Ok(())
}

View file

@ -14,10 +14,12 @@ pub const ACTIONS: [(&'static str, &'static str);4] = [
];
pub struct Sequencer {
exited: bool,
jack: Jack<Notifications>,
cursor: (u16, u16, u16),
sequence: Vec<Vec<Option<Event>>>,
exited: bool,
cursor: (u16, u16, u16),
sequence: Vec<Vec<Option<Event>>>,
transport: ::jack::Transport,
bpm: f64,
timesig: (f32, f32),
}
#[derive(Clone)]
@ -27,24 +29,15 @@ pub enum Event {
}
impl Sequencer {
pub fn new () -> Result<Self, Box<dyn Error>> {
let (client, status) = Client::new(
"bloop-sequencer",
ClientOptions::NO_START_SERVER
)?;
let jack = client.activate_async(
Notifications,
ClosureProcessHandler::new(Box::new(
move |_: &Client, _: &ProcessScope| -> Control {
Control::Continue
}) as Box<dyn FnMut(&Client, &ProcessScope)->Control + Send>
)
)?;
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
let transport = client.transport();
Ok(Self {
exited: false,
cursor: (0, 0, 0),
jack,
transport,
sequence: vec![vec![None;64];4],
bpm: 120.0,
timesig: (4.0, 4.0)
})
}
}

View file

@ -18,7 +18,6 @@ fn render_grid (
offset: (u16, u16)
) -> Result<(), Box<dyn Error>> {
let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row);
let bg = "┊···············┊···············┊···············┊···············";
let cursor: String = if state.cursor.2 == 0 {
"".into()
} else {
@ -26,6 +25,17 @@ fn render_grid (
.take(state.cursor.2 as usize)
.collect()
};
let transport = state.transport.query()?;
let frame = transport.pos.frame();
let rate = transport.pos.frame_rate().unwrap();
let second = (frame as f64) / (rate as f64);
let minute = second / 60f64;
let bpm = 120f64;
let div = 4;
let beats = minute * bpm;
let bars = beats as u32 / div as u32;
let beat = beats as u32 % div as u32 + 1;
let beat_sub = beats % 1.0;
stdout
.queue(move_to(1, 3))?.queue(Print("1.1"))?
.queue(move_to(17, 3))?.queue(Print("1.2"))?
@ -33,14 +43,23 @@ fn render_grid (
.queue(move_to(49, 3))?.queue(Print("1.4"))?;
for (index, row) in state.sequence.iter().enumerate() {
let y = index as u16 + 4;
stdout.queue(move_to(1, y))?.queue(
PrintStyledContent(bg.grey())
)?;
for (index, step) in row.iter().enumerate() {
if step.is_some() {
let x = index as u16 + 1;
stdout.queue(move_to(x, y))?.queue(
PrintStyledContent("X".white().bold())
for x in 0u16..64 {
let bg = if x as u32 == (beat - 1) * 16 + (beat_sub * 16.0) as u32 {
crossterm::style::Color::Black
} else {
crossterm::style::Color::Reset
};
if let Some(step) = &row[x as usize] {
stdout.queue(move_to(1 + x, y))?.queue(
PrintStyledContent("X".white().bold().on(bg))
)?;
} else if x % 16 == 0 {
stdout.queue(move_to(1 + x, y))?.queue(
PrintStyledContent("".grey().on(bg))
)?;
} else {
stdout.queue(move_to(1 + x, y))?.queue(
PrintStyledContent("·".grey().on(bg))
)?;
}
}

View file

@ -16,14 +16,19 @@ pub struct Transport {
exited: bool,
title: String,
transport: ::jack::Transport,
bpm: f64,
timesig: (f32, f32),
}
impl Transport {
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
let transport = client.transport();
Ok(Self {
exited: false,
title: String::from("Untitled project"),
transport: client.transport(),
bpm: 93.0,
timesig: (4.0, 4.0),
transport,
})
}

View file

@ -16,7 +16,9 @@ pub fn render (
if let Ok(position) = state.transport.query() {
let frame = position.pos.frame();
let rate = position.pos.frame_rate();
let bbt = position.pos.bbt();
let bbt = position.pos.bbt().map(|mut bbt|*bbt
.with_bpm(state.bpm)
.with_timesig(state.timesig.0, state.timesig.1));
stdout
.queue(move_to( 1, 1))?.queue(Print("Frame: "))?
.queue(move_to( 1, 2))?.queue(