mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
showing keys again
This commit is contained in:
parent
a25272ad1b
commit
ddba9e0382
6 changed files with 65 additions and 171 deletions
|
|
@ -56,7 +56,9 @@ pub trait MidiRange {
|
||||||
fn note_lo (&self) -> usize;
|
fn note_lo (&self) -> usize;
|
||||||
fn set_note_lo (&self, x: usize);
|
fn set_note_lo (&self, x: usize);
|
||||||
fn note_axis (&self) -> usize;
|
fn note_axis (&self) -> usize;
|
||||||
|
fn time_axis (&self) -> usize;
|
||||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||||
|
fn time_end (&self) -> usize { self.time_start() + self.time_axis() * self.time_zoom() }
|
||||||
}
|
}
|
||||||
impl MidiRange for MidiRangeModel {
|
impl MidiRange for MidiRangeModel {
|
||||||
fn time_zoom (&self) -> usize { self.time_zoom.load(Relaxed) }
|
fn time_zoom (&self) -> usize { self.time_zoom.load(Relaxed) }
|
||||||
|
|
@ -68,6 +70,7 @@ impl MidiRange for MidiRangeModel {
|
||||||
fn note_lo (&self) -> usize { self.note_lo.load(Relaxed) }
|
fn note_lo (&self) -> usize { self.note_lo.load(Relaxed) }
|
||||||
fn set_note_lo (&self, x: usize) { self.note_lo.store(x, Relaxed); }
|
fn set_note_lo (&self, x: usize) { self.note_lo.store(x, Relaxed); }
|
||||||
fn note_axis (&self) -> usize { self.note_axis.load(Relaxed) }
|
fn note_axis (&self) -> usize { self.note_axis.load(Relaxed) }
|
||||||
|
fn time_axis (&self) -> usize { self.time_axis.load(Relaxed) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ audio!(|self:SequencerTui,client,scope|{
|
||||||
Control::Continue
|
Control::Continue
|
||||||
});
|
});
|
||||||
|
|
||||||
render!(|self: SequencerTui|lay!([self.size, Tui::split_n(false, 4,
|
render!(|self: SequencerTui|lay!([self.size, Tui::split_n(false, 5,
|
||||||
Tui::fill_xy(col!([
|
Tui::fill_xy(col!([
|
||||||
PhraseEditStatus(&self.editor),
|
PhraseEditStatus(&self.editor),
|
||||||
SequencerStatusBar::from(self),
|
SequencerStatusBar::from(self),
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,8 @@ impl MidiRange for PhraseEditorModel {
|
||||||
fn set_time_start (&self, x: usize) { self.mode.set_time_start(x); }
|
fn set_time_start (&self, x: usize) { self.mode.set_time_start(x); }
|
||||||
fn set_note_lo (&self, x: usize) { self.mode.set_note_lo(x); }
|
fn set_note_lo (&self, x: usize) { self.mode.set_note_lo(x); }
|
||||||
fn note_lo (&self) -> usize { self.mode.note_lo() }
|
fn note_lo (&self) -> usize { self.mode.note_lo() }
|
||||||
fn note_axis (&self) -> usize { self.mode.note_lo() }
|
fn note_axis (&self) -> usize { self.mode.note_axis() }
|
||||||
|
fn time_axis (&self) -> usize { self.mode.time_axis() }
|
||||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||||
}
|
}
|
||||||
impl MidiPoint for PhraseEditorModel {
|
impl MidiPoint for PhraseEditorModel {
|
||||||
|
|
@ -232,24 +233,29 @@ render!(|self:PhraseEditStatus<'a>|row!(|add|{
|
||||||
} else {
|
} else {
|
||||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0)
|
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0)
|
||||||
};
|
};
|
||||||
let bg = color.base.rgb;
|
let bg = color.darker.rgb;
|
||||||
let fg = color.lightest.rgb;
|
let fg = color.lightest.rgb;
|
||||||
let mut field = |name:&str, value:String|add(&Tui::fixed_xy(8, 2,
|
add(&Tui::fill_x(Tui::bg(bg, row!(|add|{
|
||||||
Tui::bg(bg, Tui::fg(fg, col!([
|
add(&Tui::fixed_xy(16, 3, col!(![
|
||||||
name, Tui::bold(true, &value)
|
row!(![" Edit ", Tui::bold(true, format!("{name}"))]),
|
||||||
])))));
|
row!(![" Length ", Tui::bold(true, format!("{length}"))]),
|
||||||
|
row!(![" Loop ", Tui::bold(true, format!("on"))]),
|
||||||
field("Edit", format!("{name}"))?;
|
])))?;
|
||||||
field("Length", format!("{length}"))?;
|
add(&Tui::fixed_xy(12, 3, col!(![
|
||||||
field("TimePt", format!("{}", self.0.time_point()))?;
|
row!(!["Time ", Tui::bold(true, format!("{}", self.0.time_point()))]),
|
||||||
field("TimeZoom", format!("{}", self.0.time_zoom()))?;
|
row!(!["Note ", Tui::bold(true, format!("{}", self.0.note_point()))]),
|
||||||
field("TimeLock", format!("{}", self.0.time_lock()))?;
|
row!(!["Len ", Tui::bold(true, format!("{}", self.0.note_len()))]),
|
||||||
field("TimeStrt", format!("{}", self.0.time_start()))?;
|
])))?;
|
||||||
field("NoteLen", format!("{}", self.0.note_len()))?;
|
add(&Tui::fixed_xy(20, 3, col!(![
|
||||||
field("NoteLo", format!("{}", self.0.note_lo()))?;
|
row!(!["TimeRange ", Tui::bold(true, format!("{}-{}", self.0.time_start(), self.0.time_end()))]),
|
||||||
field("NoteAxis", format!("{}", self.0.note_axis()))?;
|
row!(!["TimeAxis ", Tui::bold(true, format!("{}", self.0.time_axis()))]),
|
||||||
field("NoteHi", format!("{}", self.0.note_hi()))?;
|
row!(!["TimeZoom ", Tui::bold(true, format!("{} {}", self.0.time_zoom(), self.0.time_lock()))]),
|
||||||
field("NotePt", format!("{}", self.0.note_point()))?;
|
])))?;
|
||||||
|
add(&Tui::fixed_xy(20, 3, col!(![
|
||||||
|
row!(!["NoteRange", Tui::bold(true, format!("{}-{}", self.0.note_lo(), self.0.note_hi()))]),
|
||||||
|
row!(!["NoteAxis ", Tui::bold(true, format!("{}", self.0.note_axis()))]),
|
||||||
|
""
|
||||||
|
])))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}))))
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,16 @@ render!(|self: PianoHorizontal|{
|
||||||
let time_point = self.point.time_point();
|
let time_point = self.point.time_point();
|
||||||
let note_point = self.point.note_point();
|
let note_point = self.point.note_point();
|
||||||
let note_len = self.point.note_len();
|
let note_len = self.point.note_len();
|
||||||
Tui::bg(bg, Tui::split_s(false, 1,
|
lay!([
|
||||||
Tui::debug(Tui::fill_x(Tui::push_x(5, Tui::bg(fg.darkest.rgb, Tui::fg(fg.lightest.rgb,
|
&self.size,
|
||||||
|
Tui::fill_xy(Tui::bg(bg, Tui::split_s(false, 1,
|
||||||
|
Tui::fill_x(Tui::push_x(5, Tui::bg(fg.darkest.rgb, Tui::fg(fg.lightest.rgb,
|
||||||
PianoHorizontalTimeline {
|
PianoHorizontalTimeline {
|
||||||
time_start,
|
time_start,
|
||||||
time_zoom,
|
time_zoom,
|
||||||
}
|
}
|
||||||
))))),
|
)))),
|
||||||
Tui::fill_xy(Split::right(true, 5, Tui::debug(lay!([
|
Tui::split_e(true, 5, Tui::debug(lay!([
|
||||||
self.size,
|
|
||||||
PianoHorizontalNotes {
|
PianoHorizontalNotes {
|
||||||
source: &self.buffer,
|
source: &self.buffer,
|
||||||
time_start,
|
time_start,
|
||||||
|
|
@ -76,8 +77,9 @@ render!(|self: PianoHorizontal|{
|
||||||
note_lo,
|
note_lo,
|
||||||
note_hi,
|
note_hi,
|
||||||
note_point: Some(note_point),
|
note_point: Some(note_point),
|
||||||
}))
|
}),
|
||||||
))
|
)))
|
||||||
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct PianoHorizontalTimeline {
|
pub struct PianoHorizontalTimeline {
|
||||||
|
|
@ -252,7 +254,8 @@ impl MidiRange for PianoHorizontal {
|
||||||
fn set_time_start (&self, x: usize) { self.range.set_time_start(x); }
|
fn set_time_start (&self, x: usize) { self.range.set_time_start(x); }
|
||||||
fn set_note_lo (&self, x: usize) { self.range.set_note_lo(x); }
|
fn set_note_lo (&self, x: usize) { self.range.set_note_lo(x); }
|
||||||
fn note_lo (&self) -> usize { self.range.note_lo() }
|
fn note_lo (&self) -> usize { self.range.note_lo() }
|
||||||
fn note_axis (&self) -> usize { self.range.note_lo() }
|
fn note_axis (&self) -> usize { self.range.note_axis() }
|
||||||
|
fn time_axis (&self) -> usize { self.range.time_axis() }
|
||||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||||
}
|
}
|
||||||
impl MidiPoint for PianoHorizontal {
|
impl MidiPoint for PianoHorizontal {
|
||||||
|
|
|
||||||
|
|
@ -26,121 +26,3 @@ pub trait StatusBar: Render<Tui> {
|
||||||
Tui::to_north(state.into(), content)
|
Tui::to_north(state.into(), content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Status bar for sequencer app
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SequencerStatusBar {
|
|
||||||
pub(crate) width: usize,
|
|
||||||
pub(crate) cpu: Option<String>,
|
|
||||||
pub(crate) size: String,
|
|
||||||
pub(crate) res: String,
|
|
||||||
pub(crate) mode: &'static str,
|
|
||||||
pub(crate) help: &'static [(&'static str, &'static str, &'static str)]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StatusBar for SequencerStatusBar {
|
|
||||||
type State = SequencerTui;
|
|
||||||
fn hotkey_fg () -> Color {
|
|
||||||
TuiTheme::HOTKEY_FG
|
|
||||||
}
|
|
||||||
fn update (&mut self, _: &SequencerTui) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&SequencerTui> for SequencerStatusBar {
|
|
||||||
fn from (state: &SequencerTui) -> Self {
|
|
||||||
let samples = state.clock.chunk.load(Ordering::Relaxed);
|
|
||||||
let rate = state.clock.timebase.sr.get() as f64;
|
|
||||||
let buffer = samples as f64 / rate;
|
|
||||||
let width = state.size.w();
|
|
||||||
Self {
|
|
||||||
width,
|
|
||||||
cpu: state.perf.percentage().map(|cpu|format!("│{cpu:.01}%")),
|
|
||||||
size: format!("{}x{}│", width, state.size.h()),
|
|
||||||
res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.),
|
|
||||||
mode: " SEQUENCER ",
|
|
||||||
help: &[
|
|
||||||
("", "SPACE", " play/pause"),
|
|
||||||
("", "✣", " cursor"),
|
|
||||||
("", "Ctrl-✣", " scroll"),
|
|
||||||
("", ".,", " length"),
|
|
||||||
("", "><", " triplet"),
|
|
||||||
("", "[]", " phrase"),
|
|
||||||
("", "{}", " order"),
|
|
||||||
("en", "q", "ueue"),
|
|
||||||
("", "e", "dit"),
|
|
||||||
("", "a", "dd note"),
|
|
||||||
("", "A", "dd phrase"),
|
|
||||||
("", "D", "uplicate phrase"),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render!(|self: SequencerStatusBar|{
|
|
||||||
lay!(|add|if self.width > 40 {
|
|
||||||
add(&Tui::fill_x(Tui::fixed_y(1, lay!([
|
|
||||||
Tui::fill_x(Tui::at_w(SequencerMode::from(self))),
|
|
||||||
Tui::fill_x(Tui::at_e(SequencerStats::from(self))),
|
|
||||||
]))))
|
|
||||||
} else {
|
|
||||||
add(&Tui::fill_x(col!(![
|
|
||||||
Tui::fill_x(Tui::center_x(SequencerMode::from(self))),
|
|
||||||
Tui::fill_x(Tui::center_x(SequencerStats::from(self))),
|
|
||||||
])))
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
struct SequencerMode {
|
|
||||||
mode: &'static str,
|
|
||||||
help: &'static [(&'static str, &'static str, &'static str)]
|
|
||||||
}
|
|
||||||
impl From<&SequencerStatusBar> for SequencerMode {
|
|
||||||
fn from (state: &SequencerStatusBar) -> Self {
|
|
||||||
Self {
|
|
||||||
mode: state.mode,
|
|
||||||
help: state.help,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
render!(|self: SequencerMode|{
|
|
||||||
let black = TuiTheme::g(0);
|
|
||||||
let light = TuiTheme::g(50);
|
|
||||||
let white = TuiTheme::g(255);
|
|
||||||
let orange = TuiTheme::orange();
|
|
||||||
let yellow = TuiTheme::yellow();
|
|
||||||
row!([
|
|
||||||
Tui::bg(orange, Tui::fg(black, Tui::bold(true, self.mode))),
|
|
||||||
Tui::bg(light, Tui::fg(white, row!((prefix, hotkey, suffix) in self.help.iter() => {
|
|
||||||
row!([" ", prefix, Tui::fg(yellow, *hotkey), suffix])
|
|
||||||
})))
|
|
||||||
])
|
|
||||||
});
|
|
||||||
|
|
||||||
struct SequencerStats<'a> {
|
|
||||||
cpu: &'a Option<String>,
|
|
||||||
size: &'a String,
|
|
||||||
res: &'a String,
|
|
||||||
}
|
|
||||||
impl<'a> From<&'a SequencerStatusBar> for SequencerStats<'a> {
|
|
||||||
fn from (state: &'a SequencerStatusBar) -> Self {
|
|
||||||
Self {
|
|
||||||
cpu: &state.cpu,
|
|
||||||
size: &state.size,
|
|
||||||
res: &state.res,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
render!(|self:SequencerStats<'a>|{
|
|
||||||
let orange = TuiTheme::orange();
|
|
||||||
let dark = TuiTheme::g(25);
|
|
||||||
let cpu = &self.cpu;
|
|
||||||
let res = &self.res;
|
|
||||||
let size = &self.size;
|
|
||||||
Tui::bg(dark, row!([
|
|
||||||
Tui::fg(orange, cpu),
|
|
||||||
Tui::fg(orange, res),
|
|
||||||
Tui::fg(orange, size),
|
|
||||||
]))
|
|
||||||
});
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue