mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
append tracks/scenes + move cursor
This commit is contained in:
parent
5bf1bad7be
commit
a670320533
2 changed files with 86 additions and 64 deletions
|
|
@ -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('·');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
127
tek/src/lib.rs
127
tek/src/lib.rs
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue