mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
fix 'beheaded' notes in phrase editor
This commit is contained in:
parent
271f431a6a
commit
8bdd088f70
3 changed files with 59 additions and 90 deletions
|
|
@ -131,6 +131,10 @@ impl Phrase {
|
|||
color: color.unwrap_or_else(ItemColorTriplet::random)
|
||||
}
|
||||
}
|
||||
pub fn set_length (&mut self, length: usize) {
|
||||
self.length = length;
|
||||
self.notes = vec![Vec::with_capacity(16);length];
|
||||
}
|
||||
pub fn duplicate (&self) -> Self {
|
||||
let mut clone = self.clone();
|
||||
clone.uuid = uuid::Uuid::new_v4();
|
||||
|
|
|
|||
|
|
@ -5,40 +5,24 @@ mod engine_input; pub(crate) use engine_input::*;
|
|||
mod engine_style; pub(crate) use engine_style::*;
|
||||
mod engine_output; pub(crate) use engine_output::*;
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
mod app_transport; pub(crate) use app_transport::*;
|
||||
|
||||
mod app_sequencer; pub(crate) use app_sequencer::*;
|
||||
mod ctrl_sequencer; pub(crate) use ctrl_sequencer::*;
|
||||
|
||||
mod app_arranger; pub(crate) use app_arranger::*;
|
||||
mod ctrl_arranger; pub(crate) use ctrl_arranger::*;
|
||||
mod model_arranger; pub(crate) use model_arranger::*;
|
||||
mod app_sequencer; pub(crate) use app_sequencer::*;
|
||||
mod app_arranger; pub(crate) use app_arranger::*;
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
mod view_status_bar; pub(crate) use view_status_bar::*;
|
||||
mod status_bar; pub(crate) use status_bar::*;
|
||||
mod file_browser; pub(crate) use file_browser::*;
|
||||
mod phrase_editor; pub(crate) use phrase_editor::*;
|
||||
mod phrase_length; pub(crate) use phrase_length::*;
|
||||
mod phrase_rename; pub(crate) use phrase_rename::*;
|
||||
mod phrase_list; pub(crate) use phrase_list::*;
|
||||
mod phrase_player; pub(crate) use phrase_player::*;
|
||||
mod phrase_select; pub(crate) use phrase_select::*;
|
||||
|
||||
mod model_file_browser; pub(crate) use model_file_browser::*;
|
||||
mod view_file_browser; pub(crate) use view_file_browser::*;
|
||||
mod ctrl_file_browser; pub(crate) use ctrl_file_browser::*;
|
||||
|
||||
mod model_phrase_editor; pub(crate) use model_phrase_editor::*;
|
||||
mod view_phrase_editor; pub(crate) use view_phrase_editor::*;
|
||||
mod ctrl_phrase_editor; pub(crate) use ctrl_phrase_editor::*;
|
||||
|
||||
mod model_phrase_length; pub(crate) use model_phrase_length::*;
|
||||
mod view_phrase_length; pub(crate) use view_phrase_length::*;
|
||||
mod ctrl_phrase_length; pub(crate) use ctrl_phrase_length::*;
|
||||
|
||||
mod model_phrase_list; pub(crate) use model_phrase_list::*;
|
||||
mod view_phrase_list; pub(crate) use view_phrase_list::*;
|
||||
mod ctrl_phrase_list; pub(crate) use ctrl_phrase_list::*;
|
||||
|
||||
mod model_phrase_player; pub(crate) use model_phrase_player::*;
|
||||
|
||||
mod view_phrase_selector; pub(crate) use view_phrase_selector::*;
|
||||
|
||||
mod ctrl_phrase_rename; pub(crate) use ctrl_phrase_rename::*;
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_export] macro_rules! render {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
|
|
@ -53,6 +37,8 @@ mod ctrl_phrase_rename; pub(crate) use ctrl_phrase_rename::*;
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
pub struct Tui {
|
||||
pub exited: Arc<AtomicBool>,
|
||||
pub buffer: Buffer,
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ render!(|self: PhraseView<'a>|{
|
|||
//now: _,
|
||||
..
|
||||
} = self;
|
||||
// is it r6d that `to` is the receiver?
|
||||
let keys = move|to: &mut TuiOutput|{
|
||||
Ok(if to.area().h() >= 2 { view_mode.render_keys(to, *note_hi, *note_lo) })
|
||||
};
|
||||
|
|
@ -214,58 +213,38 @@ render!(|self: PhraseView<'a>|{
|
|||
)
|
||||
})
|
||||
};
|
||||
//let playhead = move|_: &mut TuiOutput|{ // will this live or die?
|
||||
////let playhead_inactive = Style::default().fg(Color::Rgb(255,255,255)).bg(Color::Rgb(40,50,30));
|
||||
////let playhead_active = playhead_inactive.clone().yellow().bold().not_dim();
|
||||
////if let Some(_) = phrase {
|
||||
////let now = now.get() as usize; // TODO FIXME: self.now % phrase.read().unwrap().length;
|
||||
////let time_clamp = time_clamp;
|
||||
////for x in 0..(time_clamp/time_zoom).saturating_sub(*time_start) {
|
||||
////let this_step = time_start + (x + 0) * time_zoom;
|
||||
////let next_step = time_start + (x + 1) * time_zoom;
|
||||
////let x = to.area().x() + x as u16;
|
||||
////let active = this_step <= now && now < next_step;
|
||||
////let character = if active { "|" } else { "·" };
|
||||
////let style = if active { playhead_active } else { playhead_inactive };
|
||||
////to.blit(&character, x, to.area.y(), Some(style));
|
||||
////}
|
||||
////}
|
||||
//Ok(())
|
||||
//};
|
||||
let indicators = lay!(move|add|{
|
||||
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||
let upper_left = format!("╭{note_hi} {note_hi_name} {}",
|
||||
phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new())
|
||||
);
|
||||
let lower_left = format!("╰{note_lo} {note_lo_name}");
|
||||
let mut lower_right = format!(" {} ", size.format());
|
||||
if *focused && *entered {
|
||||
lower_right = format!("Note: {} ({}) {} {lower_right}",
|
||||
note_point, to_note_name(*note_point), pulses_to_name(*note_len)
|
||||
);
|
||||
}
|
||||
let mut upper_right = format!("[{}]", if *entered {"■"} else {" "});
|
||||
if let Some(phrase) = phrase {
|
||||
upper_right = format!("Time: {}/{} {} {upper_right}",
|
||||
time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()),
|
||||
)
|
||||
};
|
||||
add(&Tui::at_nw(Tui::fg(title_color, upper_left)))?;
|
||||
add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?;
|
||||
add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?;
|
||||
add(&Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))?;
|
||||
Ok(())
|
||||
});
|
||||
let content = Tui::bg(Color::Rgb(40, 50, 30), Tui::fill_x(row!([
|
||||
Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(2))), keys))),
|
||||
Tui::fill_x(lay!([
|
||||
Tui::push_y(1, Tui::fill_x(Widget::new(|to|Ok(Some(to)), notes))),
|
||||
Tui::push_y(1, Widget::new(|to|Ok(Some(to)), cursor))
|
||||
])),
|
||||
])));
|
||||
lay!([
|
||||
indicators,
|
||||
content
|
||||
lay!(move|add|{
|
||||
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||
let upper_left = format!("╭{note_hi} {note_hi_name} {}",
|
||||
phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new())
|
||||
);
|
||||
let lower_left = format!("╰{note_lo} {note_lo_name}");
|
||||
let mut lower_right = format!(" {} ", size.format());
|
||||
if *focused && *entered {
|
||||
lower_right = format!("Note: {} ({}) {} {lower_right}",
|
||||
note_point, to_note_name(*note_point), pulses_to_name(*note_len)
|
||||
);
|
||||
}
|
||||
let mut upper_right = format!("[{}]", if *entered {"■"} else {" "});
|
||||
if let Some(phrase) = phrase {
|
||||
upper_right = format!("Time: {}/{} {} {upper_right}",
|
||||
time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()),
|
||||
)
|
||||
};
|
||||
add(&Tui::at_nw(Tui::fg(title_color, upper_left)))?;
|
||||
add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?;
|
||||
add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?;
|
||||
add(&Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))?;
|
||||
Ok(())
|
||||
}),
|
||||
Tui::bg(Color::Rgb(40, 50, 30), Tui::fill_x(row!([
|
||||
Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(2))), keys))),
|
||||
Tui::fill_x(lay!([
|
||||
Tui::push_y(1, Tui::fill_x(Widget::new(|to|Ok(Some(to)), notes))),
|
||||
Tui::push_y(1, Widget::new(|to|Ok(Some(to)), cursor))
|
||||
])),
|
||||
])))
|
||||
])
|
||||
});
|
||||
|
||||
|
|
@ -464,16 +443,16 @@ impl PhraseViewMode {
|
|||
let mut notes_on = [false;128];
|
||||
for (x, time_start) in (0..phrase.length).step_by(time_zoom).enumerate() {
|
||||
let time_end = time_start + time_zoom;
|
||||
for time in time_start..time_end {
|
||||
for (y, note) in (0..127).rev().enumerate() {
|
||||
let cell = target.get_mut(x, y).unwrap();
|
||||
if notes_on[note] {
|
||||
cell.set_fg(Color::Rgb(255, 255, 255));
|
||||
cell.set_bg(Color::Rgb(0, 0, 0));
|
||||
cell.set_char('▄');
|
||||
cell.set_style(style);
|
||||
}
|
||||
for (y, note) in (0..127).rev().enumerate() {
|
||||
let cell = target.get_mut(x, 127 - note).unwrap();
|
||||
if notes_on[note] {
|
||||
cell.set_fg(Color::Rgb(255, 255, 255));
|
||||
cell.set_bg(Color::Rgb(0, 0, 0));
|
||||
cell.set_char('▄');
|
||||
cell.set_style(style);
|
||||
}
|
||||
}
|
||||
for time in time_start..time_end {
|
||||
for event in phrase.notes[time].iter() {
|
||||
match event {
|
||||
MidiMessage::NoteOn { key, .. } => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue