mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-05-08 16:30:13 +02:00
wip: fixing memoized arranger rendering
This commit is contained in:
parent
ec85224f3a
commit
5b797342b7
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
0
tek/src/device.rs
Normal file
0
tek/src/device.rs
Normal file
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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<ItemPalette>)
|
||||
-> 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<str> {
|
||||
format!("Sc{:3>}", self.scenes().len() + 1).into()
|
||||
}
|
||||
pub fn tracks_add (
|
||||
&mut self, count: usize, width: Option<usize>,
|
||||
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<ItemPalette>,
|
||||
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<Arc<RwLock<MidiClip>>> {
|
||||
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 {
|
||||
|
|
|
@ -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<ItemPalette>)
|
||||
-> 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<str> {
|
||||
format!("Sc{:3>}", self.scenes().len() + 1).into()
|
||||
}
|
||||
}
|
||||
pub trait HasScenes: HasSelection + HasEditor + Send + Sync {
|
||||
fn scenes (&self) -> &Vec<Scene>;
|
||||
fn scenes_mut (&mut self) -> &mut Vec<Scene>;
|
||||
|
|
|
@ -1,4 +1,59 @@
|
|||
use crate::*;
|
||||
impl Tek {
|
||||
pub fn tracks_add (
|
||||
&mut self, count: usize, width: Option<usize>,
|
||||
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<ItemPalette>,
|
||||
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<JackMidiIn>;
|
||||
fn midi_outs (&self) -> &Vec<JackMidiOut>;
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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<TuiOut> + use<'_> {
|
||||
let offset = self.scene_scroll;
|
||||
|
@ -98,26 +102,27 @@ impl Tek {
|
|||
}
|
||||
|
||||
pub fn view_scenes (&self) -> impl Content<TuiOut> + 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 (
|
||||
|
|
Loading…
Reference in a new issue