mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
Compare commits
3 commits
9aeb792f7d
...
4f6cb7cb8e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f6cb7cb8e | ||
| a45e409e6b | |||
| fca1e85611 |
9 changed files with 52 additions and 37 deletions
|
|
@ -15,7 +15,7 @@ or [**matrix** `@unspeaker:matrix.org`](https://matrix.to/#/@unspeaker:matrix.or
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|-|-|
|
|-|-|
|
||||||
||
|
||<br>|
|
||||||
|
|
||||||
## usage
|
## usage
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,6 @@
|
||||||
(fill/xy (align/n (bsp/s :view-arranger-track-names
|
(fill/xy (align/n (bsp/s :view-arranger-track-names
|
||||||
(bsp/s :view-arranger-track-outputs
|
(bsp/s :view-arranger-track-outputs
|
||||||
(bsp/s :view-arranger-track-devices :view-arranger-track-inputs)))))))
|
(bsp/s :view-arranger-track-devices :view-arranger-track-inputs)))))))
|
||||||
(bsp/w
|
(fill/xy (align/w (bsp/e
|
||||||
(fixed/x 20 :view-pool)
|
(align/w (fixed/x 20 (fill/xy (align/nw :view-arranger-scenes-names))))
|
||||||
:view-arranger-scenes)))
|
(align/w (fill/xy (align/nw :view-arranger-scenes-clips)))))))))
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@
|
||||||
(layer "./keys_global.edn"))
|
(layer "./keys_global.edn"))
|
||||||
|
|
||||||
(view (bsp/a :view-dialog (bsp/w :view-meters-output (bsp/e :view-meters-input
|
(view (bsp/a :view-dialog (bsp/w :view-meters-output (bsp/e :view-meters-input
|
||||||
(bsp/e
|
(bsp/w
|
||||||
(fill/y (align/n
|
(fill/y (align/n
|
||||||
(bsp/s :view-status-v
|
(bsp/s :view-midi-ins-status
|
||||||
(bsp/s :view-editor-status :view-pool))))
|
(bsp/s :view-midi-outs-status
|
||||||
(bsp/w
|
(bsp/s :view-audio-ins-status
|
||||||
(fill/y (align/n
|
(bsp/s :view-audio-outs-status
|
||||||
(bsp/s :view-midi-ins-status
|
:view-pool))))))
|
||||||
(bsp/s :view-midi-outs-status
|
(bsp/n
|
||||||
(bsp/s :view-audio-ins-status :view-audio-outs-status)))))
|
(fixed/y :h-sample-detail
|
||||||
(bsp/n
|
(bsp/e (fill/y (fixed/x 20 (align/nw :view-sample-status)))
|
||||||
(fixed/y :h-sample-detail
|
:view-sample-viewer))
|
||||||
(bsp/e (fill/y (fixed/x 20 (align/nw :view-sample-status)))
|
(bsp/e
|
||||||
:view-sample-viewer))
|
(fill/y (align/n (bsp/s :view-status-v :view-editor-status)))
|
||||||
(bsp/e :view-samples-keys :view-editor))))))))
|
(bsp/e :view-samples-keys :view-editor))))))))
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,9 @@ impl App {
|
||||||
fn focus_editor (&self) -> bool {
|
fn focus_editor (&self) -> bool {
|
||||||
self.is_editing()
|
self.is_editing()
|
||||||
}
|
}
|
||||||
|
fn is_editing (&self) -> bool {
|
||||||
|
HasEditor::is_editing(self)
|
||||||
|
}
|
||||||
fn focus_message (&self) -> bool {
|
fn focus_message (&self) -> bool {
|
||||||
matches!(self.dialog, Some(Dialog::Message(..)))
|
matches!(self.dialog, Some(Dialog::Message(..)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,12 @@ impl App {
|
||||||
pub fn view_arranger_scenes (&self) -> impl Content<TuiOut> + use<'_> {
|
pub fn view_arranger_scenes (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.scenes_view(&self.editor)
|
self.scenes_view(&self.editor)
|
||||||
}
|
}
|
||||||
|
pub fn view_arranger_scenes_names (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.scenes_names()
|
||||||
|
}
|
||||||
|
pub fn view_arranger_scenes_clips (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
self.scenes_clips(&self.editor)
|
||||||
|
}
|
||||||
pub fn view_arranger_scene_names <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
pub fn view_arranger_scene_names <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
||||||
let h = self.project.scenes.len() as u16 * 2;
|
let h = self.project.scenes.len() as u16 * 2;
|
||||||
let bg = self.color.darker.rgb;
|
let bg = self.color.darker.rgb;
|
||||||
|
|
@ -357,16 +363,16 @@ impl App {
|
||||||
|
|
||||||
impl ArrangerSceneRows for App {
|
impl ArrangerSceneRows for App {
|
||||||
fn arrangement (&self) -> &Arrangement {
|
fn arrangement (&self) -> &Arrangement {
|
||||||
self.project
|
&self.project
|
||||||
}
|
}
|
||||||
fn scenes_height (&self) -> u16 {
|
fn scenes_height (&self) -> u16 {
|
||||||
self.project.scenes_height
|
(self.height() as u16).saturating_sub(20)
|
||||||
}
|
}
|
||||||
fn width_side (&self) -> u16 {
|
fn width_side (&self) -> u16 {
|
||||||
20
|
20
|
||||||
}
|
}
|
||||||
fn width_mid (&self) -> u16 {
|
fn width_mid (&self) -> u16 {
|
||||||
self.width().saturating_sub(self.width_side() * 2)
|
(self.width() as u16).saturating_sub(self.width_side())
|
||||||
}
|
}
|
||||||
fn scene_selected (&self) -> Option<usize> {
|
fn scene_selected (&self) -> Option<usize> {
|
||||||
self.project.selection.scene()
|
self.project.selection.scene()
|
||||||
|
|
@ -378,7 +384,7 @@ impl ArrangerSceneRows for App {
|
||||||
self.project.selection.track()
|
self.project.selection.track()
|
||||||
}
|
}
|
||||||
fn is_editing (&self) -> bool {
|
fn is_editing (&self) -> bool {
|
||||||
self.is_editing
|
self.editor.is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ pub enum LaunchMode {
|
||||||
/// 🎧 Multi-track MIDI sequencer.
|
/// 🎧 Multi-track MIDI sequencer.
|
||||||
Arranger {
|
Arranger {
|
||||||
/// Number of scenes
|
/// Number of scenes
|
||||||
#[arg(short = 'y', long, default_value_t = 4)] scenes: usize,
|
#[arg(short = 'y', long, default_value_t = 8)] scenes: usize,
|
||||||
/// Number of tracks
|
/// Number of tracks
|
||||||
#[arg(short = 'x', long, default_value_t = 4)] tracks: usize,
|
#[arg(short = 'x', long, default_value_t = 4)] tracks: usize,
|
||||||
/// Width of tracks
|
/// Width of tracks
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ pub trait ArrangerSceneRows: Send + Sync {
|
||||||
fn width_side (&self) -> u16;
|
fn width_side (&self) -> u16;
|
||||||
fn width_mid (&self) -> u16;
|
fn width_mid (&self) -> u16;
|
||||||
fn scenes_names (&self) -> impl Content<TuiOut> {
|
fn scenes_names (&self) -> impl Content<TuiOut> {
|
||||||
Map::new(move||self.scenes_with_prev_color(),
|
let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0);
|
||||||
|
Fixed::y(h, Map::new(move||self.scenes_with_prev_color(),
|
||||||
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{
|
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{
|
||||||
let height = (1 + y2 - y1) as u16;
|
let height = (1 + y2 - y1) as u16;
|
||||||
let name = Some(scene.name.clone());
|
let name = Some(scene.name.clone());
|
||||||
|
|
@ -46,16 +47,25 @@ pub trait ArrangerSceneRows: Send + Sync {
|
||||||
Fill::x(map_south(y1 as u16, height, Fixed::y(height, Phat {
|
Fill::x(map_south(y1 as u16, height, Fixed::y(height, Phat {
|
||||||
width: 0, height: 0, content, colors: [fg, bg, hi, lo]
|
width: 0, height: 0, content, colors: [fg, bg, hi, lo]
|
||||||
})))
|
})))
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
fn scenes_with_prev_color (&self) -> impl Iterator<Item=SceneWith<Option<ItemTheme>>> + Send + Sync {
|
fn scenes_with_prev_color (&self) -> impl Iterator<Item=SceneWith<Option<ItemTheme>>> + Send + Sync {
|
||||||
self.scenes_iter().map(|(s, scene, y1, y2)|(s, scene, y1, y2,
|
self.scenes_iter().map(|(s, scene, y1, y2)|(s, scene, y1, y2,
|
||||||
(s>0).then_some(self.arrangement().scenes()[s-1].color)))
|
(s>0).then(||self.arrangement().scenes()[s-1].color)))
|
||||||
|
}
|
||||||
|
fn per_track <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
|
||||||
|
tracks: impl Fn() -> U + Send + Sync + 'a,
|
||||||
|
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
|
||||||
|
) -> impl Content<TuiOut> + 'a {
|
||||||
|
Map::new(tracks, move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{
|
||||||
|
Tui::fg_bg(track.color.lightest.rgb, track.color.darker.rgb,
|
||||||
|
map_east(x1 as u16, (x2 - x1) as u16, callback(index, track))) })
|
||||||
}
|
}
|
||||||
fn scenes_clips <'a> (&'a self, editor: &'a Option<MidiEditor>)
|
fn scenes_clips <'a> (&'a self, editor: &'a Option<MidiEditor>)
|
||||||
-> impl Content<TuiOut> + 'a
|
-> impl Content<TuiOut> + 'a
|
||||||
{
|
{
|
||||||
per_track(||self.tracks_with_sizes_scrolled(),
|
let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0);
|
||||||
|
Fixed::y(h, Self::per_track(||self.tracks_with_sizes_scrolled(),
|
||||||
move|track_index, track|Map::new(move||self.scenes_with_clip(track_index),
|
move|track_index, track|Map::new(move||self.scenes_with_clip(track_index),
|
||||||
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{
|
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{
|
||||||
let (name, theme) = if let Some(clip) = &scene.clips[track_index] {
|
let (name, theme) = if let Some(clip) = &scene.clips[track_index] {
|
||||||
|
|
@ -64,7 +74,6 @@ pub trait ArrangerSceneRows: Send + Sync {
|
||||||
} else {
|
} else {
|
||||||
(None, ItemTheme::G[32])
|
(None, ItemTheme::G[32])
|
||||||
};
|
};
|
||||||
let height = (1 + y2 - y1) as u16;
|
|
||||||
let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⏹ ", name))));
|
let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⏹ ", name))));
|
||||||
let same_track = self.track_selected() == Some(track_index);
|
let same_track = self.track_selected() == Some(track_index);
|
||||||
let selected = same_track && self.scene_selected() == Some(s);
|
let selected = same_track && self.scene_selected() == Some(s);
|
||||||
|
|
@ -73,11 +82,7 @@ pub trait ArrangerSceneRows: Send + Sync {
|
||||||
let fg = theme.lightest.rgb;
|
let fg = theme.lightest.rgb;
|
||||||
let bg = if selected { theme.light } else { theme.base }.rgb;
|
let bg = if selected { theme.light } else { theme.base }.rgb;
|
||||||
let hi = if let Some(previous) = previous {
|
let hi = if let Some(previous) = previous {
|
||||||
if neighbor {
|
if neighbor { previous.light.rgb } else { previous.base.rgb }
|
||||||
previous.light.rgb
|
|
||||||
} else {
|
|
||||||
previous.base.rgb
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Reset
|
Reset
|
||||||
};
|
};
|
||||||
|
|
@ -88,17 +93,18 @@ pub trait ArrangerSceneRows: Send + Sync {
|
||||||
} else {
|
} else {
|
||||||
theme.base.rgb
|
theme.base.rgb
|
||||||
};
|
};
|
||||||
|
let height = (1 + y2 - y1) as u16;
|
||||||
map_south(y1 as u16, height, Bsp::b(Fixed::y(height, Phat {
|
map_south(y1 as u16, height, Bsp::b(Fixed::y(height, Phat {
|
||||||
width: 0, height: 0, content, colors: [fg, bg, hi, lo]
|
width: 0, height: 0, content, colors: [fg, bg, hi, lo]
|
||||||
}), When(
|
}), When(
|
||||||
self.is_editing() && same_track && self.scene_selected() == Some(s),
|
self.is_editing() && same_track && self.scene_selected() == Some(s),
|
||||||
editor
|
editor
|
||||||
)))
|
)))
|
||||||
}))
|
})))
|
||||||
}
|
}
|
||||||
fn scenes_with_clip (&self, track_index: usize) -> impl Iterator<Item=SceneWith<'_, Option<ItemTheme>>> + Send + Sync {
|
fn scenes_with_clip (&self, track_index: usize) -> impl Iterator<Item=SceneWith<'_, Option<ItemTheme>>> + Send + Sync {
|
||||||
self.scenes_iter().map(move|(s, scene, y1, y2)|(s, scene, y1, y2,
|
self.scenes_iter().map(move|(s, scene, y1, y2)|(s, scene, y1, y2,
|
||||||
(s>0).then_some(self.arrangement().scenes()[s-1].clips[track_index].as_ref()
|
(s>0).then(||self.arrangement().scenes()[s-1].clips[track_index].as_ref()
|
||||||
.map(|c|c.read().unwrap().color)
|
.map(|c|c.read().unwrap().color)
|
||||||
.unwrap_or(ItemTheme::G[32]))))
|
.unwrap_or(ItemTheme::G[32]))))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ impl MidiViewer for MidiEditor {
|
||||||
pub trait HasEditor {
|
pub trait HasEditor {
|
||||||
fn editor (&self) -> Option<&MidiEditor>;
|
fn editor (&self) -> Option<&MidiEditor>;
|
||||||
fn editor_mut (&mut self) -> Option<&mut MidiEditor>;
|
fn editor_mut (&mut self) -> Option<&mut MidiEditor>;
|
||||||
fn is_editing (&self) -> bool { true }
|
fn is_editing (&self) -> bool { self.editor().is_some() }
|
||||||
fn editor_w (&self) -> usize { 0 }
|
fn editor_w (&self) -> usize { 0 }
|
||||||
fn editor_h (&self) -> usize { 0 }
|
fn editor_h (&self) -> usize { 0 }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
deps/tengri
vendored
2
deps/tengri
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit c954965ae125136286291e5f0d4532edf98f46ad
|
Subproject commit 4ff4ea81735548f808302c61b619ad7804e1eec0
|
||||||
Loading…
Add table
Add a link
Reference in a new issue