From 2e7252f8b9f1aac2e34deb3396be235325526abe Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 16 Jun 2024 19:25:31 +0300 Subject: [PATCH] light up keys --- src/device.rs | 30 +++++------ src/device/sequencer.rs | 107 ++++++++++++++++++++++++++-------------- src/main.rs | 2 +- 3 files changed, 86 insertions(+), 53 deletions(-) diff --git a/src/device.rs b/src/device.rs index 4d16bbfa..d9bfa3eb 100644 --- a/src/device.rs +++ b/src/device.rs @@ -215,17 +215,17 @@ pub struct Notifications(T); impl NotificationHandler for Notifications { fn thread_init (&self, _: &Client) { - println!("JACK: thread init"); + //println!("JACK: thread init"); self.0(AppEvent::Jack(JackEvent::ThreadInit)); } fn shutdown (&mut self, status: ClientStatus, reason: &str) { - println!("JACK: shutdown with status {:?} because \"{}\"", status, reason); + //println!("JACK: shutdown with status {:?} because \"{}\"", status, reason); self.0(AppEvent::Jack(JackEvent::Shutdown)); } fn freewheel (&mut self, _: &Client, is_enabled: bool) { - println!("JACK: freewheel mode is {}", if is_enabled { "on" } else { "off" }); + //println!("JACK: freewheel mode is {}", if is_enabled { "on" } else { "off" }); self.0(AppEvent::Jack(JackEvent::Freewheel)); } @@ -235,40 +235,40 @@ impl NotificationHandler for Notifications { } fn client_registration (&mut self, _: &Client, name: &str, is_reg: bool) { - println!("JACK: {} client with name \"{name}\"", - if is_reg { "registered" } else { "unregistered" }); + //println!("JACK: {} client with name \"{name}\"", + //if is_reg { "registered" } else { "unregistered" }); self.0(AppEvent::Jack(JackEvent::ClientRegistration)); } fn port_registration (&mut self, _: &Client, port_id: PortId, is_reg: bool) { - println!("JACK: {} port with id {port_id}", - if is_reg { "registered" } else { "unregistered" }); + //println!("JACK: {} port with id {port_id}", + //if is_reg { "registered" } else { "unregistered" }); self.0(AppEvent::Jack(JackEvent::PortRegistration)); } fn port_rename (&mut self, _: &Client, id: PortId, old: &str, new: &str) -> Control { - println!("JACK: port with id {id} renamed from {old} to {new}",); + //println!("JACK: port with id {id} renamed from {old} to {new}",); self.0(AppEvent::Jack(JackEvent::PortRename)); Control::Continue } fn ports_connected (&mut self, _: &Client, a: PortId, b: PortId, are: bool) { - println!("JACK: ports with id {a} and {b} are {}", if are { - "connected" - } else { - "disconnected" - }); + //println!("JACK: ports with id {a} and {b} are {}", if are { + //"connected" + //} else { + //"disconnected" + //}); self.0(AppEvent::Jack(JackEvent::PortsConnected)); } fn graph_reorder (&mut self, _: &Client) -> Control { - println!("JACK: graph reordered"); + //println!("JACK: graph reordered"); self.0(AppEvent::Jack(JackEvent::GraphReorder)); Control::Continue } fn xrun (&mut self, _: &Client) -> Control { - println!("JACK: xrun occurred"); + //println!("JACK: xrun occurred"); self.0(AppEvent::Jack(JackEvent::XRun)); Control::Continue } diff --git a/src/device/sequencer.rs b/src/device/sequencer.rs index e89d737c..68b89655 100644 --- a/src/device/sequencer.rs +++ b/src/device/sequencer.rs @@ -20,6 +20,7 @@ pub struct Sequencer { playing: bool, recording: bool, overdub: bool, + notes_on: Vec, } enum SequencerView { @@ -32,31 +33,27 @@ enum SequencerView { impl Sequencer { pub fn new (name: &str) -> Usually> { let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?; - DynamicDevice::new( - render, - handle, - process, - Self { - name: name.into(), - mode: SequencerView::Horizontal, - note_axis: (36, 60), - note_cursor: 0, - time_axis: (0, 64), - time_cursor: 0, - rate: Hz(client.sample_rate() as u32), - tempo: Tempo(120000), - transport: client.transport(), - input_port: client.register_port("in", MidiIn::default())?, - input_connect: vec!["nanoKEY Studio * (capture): *".into()], - output_port: client.register_port("out", MidiOut::default())?, - output_connect: vec![], - ppq: 96, - sequence: std::collections::BTreeMap::new(), - playing: true, - recording: true, - overdub: true, - } - ).activate(client) + DynamicDevice::new(render, handle, process, Self { + name: name.into(), + mode: SequencerView::Vertical, + note_axis: (36, 60), + note_cursor: 0, + time_axis: (0, 64), + time_cursor: 0, + rate: Hz(client.sample_rate() as u32), + tempo: Tempo(120000), + transport: client.transport(), + input_port: client.register_port("in", MidiIn::default())?, + input_connect: vec!["nanoKEY Studio * (capture): *".into()], + output_port: client.register_port("out", MidiOut::default())?, + output_connect: vec![], + ppq: 96, + sequence: std::collections::BTreeMap::new(), + playing: true, + recording: true, + overdub: true, + notes_on: vec![false;128], + }).activate(client) } } @@ -66,15 +63,15 @@ pub fn process (state: &mut Sequencer, client: &Client, scope: &ProcessScope) -> Control::Continue } -fn process_in (state: &Sequencer, scope: &ProcessScope) { +fn process_in (state: &mut Sequencer, scope: &ProcessScope) { for event in state.input_port.iter(scope) { match midly::live::LiveEvent::parse(event.bytes).unwrap() { midly::live::LiveEvent::Midi { channel, message } => match message { midly::MidiMessage::NoteOn { key, vel } => { - panic!("on") + state.notes_on[key.as_int() as usize] = true }, midly::MidiMessage::NoteOff { key, vel } => { - panic!("off") + state.notes_on[key.as_int() as usize] = false }, _ => {} }, @@ -313,21 +310,57 @@ fn draw_sequencer_vertical (sequencer: &Sequencer, buf: &mut Buffer, area: Rect) let Rect { x, y, .. } = area; let (time0, time1) = sequencer.time_axis; let (note0, note1) = sequencer.note_axis; + let bw = Style::default().dim(); let bg = Style::default().on_black(); - for step in 0..(time1-time0)/2 { - let y = y + step - time0; - buf.set_string(x + 5, y, &" ".repeat(32.max(note1-note0)as usize), bg); - if step % 2 == 0 { - buf.set_string(x + 2, y, &format!("{:2} ", step / 2 + 1), Style::default()); - } - } for key in note0..note1.max(note0+32) { let x = x + 5 + key - note0; - let color = KEY_HORIZONTAL_STYLE[key as usize % 12]; + let color = if sequencer.notes_on[key as usize] { + Style::default().red() + } else { + KEY_HORIZONTAL_STYLE[key as usize % 12] + }; buf.set_string(x, y - 1, &format!("▄"), color); if key % 12 == 0 { let octave = format!("C{}", (key / 12) as i8 - 4); - buf.set_string(x, y + 1, &octave, Style::default()); + buf.set_string(x, y, &octave, Style::default()); + } + } + for step in time0..time1 { + let y = y - time0 + step / 2; + buf.set_string(x + 5, y, &" ".repeat(32.max(note1-note0)as usize), bg); + if step % 8 == 0 { + buf.set_string(x + 2, y, &format!("{:2} ", step + 1), Style::default()); + } + if step % 2 == 0 { + let mut has_1 = false; + let (start, end) = ( + (step + 0) as u32 * sequencer.ppq, + (step + 1) as u32 * sequencer.ppq); + for (i, (t, events)) in sequencer.sequence.range(start..end).enumerate() { + if events.len() > 0 { + has_1 = true; + break + } + } + let mut has_2 = false; + let (start, end) = ( + (step + 1) as u32 * sequencer.ppq, + (step + 2) as u32 * sequencer.ppq + ); + for (i, (t, events)) in sequencer.sequence.range(start..end).enumerate() { + if events.len() > 0 { + has_2 = true; + break + } + } + if has_1 || has_2 { + buf.set_string(x + 4, y, &match (has_1, has_2) { + (true, true) => "█", + (true, false) => "▀", + (false, true) => "▄", + _ => " ", + }, Style::default()); + } } } buf.set_string( diff --git a/src/main.rs b/src/main.rs index 68d170dc..812f5877 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,6 @@ fn main () -> Result<(), Box> { //Box::new(Mixer::new("Mixer#000")?), Box::new(Sequencer::new("Melody#000")?), Box::new(Transport::new("Transport")?), - Box::new(Sequencer::new("Rhythm#000")?), + //Box::new(Sequencer::new("Rhythm#000")?), ])) }