mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
remove 1 more per-cell allocation
This commit is contained in:
parent
f7dcc28e1f
commit
93462e7501
2 changed files with 128 additions and 92 deletions
177
tek/src/lib.rs
177
tek/src/lib.rs
|
|
@ -17,7 +17,7 @@ pub use ::tek_sampler::{self, *};
|
|||
pub use ::tek_plugin::{self, *};
|
||||
pub use ::tek_tui::{
|
||||
*, tek_edn::*, tek_input::*, tek_output::*,
|
||||
ratatui, ratatui::{prelude::{Color, Style, Stylize, Buffer, Modifier}, buffer::Cell},
|
||||
ratatui, ratatui::{prelude::{Color::{self, *}, Style, Stylize, Buffer, Modifier}, buffer::Cell},
|
||||
crossterm, crossterm::event::{
|
||||
Event, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, KeyCode::{self, *},
|
||||
},
|
||||
|
|
@ -157,6 +157,7 @@ impl TekCli {
|
|||
pub fmtd_sr: Arc<RwLock<String>>,
|
||||
pub fmtd_buf: Arc<RwLock<String>>,
|
||||
pub fmtd_lat: Arc<RwLock<String>>,
|
||||
pub fmtd_stop: Arc<str>,
|
||||
}
|
||||
has_size!(<TuiOut>|self: Tek|&self.size);
|
||||
has_clock!(|self: Tek|self.clock);
|
||||
|
|
@ -238,6 +239,7 @@ impl Tek {
|
|||
fmtd_sr: Arc::new(RwLock::new(String::with_capacity(16))),
|
||||
fmtd_buf: Arc::new(RwLock::new(String::with_capacity(16))),
|
||||
fmtd_lat: Arc::new(RwLock::new(String::with_capacity(16))),
|
||||
fmtd_stop: "⏹".into(),
|
||||
..Default::default()
|
||||
};
|
||||
tek.sync_lead(sync_lead);
|
||||
|
|
@ -452,9 +454,9 @@ impl Tek {
|
|||
else if value >= -25.0 { 3 }
|
||||
else if value >= -30.0 { 2 }
|
||||
else if value >= -40.0 { 1 }
|
||||
else { 0 }, 1, Tui::bg(if value >= 0.0 { Color::Red }
|
||||
else if value >= -3.0 { Color::Yellow }
|
||||
else { Color::Green }, ())))
|
||||
else { 0 }, 1, Tui::bg(if value >= 0.0 { Red }
|
||||
else if value >= -3.0 { Yellow }
|
||||
else { Green }, ())))
|
||||
}
|
||||
fn view_meters (&self, values: &[f32;2]) -> impl Content<TuiOut> + use<'_> {
|
||||
col!(
|
||||
|
|
@ -466,14 +468,14 @@ impl Tek {
|
|||
let playing = self.clock.is_rolling();
|
||||
let compact = self.is_editing();
|
||||
Tui::bg(
|
||||
if playing{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
|
||||
if playing{Rgb(0,128,0)}else{Rgb(128,64,0)},
|
||||
Either::new(compact,
|
||||
Thunk::new(move||Fixed::x(9, Either::new(playing,
|
||||
Tui::fg(Color::Rgb(0, 255, 0), " PLAYING "),
|
||||
Tui::fg(Color::Rgb(255, 128, 0), " STOPPED ")))),
|
||||
Tui::fg(Rgb(0, 255, 0), " PLAYING "),
|
||||
Tui::fg(Rgb(255, 128, 0), " STOPPED ")))),
|
||||
Thunk::new(move||Fixed::x(5, Either::new(playing,
|
||||
Tui::fg(Color::Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
||||
Tui::fg(Color::Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",)))))))
|
||||
Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
||||
Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",)))))))
|
||||
}
|
||||
fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
self.editor.as_ref().map(|e|Bsp::e(e.clip_status(), e.edit_status()))
|
||||
|
|
@ -482,8 +484,8 @@ impl Tek {
|
|||
self.pool.as_ref().map(|pool|PoolView(self.is_editing(), pool))
|
||||
}
|
||||
fn pool (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
self.pool.as_ref()
|
||||
.map(|pool|Align::e(Fixed::x(self.sidebar_w(), PoolView(self.is_editing(), pool))))
|
||||
let by_pool = |pool|Align::e(Fixed::x(self.sidebar_w(), PoolView(self.is_editing(), pool)));
|
||||
self.pool.as_ref().map(by_pool)
|
||||
}
|
||||
fn w (&self) -> u16 {
|
||||
self.tracks_sizes(self.is_editing(), self.editor_w())
|
||||
|
|
@ -530,40 +532,65 @@ impl Tek {
|
|||
move|(_, track, x1, x2), t| {
|
||||
let last_color = Arc::new(RwLock::new(ItemPalette::default()));
|
||||
let w = (x2 - x1) as u16;
|
||||
let color: ItemPalette = track.color;
|
||||
map_east(x1 as u16, w, border(Map::new(scenes, move|(_, scene, y1, y2), s| {
|
||||
let last_color = last_color.clone();
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
let color = scene.color;
|
||||
let mut name = String::from("⏹ ");
|
||||
let mut fg = Tui::g(64);
|
||||
let mut bg = ItemPalette::G[32];
|
||||
if let Some(clip) = &scene.clips[t] {
|
||||
let clip = clip.read().unwrap();
|
||||
name.clear();
|
||||
write!(&mut name, "{}", clip.name);
|
||||
fg = clip.color.lightest.rgb;
|
||||
bg = clip.color
|
||||
};
|
||||
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.clone())));
|
||||
let mid = if active { bg.light } else { bg.base };
|
||||
let top = if neighbor { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let mid = mid.rgb;
|
||||
let low = Color::Rgb(0, 0, 0);
|
||||
let last_color = last_color.clone();
|
||||
let mut fg = Tui::g(64);
|
||||
let mut bg = ItemPalette::G[32];
|
||||
if let Some(clip) = &scene.clips[t] {
|
||||
let clip = clip.read().unwrap();
|
||||
fg = clip.color.lightest.rgb;
|
||||
bg = clip.color
|
||||
};
|
||||
|
||||
//let top = if neighbor { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let top = if s == 0 {
|
||||
Some(Reset)
|
||||
} else if neighbor {
|
||||
None
|
||||
} else {
|
||||
Some(last_color.read().unwrap().base.rgb)
|
||||
};
|
||||
let mid = if selected { bg.light } else { bg.base }.rgb;
|
||||
let low = Some(Reset);
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
*last_color.write().unwrap() = bg;
|
||||
let tab = " Tab ";
|
||||
let name = if active {
|
||||
self.editor.as_ref()
|
||||
.map(|e|e.clip().as_ref().map(|c|c.clone()))
|
||||
.flatten()
|
||||
.map(|c|c.read().unwrap().name.clone())
|
||||
.unwrap_or_else(||"".into())
|
||||
} else {
|
||||
"edit".into()
|
||||
};
|
||||
let label = move||{
|
||||
let stop = self.fmtd_stop.clone();
|
||||
let clip = scene.clips[t].clone();
|
||||
Tui::fg(fg, Push::x(1, Tui::bold(true, clip
|
||||
.map(|c|c.read().unwrap().name.clone())
|
||||
.unwrap_or(stop))))
|
||||
};
|
||||
|
||||
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 ", ""))),
|
||||
Thunk::new(move||Bsp::a(
|
||||
Fill::xy(Align::nw(button(tab, Tui::fg_bg(fg, bg.base.rgb, name.clone())))),
|
||||
&self.editor)),
|
||||
Thunk::new(move||Bsp::a(
|
||||
When::new(selected, Fill::y(Align::n(button(" Tab ", "edit")))),
|
||||
phat_sel_3(selected, label(), label(), top, mid, low)
|
||||
When::new(selected, Fill::y(Align::n(button(tab, "edit")))),
|
||||
Fill::xy(phat_sel_3(
|
||||
selected,
|
||||
label(),
|
||||
label(),
|
||||
top, mid, low
|
||||
))
|
||||
)),
|
||||
))))
|
||||
|
||||
}))).boxed()
|
||||
}
|
||||
})).boxed()).into()
|
||||
|
|
@ -679,7 +706,7 @@ handle!(TuiIn: |self: Tek, input|Ok({
|
|||
Zoom(Option<usize>),
|
||||
}
|
||||
atom_command!(TekCommand: |app: Tek| {
|
||||
("stop-all" [] Self::StopAll)
|
||||
("stop" [] Self::StopAll)
|
||||
("undo" [d: usize] Self::History(-(d.unwrap_or(0)as isize)))
|
||||
("redo" [d: usize] Self::History(d.unwrap_or(0) as isize))
|
||||
("zoom" [z: usize] Self::Zoom(z))
|
||||
|
|
@ -693,20 +720,20 @@ atom_command!(TekCommand: |app: Tek| {
|
|||
(0, s) => Self::Select(Selection::Scene(s)),
|
||||
(t, s) => Self::Select(Selection::Clip(t, s)),
|
||||
})
|
||||
("clip" [,..a] Self::Clip(ClipCommand::try_from_expr(app, a)
|
||||
.expect("invalid command")))
|
||||
("clock" [,..a] Self::Clock(ClockCommand::try_from_expr(app.clock(), a)
|
||||
.expect("invalid command")))
|
||||
("editor" [,..a] Self::Editor(MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a)
|
||||
.expect("invalid command")))
|
||||
("pool" [,..a] Self::Pool(PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a)
|
||||
.expect("invalid command")))
|
||||
("sampler" [,..a] Self::Sampler(SamplerCommand::try_from_expr(app.sampler.as_ref().expect("no sampler"), a)
|
||||
.expect("invalid command")))
|
||||
("scene" [,..a] Self::Scene(SceneCommand::try_from_expr(app, a)
|
||||
.expect("invalid command")))
|
||||
("track" [,..a] Self::Track(TrackCommand::try_from_expr(app, a)
|
||||
.expect("invalid command")))
|
||||
("clip" [,..a] Self::Clip(
|
||||
ClipCommand::try_from_expr(app, a).expect("invalid command")))
|
||||
("clock" [,..a] Self::Clock(
|
||||
ClockCommand::try_from_expr(app.clock(), a).expect("invalid command")))
|
||||
("editor" [,..a] Self::Editor(
|
||||
MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a).expect("invalid command")))
|
||||
("pool" [,..a] Self::Pool(
|
||||
PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a).expect("invalid command")))
|
||||
("sampler" [,..a] Self::Sampler(
|
||||
SamplerCommand::try_from_expr(app.sampler.as_ref().expect("no sampler"), a).expect("invalid command")))
|
||||
("scene" [,..a] Self::Scene(
|
||||
SceneCommand::try_from_expr(app, a).expect("invalid command")))
|
||||
("track" [,..a] Self::Track(
|
||||
TrackCommand::try_from_expr(app, a).expect("invalid command")))
|
||||
});
|
||||
command!(|self: TekCommand, app: Tek|match self {
|
||||
Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None },
|
||||
|
|
@ -741,7 +768,10 @@ command!(|self: TekCommand, app: Tek|match self {
|
|||
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.saturating_sub(1)].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 {
|
||||
|
|
@ -978,7 +1008,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
let fg = color.lightest.rgb;
|
||||
let bg = color.base.rgb;
|
||||
let active = self.selected().track() == Some(i + 1);
|
||||
let bfg = if active { Color::Rgb(255,255,255) } else { Color::Rgb(0,0,0) };
|
||||
let bfg = if active { Rgb(255,255,255) } else { Rgb(0,0,0) };
|
||||
let border = Style::default().fg(bfg).bg(bg);
|
||||
Tui::bg(bg, map_east(x1 as u16, (x2 - x1) as u16,
|
||||
Outer(false, border)
|
||||
|
|
@ -998,11 +1028,11 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
}
|
||||
fn rec_mon (bg: Color, rec: bool, mon: bool) -> impl Content<TuiOut> {
|
||||
row!(
|
||||
Tui::fg_bg(if rec { Color::Red } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if rec { Color::White } else { Color::Rgb(0,0,0) }, bg, "REC"),
|
||||
Tui::fg_bg(if rec { Color::White } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if mon { Color::White } else { Color::Rgb(0,0,0) }, bg, "MON"),
|
||||
Tui::fg_bg(if mon { Color::White } else { bg }, bg, "▌"),
|
||||
Tui::fg_bg(if rec { Red } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if rec { White } else { Rgb(0,0,0) }, bg, "REC"),
|
||||
Tui::fg_bg(if rec { White } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if mon { White } else { Rgb(0,0,0) }, bg, "MON"),
|
||||
Tui::fg_bg(if mon { White } else { bg }, bg, "▌"),
|
||||
)
|
||||
}
|
||||
fn output_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||
|
|
@ -1017,16 +1047,16 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
}
|
||||
fn mute_solo (bg: Color, mute: bool, solo: bool) -> impl Content<TuiOut> {
|
||||
row!(
|
||||
Tui::fg_bg(if mute { Color::White } else { Color::Rgb(0,0,0) }, bg, "MUTE"),
|
||||
Tui::fg_bg(if mute { Color::White } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if solo { Color::White } else { Color::Rgb(0,0,0) }, bg, "SOLO"),
|
||||
Tui::fg_bg(if mute { White } else { Rgb(0,0,0) }, bg, "MUT"),
|
||||
Tui::fg_bg(if mute { White } else { bg }, bg, "▐"),
|
||||
Tui::fg_bg(if solo { White } else { Rgb(0,0,0) }, bg, "SOL"),
|
||||
)
|
||||
}
|
||||
fn cell <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
||||
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
||||
}
|
||||
}
|
||||
trait Device: Send + Sync + std::fmt::Debug {}
|
||||
pub trait Device: Send + Sync + std::fmt::Debug {}
|
||||
impl Device for Sampler {}
|
||||
impl Device for Plugin {}
|
||||
#[derive(Debug, Default)] pub struct Scene {
|
||||
|
|
@ -1149,21 +1179,19 @@ trait HasScenes: HasSelection + HasEditor + Send + Sync {
|
|||
let selected = self.selected().scene();
|
||||
let iter = ||self.scenes_sizes(self.is_editing(), 2, 15);
|
||||
Map::new(iter, move|(_, scene, y1, y2), i| {
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
let name = format!("🭬{}", &scene.name);
|
||||
let color = scene.color;
|
||||
let active = selected == Some(i + 1);
|
||||
let neighbor = selected == Some(i);
|
||||
let mid = if active { color.light } else { color.base };
|
||||
let top = if neighbor { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let mid = mid.rgb;
|
||||
let low = Color::Rgb(0, 0, 0);
|
||||
let top = if i == 0 { Some(Reset) } else if selected == Some(i+0) { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let mid = if selected == Some(i+1) { color.light } else { color.base }.rgb;
|
||||
let low = Some(Reset);
|
||||
let cell = phat_sel_3(
|
||||
active,
|
||||
Tui::bold(true, name.clone()),
|
||||
Tui::bold(true, name),
|
||||
top, mid, low
|
||||
selected == Some(i),
|
||||
Tui::bold(true, Bsp::e("🭬", &scene.name)),
|
||||
Tui::bold(true, Bsp::e("🭬", &scene.name)),
|
||||
top,
|
||||
mid,
|
||||
low
|
||||
);
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
*last_color.write().unwrap() = color;
|
||||
map_south(y1 as u16, h, Push::y(1, Fixed::y(h,
|
||||
Outer(false, Style::default().fg(Tui::g(0))).enclose(cell))))
|
||||
|
|
@ -1275,7 +1303,10 @@ audio!(|self: Tek, client, scope|{
|
|||
self.perf.update(t0, scope);
|
||||
Control::Continue
|
||||
});
|
||||
fn button (key: &'static str, label: &'static str) -> impl Content<TuiOut> + 'static {
|
||||
fn button <'a> (
|
||||
key: impl Content<TuiOut> + 'a,
|
||||
label: impl Content<TuiOut> + 'a
|
||||
) -> impl Content<TuiOut> + 'a {
|
||||
Tui::bold(true, Bsp::e(
|
||||
Margin::x(1, Tui::fg_bg(Tui::g(0), Tui::orange(), key)),
|
||||
Margin::x(1, Tui::fg_bg(Tui::g(255), Tui::g(96), label)),
|
||||
|
|
|
|||
|
|
@ -158,17 +158,22 @@ pub fn phat_cell_3 <T: Content<TuiOut>> (
|
|||
)
|
||||
}
|
||||
pub fn phat_sel_3 <T: Content<TuiOut>> (
|
||||
selected: bool, field_1: T, field_2: T, top: Option<Color>, middle: Color, bottom: Color
|
||||
selected: bool, field_1: T, field_2: T,
|
||||
top: Option<Color>,
|
||||
mid: Color,
|
||||
low: Option<Color>,
|
||||
) -> impl Content<TuiOut> {
|
||||
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(middle);
|
||||
Either::new(selected,
|
||||
Tui::bg(middle, Outer(true, border)
|
||||
.enclose(Align::w(Bsp::s("", Bsp::n("", Fill::y(field_1)))))),
|
||||
Bsp::s(Fixed::y(1, top.map(|top|phat_lo(middle, top))),
|
||||
Bsp::n(Fixed::y(1, phat_hi(middle, bottom)),
|
||||
Fill::xy(Tui::bg(middle, field_2)),
|
||||
)
|
||||
)
|
||||
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(mid);
|
||||
let top = top.map(|top|phat_lo(mid, top));
|
||||
let low = low.map(|low|phat_hi(mid, low));
|
||||
Either::new(
|
||||
selected,
|
||||
Tui::bg(mid, Outer(true, border).enclose(
|
||||
Align::w(Bsp::s("", Bsp::n("", Fill::y(field_1))))
|
||||
)),
|
||||
Bsp::s(Fixed::y(1, top), Bsp::n(Fixed::y(1, low),
|
||||
Fill::xy(Tui::bg(mid, field_2))
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue