wip: highlight keys

This commit is contained in:
🪞👃🪞 2024-07-08 20:57:10 +03:00
parent dff42ca5a7
commit 1e3d96e64e
5 changed files with 124 additions and 35 deletions

View file

@ -54,7 +54,7 @@ impl Phrase {
pub fn process_out (
&self,
output: &mut MIDIChunk,
notes_on: &mut Vec<bool>,
notes_on: &mut [bool;128],
timebase: &Arc<Timebase>,
(frame0, frames, _): (usize, usize, f64),
) {

View file

@ -16,15 +16,17 @@ pub struct Track {
/// Output from current sequence.
pub midi_out: Port<MidiOut>,
midi_out_buf: Vec<Vec<Vec<u8>>>,
/// Red keys on piano roll.
pub notes_on: Vec<bool>,
/// Device chain
pub devices: Vec<JackDevice>,
/// Device selector
pub device: usize,
/// Send all notes off
/// FIXME: Some(nframes)?
pub reset: bool
pub reset: bool,
/// Highlight keys on piano roll.
pub notes_in: [bool;128],
/// Highlight keys on piano roll.
pub notes_out: [bool;128],
}
ports!(Track {
audio: {
@ -46,7 +48,8 @@ impl Track {
name: name.to_string(),
midi_out: jack.register_port(name, MidiOut)?,
midi_out_buf: vec![vec![];16384],
notes_on: vec![false;128],
notes_in: [false;128],
notes_out: [false;128],
monitoring: false,
recording: false,
overdub: true,
@ -147,14 +150,13 @@ impl Track {
) {
phrase.process_out(
&mut self.midi_out_buf,
&mut self.notes_on,
&mut self.notes_out,
timebase,
(frame0.saturating_sub(start_frame), frames, period)
);
// Monitor and record input
if self.recording || self.monitoring {
// For highlighting keys and note repeat
let notes_on = &mut self.notes_on;
for (frame, event, bytes) in parse_midi_input(input) {
match event {
LiveEvent::Midi { message, .. } => {
@ -175,10 +177,10 @@ impl Track {
}
match message {
MidiMessage::NoteOn { key, .. } => {
notes_on[key.as_int() as usize] = true;
self.notes_in[key.as_int() as usize] = true;
}
MidiMessage::NoteOff { key, .. } => {
notes_on[key.as_int() as usize] = false;
self.notes_in[key.as_int() as usize] = false;
},
_ => {}
}
@ -218,10 +220,10 @@ impl Track {
fn process_monitor_message (&mut self, message: &MidiMessage) {
match message {
MidiMessage::NoteOn { key, .. } => {
self.notes_on[key.as_int() as usize] = true;
self.notes_in[key.as_int() as usize] = true;
}
MidiMessage::NoteOff { key, .. } => {
self.notes_on[key.as_int() as usize] = false;
self.notes_in[key.as_int() as usize] = false;
},
_ => {}
}

View file

@ -129,6 +129,7 @@ impl App {
}.render(buf, area)
}
fn draw_phrase (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let track = self.tracks.get(self.track_cursor - 1);
let phrase = self.phrase();
let seq_area = SequencerView {
phrase,
@ -140,8 +141,10 @@ impl App {
time_zoom: self.time_zoom,
note_cursor: self.note_cursor,
note_start: self.note_start,
notes_in: if let Some(track) = track { &track.notes_in } else { &[false;128] },
notes_out: if let Some(track) = track { &track.notes_out } else { &[false;128] },
}.render(buf, area)?;
if let Some(track) = self.tracks.get(self.track_cursor - 1) {
if let Some(track) = track {
if phrase.is_none() && self.section == AppSection::Sequencer {
let label = format!("[ENTER] Create new clip: {}", track.name);
let x = area.x + seq_area.width / 2 - (label.len() / 2) as u16;

View file

@ -20,7 +20,12 @@ pub struct SequencerView<'a> {
/// Position of cursor within time range
pub time_cursor: usize,
/// Current time
pub now: usize
pub now: usize,
/// Highlight input keys
pub notes_in: &'a [bool; 128],
/// Highlight output keys
pub notes_out: &'a [bool; 128],
}
impl<'a> Render for SequencerView<'a> {
@ -39,8 +44,7 @@ impl<'a> SequencerView<'a> {
} else {
Style::default().green().dim()
});
let notes = &[];
self::horizontal::keys(buf, area, self.note_start, notes)?;
self::horizontal::keys(buf, area, self.note_start, self.notes_in, self.notes_out)?;
let quant = ppq_to_name(self.time_zoom);
quant.blit(
buf,
@ -76,10 +80,17 @@ mod horizontal {
}
}
pub fn keys (buf: &mut Buffer, area: Rect, note0: usize, _notes: &[bool])
-> Usually<Rect>
{
let dim = Style::default().dim();
pub fn keys (
buf: &mut Buffer,
area: Rect,
note0: usize,
notes_in: &[bool;128],
notes_out: &[bool;128],
) -> Usually<Rect> {
let dim = Style::default().not_dim();
let red = Style::default().red();
let yellow = Style::default().yellow();
let green = Style::default().green();
let mut cell_bg = Cell::default();
cell_bg.set_char('░');
@ -102,12 +113,82 @@ mod horizontal {
let Rect { x, y, width, height } = area;
let height = height.min(128);
let h = height.saturating_sub(2);
let index_to_color = |index: usize, default: Color|
if notes_in[index] && notes_out[index] {
Color::Yellow
} else if notes_in[index] {
Color::Red
} else if notes_out[index] {
Color::Green
} else {
default
};
for index in 0..h {
let y = y + h - index;
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_keys[(index % 6) as usize].clone();
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_full.clone();
match index % 6 {
0 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::White));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::Black));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
1 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::White));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::Black));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
2 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::White));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
3 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::Black));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
4 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::Black));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
5 => {
let key1 = buf.get_mut(x + 1, y);
*key1 = cell_lo.clone();
key1.set_fg(index_to_color(index as usize * 2, Color::Black));
key1.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
let key2 = buf.get_mut(x + 2, y);
*key2 = cell_lo.clone();
key2.set_fg(index_to_color(index as usize * 2, Color::White));
key2.set_bg(index_to_color(index as usize * 2 + 1, Color::White));
},
_ => { unreachable!(); }
}
for x in x+5..x+width-1 {
*buf.get_mut(x, y) = cell_bg.clone();
}