mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: highlight keys
This commit is contained in:
parent
dff42ca5a7
commit
1e3d96e64e
5 changed files with 124 additions and 35 deletions
|
|
@ -19,18 +19,21 @@
|
||||||
(:08 (36 128))
|
(:08 (36 128))
|
||||||
(:12 (36 100))
|
(:12 (36 100))
|
||||||
(:14 (36 110)))
|
(:14 (36 110)))
|
||||||
(phrase { :name "D Beat" :beats 4 })
|
(phrase { :name "D Beat" :beats 4 :steps 16 }
|
||||||
;(:00 (44 :100) (:34 :100) (:35 :100))
|
(:00 (36 128))
|
||||||
;(:02 (42 :100) )
|
(:00 (44 50))
|
||||||
;(:04 (42 :080) (:38 :100) )
|
(:02 (44 30))
|
||||||
;(:06 (44 :120) )
|
(:04 (40 100))
|
||||||
;(:08 (42 :100) (:34 :100) (:35 :100))
|
(:04 (44 80))
|
||||||
;(:10 (42 :100) (:34 :100) (:35 :100))
|
(:06 (44 50))
|
||||||
;(:12 (44 :100) (:40 :100) )
|
(:08 (36 100))
|
||||||
;(:13 (44 :100) )
|
(:08 (44 30))
|
||||||
;(:14 (44 :100) )
|
(:10 (36 100))
|
||||||
;(:15 (42 :100) )))
|
(:10 (44 50))
|
||||||
(phrase { :name "Garage" :beats 4 }
|
(:12 (40 100))
|
||||||
|
(:12 (44 80))
|
||||||
|
(:14 (44 50)))
|
||||||
|
(phrase { :name "Garage" :beats 4 :steps 16 }
|
||||||
(:00 (44 100) (36 100) (35 100))
|
(:00 (44 100) (36 100) (35 100))
|
||||||
(:01 (44 100))
|
(:01 (44 100))
|
||||||
(:02 (44 100) (35 100))
|
(:02 (44 100) (35 100))
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ impl Phrase {
|
||||||
pub fn process_out (
|
pub fn process_out (
|
||||||
&self,
|
&self,
|
||||||
output: &mut MIDIChunk,
|
output: &mut MIDIChunk,
|
||||||
notes_on: &mut Vec<bool>,
|
notes_on: &mut [bool;128],
|
||||||
timebase: &Arc<Timebase>,
|
timebase: &Arc<Timebase>,
|
||||||
(frame0, frames, _): (usize, usize, f64),
|
(frame0, frames, _): (usize, usize, f64),
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,17 @@ pub struct Track {
|
||||||
/// Output from current sequence.
|
/// Output from current sequence.
|
||||||
pub midi_out: Port<MidiOut>,
|
pub midi_out: Port<MidiOut>,
|
||||||
midi_out_buf: Vec<Vec<Vec<u8>>>,
|
midi_out_buf: Vec<Vec<Vec<u8>>>,
|
||||||
/// Red keys on piano roll.
|
|
||||||
pub notes_on: Vec<bool>,
|
|
||||||
/// Device chain
|
/// Device chain
|
||||||
pub devices: Vec<JackDevice>,
|
pub devices: Vec<JackDevice>,
|
||||||
/// Device selector
|
/// Device selector
|
||||||
pub device: usize,
|
pub device: usize,
|
||||||
/// Send all notes off
|
/// Send all notes off
|
||||||
/// FIXME: Some(nframes)?
|
/// 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 {
|
ports!(Track {
|
||||||
audio: {
|
audio: {
|
||||||
|
|
@ -46,7 +48,8 @@ impl Track {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
midi_out: jack.register_port(name, MidiOut)?,
|
midi_out: jack.register_port(name, MidiOut)?,
|
||||||
midi_out_buf: vec![vec![];16384],
|
midi_out_buf: vec![vec![];16384],
|
||||||
notes_on: vec![false;128],
|
notes_in: [false;128],
|
||||||
|
notes_out: [false;128],
|
||||||
monitoring: false,
|
monitoring: false,
|
||||||
recording: false,
|
recording: false,
|
||||||
overdub: true,
|
overdub: true,
|
||||||
|
|
@ -147,14 +150,13 @@ impl Track {
|
||||||
) {
|
) {
|
||||||
phrase.process_out(
|
phrase.process_out(
|
||||||
&mut self.midi_out_buf,
|
&mut self.midi_out_buf,
|
||||||
&mut self.notes_on,
|
&mut self.notes_out,
|
||||||
timebase,
|
timebase,
|
||||||
(frame0.saturating_sub(start_frame), frames, period)
|
(frame0.saturating_sub(start_frame), frames, period)
|
||||||
);
|
);
|
||||||
// Monitor and record input
|
// Monitor and record input
|
||||||
if self.recording || self.monitoring {
|
if self.recording || self.monitoring {
|
||||||
// For highlighting keys and note repeat
|
// For highlighting keys and note repeat
|
||||||
let notes_on = &mut self.notes_on;
|
|
||||||
for (frame, event, bytes) in parse_midi_input(input) {
|
for (frame, event, bytes) in parse_midi_input(input) {
|
||||||
match event {
|
match event {
|
||||||
LiveEvent::Midi { message, .. } => {
|
LiveEvent::Midi { message, .. } => {
|
||||||
|
|
@ -175,10 +177,10 @@ impl Track {
|
||||||
}
|
}
|
||||||
match message {
|
match message {
|
||||||
MidiMessage::NoteOn { key, .. } => {
|
MidiMessage::NoteOn { key, .. } => {
|
||||||
notes_on[key.as_int() as usize] = true;
|
self.notes_in[key.as_int() as usize] = true;
|
||||||
}
|
}
|
||||||
MidiMessage::NoteOff { key, .. } => {
|
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) {
|
fn process_monitor_message (&mut self, message: &MidiMessage) {
|
||||||
match message {
|
match message {
|
||||||
MidiMessage::NoteOn { key, .. } => {
|
MidiMessage::NoteOn { key, .. } => {
|
||||||
self.notes_on[key.as_int() as usize] = true;
|
self.notes_in[key.as_int() as usize] = true;
|
||||||
}
|
}
|
||||||
MidiMessage::NoteOff { key, .. } => {
|
MidiMessage::NoteOff { key, .. } => {
|
||||||
self.notes_on[key.as_int() as usize] = false;
|
self.notes_in[key.as_int() as usize] = false;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ impl App {
|
||||||
}.render(buf, area)
|
}.render(buf, area)
|
||||||
}
|
}
|
||||||
fn draw_phrase (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
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 phrase = self.phrase();
|
||||||
let seq_area = SequencerView {
|
let seq_area = SequencerView {
|
||||||
phrase,
|
phrase,
|
||||||
|
|
@ -140,8 +141,10 @@ impl App {
|
||||||
time_zoom: self.time_zoom,
|
time_zoom: self.time_zoom,
|
||||||
note_cursor: self.note_cursor,
|
note_cursor: self.note_cursor,
|
||||||
note_start: self.note_start,
|
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)?;
|
}.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 {
|
if phrase.is_none() && self.section == AppSection::Sequencer {
|
||||||
let label = format!("[ENTER] Create new clip: {}", track.name);
|
let label = format!("[ENTER] Create new clip: {}", track.name);
|
||||||
let x = area.x + seq_area.width / 2 - (label.len() / 2) as u16;
|
let x = area.x + seq_area.width / 2 - (label.len() / 2) as u16;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,12 @@ pub struct SequencerView<'a> {
|
||||||
/// Position of cursor within time range
|
/// Position of cursor within time range
|
||||||
pub time_cursor: usize,
|
pub time_cursor: usize,
|
||||||
/// Current time
|
/// 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> {
|
impl<'a> Render for SequencerView<'a> {
|
||||||
|
|
@ -39,8 +44,7 @@ impl<'a> SequencerView<'a> {
|
||||||
} else {
|
} else {
|
||||||
Style::default().green().dim()
|
Style::default().green().dim()
|
||||||
});
|
});
|
||||||
let notes = &[];
|
self::horizontal::keys(buf, area, self.note_start, self.notes_in, self.notes_out)?;
|
||||||
self::horizontal::keys(buf, area, self.note_start, notes)?;
|
|
||||||
let quant = ppq_to_name(self.time_zoom);
|
let quant = ppq_to_name(self.time_zoom);
|
||||||
quant.blit(
|
quant.blit(
|
||||||
buf,
|
buf,
|
||||||
|
|
@ -76,10 +80,17 @@ mod horizontal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keys (buf: &mut Buffer, area: Rect, note0: usize, _notes: &[bool])
|
pub fn keys (
|
||||||
-> Usually<Rect>
|
buf: &mut Buffer,
|
||||||
{
|
area: Rect,
|
||||||
let dim = Style::default().dim();
|
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();
|
let mut cell_bg = Cell::default();
|
||||||
cell_bg.set_char('░');
|
cell_bg.set_char('░');
|
||||||
|
|
@ -102,12 +113,82 @@ mod horizontal {
|
||||||
let Rect { x, y, width, height } = area;
|
let Rect { x, y, width, height } = area;
|
||||||
let height = height.min(128);
|
let height = height.min(128);
|
||||||
let h = height.saturating_sub(2);
|
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 {
|
for index in 0..h {
|
||||||
let y = y + h - index;
|
let y = y + h - index;
|
||||||
let key1 = buf.get_mut(x + 1, y);
|
match index % 6 {
|
||||||
*key1 = cell_keys[(index % 6) as usize].clone();
|
0 => {
|
||||||
let key2 = buf.get_mut(x + 2, y);
|
let key1 = buf.get_mut(x + 1, y);
|
||||||
*key2 = cell_full.clone();
|
*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 {
|
for x in x+5..x+width-1 {
|
||||||
*buf.get_mut(x, y) = cell_bg.clone();
|
*buf.get_mut(x, y) = cell_bg.clone();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue