mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
refactor arranger header
This commit is contained in:
parent
48f83fa94d
commit
99d8a0863e
2 changed files with 93 additions and 70 deletions
|
|
@ -9,6 +9,13 @@ pub struct GrooveboxTui {
|
||||||
from_jack!(|jack|GrooveboxTui {
|
from_jack!(|jack|GrooveboxTui {
|
||||||
let mut sequencer = SequencerTui::try_from(jack)?;
|
let mut sequencer = SequencerTui::try_from(jack)?;
|
||||||
sequencer.status = false;
|
sequencer.status = false;
|
||||||
|
let midi_in_1 = jack.read().unwrap().register_port("in1", MidiIn::default())?;
|
||||||
|
let midi_out = jack.read().unwrap().register_port("out", MidiOut::default())?;
|
||||||
|
let midi_in_2 = jack.read().unwrap().register_port("in2", MidiIn::default())?;
|
||||||
|
let audio_in_1 = jack.read().unwrap().register_port("inL", AudioIn::default())?;
|
||||||
|
let audio_in_2 = jack.read().unwrap().register_port("inR", AudioIn::default())?;
|
||||||
|
let audio_out_1 = jack.read().unwrap().register_port("out1", AudioOut::default())?;
|
||||||
|
let audio_out_2 = jack.read().unwrap().register_port("out2", AudioOut::default())?;
|
||||||
Self {
|
Self {
|
||||||
sequencer,
|
sequencer,
|
||||||
sampler: SamplerTui::try_from(jack)?,
|
sampler: SamplerTui::try_from(jack)?,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,90 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
pub struct ArrangerVHead<'a> {
|
||||||
|
focused: bool,
|
||||||
|
selected: ArrangerSelection,
|
||||||
|
scenes_w: u16,
|
||||||
|
header_h: u16,
|
||||||
|
timebase: &'a Arc<Timebase>,
|
||||||
|
current: &'a Arc<Moment>,
|
||||||
|
tracks: Vec<(&'a ArrangerTrack, usize, usize)>,
|
||||||
|
}
|
||||||
|
from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A
|
||||||
|
focused: true,
|
||||||
|
selected: state.selected,
|
||||||
|
scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16,
|
||||||
|
header_h: 3,
|
||||||
|
timebase: state.clock().timebase(),
|
||||||
|
current: &state.clock().playhead,
|
||||||
|
tracks: track_widths(state.tracks())
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, (a, b))|(&state.tracks()[i], *a, *b))
|
||||||
|
.collect(),
|
||||||
|
});
|
||||||
|
render!(<Tui>|self: ArrangerVHead<'a>|row!(
|
||||||
|
(track, w, _) in self.tracks.iter() => {
|
||||||
|
let name = Self::format_name(track, *w);
|
||||||
|
let input = Self::format_input(track)?;
|
||||||
|
let elapsed = Self::format_elapsed(track, &self.timebase);
|
||||||
|
let until_next = Self::format_until_next(track, &self.timebase, &self.current);
|
||||||
|
let output = Self::format_output(track)?;
|
||||||
|
Tui::push_x(self.scenes_w,
|
||||||
|
Tui::bg(track.color().base.rgb,
|
||||||
|
Tui::min_xy(*w as u16, self.header_h, row!([
|
||||||
|
col!(!["▎", "▎", "▎", "▎", "▎", "▎",]),
|
||||||
|
col!(![name, input, output, elapsed, until_next, output])]))))
|
||||||
|
}
|
||||||
|
));
|
||||||
|
impl<'a> ArrangerVHead<'a> {
|
||||||
|
/// name and width of track
|
||||||
|
fn format_name (track: &ArrangerTrack, w: usize) -> impl Render<Tui> {
|
||||||
|
let name = track.name().read().unwrap();
|
||||||
|
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
||||||
|
Tui::bold(true, Tui::fg(track.color.lightest.rgb, format!("▎{}", &name[0..max_w])));
|
||||||
|
}
|
||||||
|
/// input port
|
||||||
|
fn format_input (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
|
||||||
|
Ok(format!(">{}", track.player.midi_ins().get(0)
|
||||||
|
.map(|port|port.short_name())
|
||||||
|
.transpose()?
|
||||||
|
.unwrap_or("(none)".into())))
|
||||||
|
}
|
||||||
|
/// output port
|
||||||
|
fn format_output (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
|
||||||
|
Ok(format!("<{}", track.player.midi_outs().get(0)
|
||||||
|
.map(|port|port.short_name())
|
||||||
|
.transpose()?
|
||||||
|
.unwrap_or("(none)".into())))
|
||||||
|
}
|
||||||
|
/// beats elapsed
|
||||||
|
fn format_elapsed (track: &ArrangerTrack, timebase: &Arc<Timebase>) -> impl Render<Tui> {
|
||||||
|
if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
||||||
|
let length = phrase.read().unwrap().length;
|
||||||
|
let elapsed = track.player.pulses_since_start().unwrap();
|
||||||
|
let elapsed = timebase.format_beats_1_short(
|
||||||
|
(elapsed as usize % length) as f64
|
||||||
|
);
|
||||||
|
format!("+{elapsed:>}")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// beats until switchover
|
||||||
|
fn format_until_next (track: &ArrangerTrack, timebase: &Arc<Timebase>, current: &Arc<Moment>)
|
||||||
|
-> Option<impl Render<Tui>>
|
||||||
|
{
|
||||||
|
track.player.next_phrase().as_ref().map(|(t, _)|{
|
||||||
|
let target = t.pulse.get();
|
||||||
|
let current = current.pulse.get();
|
||||||
|
if target > current {
|
||||||
|
let remaining = target - current;
|
||||||
|
format!("-{:>}", timebase.format_beats_0_short(remaining))
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
pub struct ArrangerVColSep {
|
pub struct ArrangerVColSep {
|
||||||
cols: Vec<(usize, usize)>,
|
cols: Vec<(usize, usize)>,
|
||||||
scenes_w: u16,
|
scenes_w: u16,
|
||||||
|
|
@ -114,76 +200,6 @@ render!(<Tui>|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
pub struct ArrangerVHead<'a> {
|
|
||||||
tracks: &'a Vec<ArrangerTrack>,
|
|
||||||
cols: Vec<(usize, usize)>,
|
|
||||||
focused: bool,
|
|
||||||
selected: ArrangerSelection,
|
|
||||||
scenes_w: u16,
|
|
||||||
header_h: u16,
|
|
||||||
timebase: &'a Arc<Timebase>,
|
|
||||||
current: &'a Arc<Moment>,
|
|
||||||
}
|
|
||||||
from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A
|
|
||||||
tracks: &state.tracks,
|
|
||||||
cols: track_widths(state.tracks()),
|
|
||||||
focused: true,
|
|
||||||
selected: state.selected,
|
|
||||||
scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16,
|
|
||||||
header_h: 3,
|
|
||||||
timebase: state.clock().timebase(),
|
|
||||||
current: &state.clock().playhead,
|
|
||||||
});
|
|
||||||
render!(<Tui>|self: ArrangerVHead<'a>|row!(
|
|
||||||
(track, w) in self.tracks.iter().zip(self.cols.iter().map(|col|col.0)) => {
|
|
||||||
|
|
||||||
// name and width of track
|
|
||||||
let name = track.name().read().unwrap();
|
|
||||||
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
|
||||||
let name = Tui::bold(true, Tui::fg(track.color.lightest.rgb, format!("▎{}", &name[0..max_w])));
|
|
||||||
|
|
||||||
// name of active MIDI input
|
|
||||||
let input = format!(">{}", track.player.midi_ins().get(0)
|
|
||||||
.map(|port|port.short_name())
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or("(none)".into()));
|
|
||||||
|
|
||||||
// beats elapsed
|
|
||||||
let elapsed = if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
|
||||||
let length = phrase.read().unwrap().length;
|
|
||||||
let elapsed = track.player.pulses_since_start().unwrap();
|
|
||||||
let elapsed = self.timebase.format_beats_1_short(
|
|
||||||
(elapsed as usize % length) as f64
|
|
||||||
);
|
|
||||||
format!("+{elapsed:>}")
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// beats until switchover
|
|
||||||
let until_next = track.player.next_phrase().as_ref().map(|(t, _)|{
|
|
||||||
let target = t.pulse.get();
|
|
||||||
let current = self.current.pulse.get();
|
|
||||||
if target > current {
|
|
||||||
let remaining = target - current;
|
|
||||||
format!("-{:>}", self.timebase.format_beats_0_short(remaining))
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// name of active MIDI output
|
|
||||||
let output = format!("<{}", track.player.midi_outs().get(0)
|
|
||||||
.map(|port|port.short_name())
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or("(none)".into()));
|
|
||||||
Tui::push_x(self.scenes_w,
|
|
||||||
Tui::bg(track.color().base.rgb,
|
|
||||||
Tui::min_xy(w as u16, self.header_h, row!([
|
|
||||||
col!(!["▎", "▎", "▎", "▎", "▎", "▎",]),
|
|
||||||
col!(![name, input, output, elapsed, until_next, output])]))))
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
pub struct ArrangerVBody<'a> {
|
pub struct ArrangerVBody<'a> {
|
||||||
size: &'a Measure<Tui>,
|
size: &'a Measure<Tui>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue