diff --git a/tek/src/cli.rs b/tek/src/cli.rs index 8d131239..bfdd714b 100644 --- a/tek/src/cli.rs +++ b/tek/src/cli.rs @@ -193,11 +193,10 @@ impl Tek { scenes: vec![], ..Self::new_clock(jack, bpm, sync_lead, sync_follow, midi_froms, midi_tos)? }; + tek.arranger = Default::default(); + tek.selected = Selection::Clip(1, 1); tek.scenes_add(scenes); tek.tracks_add(tracks, Some(track_width), &[], &[]); - tek.selected = Selection::Clip(1, 1); - tek.arranger = Default::default(); - tek.redraw_arranger(); Ok(tek) } } diff --git a/tek/src/device.rs b/tek/src/device.rs new file mode 100644 index 00000000..e69de29b diff --git a/tek/src/keys.rs b/tek/src/keys.rs index 38e833d9..c376bd3e 100644 --- a/tek/src/keys.rs +++ b/tek/src/keys.rs @@ -4,8 +4,6 @@ pub const KEYS_CLIP: &str = include_str!("keys_clip.edn"); pub const KEYS_TRACK: &str = include_str!("keys_track.edn"); pub const KEYS_SCENE: &str = include_str!("keys_scene.edn"); pub const KEYS_MIX: &str = include_str!("keys_mix.edn"); -pub struct Keymaps { -} handle!(TuiIn: |self: Tek, input|Ok({ // If editing, editor keys take priority if self.is_editing() { diff --git a/tek/src/keys_ins.rs b/tek/src/keys_ins.rs index fd443d18..1cccea03 100644 --- a/tek/src/keys_ins.rs +++ b/tek/src/keys_ins.rs @@ -6,6 +6,7 @@ atom_command!(InputCommand: |app: Tek| { command!(|self: InputCommand, app: Tek|match self { Self::Add => { app.midi_ins.push(JackMidiIn::new(&app.jack, &format!("M/{}", app.midi_ins.len()), &[])?); + app.redraw_arranger(); None }, }); diff --git a/tek/src/keys_outs.rs b/tek/src/keys_outs.rs index 6d1b3235..333aa243 100644 --- a/tek/src/keys_outs.rs +++ b/tek/src/keys_outs.rs @@ -6,6 +6,7 @@ atom_command!(OutputCommand: |app: Tek| { command!(|self: OutputCommand, app: Tek|match self { Self::Add => { app.midi_outs.push(JackMidiOut::new(&app.jack, &format!("{}/M", app.midi_outs.len()), &[])?); + app.redraw_arranger(); None }, }); diff --git a/tek/src/lib.rs b/tek/src/lib.rs index 90c84425..56705877 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -8,6 +8,7 @@ #![feature(trait_alias)] mod cli; pub use self::cli::*; mod audio; pub use self::audio::*; +mod device; pub use self::device::*; mod keys; pub use self::keys::*; mod keys_clip; pub use self::keys_clip::*; mod keys_ins; pub use self::keys_ins::*; diff --git a/tek/src/model.rs b/tek/src/model.rs index aed7608e..64682aae 100644 --- a/tek/src/model.rs +++ b/tek/src/model.rs @@ -111,77 +111,6 @@ provide!(Selection: |self: Tek| { }, }); impl Tek { - pub 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(()) - } - pub fn scene_add (&mut self, name: Option<&str>, color: Option) - -> Usually<(usize, &mut Scene)> - { - let scene = Scene { - name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()), - clips: vec![None;self.tracks().len()], - color: color.unwrap_or_else(ItemPalette::random), - }; - self.scenes_mut().push(scene); - let index = self.scenes().len() - 1; - Ok((index, &mut self.scenes_mut()[index])) - } - pub fn scene_default_name (&self) -> Arc { - format!("Sc{:3>}", self.scenes().len() + 1).into() - } - pub fn tracks_add ( - &mut self, count: usize, width: Option, - midi_from: &[PortConnect], midi_to: &[PortConnect], - ) -> 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), midi_from, midi_to)?.1; - if let Some(width) = width { - track.width = width; - } - } - Ok(()) - } - pub fn track_add ( - &mut self, name: Option<&str>, color: Option, - midi_froms: &[PortConnect], - midi_tos: &[PortConnect], - ) -> Usually<(usize, &mut Track)> { - let name = name.map_or_else(||self.track_next_name(), |x|x.to_string().into()); - let mut track = Track { - width: (name.len() + 2).max(12), - color: color.unwrap_or_else(ItemPalette::random), - player: MidiPlayer::new( - &format!("{name}"), - self.jack(), - Some(self.clock()), - None, - midi_froms, - midi_tos - )?, - name, - ..Default::default() - }; - self.tracks_mut().push(track); - let len = self.tracks().len(); - let index = len - 1; - for scene in self.scenes_mut().iter_mut() { - while scene.clips.len() < len { - scene.clips.push(None); - } - } - Ok((index, &mut self.tracks_mut()[index])) - } fn clip (&self) -> Option>> { self.scene()?.clips.get(self.selected().track()?)?.clone() } @@ -190,12 +119,6 @@ impl Tek { clip.write().unwrap().toggle_loop() } } - pub fn track_del (&mut self, index: usize) { - self.tracks_mut().remove(index); - for scene in self.scenes_mut().iter_mut() { - scene.clips.remove(index); - } - } fn activate (&mut self) -> Usually<()> { let selected = self.selected().clone(); match selected { diff --git a/tek/src/model_scene.rs b/tek/src/model_scene.rs index c8bf0e9c..8099cf12 100644 --- a/tek/src/model_scene.rs +++ b/tek/src/model_scene.rs @@ -1,4 +1,32 @@ use crate::*; +impl Tek { + pub 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() + ))?; + } + self.redraw_arranger(); + Ok(()) + } + pub fn scene_add (&mut self, name: Option<&str>, color: Option) + -> Usually<(usize, &mut Scene)> + { + let scene = Scene { + name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()), + clips: vec![None;self.tracks().len()], + color: color.unwrap_or_else(ItemPalette::random), + }; + self.scenes_mut().push(scene); + let index = self.scenes().len() - 1; + Ok((index, &mut self.scenes_mut()[index])) + } + pub fn scene_default_name (&self) -> Arc { + format!("Sc{:3>}", self.scenes().len() + 1).into() + } +} pub trait HasScenes: HasSelection + HasEditor + Send + Sync { fn scenes (&self) -> &Vec; fn scenes_mut (&mut self) -> &mut Vec; diff --git a/tek/src/model_track.rs b/tek/src/model_track.rs index 235e8d84..3b898af5 100644 --- a/tek/src/model_track.rs +++ b/tek/src/model_track.rs @@ -1,4 +1,59 @@ use crate::*; +impl Tek { + pub fn tracks_add ( + &mut self, count: usize, width: Option, + midi_from: &[PortConnect], midi_to: &[PortConnect], + ) -> 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), midi_from, midi_to)?.1; + if let Some(width) = width { + track.width = width; + } + } + self.redraw_arranger(); + Ok(()) + } + pub fn track_add ( + &mut self, name: Option<&str>, color: Option, + midi_froms: &[PortConnect], + midi_tos: &[PortConnect], + ) -> Usually<(usize, &mut Track)> { + let name = name.map_or_else(||self.track_next_name(), |x|x.to_string().into()); + let mut track = Track { + width: (name.len() + 2).max(12), + color: color.unwrap_or_else(ItemPalette::random), + player: MidiPlayer::new( + &format!("{name}"), + self.jack(), + Some(self.clock()), + None, + midi_froms, + midi_tos + )?, + name, + ..Default::default() + }; + self.tracks_mut().push(track); + let len = self.tracks().len(); + let index = len - 1; + for scene in self.scenes_mut().iter_mut() { + while scene.clips.len() < len { + scene.clips.push(None); + } + } + Ok((index, &mut self.tracks_mut()[index])) + } + pub fn track_del (&mut self, index: usize) { + self.tracks_mut().remove(index); + for scene in self.scenes_mut().iter_mut() { + scene.clips.remove(index); + } + } +} pub trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync { fn midi_ins (&self) -> &Vec; fn midi_outs (&self) -> &Vec; diff --git a/tek/src/view_arranger.edn b/tek/src/view_arranger.edn index f1394971..7e79d1ad 100644 --- a/tek/src/view_arranger.edn +++ b/tek/src/view_arranger.edn @@ -1,3 +1 @@ -(bsp/n (fixed/y 1 :transport) - (bsp/s (fixed/y 1 :status) - (fill/xy (bsp/a (fill/xy (align/e :pool)) :arranger)))) +(bsp/n (fixed/y 2 :transport) (bsp/s (fixed/y 2 :status) (fill/xy (bsp/a (fill/xy (align/e :pool)) :arranger)))) diff --git a/tek/src/view_arranger.rs b/tek/src/view_arranger.rs index 75604641..4bd3ad69 100644 --- a/tek/src/view_arranger.rs +++ b/tek/src/view_arranger.rs @@ -1,21 +1,6 @@ use crate::*; impl Tek { - /// Draw the full arranger to the arranger view buffer. - /// - /// This should happen on changes to the arrangement contents, - /// i.e. not on scroll. Scrolling just determines which - /// part of the arranger buffer to blit in [view_arranger] - pub fn redraw_arranger (&self) { - let width = self.w_tracks(); - let height = self.h_scenes() + self.h_inputs() + self.h_outputs(); - let buffer = Buffer::empty(ratatui::prelude::Rect { x: 0, y: 0, width, height }); - let mut output = TuiOut { buffer, area: [0, 0, width, height] }; - Content::render(&Bsp::s(self.view_inputs(), Bsp::s(self.view_tracks(), - Bsp::n(self.view_outputs(), self.view_scenes()))), &mut output); - *self.arranger.write().unwrap() = output.buffer; - } - /// Blit the currently visible section of the arranger view buffer to the output. /// /// If the arranger is larger than the available display area, @@ -30,12 +15,13 @@ impl Tek { let source = self.arranger.read().unwrap(); for (source_x, target_x) in (x0..x0+w).enumerate() { for (source_y, target_y) in (y0..y0+h).enumerate() { - let source_pos = Position::from((source_x as u16, source_y as u16)); let target_pos = Position::from((target_x, target_y)); if let Some(target) = to.buffer.cell_mut(target_pos) { - //target.set_bg(Color::Red); + target.set_bg(Color::Rgb(128,0,0)); + let source_pos = Position::from((source_x as u16, source_y as u16)); if let Some(source) = source.cell(source_pos) { *target = source.clone(); + target.set_bg(Color::Rgb(0,128,0)); } } } @@ -43,6 +29,24 @@ impl Tek { })) } + /// Draw the full arranger to the arranger view buffer. + /// + /// This should happen on changes to the arrangement contents, + /// i.e. not on scroll. Scrolling just determines which + /// part of the arranger buffer to blit in [view_arranger]. + pub fn redraw_arranger (&self) { + let width = self.w_tracks(); + let height = self.h_scenes() + self.h_inputs() + self.h_outputs(); + let buffer = Buffer::empty(ratatui::prelude::Rect { x: 0, y: 0, width, height }); + let mut output = TuiOut { buffer, area: [0, 0, width, height] }; + let layout = Bsp::s(self.view_inputs(), + Bsp::s(self.view_tracks(), + Bsp::n(self.view_outputs(), + self.view_scenes()))); + Content::render(&layout, &mut output); + *self.arranger.write().unwrap() = output.buffer; + } + /// Display the current scene scroll state. fn scene_scrollbar (&self) -> impl Content + use<'_> { let offset = self.scene_scroll; @@ -98,26 +102,27 @@ impl Tek { } pub fn view_scenes (&self) -> impl Content + use<'_> { - let editing = self.is_editing(); - let s = self.w_sidebar() as u16; - let w = self.w_tracks_area(); - let w_full = self.w(); - let h = self.h_scenes(); - let h_area = self.h_tracks_area(); + let editing = self.is_editing(); + let s = self.w_sidebar() as u16; + let w = self.w_tracks_area(); + let w_full = self.w(); + let h = self.h_scenes(); + let h_area = self.h_tracks_area(); let selected_track = self.selected().track(); let selected_scene = self.selected().scene(); - Tui::bg(Reset, Bsp::s(self.track_scrollbar(), Bsp::e(self.scene_scrollbar(), - Fixed::y(self.h_tracks_area(), row(self.w_tracks_area(), h, s, - Map::new( - move||self.scenes_with_colors(editing, h_area), - move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_name( - w_full, (1 + y2 - y1) as u16, y1 as u16, s, scene, prev)), - self.per_track(move|t, track|Map::new( - move||self.scenes_with_track_colors(editing, h_area, t), - move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_clip( - w, (1 + y2 - y1) as u16, y1 as u16, - scene, prev, s, t, editing, selected_track == Some(t), selected_scene))), - () ))))) + let track_scroll = self.track_scrollbar(); + let scene_scroll = self.scene_scrollbar(); + Tui::bg(Reset, Bsp::s(track_scroll, Bsp::e(scene_scroll, Fixed::y(h_area, row(w, h, s, + Map::new( + move||self.scenes_with_colors(editing, h_area), + move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_name( + w_full, (1 + y2 - y1) as u16, y1 as u16, s, scene, prev)), + self.per_track(move|t, track|Map::new( + move||self.scenes_with_track_colors(editing, h_area, t), + move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_clip( + w, (1 + y2 - y1) as u16, y1 as u16, + scene, prev, s, t, editing, selected_track == Some(t), selected_scene))), + () ))))) } fn view_scene_name (