mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
full block piano roll, pt.2
This commit is contained in:
parent
64ac577f4a
commit
35c0470d15
3 changed files with 90 additions and 59 deletions
|
|
@ -122,3 +122,9 @@ impl Command<PhraseEditorModel> for PhraseCommand {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PhraseEditMode {
|
||||
Note,
|
||||
Scroll,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,16 @@ impl Default for PhraseEditorModel {
|
|||
now: Pulse::default().into(),
|
||||
size: Measure::new(),
|
||||
edit_mode: PhraseEditMode::Scroll,
|
||||
view_mode: PhraseViewMode::Horizontal,
|
||||
note_lo: 0.into(),
|
||||
note_point: 24.into(),
|
||||
time_start: 0.into(),
|
||||
time_point: 0.into(),
|
||||
time_clamp: 0.into(),
|
||||
time_scale: 24.into(),
|
||||
view_mode: PhraseViewMode::PianoHorizontal {
|
||||
time_zoom: 24,
|
||||
note_zoom: PhraseViewNoteZoom::N(1)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +84,7 @@ impl PhraseEditorModel {
|
|||
let end = (start + self.note_len) % phrase.length;
|
||||
phrase.notes[time].push(MidiMessage::NoteOn { key, vel });
|
||||
phrase.notes[end].push(MidiMessage::NoteOff { key, vel });
|
||||
self.buffer = Self::redraw(&phrase);
|
||||
self.buffer = self.view_mode.draw(&phrase);
|
||||
}
|
||||
}
|
||||
/// Move time cursor forward by current note length
|
||||
|
|
@ -96,7 +99,7 @@ impl PhraseEditorModel {
|
|||
if let Some(phrase) = phrase {
|
||||
self.phrase = Some(phrase.clone());
|
||||
self.time_clamp.store(phrase.read().unwrap().length, Ordering::Relaxed);
|
||||
self.buffer = Self::redraw(&*phrase.read().unwrap());
|
||||
self.buffer = self.view_mode.draw(&*phrase.read().unwrap());
|
||||
} else {
|
||||
self.phrase = None;
|
||||
self.time_clamp.store(0, Ordering::Relaxed);
|
||||
|
|
@ -105,19 +108,6 @@ impl PhraseEditorModel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PhraseEditMode {
|
||||
Note,
|
||||
Scroll,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PhraseViewMode {
|
||||
Horizontal,
|
||||
HorizontalHalf,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
pub trait HasEditor {
|
||||
fn editor (&self) -> &PhraseEditorModel;
|
||||
fn editor_focused (&self) -> bool;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct PhraseView<'a> {
|
||||
focused: bool,
|
||||
entered: bool,
|
||||
phrase: &'a Option<Arc<RwLock<Phrase>>>,
|
||||
buffer: &'a BigBuffer,
|
||||
note_len: usize,
|
||||
now: &'a Arc<Pulse>,
|
||||
|
||||
size: &'a Measure<Tui>,
|
||||
focused: bool,
|
||||
entered: bool,
|
||||
phrase: &'a Option<Arc<RwLock<Phrase>>>,
|
||||
buffer: &'a BigBuffer,
|
||||
note_len: usize,
|
||||
now: &'a Arc<Pulse>,
|
||||
size: &'a Measure<Tui>,
|
||||
view_mode: &'a PhraseViewMode,
|
||||
|
||||
note_point: usize,
|
||||
note_range: (usize, usize),
|
||||
|
|
@ -42,14 +42,14 @@ impl<'a, T: HasEditor> From<&'a T> for PhraseView<'a> {
|
|||
}
|
||||
|
||||
Self {
|
||||
focused: state.editor_focused(),
|
||||
entered: state.editor_entered(),
|
||||
note_len: editor.note_len,
|
||||
phrase: &editor.phrase,
|
||||
buffer: &editor.buffer,
|
||||
now: &editor.now,
|
||||
|
||||
size: &editor.size,
|
||||
focused: state.editor_focused(),
|
||||
entered: state.editor_entered(),
|
||||
note_len: editor.note_len,
|
||||
phrase: &editor.phrase,
|
||||
buffer: &editor.buffer,
|
||||
now: &editor.now,
|
||||
size: &editor.size,
|
||||
view_mode: &editor.view_mode,
|
||||
|
||||
note_point,
|
||||
note_range: (note_lo, note_hi),
|
||||
|
|
@ -72,6 +72,7 @@ impl<'a> Content for PhraseView<'a> {
|
|||
phrase,
|
||||
size,
|
||||
buffer,
|
||||
view_mode,
|
||||
note_len,
|
||||
note_range: (note_lo, note_hi),
|
||||
note_names: (note_lo_name, note_hi_name),
|
||||
|
|
@ -122,18 +123,19 @@ impl<'a> Content for PhraseView<'a> {
|
|||
size.set_wh(area.w(), h - 1);
|
||||
Ok(if to.area().h() >= 2 {
|
||||
let area = to.area();
|
||||
to.buffer_update(area, &move |cell, x, y|{
|
||||
cell.set_bg(notes_bg_null);
|
||||
let src_x = (x as usize + time_start) * time_scale;
|
||||
let src_y = y as usize + note_lo / 2;
|
||||
if src_x < buffer.width && src_y < buffer.height - 1 {
|
||||
buffer.get(src_x, (note_hi - y as usize) / 2).map(|src|{
|
||||
cell.set_symbol(src.symbol());
|
||||
cell.set_fg(src.fg);
|
||||
cell.set_bg(src.bg);
|
||||
});
|
||||
}
|
||||
});
|
||||
view_mode.blit(buffer, &mut to.buffer, area, *time_start, *note_hi);
|
||||
//to.buffer_update(area, &move |cell, x, y|{
|
||||
//cell.set_bg(notes_bg_null);
|
||||
//let src_x = (x as usize + time_start) * time_scale;
|
||||
//let src_y = y as usize + note_lo / 2;
|
||||
//if src_x < buffer.width && src_y < buffer.height - 1 {
|
||||
//buffer.get(src_x, (note_hi - y as usize) / 2).map(|src|{
|
||||
//cell.set_symbol(src.symbol());
|
||||
//cell.set_fg(src.fg);
|
||||
//cell.set_bg(src.bg);
|
||||
//});
|
||||
//}
|
||||
//});
|
||||
})
|
||||
};
|
||||
let cursor = move|to: &mut TuiOutput|Ok(if *focused && *entered {
|
||||
|
|
@ -230,27 +232,53 @@ pub enum PhraseViewMode {
|
|||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PhraseViewNoteZoom {
|
||||
Half,
|
||||
N(usize),
|
||||
Half,
|
||||
Octant,
|
||||
}
|
||||
|
||||
impl PhraseViewMode {
|
||||
/// Return a new [BigBuffer] containing a render of the phrase.
|
||||
fn draw (&self, phrase: &Phrase) -> BigBuffer {
|
||||
pub fn draw (&self, phrase: &Phrase) -> BigBuffer {
|
||||
let mut buffer = BigBuffer::new(self.buffer_width(phrase), self.buffer_height(phrase));
|
||||
match self {
|
||||
Self::PianoHorizontal { time_zoom, note_zoom } => match note_zoom {
|
||||
PhraseViewNoteZoom::Half => Self::draw_piano_horizontal_half(
|
||||
&mut buffer, phrase, *time_zoom
|
||||
),
|
||||
PhraseViewNoteZoom::N(_) => Self::draw_piano_horizontal(
|
||||
&mut buffer, phrase, *time_zoom, 1
|
||||
),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
buffer
|
||||
}
|
||||
/// Draw a subsection of the [BigBuffer] onto a regular ratatui [Buffer].
|
||||
fn blit (
|
||||
&self,
|
||||
source: &BigBuffer,
|
||||
target: &mut Buffer,
|
||||
area: impl Area<u16>,
|
||||
time_start: usize,
|
||||
note_hi: usize,
|
||||
) {
|
||||
match self {
|
||||
Self::PianoHorizontal { .. } => {
|
||||
let [x0, y0, w, h] = area.xywh();
|
||||
for (x, target_x) in (x0..x0+w).enumerate() {
|
||||
for (y, target_y) in (y0..y0+h).enumerate() {
|
||||
let source_x = time_start + x;
|
||||
let source_y = note_hi - y;
|
||||
let target_cell = target.get_mut(target_x, target_y);
|
||||
target_cell.set_char('x');
|
||||
if let Some(source_cell) = source.get(source_x, source_y) {
|
||||
*target_cell = source_cell.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
/// Determine the required width to render the phrase.
|
||||
fn buffer_width (&self, phrase: &Phrase) -> usize {
|
||||
match self {
|
||||
|
|
@ -260,6 +288,7 @@ impl PhraseViewMode {
|
|||
Self::PianoVertical { note_zoom, .. } => match note_zoom {
|
||||
PhraseViewNoteZoom::Half => 64,
|
||||
PhraseViewNoteZoom::N(n) => 128*n,
|
||||
_ => unimplemented!()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -269,19 +298,16 @@ impl PhraseViewMode {
|
|||
Self::PianoHorizontal { note_zoom, .. } => match note_zoom {
|
||||
PhraseViewNoteZoom::Half => 64,
|
||||
PhraseViewNoteZoom::N(n) => 128*n,
|
||||
_ => unimplemented!()
|
||||
},
|
||||
Self::PianoVertical { time_zoom, .. } => {
|
||||
phrase.length / time_zoom
|
||||
},
|
||||
}
|
||||
}
|
||||
fn draw_piano_horizontal_half (
|
||||
_: &mut BigBuffer, _: &Phrase, _: usize
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
/// Draw the piano roll using full blocks on note on and half blocks on legato: █▄ █▄ █▄
|
||||
fn draw_piano_horizontal (
|
||||
buffer: &mut BigBuffer, phrase: &Phrase, time_zoom: usize, note_zoom: usize
|
||||
buffer: &mut BigBuffer, phrase: &Phrase, time_zoom: usize, _: usize
|
||||
) {
|
||||
let mut notes_on = [false;128];
|
||||
for col in 0..buffer.width {
|
||||
|
|
@ -295,6 +321,8 @@ impl PhraseViewMode {
|
|||
} else {
|
||||
cell.set_char(' ');
|
||||
}
|
||||
cell.set_fg(Color::Rgb(255, 255, 255));
|
||||
cell.set_bg(Color::Rgb(28, 35, 25));
|
||||
}
|
||||
for event in phrase.notes[time].iter() {
|
||||
match event {
|
||||
|
|
@ -311,10 +339,17 @@ impl PhraseViewMode {
|
|||
}
|
||||
}
|
||||
}
|
||||
//for row in 0..buf.height {
|
||||
//let pitch = 127 - row;
|
||||
|
||||
//}
|
||||
}
|
||||
/// TODO: Draw the piano roll using octant blocks (U+1CD00-U+1CDE5)
|
||||
fn draw_piano_horizontal_octant (
|
||||
_: &mut BigBuffer, _: &Phrase, _: usize
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
/// TODO: Draw the piano roll using half blocks: ▄▀▄
|
||||
fn draw_piano_horizontal_half (
|
||||
_: &mut BigBuffer, _: &Phrase, _: usize
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue