mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
advance play cursor in sequencer
This commit is contained in:
parent
4fd208d53f
commit
7c1dc9ce9b
9 changed files with 53 additions and 37 deletions
|
|
@ -101,7 +101,7 @@ impl Engine {
|
||||||
stdout
|
stdout
|
||||||
.queue(crossterm::terminal::EnterAlternateScreen)?
|
.queue(crossterm::terminal::EnterAlternateScreen)?
|
||||||
.flush()?;
|
.flush()?;
|
||||||
let sleep = std::time::Duration::from_millis(16);
|
let sleep = std::time::Duration::from_millis(20);
|
||||||
loop {
|
loop {
|
||||||
stdout
|
stdout
|
||||||
.queue(crossterm::terminal::BeginSynchronizedUpdate)?
|
.queue(crossterm::terminal::BeginSynchronizedUpdate)?
|
||||||
|
|
@ -122,7 +122,7 @@ impl Engine {
|
||||||
crossterm::terminal::disable_raw_mode()?;
|
crossterm::terminal::disable_raw_mode()?;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
std::thread::sleep(sleep);
|
//std::thread::sleep(sleep);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ pub fn render (
|
||||||
.queue(move_to(0, 1))?.queue(PrintStyledContent(" Metronome [ ] ████ Track 1".bold()))?
|
.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, 2))?.queue(PrintStyledContent(" Loop 1 [ ] ████ Track 1".bold()))?
|
||||||
.queue(move_to(0, 3))?.queue(PrintStyledContent(" Loop 2 [ ] ████████ Track 2".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()))?
|
.queue(move_to(0, 4))?.queue(PrintStyledContent(" Loop 3 [ ] ████████ Track 3".bold()))?;
|
||||||
.flush()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ fn run_one (command: &cli::Command) -> Result<(), Box<dyn Error>> {
|
||||||
),
|
),
|
||||||
|
|
||||||
cli::Command::Sequencer => engine.run(
|
cli::Command::Sequencer => engine.run(
|
||||||
&mut sequencer::Sequencer::new()?,
|
&mut sequencer::Sequencer::new(engine.jack_client.as_client())?,
|
||||||
|state, stdout, mut offset| {
|
|state, stdout, mut offset| {
|
||||||
let (w, h) = render::render_toolbar_vertical(stdout, offset, &sequencer::ACTIONS)?;
|
let (w, h) = render::render_toolbar_vertical(stdout, offset, &sequencer::ACTIONS)?;
|
||||||
offset.0 = offset.0 + w + 2;
|
offset.0 = offset.0 + w + 2;
|
||||||
|
|
@ -122,10 +122,10 @@ fn run_all () -> Result<(), Box<dyn Error>> {
|
||||||
exited: false,
|
exited: false,
|
||||||
mode: Mode::Sequencer,
|
mode: Mode::Sequencer,
|
||||||
transport: transport::Transport::new(engine.jack_client.as_client())?,
|
transport: transport::Transport::new(engine.jack_client.as_client())?,
|
||||||
|
sequencer: sequencer::Sequencer::new(engine.jack_client.as_client())?,
|
||||||
mixer: mixer::Mixer::new()?,
|
mixer: mixer::Mixer::new()?,
|
||||||
looper: looper::Looper::new()?,
|
looper: looper::Looper::new()?,
|
||||||
sampler: sampler::Sampler::new()?,
|
sampler: sampler::Sampler::new()?,
|
||||||
sequencer: sequencer::Sequencer::new()?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let render = |state: &mut App, stdout: &mut Stdout, mut offset: (u16, u16)| {
|
let render = |state: &mut App, stdout: &mut Stdout, mut offset: (u16, u16)| {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ pub fn render (
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
render_table(state, stdout, offset)?;
|
render_table(state, stdout, offset)?;
|
||||||
render_meters(state, stdout, offset)?;
|
render_meters(state, stdout, offset)?;
|
||||||
stdout.flush()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ pub fn render (
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
render_table(state, stdout, offset)?;
|
render_table(state, stdout, offset)?;
|
||||||
render_meters(state, stdout, offset)?;
|
render_meters(state, stdout, offset)?;
|
||||||
stdout.flush()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ pub const ACTIONS: [(&'static str, &'static str);4] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
pub struct Sequencer {
|
pub struct Sequencer {
|
||||||
exited: bool,
|
exited: bool,
|
||||||
jack: Jack<Notifications>,
|
cursor: (u16, u16, u16),
|
||||||
cursor: (u16, u16, u16),
|
sequence: Vec<Vec<Option<Event>>>,
|
||||||
sequence: Vec<Vec<Option<Event>>>,
|
transport: ::jack::Transport,
|
||||||
|
bpm: f64,
|
||||||
|
timesig: (f32, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -27,24 +29,15 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sequencer {
|
impl Sequencer {
|
||||||
pub fn new () -> Result<Self, Box<dyn Error>> {
|
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
|
||||||
let (client, status) = Client::new(
|
let transport = client.transport();
|
||||||
"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>
|
|
||||||
)
|
|
||||||
)?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
exited: false,
|
exited: false,
|
||||||
cursor: (0, 0, 0),
|
cursor: (0, 0, 0),
|
||||||
jack,
|
transport,
|
||||||
sequence: vec![vec![None;64];4],
|
sequence: vec![vec![None;64];4],
|
||||||
|
bpm: 120.0,
|
||||||
|
timesig: (4.0, 4.0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ fn render_grid (
|
||||||
offset: (u16, u16)
|
offset: (u16, u16)
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row);
|
let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row);
|
||||||
let bg = "┊···············┊···············┊···············┊···············";
|
|
||||||
let cursor: String = if state.cursor.2 == 0 {
|
let cursor: String = if state.cursor.2 == 0 {
|
||||||
"❱".into()
|
"❱".into()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -26,6 +25,17 @@ fn render_grid (
|
||||||
.take(state.cursor.2 as usize)
|
.take(state.cursor.2 as usize)
|
||||||
.collect()
|
.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
|
stdout
|
||||||
.queue(move_to(1, 3))?.queue(Print("1.1"))?
|
.queue(move_to(1, 3))?.queue(Print("1.1"))?
|
||||||
.queue(move_to(17, 3))?.queue(Print("1.2"))?
|
.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"))?;
|
.queue(move_to(49, 3))?.queue(Print("1.4"))?;
|
||||||
for (index, row) in state.sequence.iter().enumerate() {
|
for (index, row) in state.sequence.iter().enumerate() {
|
||||||
let y = index as u16 + 4;
|
let y = index as u16 + 4;
|
||||||
stdout.queue(move_to(1, y))?.queue(
|
for x in 0u16..64 {
|
||||||
PrintStyledContent(bg.grey())
|
let bg = if x as u32 == (beat - 1) * 16 + (beat_sub * 16.0) as u32 {
|
||||||
)?;
|
crossterm::style::Color::Black
|
||||||
for (index, step) in row.iter().enumerate() {
|
} else {
|
||||||
if step.is_some() {
|
crossterm::style::Color::Reset
|
||||||
let x = index as u16 + 1;
|
};
|
||||||
stdout.queue(move_to(x, y))?.queue(
|
if let Some(step) = &row[x as usize] {
|
||||||
PrintStyledContent("X".white().bold())
|
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))
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,19 @@ pub struct Transport {
|
||||||
exited: bool,
|
exited: bool,
|
||||||
title: String,
|
title: String,
|
||||||
transport: ::jack::Transport,
|
transport: ::jack::Transport,
|
||||||
|
bpm: f64,
|
||||||
|
timesig: (f32, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transport {
|
impl Transport {
|
||||||
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
|
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
|
||||||
|
let transport = client.transport();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
exited: false,
|
exited: false,
|
||||||
title: String::from("Untitled project"),
|
title: String::from("Untitled project"),
|
||||||
transport: client.transport(),
|
bpm: 93.0,
|
||||||
|
timesig: (4.0, 4.0),
|
||||||
|
transport,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ pub fn render (
|
||||||
if let Ok(position) = state.transport.query() {
|
if let Ok(position) = state.transport.query() {
|
||||||
let frame = position.pos.frame();
|
let frame = position.pos.frame();
|
||||||
let rate = position.pos.frame_rate();
|
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
|
stdout
|
||||||
.queue(move_to( 1, 1))?.queue(Print("Frame: "))?
|
.queue(move_to( 1, 1))?.queue(Print("Frame: "))?
|
||||||
.queue(move_to( 1, 2))?.queue(
|
.queue(move_to( 1, 2))?.queue(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue