From c08d1bee5d03c7e3c1a95a113897b2a0773b5dce Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 16 Jan 2025 16:49:53 +0100 Subject: [PATCH] autoedit --- midi/src/midi_edit.rs | 72 ++++++------ midi/src/piano_h.rs | 6 +- tek/src/keys.edn | 2 +- tek/src/keys_clip.edn | 2 +- tek/src/lib.rs | 235 +++++++++++++++++++++----------------- tek/src/view_arranger.edn | 4 +- tui/src/tui_content.rs | 6 +- 7 files changed, 177 insertions(+), 150 deletions(-) diff --git a/midi/src/midi_edit.rs b/midi/src/midi_edit.rs index b8ed17ef..6ff67149 100644 --- a/midi/src/midi_edit.rs +++ b/midi/src/midi_edit.rs @@ -94,11 +94,11 @@ impl Default for MidiEditor { } } impl MidiEditor { - pub fn clip_length (&self) -> usize { - self.clip().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1) - } + //fn clip_length (&self) -> usize { + //self.clip().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1) + //} /// Put note at current position - pub fn put_note (&mut self, advance: bool) { + fn put_note (&mut self, advance: bool) { let mut redraw = false; if let Some(clip) = self.clip() { let mut clip = clip.write().unwrap(); @@ -127,6 +127,34 @@ impl MidiEditor { self.mode.redraw(); } } + pub fn clip_status (&self) -> impl Content + '_ { + let (color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { + (clip.color, clip.name.clone(), clip.length, clip.looped) + } else { + (ItemPalette::from(TuiTheme::g(64)), String::new().into(), 0, false) + }; + row!( + FieldV(color, "Edit", format!("{name} ({length})")), + FieldV(color, "Loop", looped.to_string()) + ) + } + pub fn edit_status (&self) -> impl Content + '_ { + let (color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { + (clip.color, clip.length) + } else { + (ItemPalette::from(TuiTheme::g(64)), 0) + }; + let time_pos = self.time_pos(); + let time_zoom = self.time_zoom().get(); + let time_lock = if self.time_lock().get() { "[lock]" } else { " " }; + let note_pos = format!("{:>3}", self.note_pos()); + let note_name = format!("{:4}", Note::pitch_to_name(self.note_pos())); + let note_len = format!("{:>4}", self.note_len()); + Bsp::e( + FieldV(color, "Time", format!("{length}/{time_zoom}+{time_pos} {time_lock}")), + FieldV(color, "Note", format!("{note_name} {note_pos} {note_len}")), + ) + } } impl TimeRange for MidiEditor { fn time_len (&self) -> &AtomicUsize { self.mode.time_len() } @@ -156,39 +184,9 @@ impl MidiViewer for MidiEditor { fn clip_mut (&mut self) -> &mut Option>> { self.mode.clip_mut() } fn set_clip (&mut self, p: Option<&Arc>>) { self.mode.set_clip(p) } } -impl MidiEditor { - pub fn clip_status (&self) -> impl Content + '_ { - let (color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { - (clip.color, clip.name.clone(), clip.length, clip.looped) - } else { - (ItemPalette::from(TuiTheme::g(64)), String::new().into(), 0, false) - }; - row!( - FieldV(color, "Edit", format!("{name} ({length})")), - FieldV(color, "Loop", looped.to_string()) - ) - } - pub fn edit_status (&self) -> impl Content + '_ { - let (color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { - (clip.color, clip.length) - } else { - (ItemPalette::from(TuiTheme::g(64)), 0) - }; - let time_pos = self.time_pos(); - let time_zoom = self.time_zoom().get(); - let time_lock = if self.time_lock().get() { "[lock]" } else { " " }; - let note_pos = format!("{:>3}", self.note_pos()); - let note_name = format!("{:4}", Note::pitch_to_name(self.note_pos())); - let note_len = format!("{:>4}", self.note_len()); - Bsp::e( - FieldV(color, "Time", format!("{length}/{time_zoom}+{time_pos} {time_lock}")), - FieldV(color, "Note", format!("{note_name} {note_pos} {note_len}")), - ) - } -} edn_command!(MidiEditCommand: |state: MidiEditor| { - ("note/put" [a: bool] Self::PutNote) - ("note/del" [a: bool] Self::PutNote) + ("note/put" [_a: bool] Self::PutNote) + ("note/del" [_a: bool] Self::PutNote) ("note/pos" [a: usize] Self::SetNoteCursor(a.expect("no note cursor"))) ("note/len" [a: usize] Self::SetNoteLength(a.expect("no note length"))) ("time/pos" [a: usize] Self::SetTimeCursor(a.expect("no time cursor"))) @@ -210,7 +208,7 @@ edn_command!(MidiEditCommand: |state: MidiEditor| { Show(Option>>), } impl MidiEditCommand { - pub fn from_tui_event (state: &MidiEditor, input: &impl EdnInput) -> Usually> { + fn from_tui_event (state: &MidiEditor, input: &impl EdnInput) -> Usually> { use EdnItem::*; let edns = EdnItem::<&str>::read_all(KEYS_EDIT)?; for item in edns.iter() { diff --git a/midi/src/piano_h.rs b/midi/src/piano_h.rs index bb6438c9..97adcc94 100644 --- a/midi/src/piano_h.rs +++ b/midi/src/piano_h.rs @@ -144,10 +144,10 @@ impl PianoHorizontal { } fn cursor (&self) -> impl Content { let style = Some(Style::default().fg(self.color.lightest.rgb)); - let note_hi = self.note_hi(); - let note_len = self.note_len(); - let note_lo = self.note_lo().get(); + let note_hi = self.note_hi(); + let note_lo = self.note_lo().get(); let note_pos = self.note_pos(); + let note_len = self.note_len(); let time_pos = self.time_pos(); let time_start = self.time_start().get(); let time_zoom = self.time_zoom().get(); diff --git a/tek/src/keys.edn b/tek/src/keys.edn index 308e926d..74494b06 100644 --- a/tek/src/keys.edn +++ b/tek/src/keys.edn @@ -2,7 +2,7 @@ (@shift-u redo 1) (@space clock toggle) (@shift-space clock toggle 0) -(@e editor show :pool-clip) (@ctrl-a scene add) (@ctrl-t track add) (@tab edit) +(@c color) diff --git a/tek/src/keys_clip.edn b/tek/src/keys_clip.edn index 1559c363..cb908c88 100644 --- a/tek/src/keys_clip.edn +++ b/tek/src/keys_clip.edn @@ -3,7 +3,7 @@ (@left select :track-prev :scene) (@right select :track-next :scene) -(@q clip launch) +(@q enqueue :clip) (@c clip color) (@g clip get) (@p clip put) diff --git a/tek/src/lib.rs b/tek/src/lib.rs index ece29809..6d81ac31 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -98,17 +98,22 @@ impl TekCli { Ok(match self.mode { TekMode::Clock => engine.run(&jack.activate_with(|jack|Tek::new_clock( - jack, self.bpm))?)?, + jack, self.bpm, self.sync_lead, self.sync_follow))?)?, TekMode::Sequencer => engine.run(&jack.activate_with(|jack|Tek::new_sequencer( - jack, self.bpm, &midi_froms, &midi_tos))?)?, + jack, self.bpm, self.sync_lead, self.sync_follow, + &midi_froms, &midi_tos))?)?, TekMode::Groovebox => engine.run(&jack.activate_with(|jack|Tek::new_groovebox( - jack, self.bpm, &midi_froms, &midi_tos, &audio_froms, &audio_tos))?)?, + jack, self.bpm, self.sync_lead, self.sync_follow, + &midi_froms, &midi_tos, + &audio_froms, &audio_tos))?)?, TekMode::Arranger { scenes, tracks, track_width, .. } => engine.run(&jack.activate_with(|jack|Tek::new_arranger( - jack, self.bpm, &midi_froms, &midi_tos, &audio_froms, &audio_tos, - scenes, tracks, track_width, + jack, self.bpm, self.sync_lead, self.sync_follow, + &midi_froms, &midi_tos, + &audio_froms, &audio_tos, + scenes, tracks, track_width ))?)?, _ => todo!() }) @@ -198,6 +203,8 @@ impl Tek { fn new_arranger ( jack: &Arc>, bpm: Option, + sync_lead: bool, + sync_follow: bool, midi_froms: &[PortConnection], midi_tos: &[PortConnection], audio_froms: &[&[PortConnection];2], @@ -208,7 +215,10 @@ impl Tek { ) -> Usually { let mut arranger = Self { edn: include_str!("./view_arranger.edn").to_string(), - ..Self::new_groovebox(jack, bpm, midi_froms, midi_tos, audio_froms, audio_tos)? + ..Self::new_groovebox( + jack, bpm, sync_lead, sync_follow, + midi_froms, midi_tos, audio_froms, audio_tos, + )? }; arranger.scenes_add(scenes); arranger.tracks_add(tracks, track_width, &[], &[]); @@ -217,6 +227,8 @@ impl Tek { fn new_groovebox ( jack: &Arc>, bpm: Option, + sync_lead: bool, + sync_follow: bool, midi_froms: &[PortConnection], midi_tos: &[PortConnection], audio_froms: &[&[PortConnection];2], @@ -225,7 +237,7 @@ impl Tek { let app = Self { edn: include_str!("./view_groovebox.edn").to_string(), sampler: Some(Sampler::new(jack, &"sampler", midi_froms, audio_froms, audio_tos)?), - ..Self::new_sequencer(jack, bpm, midi_froms, midi_tos)? + ..Self::new_sequencer(jack, bpm, sync_lead, sync_follow, midi_froms, midi_tos)? }; if let Some(sampler) = app.sampler.as_ref().unwrap().midi_in.as_ref() { jack.connect_ports(&app.player.as_ref().unwrap().midi_outs[0].port, &sampler.port)?; @@ -235,6 +247,8 @@ impl Tek { fn new_sequencer ( jack: &Arc>, bpm: Option, + sync_lead: bool, + sync_follow: bool, midi_froms: &[PortConnection], midi_tos: &[PortConnection], ) -> Usually { @@ -247,32 +261,25 @@ impl Tek { editing: false.into(), midi_buf: vec![vec![];65536], player: Some(MidiPlayer::new(&jack, "sequencer", Some(&clip), &midi_froms, &midi_tos)?), - ..Self::new_clock(jack, bpm)? + ..Self::new_clock(jack, bpm, sync_lead, sync_follow)? }) } fn new_clock ( jack: &Arc>, bpm: Option, + sync_lead: bool, + sync_follow: bool, ) -> Usually { - // TODO: enable sync master/follow - //let sync_clock = |jack: &Arc>, app|{ - //if cli.sync_lead { - //} else if cli.sync_follow { - //jack.read().unwrap().client().register_timebase_callback(false, |state|{ - //app.clock().playhead.update_from_sample(state.position.frame() as f64); - //state.position - //}) - //} else { - //Ok(()) - //} - //}; - Ok(Self { + let tek = Self { edn: include_str!("./view_transport.edn").to_string(), jack: jack.clone(), color: ItemPalette::random(), clock: Clock::new(jack, bpm), ..Default::default() - }) + }; + tek.sync_lead(sync_lead); + tek.sync_follow(sync_follow); + Ok(tek) } fn sync_lead (&self, enable: bool) -> Usually<()> { if enable { @@ -285,8 +292,9 @@ impl Tek { } Ok(()) } - fn sync_follow (&self) { - // TODO + fn sync_follow (&self, enable: bool) -> Usually<()> { + // TODO: sync follow + Ok(()) } fn editor (&self) -> impl Content + '_ { &self.editor } fn view_clock (&self) -> impl Content + use<'_> { @@ -297,6 +305,7 @@ impl Tek { )) } fn view_beat_stats (&self) -> impl Content + use<'_> { + let compact = self.size.w() > 80; let clock = self.clock(); let now = clock.started.read().unwrap().as_ref().map(|start|clock.global.usec.get() - start.usec.get()); let beat = ||now.map(|now|clock.timebase.format_beats_1(clock.timebase.usecs_to_pulse(now))) @@ -304,29 +313,29 @@ impl Tek { let time = ||now.map(|now|format!("{:.3}s", now/1000000.)) .unwrap_or("-.---s".into()); let bpm = ||format!("{:.3}", clock.timebase.bpm.get()); - Either::new(self.is_editing(), + Either::new(compact, + row!(Field(TuiTheme::g(128).into(), "BPM", bpm()), + Field(TuiTheme::g(128).into(), "Beat", beat()), + Field(TuiTheme::g(128).into(), "Time", time())), row!(FieldV(TuiTheme::g(128).into(), "BPM", bpm()), FieldV(TuiTheme::g(128).into(), "Beat", beat()), - FieldV(TuiTheme::g(128).into(), "Time", time()),), - col!(Bsp::e(Tui::fg(TuiTheme::g(255), bpm()), " BPM"), - Bsp::e("Beat ", Tui::fg(TuiTheme::g(255), beat())), - Bsp::e("Time ", Tui::fg(TuiTheme::g(255), time())))) + FieldV(TuiTheme::g(128).into(), "Time", time()))) } fn view_engine_stats (&self) -> impl Content + use<'_> { - let clock = self.clock(); - let compact = self.is_editing(); - let rate = clock.timebase.sr.get(); - let chunk = clock.chunk.load(Relaxed); - let sr = move||format!("{}", if compact {format!("{:.1}kHz", rate / 1000.)} else {format!("{:.0}Hz", rate)}); - let buffer_size = move||format!("{chunk}"); - let latency = move||format!("{:.1}ms", chunk as f64 / rate * 1000.); + let compact = self.size.w() > 80; + let clock = self.clock(); + let rate = clock.timebase.sr.get(); + let chunk = clock.chunk.load(Relaxed); + let sr = move||format!("{}", if compact {format!("{:.1}kHz", rate / 1000.)} else {format!("{:.0}Hz", rate)}); + let buf = move||format!("{chunk}"); + let latency = move||format!("{:.1}ms", chunk as f64 / rate * 1000.); Either::new(compact, + row!(Field(TuiTheme::g(128).into(), "SR", sr()), + Field(TuiTheme::g(128).into(), "Buf", buf()), + Field(TuiTheme::g(128).into(), "Lat", latency())), row!(FieldV(TuiTheme::g(128).into(), "SR", sr()), - FieldV(TuiTheme::g(128).into(), "Buf", buffer_size()), - FieldV(TuiTheme::g(128).into(), "Lat", latency())), - col!(Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", sr())), " sample rate"), - Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", buffer_size())), " sample buffer"), - Bsp::e(Tui::fg(TuiTheme::g(255), format!("{:.3}ms", latency())), " latency"))) + FieldV(TuiTheme::g(128).into(), "Buf", buf()), + FieldV(TuiTheme::g(128).into(), "Lat", latency()))) } fn view_meter <'a> (&'a self, label: &'a str, value: f32) -> impl Content + 'a { col!( @@ -356,9 +365,10 @@ impl Tek { } fn view_play_pause (&self) -> impl Content + use<'_> { 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)}, - Either::new(self.is_editing(), + 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 ")))), @@ -404,12 +414,6 @@ impl Tek { clip.write().unwrap().toggle_loop() } } - fn track_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { - (||Tui::bg(TuiTheme::g(32), Bsp::s( - Fill::x(Align::w(button(" C-a ".to_string(), format!(" add scene ({})", self.scenes().len())))), - Fill::x(Align::w(button(" C-t ".to_string(), format!(" add track ({})", self.tracks().len())))), - )).boxed()).into() - } fn track_add ( &mut self, name: Option<&str>, @@ -435,8 +439,8 @@ impl Tek { } fn tracks_add ( &mut self, - count: usize, - width: usize, + count: usize, + width: usize, midi_from: &[PortConnection], midi_to: &[PortConnection], ) -> Usually<()> { @@ -508,7 +512,9 @@ impl Tek { let neighbor = selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s); map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new( active, - Thunk::new(||self.editor()), + Thunk::new(||Bsp::a( + Fill::xy(Align::nw(button(" Tab ".into(), "".into()))), + self.editor())), Thunk::new(move||Bsp::a( When::new(selected, Fill::y(Align::n(button(" Tab ".into(), "edit".into())))), phat_sel_3( @@ -549,6 +555,37 @@ impl Tek { } Ok(()) } + fn button (&self, key: String, label: String) -> impl Content { + let compact = !self.is_editing(); + Tui::bold(true, Bsp::e( + Margin::x(1, Tui::fg_bg(TuiTheme::g(0), TuiTheme::orange(), key)), + When::new(compact, Margin::x(1, Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(96), label))), + )) + } + fn input_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { + let fg = TuiTheme::g(224); + let bg = TuiTheme::g(64); + (move||Bsp::s(Fill::x(Align::w(self.button(" I ".to_string(), format!(" midi ins ({})", self.midi_ins().len())))), self.midi_ins().get(0).map(|inp|Bsp::s( + Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(inp.name.clone())))), + inp.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false, + Tui::fg_bg(fg, bg, connect.info()))))), + ))).boxed()).into() + } + fn output_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { + let fg = TuiTheme::g(224); + let bg = TuiTheme::g(64); + (move||Bsp::s(Fill::x(Align::w(self.button(" O ".to_string(), format!(" midi outs ({}) ", self.midi_outs().len())))), self.midi_outs().get(0).map(|out|Bsp::s( + Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(out.name.clone())))), + out.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false, + Tui::fg_bg(fg, bg, connect.info()))))), + ))).boxed()).into() + } + fn track_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { + (||Tui::bg(TuiTheme::g(32), Bsp::s( + Fill::x(Align::w(self.button(" C-a ".to_string(), format!(" add scene ({})", self.scenes().len())))), + Fill::x(Align::w(self.button(" C-t ".to_string(), format!(" add track ({})", self.tracks().len())))), + )).boxed()).into() + } } const KEYS_APP: &str = include_str!("keys.edn"); const KEYS_CLIP: &str = include_str!("keys_clip.edn"); @@ -600,17 +637,13 @@ handle!(TuiIn: |self: Tek, input|Ok({ Zoom(Option), } edn_command!(TekCommand: |app: Tek| { - ("edit" [] Self::Edit(None)) - ("edit" [c: bool] Self::Edit(c)) - - ("color" [c: Color] Self::Color(c.map(ItemPalette::from).unwrap_or_default())) - + ("stop-all" [] 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)) - - ("stop-all" [] Self::StopAll) + ("edit" [] Self::Edit(None)) + ("edit" [c: bool] Self::Edit(c)) + ("color" [c: Color] Self::Color(c.map(ItemPalette::from).unwrap_or_default())) ("enqueue" [c: Arc>] Self::Enqueue(c)) ("select" [t: usize, s: usize] match (t.expect("no track"), s.expect("no scene")) { (0, 0) => Self::Select(Selection::Mix), @@ -618,7 +651,6 @@ edn_command!(TekCommand: |app: Tek| { (0, s) => Self::Select(Selection::Scene(s)), (t, s) => Self::Select(Selection::Clip(t, s)), }) - ("clip" [a, ..b] Self::Clip(ClipCommand::from_edn(app, &a.to_ref(), b) .expect("invalid command"))) ("clock" [a, ..b] Self::Clock(ClockCommand::from_edn(app.clock(), &a.to_ref(), b) @@ -635,18 +667,42 @@ edn_command!(TekCommand: |app: Tek| { .expect("invalid command"))) }); command!(|self: TekCommand, app: Tek|match self { - Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None }, + Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None }, Self::History(delta) => { println!("\n\rtodo: undo/redo"); None }, - Self::Select(s) => { app.selected = s; None }, - Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?, - Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?, - Self::Track(cmd) => cmd.delegate(app, Self::Track)?, - Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?, - Self::Editor(cmd) => app.editor.as_mut() + Self::Select(s) => { + app.selected = s; + // autoedit: load focused clip in editor. + if let Some(ref mut editor) = app.editor { + editor.set_clip(match app.selected { + Selection::Clip(t, s) if let Some(Some(Some(clip))) = app + .scenes + .get(s) + .map(|s|s.clips.get(t)) => Some(clip), + _ => None + }); + } + None + }, + Self::Edit(value) => { + // TODO: autocreate: create new clip when entering empty cell + if let Some(value) = value { + if app.is_editing() != value { + app.editing.store(value, Relaxed); + } + } else { + app.editing.store(!app.is_editing(), Relaxed); + }; + None + }, + Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?, + Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?, + Self::Track(cmd) => cmd.delegate(app, Self::Track)?, + Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?, + Self::Editor(cmd) => app.editor.as_mut() .map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(), - Self::Sampler(cmd) => app.sampler.as_mut() + Self::Sampler(cmd) => app.sampler.as_mut() .map(|sampler|cmd.delegate(sampler, Self::Sampler)).transpose()?.flatten(), - Self::Enqueue(clip) => app.player.as_mut() + Self::Enqueue(clip) => app.player.as_mut() .map(|player|{player.enqueue_next(clip.as_ref());None}).flatten(), Self::Color(palette) => { let old = app.color; @@ -672,17 +728,6 @@ command!(|self: TekCommand, app: Tek|match self { } else { None }, - Self::Edit(value) => if let Some(value) = value { - if app.is_editing() != value { - app.editing.store(value, Relaxed); - Some(Self::Edit(Some(!value))) - } else { - None - } - } else { - app.editing.store(!app.is_editing(), Relaxed); - Some(Self::Edit(Some(!app.is_editing()))) - } }); /// Represents the current user selection in the arranger #[derive(PartialEq, Clone, Copy, Debug, Default)] pub enum Selection { @@ -736,19 +781,19 @@ trait HasSelection { } #[derive(Debug, Default)] struct Track { /// Name of track - name: Arc, + name: Arc, /// Preferred width of track column - width: usize, + width: usize, /// Identifying color of track - color: ItemPalette, + color: ItemPalette, /// MIDI player state - player: MidiPlayer, + player: MidiPlayer, + /// Device chain + devices: Vec>, /// Inputs of 1st device audio_ins: Vec>, /// Outputs of last device audio_outs: Vec>, - /// Device chain - devices: Vec>, } has_clock!(|self: Track|self.player.clock); has_player!(|self: Track|self.player); @@ -840,15 +885,6 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync { )) })).boxed()).into() } - fn input_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { - let fg = TuiTheme::g(224); - let bg = TuiTheme::g(64); - (move||Bsp::s(Fill::x(Align::w(button(" I ".to_string(), format!(" midi ins ({})", self.midi_ins().len())))), self.midi_ins().get(0).map(|inp|Bsp::s( - Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(inp.name.clone())))), - inp.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false, - Tui::fg_bg(fg, bg, connect.info()))))), - ))).boxed()).into() - } fn input_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> { (move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| { let w = (x2 - x1) as u16; @@ -868,15 +904,6 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync { Tui::fg_bg(if mon { Color::White } else { bg }, bg, "▌"), ) } - fn output_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> { - let fg = TuiTheme::g(224); - let bg = TuiTheme::g(64); - (move||Bsp::s(Fill::x(Align::w(button(" O ".to_string(), format!(" midi outs ({}) ", self.midi_outs().len())))), self.midi_outs().get(0).map(|out|Bsp::s( - Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(out.name.clone())))), - out.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false, - Tui::fg_bg(fg, bg, connect.info()))))), - ))).boxed()).into() - } fn output_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> { (move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| { let w = (x2 - x1) as u16; diff --git a/tek/src/view_arranger.edn b/tek/src/view_arranger.edn index c30a2520..d1270286 100644 --- a/tek/src/view_arranger.edn +++ b/tek/src/view_arranger.edn @@ -1,3 +1,5 @@ (bsp/s (fixed/y 2 :toolbar) (fill/x (align/c (bsp/w (fixed/x :pool-w :pool) - (bsp/n (fixed/y 3 :outputs) (bsp/n (fixed/y 3 :inputs) (bsp/n (fixed/y 3 :tracks) :scenes))))))) + (bsp/n (fixed/y 3 :outputs) + (bsp/n (fixed/y 3 :inputs) + (bsp/n (fixed/y 3 :tracks) :scenes))))))) diff --git a/tui/src/tui_content.rs b/tui/src/tui_content.rs index 1a8838db..cb09556e 100644 --- a/tui/src/tui_content.rs +++ b/tui/src/tui_content.rs @@ -38,7 +38,7 @@ impl Content for Repeat<'_> { fn render (&self, to: &mut TuiOut) { let [x, y, w, h] = to.area().xywh(); let a = self.0.len(); - for (v, y) in (y..y+h).enumerate() { + for (_v, y) in (y..y+h).enumerate() { for (u, x) in (x..x+w).enumerate() { if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { let u = u % a; @@ -56,7 +56,7 @@ impl Content for RepeatV<'_> { to } fn render (&self, to: &mut TuiOut) { - let [x, y, w, h] = to.area().xywh(); + let [x, y, _w, h] = to.area().xywh(); for y in y..y+h { if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { cell.set_symbol(&self.0); @@ -72,7 +72,7 @@ impl Content for RepeatH<'_> { to } fn render (&self, to: &mut TuiOut) { - let [x, y, w, h] = to.area().xywh(); + let [x, y, w, _h] = to.area().xywh(); for x in x..x+w { if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { cell.set_symbol(&self.0);