wip: prototype chains/stacks

This commit is contained in:
🪞👃🪞 2024-06-12 12:43:17 +03:00
parent dc09ea901f
commit d330d31ce4
3 changed files with 239 additions and 66 deletions

View file

@ -1,6 +1,9 @@
use crate::prelude::*;
use ratatui::style::Stylize;
mod midi;
pub use midi::*;
pub const ACTIONS: [(&'static str, &'static str);4] = [
("+/-", "Zoom"),
("A/D", "Add/delete note"),
@ -14,10 +17,13 @@ pub struct Sequencer {
playing: Arc<AtomicBool>,
recording: Arc<AtomicBool>,
overdub: Arc<AtomicBool>,
sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>>,
inputs_open: Arc<AtomicBool>,
outputs_open: Arc<AtomicBool>,
cursor: (u16, u16, u16),
timesig: (f32, f32),
pub jack_client: Jack<Notifications>,
sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>>,
sequences: Arc<Mutex<Vec<MIDISequence>>>,
}
#[derive(Clone)]
@ -76,6 +82,10 @@ impl Sequencer {
recording: recording.clone(),
overdub: overdub.clone(),
sequence: sequence.clone(),
inputs_open: Arc::new(AtomicBool::new(false)),
outputs_open: Arc::new(AtomicBool::new(false)),
sequences: Arc::new(Mutex::new(vec![
])),
cursor: (11, 0, 0),
timesig: (4.0, 4.0),
jack_client: crate::engine::activate_jack_client(
@ -194,6 +204,12 @@ fn handle (state: &mut Sequencer, event: &crate::engine::Event) -> Result<(), Bo
KeyCode::Char(']') => {
state.cursor.2 = state.cursor.2 + 1
},
KeyCode::Char('i') => {
state.inputs_open.fetch_xor(true, Ordering::Relaxed);
},
KeyCode::Char('o') => {
state.outputs_open.fetch_xor(true, Ordering::Relaxed);
},
KeyCode::Char('a') => {
let row = state.cursor.0 as usize;
let step = state.cursor.1 as usize;
@ -213,10 +229,10 @@ fn handle (state: &mut Sequencer, event: &crate::engine::Event) -> Result<(), Bo
}
const NOTE_NAMES: [&'static str;12] = [
"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B ",
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
];
const KEYS: [&'static str; 6] = [
const KEYS_VERTICAL: [&'static str; 6] = [
"", "", "", "", "", "",
];
@ -227,42 +243,138 @@ impl WidgetRef for Sequencer {
}
fn draw_sequencer (sequencer: &Sequencer, buf: &mut Buffer, mut area: Rect) {
area.height = 15;
draw_box(buf, area);
area.height = 18;
//draw_box(buf, area);
let Rect { x, y, width, height } = area;
//{
//let mut area = area.clone();
//area.y = area.y + 3;
//area.x = area.x + 1;
//area.height = area.height - 2;
//draw_sequence_keys(area, buf,
//&sequencer.jack_client.as_client().transport().query().unwrap(),
//&sequencer.sequence,
//&sequencer.cursor);
//draw_sequence_cursor(area, buf,
//&sequencer.cursor);
//}
//draw_box(buf, Rect { x, y, width: 18, height });
draw_box(buf, Rect { x, y, width: 40, height: 8 });
draw_box(buf, Rect { x, y, width: 40, height: 6 });
let style = Style::default().gray();
buf.set_string(x + 1, y + 1, &format!(" │ 00:00.00 / 00:00.00"), style);
buf.set_string(x + 2, y + 1, &format!("{}", &sequencer.name), style.bold());
buf.set_string(x + 1, y + 2, &format!(" ▶ PLAY │ ⏹ STOP │ ⏺ REC │ ⏺ DUB "), style);
buf.set_string(x + 0, y + 3, &format!("├--------------------------------------┤"), style.dim());
buf.set_string(x + 1, y + 6, &format!(" Inputs... │ Outputs... "), style);
buf.set_string(x + 0, y + 5, &format!("├--------------------------------------┤"), style.dim());
for i in 0..3 {
buf.set_string(1 + i * 12 + x + 1, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 2, y + 4, &format!(" "), Style::default().on_black());
buf.set_string(1 + i * 12 + x + 3, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 4, y + 4, &format!(" "), Style::default().on_black());
buf.set_string(1 + i * 12 + x + 5, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 6, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 7, y + 4, &format!(" "), Style::default().on_black());
buf.set_string(1 + i * 12 + x + 8, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 9, y + 4, &format!(" "), Style::default().on_black());
buf.set_string(1 + i * 12 + x + 10, y + 4, &format!(" "), Style::default().on_white());
buf.set_string(1 + i * 12 + x + 11, y + 4, &format!(" "), Style::default().on_black());
buf.set_string(1 + i * 12 + x + 12, y + 4, &format!(" "), Style::default().on_white());
}
//buf.set_string(x + 1, y + 3,
//&format!(" │ INPUT │ OUTPUT │"),
//Style::default().gray());
//buf.set_string(x + 1, y + 5,
//&format!(" {} │ IN │ ⏺ REC │ ⏺ DUB │ ▶ PLAY │ ⏹ STOP │ OUT │ 00:00.00 / 00:00.00", &sequencer.name),
//Style::default().gray());
if sequencer.inputs_open.fetch_and(true, Ordering::Relaxed) {
buf.set_string(x + 15, y + 1, "IN", Style::default().green().bold());
}
if sequencer.outputs_open.fetch_and(true, Ordering::Relaxed) {
buf.set_string(x + 54, y + 1, "OUT", Style::default().green().bold());
}
let mut command = |y2: u16, c: &str, ommand: &str, value: &str| {
buf.set_string(x + 1, y + y2, c, Style::default().bold());
buf.set_string(x + 2, y + y2, ommand, Style::default().dim());
buf.set_string(x + 4 + ommand.len() as u16, y + y2, value, Style::default().bold());
};
for (y, c, ommand, value) in [
(5, "I", "nputs", "[+]"),
(6, "O", "utputs", "[+]"),
(7, "C", "hannel", "01"),
(8, "G", "rid", "1/16"),
(9, "Z", "oom", "1/64"),
(10, "R", "ate", "1/1"),
(11, "S", "ync", "1 bar"),
(12, "A", "dd note", ""),
(13, "D", "elete note", ""),
] {
command(y, c, ommand, value)
}
{
let mut area = area.clone();
//area.y = area.y + 1;
area.x = area.x + 19;
area.height = area.height - 2;
draw_sequence_keys(area, buf,
&sequencer.jack_client.as_client().transport().query().unwrap(),
&sequencer.sequence,
&sequencer.cursor);
draw_sequence_cursor(area, buf,
&sequencer.cursor);
}
draw_box(buf, Rect { x, y, width: 18, height });
draw_rec_dub_button(buf, x, y + 2);
draw_sequence_button(buf, x, y, &sequencer.name);
//for (y, c, ommand, value) in [
////(5, "I", "nputs", "[+]"),
////(6, "O", "utputs", "[+]"),
////(7, "C", "hannel", "01"),
//(8, "G", "rid", "1/16"),
//(9, "Z", "oom", "1/64"),
//(10, "R", "ate", "1/1"),
//(11, "S", "ync", "1 bar"),
//(12, "A", "dd note", ""),
//(13, "D", "elete note", ""),
//] {
//command(y, c, ommand, value)
//}
//draw_box(buf, Rect { x, y: y + height - 1, width, height: 3 });
//buf.set_string(x + 1, y + height,
//&format!(" Grid 1/16 │ Zoom 1/64 │ Rate 1/1 │ Sync 1 bar │ Add note │ Delete note "),
//Style::default().gray());
//buf.set_string(x + 1, y + 1, &format!(" ▶ {} ", &sequencer.name),
//Style::default().white().bold().not_dim());
//buf.set_string(x + 4, y + 0, "┬", Style::default().gray());
//buf.set_string(x + 4, y + 1, "│", Style::default().gray().dim());
//buf.set_string(x + 4, y + 2, "┴", Style::default().gray());
//buf.set_string(x + 21, y + 1, " ⏺ REC DUB ",
//Style::default().white().bold().not_dim());
//buf.set_string(x + 18, y + 0, "┬", Style::default().gray());
//buf.set_string(x + 18, y + 1, "│", Style::default().gray().dim());
//buf.set_string(x + 18, y + 2, "┴", Style::default().gray());
//draw_rec_dub_button(buf, x + 17, y);
//draw_sequence_button(buf, x, y, &sequencer.name);
//draw_leaf(buf, Rect { x, y: y + height, width, height: 2 }, 0, 0, "Inputs ");
//draw_leaf(buf, Rect { x, y: y + height, width, height: 2 }, 0, 8, "Outputs");
//for x2 in 0..4 {
//for y2 in 0..4 {
//buf.set_string(
//x + 2 + x2 * 3,
//y + 5 + y2,
//format!("{:>02} ", 1 + x2 + y2 * 4),
//Style::default().green().bold().not_dim()
//)
//}
//}
//
let y = y + 8;
draw_box(buf, Rect { x, y: y, width: 40, height: 10 });
buf.set_string(x + 1, y + 1, &format!(" LV2Host#00"), style.bold());
buf.set_string(x + 13, y + 1, &format!("│ Plugin Name"), style.not_dim());
buf.set_string(x + 0, y + 2, &format!("├--------------------------------------┤"), style.dim());
buf.set_string(x + 1, y + 3, &format!(" Parameter 1 0.0"), style);
buf.set_string(x + 1, y + 4, &format!(" Parameter 2 0.0"), style);
buf.set_string(x + 1, y + 5, &format!(" Parameter 3 0.0"), style);
buf.set_string(x + 1, y + 6, &format!(" Parameter 4 0.0"), style);
buf.set_string(x + 0, y + 7, &format!("├--------------------------------------┤"), style.dim());
buf.set_string(x + 1, y + 8, &format!(" Inputs... │ Outputs... "), style);
let y = y + 10;
draw_box(buf, Rect { x, y: y, width: 40, height: 14 });
buf.set_string(x + 1, y + 1, &format!(" Sampler#00 │"), style.bold());
buf.set_string(x + 0, y + 2, &format!("├--------------------------------------┤"), style.dim());
buf.set_string(x + 2, y + 3, &format!("C0 Sample#000"), style.bold());
buf.set_string(x + 2, y + 4, &format!(" {:.03}s",
100000.0/44100.0), style);
buf.set_string(x + 2, y + 5, &format!("C#0 Sample#001"), style.bold());
buf.set_string(x + 2, y + 6, &format!(" {:.03}-{:.03}s",
50000.0/44100.0, 100000.0/44100.0), style);
buf.set_string(x + 2, y + 7, &format!("D0 Sample#002"), style.bold());
buf.set_string(x + 2, y + 8, &format!(" {:.03}-{:.03}/{:.03}s",
0.0, 50000.0/44100.0, 100000.0/44100.0), style);
buf.set_string(x + 2, y + 9, &format!("D#0 Sample#003"), style.bold());
buf.set_string(x + 2, y + 10, &format!(" {:.03}-[{:.03}-{:.03}]/{:.03}s ",
10000.0/44100.0, 25000.0/44100.0, 50000.0/44100.0, 100000.0/44100.0), style);
buf.set_string(x + 0, y + 7 + 4, &format!("├--------------------------------------┤"), style.dim());
buf.set_string(x + 1, y + 7 + 5, &format!(" Inputs... │ Outputs... "), style);
}
fn draw_sequence_button (
@ -285,11 +397,14 @@ fn draw_rec_dub_button (
y: u16,
) {
draw_box(buf, Rect { x, y, width: 18, height: 3 });
buf.set_string(x + 1, y + 1, "REC DUB ",
buf.set_string(x + 1, y + 1, " REC DUB ",
Style::default().white().bold().not_dim());
buf.set_string(x + 4, y + 0, "", Style::default().gray());
buf.set_string(x + 4, y + 1, "", Style::default().gray().dim());
buf.set_string(x + 4, y + 2, "", Style::default().gray());
buf.set_string(x + 5, y + 0, "", Style::default().gray());
buf.set_string(x + 5, y + 1, "", Style::default().gray().dim());
buf.set_string(x + 5, y + 2, "", Style::default().gray());
buf.set_string(x + 11, y + 0, "", Style::default().gray());
buf.set_string(x + 11, y + 1, "", Style::default().gray().dim());
buf.set_string(x + 11, y + 2, "", Style::default().gray());
}
fn draw_sequence_keys (
@ -324,7 +439,7 @@ fn draw_sequence_keys (
//);
let sequence = sequence.lock().unwrap();
for key in 0..12 {
buf.set_string(area.x, area.y + 1 + key, KEYS[(key % 6) as usize],
buf.set_string(area.x, area.y + 1 + key, KEYS_VERTICAL[(key % 6) as usize],
Style::default().dim());
buf.set_string(area.x + 1, area.y + 1 + key, "",
Style::default().dim());

View file

@ -0,0 +1,52 @@
pub struct MIDISequence {
channels: [MIDISequenceChannel;16],
}
pub struct MIDISequenceChannel {
number: u8,
notes: [MIDISequenceVoice;128],
}
pub type MIDISequenceVoice = std::collections::BTreeMap<u32, NoteEvent>;
#[derive(Clone)]
pub enum NoteEvent {
On(u8),
Off(u8),
}
const VOICE_EMPTY: MIDISequenceVoice = MIDISequenceVoice::new();
impl MIDISequence {
fn new () -> Self {
Self {
channels: [
MIDISequenceChannel::new(1),
MIDISequenceChannel::new(2),
MIDISequenceChannel::new(3),
MIDISequenceChannel::new(4),
MIDISequenceChannel::new(5),
MIDISequenceChannel::new(6),
MIDISequenceChannel::new(7),
MIDISequenceChannel::new(8),
MIDISequenceChannel::new(9),
MIDISequenceChannel::new(10),
MIDISequenceChannel::new(11),
MIDISequenceChannel::new(12),
MIDISequenceChannel::new(13),
MIDISequenceChannel::new(14),
MIDISequenceChannel::new(15),
MIDISequenceChannel::new(16),
]
}
}
}
impl MIDISequenceChannel {
fn new (number: u8) -> Self {
Self {
number,
notes: [VOICE_EMPTY;128]
}
}
}

View file

@ -48,9 +48,6 @@ fn main () -> Result<(), Box<dyn Error>> {
)?,
focus: 0,
devices: vec![
crate::device::Device::Mixer(
crate::device::mixer::Mixer::new()?
),
crate::device::Device::Sequencer(
crate::device::sequencer::Sequencer::new(
Some("Melody#000"),
@ -58,19 +55,22 @@ fn main () -> Result<(), Box<dyn Error>> {
None
)?
),
crate::device::Device::Sequencer(
crate::device::sequencer::Sequencer::new(
Some("Rhythm#000"),
None,
None,
)?
),
crate::device::Device::Sampler(
crate::device::sampler::Sampler::new()?
),
crate::device::Device::Looper(
crate::device::looper::Looper::new()?
),
//crate::device::Device::Sequencer(
//crate::device::sequencer::Sequencer::new(
//Some("Rhythm#000"),
//None,
//None,
//)?
//),
//crate::device::Device::Mixer(
//crate::device::mixer::Mixer::new()?
//),
//crate::device::Device::Sampler(
//crate::device::sampler::Sampler::new()?
//),
//crate::device::Device::Looper(
//crate::device::looper::Looper::new()?
//),
]
})
}
@ -106,24 +106,30 @@ impl WidgetRef for App {
fn render_ref (&self, area: Rect, buffer: &mut Buffer) {
use ratatui::style::Stylize;
let mut constraints = vec![
Constraint::Length(4),
Constraint::Length(10),
Constraint::Max(18),
Constraint::Max(18),
Constraint::Max(0),
Constraint::Max(0),
Constraint::Max(0),
Constraint::Max(40),
Constraint::Max(40),
];
let areas = Layout::default()
.direction(Direction::Vertical)
.direction(Direction::Horizontal)
.constraints(&constraints)
.split(area);
.split(Rect {
x: area.x,
y: area.y,
width: area.width,
height: area.height - 4
});
self.transport.render(Rect {
x: area.width.saturating_sub(80u16) / 2,
y: area.y + area.height - 4,
width: area.width,
height: 4
}, buffer);
self.transport.render(areas[0], buffer);
for (index, device) in self.devices.iter().enumerate() {
device.render(areas[index + 1], buffer);
device.render(areas[index], buffer);
if index == self.focus {
draw_focus_corners(buffer, areas[index+1]);
draw_focus_corners(buffer, areas[index]);
}
}
}