mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: prototype chains/stacks
This commit is contained in:
parent
dc09ea901f
commit
d330d31ce4
3 changed files with 239 additions and 66 deletions
|
|
@ -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());
|
||||
|
|
|
|||
52
src/device/sequencer/midi.rs
Normal file
52
src/device/sequencer/midi.rs
Normal 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]
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/main.rs
62
src/main.rs
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue