mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
perf: use Vec instead of BTreeMap in Phrase
This commit is contained in:
parent
db25099268
commit
4a8f5b267f
7 changed files with 150 additions and 221 deletions
|
|
@ -106,11 +106,9 @@ const KEYMAP: &'static [KeyBinding<App>] = keymap!(App {
|
|||
|
||||
[Char('x'), NONE, "extend", "double the current clip", |app: &mut App| {
|
||||
if let Some(phrase) = app.phrase_mut() {
|
||||
let mut notes = BTreeMap::new();
|
||||
for (time, events) in phrase.notes.iter() {
|
||||
notes.insert(time + phrase.length, events.clone());
|
||||
}
|
||||
phrase.notes.append(&mut notes);
|
||||
let mut notes = phrase.notes.clone();
|
||||
notes.extend_from_slice(&mut phrase.notes);
|
||||
phrase.notes = notes;
|
||||
phrase.length = phrase.length * 2;
|
||||
}
|
||||
Ok(true)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
use crate::core::*;
|
||||
|
||||
pub type PhraseData =
|
||||
BTreeMap<usize, Vec<MidiMessage>>;
|
||||
|
||||
pub type MIDIMessage =
|
||||
Vec<u8>;
|
||||
|
||||
|
|
|
|||
14
src/edn.rs
14
src/edn.rs
|
|
@ -137,10 +137,10 @@ impl Track {
|
|||
|
||||
impl Phrase {
|
||||
fn load_edn <'e> (ppq: usize, args: &[Edn<'e>]) -> Usually<Self> {
|
||||
let mut phrase = Self::default();
|
||||
let mut name = String::new();
|
||||
let mut beats = 0usize;
|
||||
let mut steps = 0usize;
|
||||
let mut data = BTreeMap::new();
|
||||
edn!(edn in args {
|
||||
Edn::Map(map) => {
|
||||
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
|
||||
|
|
@ -148,6 +148,10 @@ impl Phrase {
|
|||
}
|
||||
if let Some(Edn::Int(b)) = map.get(&Edn::Key(":beats")) {
|
||||
beats = *b as usize;
|
||||
phrase.length = ppq * beats;
|
||||
for _ in phrase.notes.len()..phrase.length {
|
||||
phrase.notes.push(Vec::with_capacity(16))
|
||||
}
|
||||
}
|
||||
if let Some(Edn::Int(s)) = map.get(&Edn::Key(":steps")) {
|
||||
steps = *s as usize;
|
||||
|
|
@ -169,15 +173,11 @@ impl Phrase {
|
|||
args.get(0),
|
||||
args.get(1),
|
||||
) {
|
||||
if !data.contains_key(&time) {
|
||||
data.insert(time, vec![]);
|
||||
}
|
||||
let (key, vel) = (
|
||||
u7::from((*key as u8).min(127)),
|
||||
u7::from((*vel as u8).min(127))
|
||||
);
|
||||
data.get_mut(&time).unwrap()
|
||||
.push(MidiMessage::NoteOn { key, vel })
|
||||
phrase.notes[time].push(MidiMessage::NoteOn { key, vel })
|
||||
} else {
|
||||
panic!("unexpected list in phrase '{name}'")
|
||||
},
|
||||
|
|
@ -187,7 +187,7 @@ impl Phrase {
|
|||
},
|
||||
_ => panic!("unexpected in phrase '{name}': {edn:?}"),
|
||||
});
|
||||
Ok(Self::new(&name, beats * ppq, Some(data)))
|
||||
Ok(phrase)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub mod sampler;
|
|||
pub mod scene;
|
||||
pub mod track;
|
||||
|
||||
pub use self::phrase::Phrase;
|
||||
pub use self::phrase::{Phrase, PhraseData};
|
||||
pub use self::scene::Scene;
|
||||
pub use self::track::Track;
|
||||
pub use self::sampler::{Sampler, Sample, read_sample_data};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use crate::{core::*, model::App};
|
|||
}}
|
||||
}
|
||||
|
||||
pub type PhraseData = Vec<Vec<MidiMessage>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Phrase {
|
||||
pub name: String,
|
||||
|
|
@ -30,13 +32,20 @@ impl Phrase {
|
|||
Self {
|
||||
name: name.to_string(),
|
||||
length,
|
||||
notes: notes.unwrap_or(BTreeMap::new()),
|
||||
notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]),
|
||||
looped: Some((0, length))
|
||||
}
|
||||
}
|
||||
pub fn record_event (&mut self, pulse: usize, message: MidiMessage) {
|
||||
if pulse >= self.length {
|
||||
panic!("extend phrase first")
|
||||
}
|
||||
self.notes[pulse].push(message);
|
||||
}
|
||||
/// Check if a range `start..end` contains MIDI Note On `k`
|
||||
pub fn contains_note_on (&self, k: u7, start: usize, end: usize) -> bool {
|
||||
for (_, (_, events)) in self.notes.range(start..end).enumerate() {
|
||||
//panic!("{:?} {start} {end}", &self);
|
||||
for events in self.notes[start.max(0)..end.min(self.notes.len())].iter() {
|
||||
for event in events.iter() {
|
||||
match event {
|
||||
MidiMessage::NoteOn {key,..} => {
|
||||
|
|
@ -63,8 +72,7 @@ impl Phrase {
|
|||
frame0, frame0 + frames
|
||||
) {
|
||||
let tick = tick % self.length;
|
||||
if let Some(events) = self.notes.get(&(tick as usize)) {
|
||||
for message in events.iter() {
|
||||
for message in self.notes[tick].iter() {
|
||||
buf.clear();
|
||||
let channel = 0.into();
|
||||
let message = *message;
|
||||
|
|
@ -78,16 +86,6 @@ impl Phrase {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_event (&mut self, pulse: usize, message: MidiMessage) {
|
||||
let contains = self.notes.contains_key(&pulse);
|
||||
if contains {
|
||||
self.notes.get_mut(&pulse).unwrap().push(message.clone());
|
||||
} else {
|
||||
self.notes.insert(pulse, vec![message.clone()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
|
|
|||
|
|
@ -11,45 +11,49 @@ pub trait BorderStyle {
|
|||
const W: &'static str = "";
|
||||
|
||||
#[inline]
|
||||
fn draw (&self, buf: &mut Buffer, area: Rect) {
|
||||
self.draw_horizontal(buf, area, None);
|
||||
self.draw_vertical(buf, area, None);
|
||||
self.draw_corners(buf, area, None);
|
||||
fn draw (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
||||
self.draw_horizontal(buf, area, None)?;
|
||||
self.draw_vertical(buf, area, None)?;
|
||||
self.draw_corners(buf, area, None)?;
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_horizontal (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
|
||||
fn draw_horizontal (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) -> Usually<Rect> {
|
||||
let style = style.or_else(||self.style_horizontal());
|
||||
for x in area.x..(area.x+area.width).saturating_sub(1) {
|
||||
self.draw_north(buf, x, area.y, style);
|
||||
self.draw_south(buf, x, (area.y + area.height).saturating_sub(1), style);
|
||||
self.draw_north(buf, x, area.y, style)?;
|
||||
self.draw_south(buf, x, (area.y + area.height).saturating_sub(1), style)?;
|
||||
}
|
||||
Ok(area)
|
||||
}
|
||||
#[inline]
|
||||
fn draw_north (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) {
|
||||
Self::N.blit(buf, x, y, style);
|
||||
fn draw_north (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Usually<Rect> {
|
||||
Self::N.blit(buf, x, y, style)
|
||||
}
|
||||
#[inline]
|
||||
fn draw_south (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) {
|
||||
Self::S.blit(buf, x, y, style);
|
||||
fn draw_south (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Usually<Rect> {
|
||||
Self::S.blit(buf, x, y, style)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_vertical (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
|
||||
fn draw_vertical (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) -> Usually<Rect> {
|
||||
let style = style.or_else(||self.style_vertical());
|
||||
for y in area.y..(area.y+area.height).saturating_sub(1) {
|
||||
Self::W.blit(buf, area.x, y, style);
|
||||
Self::E.blit(buf, area.x + area.width - 1, y, style);
|
||||
Self::W.blit(buf, area.x, y, style)?;
|
||||
Self::E.blit(buf, area.x + area.width - 1, y, style)?;
|
||||
}
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_corners (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
|
||||
fn draw_corners (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) -> Usually<Rect> {
|
||||
let style = style.or_else(||self.style_corners());
|
||||
Self::NW.blit(buf, area.x, area.y, style);
|
||||
Self::NE.blit(buf, area.x + area.width - 1, area.y, style);
|
||||
Self::SW.blit(buf, area.x, area.y + area.height - 1, style);
|
||||
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style);
|
||||
Self::NW.blit(buf, area.x, area.y, style)?;
|
||||
Self::NE.blit(buf, area.x + area.width - 1, area.y, style)?;
|
||||
Self::SW.blit(buf, area.x, area.y + area.height - 1, style)?;
|
||||
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style)?;
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,31 +1,28 @@
|
|||
use crate::{core::*,model::*};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SequencerMode { Tiny, Compact, Horizontal, Vertical, }
|
||||
|
||||
pub struct SequencerView<'a> {
|
||||
pub focused: bool,
|
||||
focused: bool,
|
||||
/// Displayed phrase
|
||||
pub phrase: Option<&'a Phrase>,
|
||||
phrase: Option<&'a Phrase>,
|
||||
/// Resolution of MIDI sequence
|
||||
pub ppq: usize,
|
||||
ppq: usize,
|
||||
/// Range of notes to display
|
||||
pub note_start: usize,
|
||||
note_start: usize,
|
||||
/// Position of cursor within note range
|
||||
pub note_cursor: usize,
|
||||
note_cursor: usize,
|
||||
/// PPQ per display unit
|
||||
pub time_zoom: usize,
|
||||
time_zoom: usize,
|
||||
/// Range of time steps to display
|
||||
pub time_start: usize,
|
||||
time_start: usize,
|
||||
/// Position of cursor within time range
|
||||
pub time_cursor: usize,
|
||||
time_cursor: usize,
|
||||
/// Current time
|
||||
pub now: usize,
|
||||
now: usize,
|
||||
|
||||
/// Highlight input keys
|
||||
pub notes_in: &'a [bool; 128],
|
||||
notes_in: &'a [bool; 128],
|
||||
/// Highlight output keys
|
||||
pub notes_out: &'a [bool; 128],
|
||||
notes_out: &'a [bool; 128],
|
||||
}
|
||||
|
||||
impl<'a> SequencerView<'a> {
|
||||
|
|
@ -34,9 +31,8 @@ impl<'a> SequencerView<'a> {
|
|||
0 => None,
|
||||
_ => app.tracks.get(app.track_cursor - 1)
|
||||
};
|
||||
let phrase = app.phrase();
|
||||
Self {
|
||||
phrase,
|
||||
phrase: app.phrase(),
|
||||
focused: app.section == AppSection::Sequencer,
|
||||
ppq: app.timebase.ppq() as usize,
|
||||
now: app.timebase.frame_to_pulse(app.playhead as f64) as usize,
|
||||
|
|
@ -75,38 +71,46 @@ impl<'a> SequencerView<'a> {
|
|||
Style::default()
|
||||
}
|
||||
}
|
||||
fn index_to_color (&self, index: usize, default: Color) -> Color {
|
||||
if self.notes_in[index] && self.notes_out[index] {
|
||||
Color::Yellow
|
||||
} else if self.notes_in[index] {
|
||||
Color::Red
|
||||
} else if self.notes_out[index] {
|
||||
Color::Green
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SequencerView<'a> {
|
||||
fn horizontal_draw (&self, buf: &mut Buffer, area: Rect) -> Usually<()> {
|
||||
self.horizontal_keys(buf, area)?;
|
||||
self.horizontal_quant(buf, area);
|
||||
self.horizontal_timer(buf, area, self.phrase);
|
||||
self.horizontal_lanes(buf, area, self.phrase);
|
||||
self.horizontal_cursor(buf, area);
|
||||
self.horizontal_quant(buf, area)?;
|
||||
self.horizontal_timer(buf, area, self.phrase)?;
|
||||
self.horizontal_lanes(buf, area, self.phrase)?;
|
||||
self.horizontal_cursor(buf, area)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn horizontal_quant (&self, buf: &mut Buffer, area: Rect) {
|
||||
fn horizontal_quant (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
||||
let quant = ppq_to_name(self.time_zoom);
|
||||
let quant_x = area.x + area.width - 1 - quant.len() as u16;
|
||||
let quant_y = area.y + area.height - 2;
|
||||
quant.blit(buf, quant_x, quant_y, self.style_focus());
|
||||
quant.blit(buf, quant_x, quant_y, self.style_focus())
|
||||
}
|
||||
|
||||
fn horizontal_cursor (&self, buf: &mut Buffer, area: Rect) {
|
||||
fn horizontal_cursor (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
||||
let (time, note) = (self.time_cursor, self.note_cursor);
|
||||
let x = area.x + 5 + time as u16;
|
||||
let y = area.y + 1 + note as u16 / 2;
|
||||
let c = if note % 2 == 0 { "▀" } else { "▄" };
|
||||
c.blit(buf, x, y, self.style_focus());
|
||||
c.blit(buf, x, y, self.style_focus())
|
||||
}
|
||||
|
||||
fn horizontal_timer (&self, buf: &mut Buffer, area: Rect, phrase: Option<&Phrase>) {
|
||||
if phrase.is_none() {
|
||||
return
|
||||
}
|
||||
let phrase = phrase.unwrap();
|
||||
fn horizontal_timer (&self, buf: &mut Buffer, area: Rect, phrase: Option<&Phrase>) -> Usually<Rect> {
|
||||
if let Some(phrase) = phrase {
|
||||
let (time0, time_z, now) = (self.time_start, self.time_zoom, self.now % phrase.length);
|
||||
let Rect { x, width, .. } = area;
|
||||
let offset = 5;
|
||||
|
|
@ -114,135 +118,69 @@ impl<'a> SequencerView<'a> {
|
|||
let step = (time0 + (x-offset) as usize) * time_z;
|
||||
let next_step = (time0 + (x-offset) as usize + 1) * time_z;
|
||||
let style = Self::style_timer_step(now, step, next_step);
|
||||
"-".blit(buf, x, area.y, Some(style));
|
||||
"-".blit(buf, x, area.y, Some(style))?;
|
||||
}
|
||||
}
|
||||
return Ok(Rect { x: area.x, y: area.y, width: area.width, height: 1 })
|
||||
}
|
||||
|
||||
fn horizontal_keys (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
||||
let (note0, notes_in, notes_out) = (self.note_start, self.notes_in, self.notes_out);
|
||||
let mut cell_bg = Cell::default();
|
||||
cell_bg.set_char('░');
|
||||
cell_bg.set_style(Style::default().not_dim().black());
|
||||
|
||||
let mut cell_full = Cell::default();
|
||||
cell_full.set_char('█');
|
||||
cell_full.set_style(Style::default().not_dim());
|
||||
|
||||
let mut cell_hi = Cell::default();
|
||||
cell_hi.set_char('▀');
|
||||
cell_hi.set_style(Style::default().not_dim());
|
||||
|
||||
let mut cell_lo = Cell::default();
|
||||
cell_lo.set_char('▄');
|
||||
cell_lo.set_style(Style::default().not_dim());
|
||||
|
||||
let note0 = self.note_start;
|
||||
let not_dim = Style::default().not_dim();
|
||||
let black = not_dim.black();
|
||||
let Rect { x, y, width, height } = area;
|
||||
let height = height.min(128);
|
||||
let h = height.saturating_sub(3);
|
||||
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;
|
||||
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));
|
||||
},
|
||||
key1.set_char('▄');
|
||||
key1.set_style(not_dim);
|
||||
let (fg, bg) = match index % 6 {
|
||||
0 => (Color::White, Color::Black),
|
||||
1 => (Color::White, Color::Black),
|
||||
2 => (Color::White, Color::White),
|
||||
3 => (Color::Black, Color::White),
|
||||
4 => (Color::Black, Color::White),
|
||||
5 => (Color::Black, Color::White),
|
||||
_ => { unreachable!(); }
|
||||
}
|
||||
};
|
||||
key1.set_fg(self.index_to_color(index as usize * 2, fg));
|
||||
key1.set_bg(self.index_to_color(index as usize * 2 + 1, bg));
|
||||
let key2 = buf.get_mut(x + 2, y);
|
||||
key2.set_char('▄');
|
||||
key2.set_style(not_dim);
|
||||
key2.set_fg(self.index_to_color(index as usize * 2, Color::White));
|
||||
key2.set_bg(self.index_to_color(index as usize * 2 + 1, Color::White));
|
||||
for x in x+5..x+width-1 {
|
||||
*buf.get_mut(x, y) = cell_bg.clone();
|
||||
let cell = buf.get_mut(x, y);
|
||||
cell.set_char('░');
|
||||
cell.set_style(black);
|
||||
}
|
||||
let note_a = note0 + (index * 2) as usize;
|
||||
if note_a % 12 == 0 {
|
||||
let octave = format!("C{}", (note_a / 12) as i8 - 2);
|
||||
octave.blit(buf, x + 3, y, None);
|
||||
octave.blit(buf, x + 3, y, None)?;
|
||||
continue
|
||||
}
|
||||
let note_b = note0 + (index * 2) as usize;
|
||||
if note_b % 12 == 0 {
|
||||
let octave = format!("C{}", (note_b / 12) as i8 - 2);
|
||||
octave.blit(buf, x + 3, y, None);
|
||||
octave.blit(buf, x + 3, y, None)?;
|
||||
continue
|
||||
}
|
||||
}
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
fn horizontal_lanes (&self, buf: &mut Buffer, area: Rect, phrase: Option<&Phrase>) {
|
||||
fn horizontal_lanes (&self, buf: &mut Buffer, area: Rect, phrase: Option<&Phrase>) -> Usually<Rect> {
|
||||
if phrase.is_none() {
|
||||
return
|
||||
return Ok(Rect { x: area.x, y: area.x, width: 0, height: 0 })
|
||||
}
|
||||
let phrase = phrase.unwrap();
|
||||
let (ppq, time_z, time0, note0) =
|
||||
(self.ppq, self.time_zoom, self.time_start, self.note_start);
|
||||
let bg = Style::default();
|
||||
let (bw, wh) = (bg.dim(), bg.white().not_dim());
|
||||
let dim = Style::default().dim();
|
||||
|
||||
let Rect { x, y, width, height } = area;
|
||||
|
||||
|
|
@ -251,18 +189,6 @@ impl<'a> SequencerView<'a> {
|
|||
x: x + offset, y, width: width - offset, height: height - 2
|
||||
};
|
||||
|
||||
let mut cell_a = Cell::default();
|
||||
cell_a.set_char('▄');
|
||||
cell_a.set_style(wh);
|
||||
|
||||
let mut cell_b = Cell::default();
|
||||
cell_b.set_char('▀');
|
||||
cell_b.set_style(wh);
|
||||
|
||||
let mut cell_ab = Cell::default();
|
||||
cell_ab.set_char('█');
|
||||
cell_ab.set_style(wh);
|
||||
|
||||
let mut steps = vec![];
|
||||
for x in phrase_area.x .. phrase_area.x + phrase_area.width {
|
||||
let x0 = x.saturating_sub(phrase_area.x) as usize;
|
||||
|
|
@ -275,20 +201,21 @@ impl<'a> SequencerView<'a> {
|
|||
for y in phrase_area.y .. phrase_area.y + phrase_area.height {
|
||||
if y == phrase_area.y {
|
||||
if step % (4 * ppq) == 0 {
|
||||
format!("{}", 1 + step / (4 * ppq)).blit(buf, x, y, None);
|
||||
format!("{}", 1 + step / (4 * ppq)).blit(buf, x, y, None)?;
|
||||
} else if step % ppq == 0 {
|
||||
let cell = buf.get_mut(x, y);
|
||||
cell.set_char(if step % ppq == 0 { '|' } else { '·' });
|
||||
cell.set_style(bw);
|
||||
cell.set_style(dim);
|
||||
}
|
||||
} else {
|
||||
let cell = buf.get_mut(x, y);
|
||||
cell.set_char(if step % ppq == 0 { '|' } else { '·' });
|
||||
cell.set_style(bw);
|
||||
cell.set_style(dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let wh = Style::default().white().not_dim();
|
||||
for index in 0..height-2 {
|
||||
let note_a = note0 + index as usize * 2;
|
||||
let note_b = note0 + index as usize * 2 + 1;
|
||||
|
|
@ -297,20 +224,25 @@ impl<'a> SequencerView<'a> {
|
|||
phrase.contains_note_on(u7::from_int_lossy(note_a as u8), *step, *next_step),
|
||||
phrase.contains_note_on(u7::from_int_lossy(note_b as u8), *step, *next_step),
|
||||
);
|
||||
let cell = if a && b {
|
||||
&cell_ab
|
||||
} else if a {
|
||||
&cell_a
|
||||
} else if b {
|
||||
&cell_b
|
||||
} else {
|
||||
continue
|
||||
};
|
||||
if let Some(block) = half_block(a, b) {
|
||||
let y = y + height.saturating_sub(index+2) as u16;
|
||||
*buf.get_mut(*x, y) = cell.clone()
|
||||
let cell = buf.get_mut(*x, y);
|
||||
cell.set_char(block);
|
||||
cell.set_style(wh);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(area)
|
||||
}
|
||||
}
|
||||
|
||||
fn half_block (lower: bool, upper: bool) -> Option<char> {
|
||||
match (lower, upper) {
|
||||
(true, true) => Some('█'),
|
||||
(true, false) => Some('▄'),
|
||||
(false, true) => Some('▀'),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
//pub fn footer (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue