append tracks/scenes + move cursor

This commit is contained in:
🪞👃🪞 2025-01-16 19:23:56 +01:00
parent 5bf1bad7be
commit a670320533
2 changed files with 86 additions and 64 deletions

View file

@ -60,20 +60,25 @@ impl PianoHorizontal {
for (x, time) in (0..buf.width).map(|x|(x, x*zoom)) {
let cell = buf.get_mut(x, y).unwrap();
cell.set_bg(clip.color.darkest.rgb);
cell.set_fg(clip.color.darker.rgb);
cell.set_char(if time % 384 == 0 {
'│'
if time % 384 == 0 {
cell.set_fg(clip.color.darker.rgb);
cell.set_char('│');
} else if time % 96 == 0 {
'╎'
cell.set_fg(clip.color.dark.rgb);
cell.set_char('╎');
} else if time % note_len == 0 {
'┊'
cell.set_fg(clip.color.darker.rgb);
cell.set_char('┊');
} else if (127 - note) % 12 == 0 {
'='
cell.set_fg(clip.color.darker.rgb);
cell.set_char('=');
} else if (127 - note) % 6 == 0 {
'—'
cell.set_fg(clip.color.darker.rgb);
cell.set_char('—');
} else {
'·'
});
cell.set_fg(clip.color.darker.rgb);
cell.set_char('·');
}
}
}
}

View file

@ -225,9 +225,41 @@ impl Tek {
)?
};
arranger.scenes_add(scenes);
arranger.tracks_add(tracks, track_width, &[], &[]);
arranger.tracks_add(tracks, track_width, midi_froms, midi_tos);
arranger.selected = Selection::Clip(1, 1);
Ok(arranger)
}
fn scenes_add (&mut self, n: usize) -> Usually<()> {
let scene_color_1 = ItemColor::random();
let scene_color_2 = ItemColor::random();
for i in 0..n {
let _ = self.scene_add(None, Some(
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
))?;
}
Ok(())
}
fn tracks_add (
&mut self,
count: usize,
width: usize,
midi_from: &[PortConnection],
midi_to: &[PortConnection],
) -> Usually<()> {
let jack = self.jack().clone();
let track_color_1 = ItemColor::random();
let track_color_2 = ItemColor::random();
for i in 0..count {
let color = track_color_1.mix(track_color_2, i as f32 / count as f32).into();
let mut track = self.track_add(None, Some(color))?.1;
track.width = width;
let port = JackPort::<MidiIn>::new(&jack, &format!("{}I", &track.name), midi_from)?;
track.player.midi_ins.push(port);
let port = JackPort::<MidiOut>::new(&jack, &format!("{}O", &track.name), midi_to)?;
track.player.midi_outs.push(port);
}
Ok(())
}
fn new_groovebox (
jack: &Arc<RwLock<JackConnection>>,
bpm: Option<f64>,
@ -300,7 +332,6 @@ impl Tek {
// TODO: sync follow
Ok(())
}
fn editor (&self) -> impl Content<TuiOut> + '_ { &self.editor }
fn view_clock (&self) -> impl Content<TuiOut> + use<'_> {
Outer(Style::default().fg(TuiTheme::g(0))).enclose(row!(
self.view_engine_stats(), " ",
@ -422,7 +453,7 @@ impl Tek {
&mut self,
name: Option<&str>,
color: Option<ItemPalette>
) -> Usually<&mut Track> {
) -> Usually<(usize, &mut Track)> {
let name = name.map_or_else(||self.track_next_name(), |x|x.to_string().into());
let track = Track {
width: (name.len() + 2).max(9),
@ -439,28 +470,7 @@ impl Tek {
scene.clips.push(None);
}
}
Ok(&mut self.tracks_mut()[index])
}
fn tracks_add (
&mut self,
count: usize,
width: usize,
midi_from: &[PortConnection],
midi_to: &[PortConnection],
) -> Usually<()> {
let jack = self.jack().clone();
let track_color_1 = ItemColor::random();
let track_color_2 = ItemColor::random();
for i in 0..count {
let color = track_color_1.mix(track_color_2, i as f32 / count as f32).into();
let mut track = self.track_add(None, Some(color))?;
track.width = width;
let port = JackPort::<MidiIn>::new(&jack, &format!("{}I", &track.name), midi_from)?;
track.player.midi_ins.push(port);
let port = JackPort::<MidiOut>::new(&jack, &format!("{}O", &track.name), midi_to)?;
track.player.midi_outs.push(port);
}
Ok(())
Ok((index, &mut self.tracks_mut()[index]))
}
fn track_del (&mut self, index: usize) {
self.tracks_mut().remove(index);
@ -469,7 +479,7 @@ impl Tek {
}
}
fn scene_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
-> Usually<&mut Scene>
-> Usually<(usize, &mut Scene)>
{
let scene = Scene {
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
@ -478,17 +488,7 @@ impl Tek {
};
self.scenes_mut().push(scene);
let index = self.scenes().len() - 1;
Ok(&mut self.scenes_mut()[index])
}
fn scenes_add (&mut self, n: usize) -> Usually<()> {
let scene_color_1 = ItemColor::random();
let scene_color_2 = ItemColor::random();
for i in 0..n {
let _scene = self.scene_add(None, Some(
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
))?;
}
Ok(())
Ok((index, &mut self.scenes_mut()[index]))
}
fn clip_columns <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
let editing = self.is_editing();
@ -511,15 +511,14 @@ impl Tek {
("".to_string(), TuiTheme::g(64), TuiTheme::g(32))
};
let same_track = selected_track == Some(t+1);
let selected = same_track && Some(s+1) == selected_scene;
let neighbor = same_track && Some(s) == selected_scene;
let active = editing && selected;
let label = move||Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string())));
map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new(
active,
let selected = same_track && Some(s+1) == selected_scene;
let neighbor = same_track && Some(s) == selected_scene;
let active = editing && selected;
let label = move||Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string())));
map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new(active,
Thunk::new(||Bsp::a(
Fill::xy(Align::nw(button(" Tab ".into(), "".into()))),
self.editor())),
&self.editor)),
Thunk::new(move||Bsp::a(
When::new(selected, Fill::y(Align::n(button(" Tab ".into(), "edit".into())))),
phat_sel_3(
@ -704,13 +703,13 @@ command!(|self: TekCommand, app: Tek|match self {
if let Some(ref pool) = app.pool {
if app.is_editing() {
if let Selection::Clip(t, s) = app.selected {
if let Some(scene) = app.scenes.get_mut(s) {
if let Some(slot) = scene.clips.get_mut(t) {
if let Some(scene) = app.scenes.get_mut(s.saturating_sub(1)) {
if let Some(slot) = scene.clips.get_mut(t.saturating_sub(1)) {
if slot.is_none() {
let (index, mut clip) = pool.add_new_clip();
// autocolor: new clip colors from scene and track color
clip.write().unwrap().color = ItemColor::random_near(
app.tracks[t].color.base.mix(scene.color.base, 0.5),
app.tracks[t.saturating_sub(1)].color.base.mix(scene.color.base, 0.5),
0.2
).into();
if let Some(ref mut editor) = app.editor {
@ -852,8 +851,17 @@ edn_command!(TrackCommand: |app: Tek| {
("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap()))
});
command!(|self: TrackCommand, app: Tek|match self {
Self::Add => { app.track_add(None, None)?; None },
Self::Del(index) => { app.track_del(index); None },
Self::Add => {
use Selection::*;
let index = app.track_add(None, None)?.0 + 1;
app.selected = match app.selected {
Track(t) => Track(index),
Clip(t, s) => Clip(index, s),
_ => app.selected
};
Some(Self::Del(index))
},
Self::Del(index) => { app.track_del(index); None },
Self::Stop(track) => { app.tracks[track].player.enqueue_next(None); None },
Self::SetColor(index, color) => {
let old = app.tracks[index].color;
@ -881,12 +889,12 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
{
let mut x = 0;
let active = match self.selected() {
Selection::Track(t) if editing => Some(t),
Selection::Clip(t, _) if editing => Some(t),
Selection::Track(t) if editing => Some(t.saturating_sub(1)),
Selection::Clip(t, _) if editing => Some(t.saturating_sub(1)),
_ => None
};
self.tracks().iter().enumerate().map(move |(index, track)|{
let width = if Some(&index) == active { bigger } else { track.width.max(8) };
let width = if Some(index) == active { bigger } else { track.width.max(8) };
let data = (index, track, x, x + width);
x += width;
data
@ -1014,7 +1022,16 @@ edn_command!(SceneCommand: |app: Tek| {
("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap()))
});
command!(|self: SceneCommand, app: Tek|match self {
Self::Add => { app.scene_add(None, None)?; None }
Self::Add => {
use Selection::*;
let index = app.scene_add(None, None)?.0 + 1;
app.selected = match app.selected {
Scene(s) => Scene(index),
Clip(t, s) => Clip(t, index),
_ => app.selected
};
Some(Self::Del(index))
},
Self::Del(index) => { app.scene_del(index); None },
Self::SetColor(index, color) => {
let old = app.scenes[index].color;
@ -1044,11 +1061,11 @@ trait HasScenes: HasSelection + HasEditor + Send + Sync {
{
let mut y = 0;
let (selected_track, selected_scene) = match self.selected() {
Selection::Clip(t, s) => (Some(t), Some(s)),
Selection::Clip(t, s) => (Some(t.saturating_sub(1)), Some(s.saturating_sub(1))),
_ => (None, None)
};
self.scenes().iter().enumerate().map(move|(s, scene)|{
let active = editing && selected_track.is_some() && selected_scene == Some(&s);
let active = editing && selected_track.is_some() && selected_scene == Some(s);
let height = if active { larger } else { height };
let data = (s, scene, y, y + height);
y += height;