mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
layer midi status; navigate sample list
This commit is contained in:
parent
fc0a398702
commit
e69cf6d9cb
5 changed files with 127 additions and 54 deletions
|
|
@ -97,7 +97,7 @@ render!(<Tui>|self: ArrangerTui|{
|
|||
let pool_size = if self.phrases.visible { self.splits[1] } else { 0 };
|
||||
let with_pool = |x|Split::left(false, pool_size, PoolView(&self.phrases), x);
|
||||
let status = ArrangerStatus::from(self);
|
||||
let with_editbar = |x|Tui::split_n(false, 3, MidiEditStatus(&self.editor), x);
|
||||
let with_editbar = |x|Tui::split_n(false, 1, MidiEditStatus(&self.editor), x);
|
||||
let with_status = |x|Tui::split_n(false, 2, status, x);
|
||||
let with_size = |x|lay!([&self.size, x]);
|
||||
let arranger = ||lay!(|add|{
|
||||
|
|
|
|||
|
|
@ -24,27 +24,10 @@ pub struct SamplerTui {
|
|||
pub size: Measure<Tui>,
|
||||
/// Lowest note displayed
|
||||
pub note_lo: AtomicUsize,
|
||||
color: ItemColor
|
||||
pub note_pt: AtomicUsize,
|
||||
color: ItemPalette
|
||||
}
|
||||
|
||||
render!(<Tui>|self: SamplerTui|{
|
||||
let keys_width = 5;
|
||||
let keys = move||SamplerKeys(self);
|
||||
let fg = TuiTheme::g(200);
|
||||
let bg = TuiTheme::g(50);
|
||||
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
||||
let with_border = |x|lay!([
|
||||
border,
|
||||
Tui::inset_xy(1, 1, Fill::wh(&x))
|
||||
]);
|
||||
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
||||
"Sampler",
|
||||
Bsp::e(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(lay!([&self.size, Fill::wh("Sample")])),
|
||||
),
|
||||
))))
|
||||
});
|
||||
from_jack!(|jack|SamplerTui{
|
||||
let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?;
|
||||
let audio_outs = vec![
|
||||
|
|
@ -57,7 +40,8 @@ from_jack!(|jack|SamplerTui{
|
|||
mode: None,
|
||||
size: Measure::new(),
|
||||
note_lo: 36.into(),
|
||||
color: ItemColor::default(),
|
||||
note_pt: 36.into(),
|
||||
color: ItemPalette::from(Color::Rgb(64, 128, 32)),
|
||||
state: Sampler {
|
||||
jack: jack.clone(),
|
||||
name: "Sampler".into(),
|
||||
|
|
@ -72,8 +56,52 @@ from_jack!(|jack|SamplerTui{
|
|||
}
|
||||
});
|
||||
|
||||
render!(<Tui>|self: SamplerTui|{
|
||||
let keys_width = 5;
|
||||
let keys = move||SamplerKeys(self);
|
||||
let fg = self.color.base.rgb;
|
||||
let bg = self.color.darkest.rgb;
|
||||
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
||||
let inset = 0;
|
||||
let with_border = |x|lay!([border, Tui::inset_xy(inset, inset, Fill::wh(&x))]);
|
||||
let with_size = |x|lay!([self.size, x]);
|
||||
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
||||
Tui::push_x(1, Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler"))),
|
||||
with_size(Tui::shrink_y(1, Bsp::e(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
||||
let x = to.area.x() + 1;
|
||||
let rows = self.size.h() as u16;
|
||||
let bg_base = self.color.darkest.rgb;
|
||||
let bg_selected = self.color.darker.rgb;
|
||||
let style_empty = Style::default().fg(self.color.base.rgb);
|
||||
let style_full = Style::default().fg(self.color.lighter.rgb);
|
||||
let note_hi = self.note_hi();
|
||||
let note_pt = self.note_point();
|
||||
for y in 0..rows {
|
||||
let note = note_hi - y as usize;
|
||||
let bg = if note == note_pt { bg_selected } else { bg_base };
|
||||
let style = Some(style_empty.bg(bg));
|
||||
to.blit(&" (no sample) ", x, to.area.y() + y, style)
|
||||
}
|
||||
})))
|
||||
))),
|
||||
))))
|
||||
});
|
||||
|
||||
impl NoteRange for SamplerTui {
|
||||
fn note_lo (&self) -> &AtomicUsize { &self.note_lo }
|
||||
fn note_axis (&self) -> &AtomicUsize { &self.size.y }
|
||||
}
|
||||
impl NotePoint for SamplerTui {
|
||||
fn note_len (&self) -> usize {0/*TODO*/}
|
||||
fn set_note_len (&self, x: usize) {}
|
||||
fn note_point (&self) -> usize { self.note_pt.load(Relaxed) }
|
||||
fn set_note_point (&self, x: usize) { self.note_pt.store(x, Relaxed); }
|
||||
}
|
||||
|
||||
struct SamplerKeys<'a>(&'a SamplerTui);
|
||||
has_color!(|self: SamplerKeys<'a>|self.0.color);
|
||||
has_color!(|self: SamplerKeys<'a>|self.0.color.base);
|
||||
render!(<Tui>|self: SamplerKeys<'a>|render(|to|Ok(render_keys_v(to, self))));
|
||||
impl<'a> NoteRange for SamplerKeys<'a> {
|
||||
fn note_lo (&self) -> &AtomicUsize { &self.0.note_lo }
|
||||
|
|
@ -82,8 +110,8 @@ impl<'a> NoteRange for SamplerKeys<'a> {
|
|||
impl<'a> NotePoint for SamplerKeys<'a> {
|
||||
fn note_len (&self) -> usize {0/*TODO*/}
|
||||
fn set_note_len (&self, x: usize) {}
|
||||
fn note_point (&self) -> usize {0/*TODO*/}
|
||||
fn set_note_point (&self, x: usize) {}
|
||||
fn note_point (&self) -> usize { self.0.note_point() }
|
||||
fn set_note_point (&self, x: usize) { self.0.set_note_point(x); }
|
||||
}
|
||||
|
||||
pub enum SamplerMode {
|
||||
|
|
@ -101,15 +129,19 @@ pub enum SamplerCommand {
|
|||
NoteOn(u7, u7),
|
||||
NoteOff(u7)
|
||||
}
|
||||
input_to_command!(SamplerCommand:<Tui>|state:SamplerTui,input|match state.mode {
|
||||
input_to_command!(SamplerCommand: <Tui>|state: SamplerTui, input|match state.mode {
|
||||
Some(SamplerMode::Import(..)) => Self::Import(
|
||||
FileBrowserCommand::input_to_command(state, input)?
|
||||
),
|
||||
_ => match input.event() {
|
||||
// load sample
|
||||
key_pat!(Char('l')) => Self::Import(FileBrowserCommand::Begin),
|
||||
key_pat!(KeyCode::Up) => { todo!() },
|
||||
key_pat!(KeyCode::Down) => { todo!() },
|
||||
key_pat!(KeyCode::Up) => {
|
||||
Self::SelectNote(state.note_point().overflowing_add(1).0.min(127))
|
||||
},
|
||||
key_pat!(KeyCode::Down) => {
|
||||
Self::SelectNote(state.note_point().overflowing_sub(1).0.min(127))
|
||||
},
|
||||
_ => return None
|
||||
}
|
||||
//key_pat!(KeyCode::Char('p')) => if let Some(sample) = self.sample() {
|
||||
|
|
@ -135,12 +167,17 @@ input_to_command!(FileBrowserCommand:<Tui>|state:SamplerTui,input|match input {
|
|||
_ => return None
|
||||
});
|
||||
command!(|self:SamplerCommand,state:SamplerTui|match self {
|
||||
SamplerCommand::Import(FileBrowserCommand::Begin) => {
|
||||
Self::Import(FileBrowserCommand::Begin) => {
|
||||
let voices = &state.state.voices;
|
||||
let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
||||
state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?));
|
||||
None
|
||||
},
|
||||
Self::SelectNote(index) => {
|
||||
let old = state.note_point();
|
||||
state.set_note_point(index);
|
||||
Some(Self::SelectNote(old))
|
||||
},
|
||||
_ => todo!()
|
||||
});
|
||||
command!(|self:FileBrowserCommand,state:SamplerTui|match self {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ render!(<Tui>|self: SequencerTui|{
|
|||
let with_pool = move|x|Tui::split_w(false, pool_w, pool, x);
|
||||
let status = SequencerStatus::from(self);
|
||||
let with_status = |x|Tui::split_n(false, if self.status { 2 } else { 0 }, status, x);
|
||||
let with_editbar = |x|Tui::split_n(false, 3, MidiEditStatus(&self.editor), x);
|
||||
let with_editbar = |x|Tui::split_n(false, 1, MidiEditStatus(&self.editor), x);
|
||||
let with_size = |x|lay!([self.size, x]);
|
||||
let editor = with_editbar(with_pool(Fill::wh(&self.editor)));
|
||||
let color = self.player.play_phrase().as_ref().map(|(_,p)|
|
||||
|
|
|
|||
|
|
@ -52,20 +52,55 @@ impl PianoHorizontal {
|
|||
}
|
||||
|
||||
render!(<Tui>|self: PianoHorizontal|{
|
||||
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
|
||||
};
|
||||
|
||||
let field = move|x, y|row!([
|
||||
Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)),
|
||||
Tui::fg_bg(color.light.rgb, color.darker.rgb, Tui::bold(true, "│")),
|
||||
Tui::fg_bg(color.lighter.rgb, color.dark.rgb, &y),
|
||||
]);
|
||||
|
||||
let keys_width = 5;
|
||||
let keys = move||PianoHorizontalKeys(self);
|
||||
|
||||
let timeline = move||PianoHorizontalTimeline(self);
|
||||
|
||||
let notes = move||PianoHorizontalNotes(self);
|
||||
|
||||
let cursor = move||PianoHorizontalCursor(self);
|
||||
|
||||
let border = Fill::wh(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)));
|
||||
let with_border = |x|lay!([border, Tui::inset_xy(1, 1, &x)]);
|
||||
with_border(Fill::wh(Bsp::s(
|
||||
Fixed::h(1, Bsp::e(Fixed::w(keys_width, ""), Fill::w(timeline()),)),
|
||||
Bsp::e(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(lay!([&self.size, Fill::wh(lay!([Fill::wh(notes()), Fill::wh(cursor()),]))])),
|
||||
),
|
||||
)))
|
||||
let with_border = |x|lay!([border, Tui::inset_xy(0, 0, &x)]);
|
||||
|
||||
with_border(lay!([
|
||||
Tui::push_x(0, row!(![
|
||||
" ",
|
||||
field(" Edit", name.to_string()),
|
||||
field(" Length", length.to_string()),
|
||||
field(" Loop", looped.to_string())
|
||||
])),
|
||||
Tui::inset_xy(0, 1, Fill::wh(Bsp::s(
|
||||
Fixed::h(1, Bsp::e(
|
||||
Fixed::w(keys_width, ""),
|
||||
Fill::w(timeline()),
|
||||
)),
|
||||
Bsp::e(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(lay!([
|
||||
&self.size,
|
||||
Fill::wh(lay!([
|
||||
Fill::wh(notes()),
|
||||
Fill::wh(cursor()),
|
||||
]))
|
||||
])),
|
||||
),
|
||||
)))
|
||||
]))
|
||||
});
|
||||
|
||||
impl PianoHorizontal {
|
||||
|
|
|
|||
|
|
@ -2,29 +2,30 @@ use crate::*;
|
|||
|
||||
pub struct MidiEditStatus<'a>(pub &'a MidiEditorModel);
|
||||
render!(<Tui>|self:MidiEditStatus<'a>|{
|
||||
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
|
||||
};
|
||||
let bg = color.darkest.rgb;
|
||||
let fg = color.lightest.rgb;
|
||||
|
||||
let field = move|x, y|row!([
|
||||
Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)),
|
||||
Tui::fg_bg(color.light.rgb, color.darker.rgb, Tui::bold(true, "│")),
|
||||
Fill::w(Tui::fg_bg(color.lightest.rgb, color.dark.rgb, &y)),
|
||||
Tui::fg_bg(color.lightest.rgb, color.dark.rgb, &y),
|
||||
]);
|
||||
Fill::w(Tui::fg_bg(fg, bg, row!([
|
||||
Fixed::wh(26, 3, col!(![
|
||||
field(" Edit", name.to_string()),
|
||||
field(" Length", length.to_string()),
|
||||
field(" Loop", looped.to_string())])),
|
||||
Fixed::wh(30, 3, col!(![
|
||||
field(" Time", format!("{}/{}-{} ({}*{}) {}",
|
||||
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),
|
||||
self.0.time_axis().get(), self.0.time_zoom().get(),
|
||||
if self.0.time_lock().get() { "[lock]" } else { " " })),
|
||||
field(" Note", format!("{} ({}) {} | {}-{} ({})",
|
||||
self.0.note_point(), to_note_name(self.0.note_point()), self.0.note_len(),
|
||||
to_note_name(self.0.note_lo().get()), to_note_name(self.0.note_hi()),
|
||||
self.0.note_axis().get()))]))])))});
|
||||
|
||||
let bg = color.darkest.rgb;
|
||||
let fg = color.lightest.rgb;
|
||||
Tui::bg(bg, Fill::w(Tui::fg(fg, row!([
|
||||
field(" Time", format!("{}/{}-{} ({}*{}) {}",
|
||||
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),
|
||||
self.0.time_axis().get(), self.0.time_zoom().get(),
|
||||
if self.0.time_lock().get() { "[lock]" } else { " " })),
|
||||
" ",
|
||||
field(" Note", format!("{} ({}) {} | {}-{} ({})",
|
||||
self.0.note_point(), to_note_name(self.0.note_point()), self.0.note_len(),
|
||||
to_note_name(self.0.note_lo().get()), to_note_name(self.0.note_hi()),
|
||||
self.0.note_axis().get()))
|
||||
]))))
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue