mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
light up keys
This commit is contained in:
parent
e4f3942757
commit
2e7252f8b9
3 changed files with 86 additions and 53 deletions
|
|
@ -215,17 +215,17 @@ pub struct Notifications<T: Fn(AppEvent) + Send>(T);
|
|||
|
||||
impl<T: Fn(AppEvent) + Send> NotificationHandler for Notifications<T> {
|
||||
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<T: Fn(AppEvent) + Send> NotificationHandler for Notifications<T> {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub struct Sequencer {
|
|||
playing: bool,
|
||||
recording: bool,
|
||||
overdub: bool,
|
||||
notes_on: Vec<bool>,
|
||||
}
|
||||
|
||||
enum SequencerView {
|
||||
|
|
@ -32,31 +33,27 @@ enum SequencerView {
|
|||
impl Sequencer {
|
||||
pub fn new (name: &str) -> Usually<DynamicDevice<Self>> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -35,6 +35,6 @@ fn main () -> Result<(), Box<dyn Error>> {
|
|||
//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")?),
|
||||
]))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue