mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 20:56:43 +01:00
chore: tidy up
This commit is contained in:
parent
5afed6f055
commit
dc09ea901f
10 changed files with 321 additions and 160 deletions
|
|
@ -11,6 +11,9 @@ pub const ACTIONS: [(&'static str, &'static str);4] = [
|
|||
pub struct Sequencer {
|
||||
name: Arc<str>,
|
||||
exited: Arc<AtomicBool>,
|
||||
playing: Arc<AtomicBool>,
|
||||
recording: Arc<AtomicBool>,
|
||||
overdub: Arc<AtomicBool>,
|
||||
sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>>,
|
||||
cursor: (u16, u16, u16),
|
||||
timesig: (f32, f32),
|
||||
|
|
@ -25,12 +28,11 @@ pub enum Event {
|
|||
|
||||
impl Sequencer {
|
||||
|
||||
pub fn new (name: Option<&str>) -> Result<Self, Box<dyn Error>> {
|
||||
let exited = Arc::new(AtomicBool::new(false));
|
||||
let name = name.unwrap_or("sequencer");
|
||||
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
|
||||
let mut port = client.register_port("sequence", ::jack::MidiOut::default())?;
|
||||
let sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>> = Arc::new(Mutex::new(vec![vec![None;64];128]));
|
||||
pub fn new (
|
||||
name: Option<&str>,
|
||||
connect_inputs: Option<&[String]>,
|
||||
connect_outputs: Option<&[String]>,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
let beats = 4;
|
||||
let steps = 16;
|
||||
let bpm = 120.0;
|
||||
|
|
@ -40,6 +42,23 @@ impl Sequencer {
|
|||
let t_beat = 60.0 / bpm; // msec
|
||||
let t_loop = t_beat * beats as f64; // msec
|
||||
let t_step = t_beat / steps as f64; // msec
|
||||
let exited = Arc::new(AtomicBool::new(false));
|
||||
let playing = Arc::new(AtomicBool::new(true));
|
||||
let recording = Arc::new(AtomicBool::new(true));
|
||||
let overdub = Arc::new(AtomicBool::new(false));
|
||||
let name = name.unwrap_or("sequencer");
|
||||
let (client, _status) = Client::new(
|
||||
name, ClientOptions::NO_START_SERVER
|
||||
)?;
|
||||
let mut input = client.register_port(
|
||||
"input", ::jack::MidiIn::default()
|
||||
)?;
|
||||
let mut output = client.register_port(
|
||||
"output", ::jack::MidiOut::default()
|
||||
)?;
|
||||
let sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>> = Arc::new(
|
||||
Mutex::new(vec![vec![None;64];128])
|
||||
);
|
||||
let mut step_frames = vec![];
|
||||
for step in 0..beats*steps {
|
||||
let step_index = (step as f64 * t_step / frame) as usize;
|
||||
|
|
@ -51,11 +70,14 @@ impl Sequencer {
|
|||
frame_steps[*frame] = Some(index);
|
||||
}
|
||||
Ok(Self {
|
||||
name: name.into(),
|
||||
exited: exited.clone(),
|
||||
sequence: sequence.clone(),
|
||||
cursor: (11, 0, 0),
|
||||
timesig: (4.0, 4.0),
|
||||
name: name.into(),
|
||||
exited: exited.clone(),
|
||||
playing: playing.clone(),
|
||||
recording: recording.clone(),
|
||||
overdub: overdub.clone(),
|
||||
sequence: sequence.clone(),
|
||||
cursor: (11, 0, 0),
|
||||
timesig: (4.0, 4.0),
|
||||
jack_client: crate::engine::activate_jack_client(
|
||||
client,
|
||||
Notifications,
|
||||
|
|
@ -69,28 +91,41 @@ impl Sequencer {
|
|||
let chunk_end = chunk_start + chunk_size;
|
||||
let start_looped = chunk_start as usize % loop_frames;
|
||||
let end_looped = chunk_end as usize % loop_frames;
|
||||
let mut writer = port.writer(scope);
|
||||
let sequence = sequence.lock().unwrap();
|
||||
for frame in 0..chunk_size {
|
||||
let value = frame_steps[(start_looped + frame as usize) % loop_frames];
|
||||
if let Some(step) = value {
|
||||
for track in sequence.iter() {
|
||||
for event in track[step].iter() {
|
||||
writer.write(&::jack::RawMidi {
|
||||
time: frame as u32,
|
||||
bytes: &match event {
|
||||
Event::NoteOn(pitch, velocity) => [
|
||||
0b10010000,
|
||||
*pitch,
|
||||
*velocity
|
||||
],
|
||||
Event::NoteOff(pitch) => [
|
||||
0b10000000,
|
||||
*pitch,
|
||||
0b00000000
|
||||
],
|
||||
}
|
||||
}).unwrap()
|
||||
|
||||
// Write MIDI notes from input to sequence
|
||||
if recording.fetch_and(true, Ordering::Relaxed) {
|
||||
//let overdub = overdub.fetch_and(true, Ordering::Relaxed);
|
||||
for event in input.iter(scope) {
|
||||
let ::jack::RawMidi { time, bytes } = event;
|
||||
println!("\n{time} {bytes:?}");
|
||||
}
|
||||
}
|
||||
|
||||
// Write MIDI notes from sequence to output
|
||||
if playing.fetch_and(true, Ordering::Relaxed) {
|
||||
let mut writer = output.writer(scope);
|
||||
let sequence = sequence.lock().unwrap();
|
||||
for frame in 0..chunk_size {
|
||||
let value = frame_steps[(start_looped + frame as usize) % loop_frames];
|
||||
if let Some(step) = value {
|
||||
for track in sequence.iter() {
|
||||
for event in track[step].iter() {
|
||||
writer.write(&::jack::RawMidi {
|
||||
time: frame as u32,
|
||||
bytes: &match event {
|
||||
Event::NoteOn(pitch, velocity) => [
|
||||
0b10010000,
|
||||
*pitch,
|
||||
*velocity
|
||||
],
|
||||
Event::NoteOff(pitch) => [
|
||||
0b10000000,
|
||||
*pitch,
|
||||
0b00000000
|
||||
],
|
||||
}
|
||||
}).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -186,44 +221,88 @@ const KEYS: [&'static str; 6] = [
|
|||
];
|
||||
|
||||
impl WidgetRef for Sequencer {
|
||||
fn render_ref (&self, area: Rect, buf: &mut Buffer) {
|
||||
draw_leaf(buf, area, 1, 0, &format!("{} ", &self.name));
|
||||
draw_leaf(buf, area, 3, 0, "Channel: 01");
|
||||
draw_leaf(buf, area, 5, 0, "Zoom: 1/64");
|
||||
draw_leaf(buf, area, 7, 0, "Rate: 1/1");
|
||||
|
||||
draw_leaf(buf, area, 10, 0, "Inputs: ");
|
||||
draw_leaf(buf, area, 13, 0, "Outputs: ");
|
||||
{
|
||||
let mut area = area.clone();
|
||||
area.height = 18;
|
||||
draw_box(buf, area);
|
||||
}
|
||||
{
|
||||
let mut area = area.inner(&Margin { horizontal: 1, vertical: 3, });
|
||||
area.x = area.x + 14;
|
||||
draw_sequence_keys(area, buf, &self.jack_client.as_client().transport().query().unwrap(), &self.sequence);
|
||||
draw_sequence_header(area, buf);
|
||||
draw_sequence_cursor(area, buf, self.cursor);
|
||||
}
|
||||
fn render_ref (&self, mut area: Rect, buf: &mut Buffer) {
|
||||
draw_sequencer(self, buf, area)
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_sequence_header (
|
||||
area: Rect, buf: &mut Buffer
|
||||
fn draw_sequencer (sequencer: &Sequencer, buf: &mut Buffer, mut area: Rect) {
|
||||
area.height = 15;
|
||||
draw_box(buf, area);
|
||||
let Rect { x, y, width, height } = area;
|
||||
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);
|
||||
}
|
||||
|
||||
fn draw_sequence_button (
|
||||
buf: &mut Buffer,
|
||||
x: u16,
|
||||
y: u16,
|
||||
name: &str
|
||||
) {
|
||||
buf.set_string(area.x + 3, area.y, "╭1.1.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 16, area.y, "╭1.2.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 32, area.y, "╭1.3.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 48, area.y, "╭1.4.", Style::default().dim());
|
||||
draw_box(buf, Rect { x, y, width: 18, height: 3 });
|
||||
buf.set_string(x + 1, y + 1, &format!(" ▶ {} ", 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());
|
||||
}
|
||||
|
||||
fn draw_rec_dub_button (
|
||||
buf: &mut Buffer,
|
||||
x: u16,
|
||||
y: u16,
|
||||
) {
|
||||
draw_box(buf, Rect { x, y, width: 18, height: 3 });
|
||||
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());
|
||||
}
|
||||
|
||||
fn draw_sequence_keys (
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
transport: &::jack::TransportStatePosition,
|
||||
sequence: &Arc<Mutex<Vec<Vec<Option<self::Event>>>>>
|
||||
sequence: &Arc<Mutex<Vec<Vec<Option<self::Event>>>>>,
|
||||
cursor: &(u16, u16, u16)
|
||||
) {
|
||||
buf.set_string(area.x + 3, area.y, "╭1.1.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 16, area.y, "╭1.2.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 32, area.y, "╭1.3.", Style::default().dim());
|
||||
buf.set_string(area.x + 3 + 48, area.y, "╭1.4.", Style::default().dim());
|
||||
//buf.set_string(area.x + 2, area.y, "╭", Style::default().dim());
|
||||
//buf.set_string(area.x + 2, area.y + 13, "╰", Style::default().dim());
|
||||
buf.set_string(area.x + 2 + 65, area.y, "╮", Style::default().dim());
|
||||
|
|
@ -238,17 +317,21 @@ fn draw_sequence_keys (
|
|||
let bars = beats as u32 / div as u32;
|
||||
let beat = beats as u32 % div as u32 + 1;
|
||||
let beat_sub = beats % 1.0;
|
||||
//buf.set_string(
|
||||
//area.x - 18, area.y + area.height,
|
||||
//format!("BBT {bars:04}:{beat:02}.{:02}", (beat_sub * 16.0) as u32),
|
||||
//Style::default()
|
||||
//);
|
||||
let sequence = sequence.lock().unwrap();
|
||||
buf.set_string(
|
||||
area.x + area.width - 25, area.y - 2, format!("{bars:04}:{beat:02}.{:02}", (beat_sub * 16.0) as u32), Style::default()
|
||||
);
|
||||
for key in 0..12 {
|
||||
buf.set_string(area.x, area.y + 1 + key, KEYS[(key % 6) as usize],
|
||||
Style::default().black());
|
||||
Style::default().dim());
|
||||
buf.set_string(area.x + 1, area.y + 1 + key, "█",
|
||||
Style::default().black());
|
||||
Style::default().dim());
|
||||
for step in 0..64 {
|
||||
let bg = if step as u32 == (beat - 1) * 16 + (beat_sub * 16.0) as u32 {
|
||||
ratatui::style::Color::Gray
|
||||
} else if step == cursor.1 as usize || key == cursor.0/2 {
|
||||
ratatui::style::Color::Black
|
||||
} else {
|
||||
ratatui::style::Color::Reset
|
||||
|
|
@ -258,22 +341,22 @@ fn draw_sequence_keys (
|
|||
match (top, bottom) {
|
||||
(true, true) => {
|
||||
buf.set_string(area.x + 3 + step as u16, area.y + 1 + key, "█",
|
||||
Style::default().yellow().bold().bg(bg));
|
||||
Style::default().yellow().not_dim().bold().bg(bg));
|
||||
},
|
||||
(true, false) => {
|
||||
buf.set_string(area.x + 3 + step as u16, area.y + 1 + key, "▀",
|
||||
Style::default().yellow().bold().bg(bg));
|
||||
Style::default().yellow().not_dim().bold().bg(bg));
|
||||
},
|
||||
(false, true) => {
|
||||
buf.set_string(area.x + 3 + step as u16, area.y + 1 + key, "▄",
|
||||
Style::default().yellow().bold().bg(bg));
|
||||
Style::default().yellow().not_dim().bold().bg(bg));
|
||||
},
|
||||
(false, false) => if step % 16 == 0 {
|
||||
buf.set_string(area.x + 3 + step as u16, area.y + 1 + key, "┊",
|
||||
Style::default().black().bg(bg))
|
||||
Style::default().dim().bg(bg))
|
||||
} else {
|
||||
buf.set_string(area.x + 3 + step as u16, area.y + 1 + key, "·",
|
||||
Style::default().black().bg(bg))
|
||||
Style::default().dim().bg(bg))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -289,7 +372,7 @@ fn draw_sequence_keys (
|
|||
}
|
||||
|
||||
fn draw_sequence_cursor (
|
||||
area: Rect, buf: &mut Buffer, cursor: (u16, u16, u16)
|
||||
area: Rect, buf: &mut Buffer, cursor: &(u16, u16, u16)
|
||||
) {
|
||||
let cursor_character = match cursor.0 % 2 {
|
||||
0 => "▀",
|
||||
|
|
@ -297,11 +380,13 @@ fn draw_sequence_cursor (
|
|||
_ => unreachable!()
|
||||
};
|
||||
let cursor_y = cursor.0 / 2;
|
||||
buf.set_string(area.x + cursor.1 + 3, area.y + 1 + cursor_y, if cursor.2 == 0 {
|
||||
let cursor_text = if cursor.2 == 0 {
|
||||
cursor_character.into()
|
||||
} else {
|
||||
cursor_character.repeat(cursor.2 as usize)
|
||||
}, Style::default().yellow());
|
||||
};
|
||||
let style = Style::default().yellow().dim();
|
||||
buf.set_string(area.x + cursor.1 + 3, area.y + 1 + cursor_y, cursor_text, style);
|
||||
}
|
||||
|
||||
pub struct Notifications;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue