provide components to App

This commit is contained in:
🪞👃🪞 2025-01-11 20:48:29 +01:00
parent cff87657b9
commit ed462cd0f6
5 changed files with 172 additions and 82 deletions

View file

@ -76,8 +76,8 @@ pub fn main () -> Usually<()> {
let left_tos = PortConnection::collect(&cli.left_to, empty, empty);
let right_froms = PortConnection::collect(&cli.right_from, empty, empty);
let right_tos = PortConnection::collect(&cli.right_to, empty, empty);
let audio_froms = &[&left_froms, &right_froms];
let audio_tos = &[&left_tos, &right_tos ];
let audio_froms = &[left_froms.as_slice(), right_froms.as_slice()];
let audio_tos = &[left_tos.as_slice(), right_tos.as_slice() ];
let perf = PerfModel::default();
let size = Measure::new();
let default_clip = ||Arc::new(RwLock::new(MidiClip::new(
@ -93,10 +93,7 @@ pub fn main () -> Usually<()> {
}
clock
};
let default_clock = |jack: &Arc<RwLock<JackConnection>>|{
let clock = Clock::from(jack);
default_bpm(clock)
};
let default_clock = |jack: &Arc<RwLock<JackConnection>>|default_bpm(Clock::from(jack));
// TODO: enable sync master/follow
//let sync_clock = |jack: &Arc<RwLock<JackConnection>>, app|{
//if cli.sync_lead {
@ -148,7 +145,7 @@ pub fn main () -> Usually<()> {
App::groovebox(
jack, (&clip).into(), (&clip).into(),
Some(player), &midi_froms, &midi_tos,
sampler, &audio_froms, &audio_tos,
sampler, audio_froms, audio_tos,
)
}))?)?,
TekMode::Arranger { scenes, tracks, track_width, .. } => engine.run(&jack.activate_with(|jack|Ok({
@ -156,7 +153,7 @@ pub fn main () -> Usually<()> {
jack,
PoolModel::default(),
MidiEditor::default(), &midi_froms, &midi_tos,
default_sampler(jack)?, &audio_froms, &audio_tos,
default_sampler(jack)?, audio_froms, audio_tos,
scenes, tracks, track_width
)
}))?)?,

View file

@ -1,17 +1,6 @@
use crate::*;
#[derive(Default)]
pub struct App {
//jack: Arc<RwLock<JackConnection>>,
//view: EdnView<TuiOut, &'a Self>,
//pool: Option<PoolModel>,
//editor: Option<MidiEditor>,
//player: Option<MidiPlayer>,
//compact: AtomicBool,
//size: Measure<TuiOut>,
//perf: PerfModel,
//note_buf: Vec<u8>,
//midi_buf: Vec<Vec<Vec<u8>>>
pub jack: Arc<RwLock<JackConnection>>,
pub edn: String,
pub clock: Clock,
@ -34,7 +23,6 @@ pub struct App {
pub size: Measure<TuiOut>,
pub perf: PerfModel,
}
impl EdnViewData<TuiOut> for &App {}
impl App {
pub fn sequencer (
jack: &Arc<RwLock<JackConnection>>,
@ -100,58 +88,120 @@ impl App {
}
}
render!(TuiOut: (self: App) => self.size.of(EdnView::from_source(self, self.edn.as_ref())));
/// Root view for standalone `tek_sequencer`.
pub struct Sequencer {
pub _jack: Arc<RwLock<JackConnection>>,
pub pool: PoolModel,
pub editor: MidiEditor,
pub player: MidiPlayer,
pub transport: bool,
pub selectors: bool,
pub compact: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub perf: PerfModel,
audio!(|self: App, _client, _scope|Control::Continue);
handle!(TuiIn: |self: App, input| Ok(None));
impl EdnViewData<TuiOut> for &App {
fn get_content <'a> (&'a self, item: EdnItem<&'a str>) -> RenderBox<'a, TuiOut> {
use EdnItem::*;
let w = self.tracks_with_sizes().last().map(|x|x.3 as u16).unwrap_or(0);
match item {
Nil => Box::new(()),
Exp(items) => Box::new(EdnView::from_items(*self, items.as_slice())),
Sym(":editor") => (&self.editor).boxed(),
Sym(":inputs") => self.input_row(w).boxed(),
Sym(":outputs") => self.output_row(w).boxed(),
Sym(":pool") => self.pool().boxed(),
Sym(":sample") => self.sample().boxed(),
Sym(":sampler") => self.sampler().boxed(),
Sym(":scenes") => self.scene_row(w).boxed(),
Sym(":status") => self.status(0).boxed(),
Sym(":toolbar") => self.toolbar().boxed(),
Sym(":tracks") => self.track_row(w).boxed(),
_ => panic!("no content for {item:?}")
}
}
fn get_unit (&self, item: EdnItem<&str>) -> u16 {
use EdnItem::*;
match item.to_str() {
":sample-h" => if self.compact() { 0 } else { 5 },
":samples-w" => if self.compact() { 4 } else { 11 },
":samples-y" => if self.compact() { 1 } else { 0 },
":pool-w" => if self.compact() { 5 } else {
let w = self.size.w();
if w > 60 { 20 } else if w > 40 { 15 } else { 10 }
},
_ => 0
}
}
}
impl App {
fn compact (&self) -> bool { false }
fn toolbar (&self) -> impl Content<TuiOut> + use<'_> {
Fill::x(Fixed::y(2, Align::x(TransportView::new(true, &self.clock))))
}
fn status (&self, note_pt: usize) -> impl Content<TuiOut> + use<'_> {
self.editor.as_ref()
.map(|e|Bsp::e(e.clip_status(), e.edit_status()))
}
fn pool (&self) -> impl Content<TuiOut> + use<'_> {
self.pool.as_ref()
.map(|pool|Align::e(Fixed::x(self.sidebar_w(), PoolView(self.compact(), pool))))
}
fn editor (&self) -> impl Content<TuiOut> + '_ {
&self.editor
}
fn sample <'a> (&'a self) -> impl Content<TuiOut> + 'a {
let compact = self.is_editing();
if let (Some(editor), Some(sampler)) = (&self.editor, &self.sampler) {
let note_pt = editor.note_point();
let sample_h = if compact { 0 } else { 5 };
return Some(Max::y(sample_h, Fill::xy(Bsp::a(
Fill::x(Align::w(Fixed::y(1, self.status(note_pt)))),
sampler.viewer(note_pt)
))))
}
None
}
fn sampler (&self) -> impl Content<TuiOut> + use<'_> {
let compact = self.is_editing();
if let (Some(editor), Some(sampler)) = (&self.editor, &self.sampler) {
let note_pt = editor.note_point();
let w = if compact { 4 } else { 40 };
let y = if compact { 1 } else { 0 };
return Some(Fixed::x(w, Push::y(y, Fill::y(sampler.list(compact, editor)))))
}
None
}
fn track_row (&self, w: u16) -> impl Content<TuiOut> + '_ { "" }
fn input_row (&self, w: u16) -> impl Content<TuiOut> + '_ { "" }
fn scene_row (&self, w: u16) -> impl Content<TuiOut> + '_ { "" }
fn output_row (&self, w: u16) -> impl Content<TuiOut> + '_ { "" }
pub struct Groovebox {
pub _jack: Arc<RwLock<JackConnection>>,
pub player: MidiPlayer,
pub pool: PoolModel,
pub editor: MidiEditor,
pub sampler: Sampler,
pub compact: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub perf: PerfModel,
pub fn tracks_with_sizes (&self)
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
{
tracks_with_sizes(self.tracks.iter(), match self.selected {
ArrangerSelection::Track(t) if self.is_editing() => Some(t),
ArrangerSelection::Clip(t, _) if self.is_editing() => Some(t),
_ => None
}, self.editor_w())
}
fn is_editing (&self) -> bool {
self.editing.load(Relaxed)
}
fn editor_w (&self) -> usize {
let editor = self.editor.as_ref().expect("missing editor");
(5 + (editor.time_len().get() / editor.time_zoom().get()))
.min(self.size.w().saturating_sub(20))
.max(16)
}
fn sidebar_w (&self) -> u16 {
let w = self.size.w();
let w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
let w = if self.is_editing() { 8 } else { w };
w
}
}
/// Root view for standalone `tek_arranger`
pub struct Arranger {
pub jack: Arc<RwLock<JackConnection>>,
pub midi_ins: Vec<JackPort<MidiIn>>,
pub midi_outs: Vec<JackPort<MidiOut>>,
pub clock: Clock,
pub pool: PoolModel,
pub tracks: Vec<ArrangerTrack>,
pub scenes: Vec<ArrangerScene>,
pub splits: [u16;2],
pub selected: ArrangerSelection,
pub color: ItemPalette,
pub size: Measure<TuiOut>,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub editor: MidiEditor,
pub editing: AtomicBool,
pub perf: PerfModel,
pub compact: bool,
pub fn tracks_with_sizes <'a> (
tracks: impl Iterator<Item=&'a ArrangerTrack>,
active: Option<usize>,
bigger: usize
) -> impl Iterator<Item=(usize,&'a ArrangerTrack,usize,usize)> {
let mut x = 0;
tracks.enumerate().map(move |(index, track)|{
let width = if Some(index) == active { bigger } else { track.width.max(8) };
let data = (index, track, x, x + width);
x += width;
data
})
}

View file

@ -5,11 +5,30 @@ mod arranger_track; pub use self::arranger_track::*;
mod arranger_h;
use ClockCommand::{Play, Pause};
use self::ArrangerCommand as Cmd;
/// Root view for standalone `tek_arranger`
pub struct Arranger {
pub jack: Arc<RwLock<JackConnection>>,
pub midi_ins: Vec<JackPort<MidiIn>>,
pub midi_outs: Vec<JackPort<MidiOut>>,
pub clock: Clock,
pub pool: PoolModel,
pub tracks: Vec<ArrangerTrack>,
pub scenes: Vec<ArrangerScene>,
pub splits: [u16;2],
pub selected: ArrangerSelection,
pub color: ItemPalette,
pub size: Measure<TuiOut>,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub editor: MidiEditor,
pub editing: AtomicBool,
pub perf: PerfModel,
pub compact: bool,
}
render!(TuiOut: (self: Arranger) => self.size.of(EdnView::from_source(self, Self::EDN)));
impl EdnViewData<TuiOut> for &Arranger {
fn get_content <'a> (&'a self, item: EdnItem<&'a str>) -> RenderBox<'a, TuiOut> {
use EdnItem::*;
let scenes_w = self.sidebar_w();
let tracks_w = self.tracks_with_sizes().last().unwrap().3 as u16;
match item {
Nil => Box::new(()),
@ -77,19 +96,11 @@ impl Arranger {
pub fn tracks_with_sizes (&self)
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
{
let active = match self.selected {
tracks_with_sizes(self.tracks.iter(), match self.selected {
ArrangerSelection::Track(t) if self.is_editing() => Some(t),
ArrangerSelection::Clip(t, _) if self.is_editing() => Some(t),
_ => None
};
let big = self.editor_w();
let mut x = 0;
self.tracks.iter().enumerate().map(move |(index, track)|{
let width = if Some(index) == active { big } else { track.width.max(8) };
let data = (index, track, x, x + width);
x += width;
data
})
}, self.editor_w())
}
fn play_row (&self, tracks_w: u16) -> impl Content<TuiOut> + '_ {

View file

@ -7,6 +7,20 @@ use MidiEditCommand::*;
use MidiPoolCommand::*;
use KeyCode::{Char, Delete, Tab, Up, Down, Left, Right};
use std::marker::ConstParamTy;
pub struct Groovebox {
pub _jack: Arc<RwLock<JackConnection>>,
pub player: MidiPlayer,
pub pool: PoolModel,
pub editor: MidiEditor,
pub sampler: Sampler,
pub compact: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub perf: PerfModel,
}
render!(TuiOut: (self: Groovebox) => self.size.of(EdnView::from_source(self, Self::EDN)));
impl EdnViewData<TuiOut> for &Groovebox {
fn get_content <'a> (&'a self, item: EdnItem<&'a str>) -> RenderBox<'a, TuiOut> {

View file

@ -5,6 +5,24 @@ use SequencerCommand as Cmd;
use MidiEditCommand::*;
use MidiPoolCommand::*;
render!(TuiOut: (self: Sequencer) => self.size.of(EdnView::from_source(self, Self::EDN)));
/// Root view for standalone `tek_sequencer`.
pub struct Sequencer {
pub _jack: Arc<RwLock<JackConnection>>,
pub pool: PoolModel,
pub editor: MidiEditor,
pub player: MidiPlayer,
pub transport: bool,
pub selectors: bool,
pub compact: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub note_buf: Vec<u8>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub perf: PerfModel,
}
impl EdnViewData<TuiOut> for &Sequencer {
fn get_content <'a> (&'a self, item: EdnItem<&'a str>) -> RenderBox<'a, TuiOut> {
use EdnItem::*;