From bc9be689a8c2f3584f300a9a26184ee7edcee681 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 3 Nov 2024 07:51:11 +0200 Subject: [PATCH] create input/output per track --- crates/tek_core/src/color.rs | 15 ++-- crates/tek_sequencer/src/arranger.rs | 105 ++++++++++++---------- crates/tek_sequencer/src/arranger_cmd.rs | 20 ++--- crates/tek_sequencer/src/arranger_tui.rs | 13 ++- crates/tek_sequencer/src/sequencer.rs | 18 ++-- crates/tek_sequencer/src/sequencer_cli.rs | 2 +- crates/tek_sequencer/src/sequencer_cmd.rs | 4 +- 7 files changed, 93 insertions(+), 84 deletions(-) diff --git a/crates/tek_core/src/color.rs b/crates/tek_core/src/color.rs index f4d76061..26f9da6d 100644 --- a/crates/tek_core/src/color.rs +++ b/crates/tek_core/src/color.rs @@ -32,8 +32,8 @@ impl ItemColor { } pub fn random_dark () -> Self { let mut rng = thread_rng(); - let lo = Okhsl::new(-180.0, 0.01, 0.05); - let hi = Okhsl::new( 180.0, 0.5, 0.2); + let lo = Okhsl::new(-180.0, 0.025, 0.075); + let hi = Okhsl::new( 180.0, 0.5, 0.150); UniformOkhsl::new(lo, hi).sample(&mut rng).into() } pub fn random_near (color: Self, distance: f32) -> Self { @@ -47,9 +47,10 @@ impl ItemColor { impl From for ItemColorTriplet { fn from (base: ItemColor) -> Self { let mut light = base.okhsl.clone(); - light.lightness = (light.lightness * 1.15).min(Okhsl::::max_saturation()); + light.lightness = (light.lightness * 1.15).min(Okhsl::::max_lightness()); let mut dark = base.okhsl.clone(); - dark.lightness = (dark.lightness * 0.85).max(Okhsl::::min_saturation()); + dark.lightness = (dark.lightness * 0.85).max(Okhsl::::min_lightness()); + dark.saturation = (dark.saturation * 0.85).max(Okhsl::::min_saturation()); Self { base, light: light.into(), dark: dark.into() } } } @@ -67,11 +68,7 @@ pub fn okhsl_to_rgb (color: Okhsl) -> Color { } pub fn rgb_to_okhsl (color: Color) -> Okhsl { if let Color::Rgb(r, g, b) = color { - Okhsl::from_color(Srgb::new( - r as f32 / 255.0, - g as f32 / 255.0, - b as f32 / 255.0, - )) + Okhsl::from_color(Srgb::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0)) } else { unreachable!("only Color::Rgb is supported") } diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index 2ab22242..c522dabe 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -153,12 +153,21 @@ impl Arranger { } Ok(Some(true)) } + pub fn next_color (&self) -> ItemColor { + if let ArrangementFocus::Clip(track, scene) = self.arrangement.selected { + let track_color = self.arrangement.tracks[track].color; + let scene_color = self.arrangement.scenes[scene].color; + track_color.mix(scene_color, 0.5).mix(ItemColor::random(), 0.25) + } else { + panic!("could not compute next color") + } + } /// Focus the editor with the current phrase pub fn show_phrase (&mut self) { self.editor.show(self.arrangement.phrase().as_ref()); } /// Focus the editor with the current phrase pub fn edit_phrase (&mut self) { - if self.arrangement.phrase().is_none() { - self.phrases.write().unwrap().append_new(None, None); + if self.arrangement.selected.is_clip() && self.arrangement.phrase().is_none() { + self.phrases.write().unwrap().append_new(None, Some(self.next_color().into())); self.arrangement.phrase_put(); } self.show_phrase(); @@ -415,7 +424,7 @@ impl Arrangement { |name| ArrangementTrack::new( &self.jack, &self.clock, name, color ), - )); + )?); let index = self.tracks.len() - 1; Ok(&mut self.tracks[index]) } @@ -456,7 +465,9 @@ impl Arrangement { pub fn scene_prev (&mut self) { self.selected.scene_prev() } - pub fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<&mut Scene> { + pub fn scene_add ( + &mut self, name: Option<&str>, color: Option + ) -> Usually<&mut Scene> { let clips = vec![None;self.tracks.len()]; let name = name.map(|x|x.to_string()).unwrap_or_else(||self.scene_default_name()); self.scenes.push(Scene::new(name, clips, color)); @@ -488,11 +499,9 @@ impl Arrangement { let scene_index = self.selected.scene(); track_index .and_then(|index|self.tracks.get_mut(index).map(|track|(index, track))) - .map(|(track_index, _)|{ - scene_index - .and_then(|index|self.scenes.get_mut(index)) - .map(|scene|scene.clips[track_index] = None); - }); + .map(|(track_index, _)|scene_index + .and_then(|index|self.scenes.get_mut(index)) + .map(|scene|scene.clips[track_index] = None)); } pub fn phrase_put (&mut self) { if let ArrangementFocus::Clip(track, scene) = self.selected { @@ -542,13 +551,13 @@ impl ArrangementTrack { clock: &Arc, name: &str, color: Option - ) -> Self { - Self { + ) -> Usually { + Ok(Self { name: Arc::new(RwLock::new(name.into())), width: name.len() + 2, color: color.unwrap_or_else(ItemColor::random), - player: PhrasePlayer::new(&jack, clock), - } + player: PhrasePlayer::new(&jack, clock, name)?, + }) } pub fn longest_name (tracks: &[Self]) -> usize { tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max) @@ -583,35 +592,35 @@ impl ArrangementFocus { } }) } - pub fn is_mix (&self) -> bool { match self { Self::Mix => true, _ => false } } - pub fn is_track (&self) -> bool { match self { Self::Track(_) => true, _ => false } } - pub fn is_scene (&self) -> bool { match self { Self::Scene(_) => true, _ => false } } + pub fn is_mix (&self) -> bool { match self { Self::Mix => true, _ => false } } + pub fn is_track (&self) -> bool { match self { Self::Track(_) => true, _ => false } } + pub fn is_scene (&self) -> bool { match self { Self::Scene(_) => true, _ => false } } pub fn is_clip (&self) -> bool { match self { Self::Clip(_, _) => true, _ => false } } pub fn track (&self) -> Option { match self { Self::Clip(t, _) => Some(*t), Self::Track(t) => Some(*t), _ => None } } pub fn track_next (&mut self, last_track: usize) { *self = match self { - Self::Mix => Self::Track(0), - Self::Track(t) => Self::Track(last_track.min(*t + 1)), - Self::Scene(s) => Self::Clip(0, *s), - Self::Clip(t, s) => Self::Clip(last_track.min(*t + 1), *s), + Self::Mix => + Self::Track(0), + Self::Track(t) => + Self::Track(last_track.min(*t + 1)), + Self::Scene(s) => + Self::Clip(0, *s), + Self::Clip(t, s) => + Self::Clip(last_track.min(*t + 1), *s), } } pub fn track_prev (&mut self) { *self = match self { - Self::Mix => Self::Mix, - Self::Scene(s) => Self::Scene(*s), - Self::Track(t) => if *t == 0 { - Self::Mix - } else { - Self::Track(*t - 1) - }, - Self::Clip(t, s) => if *t == 0 { - Self::Scene(*s) - } else { - Self::Clip(t.saturating_sub(1), *s) - } + Self::Mix => + Self::Mix, + Self::Scene(s) => + Self::Scene(*s), + Self::Track(t) => + if *t == 0 { Self::Mix } else { Self::Track(*t - 1) }, + Self::Clip(t, s) => + if *t == 0 { Self::Scene(*s) } else { Self::Clip(t.saturating_sub(1), *s) } } } pub fn scene (&self) -> Option { @@ -619,26 +628,26 @@ impl ArrangementFocus { } pub fn scene_next (&mut self, last_scene: usize) { *self = match self { - Self::Mix => Self::Scene(0), - Self::Track(t) => Self::Clip(*t, 0), - Self::Scene(s) => Self::Scene(last_scene.min(*s + 1)), - Self::Clip(t, s) => Self::Clip(*t, last_scene.min(*s + 1)), + Self::Mix => + Self::Scene(0), + Self::Track(t) => + Self::Clip(*t, 0), + Self::Scene(s) => + Self::Scene(last_scene.min(*s + 1)), + Self::Clip(t, s) => + Self::Clip(*t, last_scene.min(*s + 1)), } } pub fn scene_prev (&mut self) { *self = match self { - Self::Mix => Self::Mix, - Self::Track(t) => Self::Track(*t), - Self::Scene(s) => if *s == 0 { - Self::Mix - } else { - Self::Scene(*s - 1) - }, - Self::Clip(t, s) => if *s == 0 { - Self::Track(*t) - } else { - Self::Clip(*t, s.saturating_sub(1)) - } + Self::Mix => + Self::Mix, + Self::Track(t) => + Self::Track(*t), + Self::Scene(s) => + if *s == 0 { Self::Mix } else { Self::Scene(*s - 1) }, + Self::Clip(t, s) => + if *s == 0 { Self::Track(*t) } else { Self::Clip(*t, s.saturating_sub(1)) } } } } diff --git a/crates/tek_sequencer/src/arranger_cmd.rs b/crates/tek_sequencer/src/arranger_cmd.rs index dd187f04..7ff8b09a 100644 --- a/crates/tek_sequencer/src/arranger_cmd.rs +++ b/crates/tek_sequencer/src/arranger_cmd.rs @@ -4,16 +4,16 @@ impl Handle for Arranger { fn handle (&mut self, from: &TuiInput) -> Perhaps { if !self.handle_focused(from)?.unwrap_or(false) { match from.event() { - key!(KeyCode::Tab) => { self.focus_next(); }, - key!(Shift-KeyCode::Tab) => { self.focus_prev(); }, - key!(KeyCode::BackTab) => { self.focus_prev(); }, - key!(Shift-KeyCode::BackTab) => { self.focus_prev(); }, - key!(KeyCode::Up) => { self.focus_up(); }, - key!(KeyCode::Down) => { self.focus_down(); }, - key!(KeyCode::Left) => { self.focus_left(); }, - key!(KeyCode::Right) => { self.focus_right(); }, - key!(KeyCode::Char('e')) => { self.edit_phrase(); }, - key!(KeyCode::Char(' ')) => { self.toggle_play()?; }, + key!(KeyCode::Tab) => { self.focus_next(); }, + key!(Shift-KeyCode::Tab) => { self.focus_prev(); }, + key!(KeyCode::BackTab) => { self.focus_prev(); }, + key!(Shift-KeyCode::BackTab) => { self.focus_prev(); }, + key!(KeyCode::Up) => { self.focus_up(); }, + key!(KeyCode::Down) => { self.focus_down(); }, + key!(KeyCode::Left) => { self.focus_left(); }, + key!(KeyCode::Right) => { self.focus_right(); }, + key!(KeyCode::Char('e')) => { self.edit_phrase(); }, + key!(KeyCode::Char(' ')) => { self.toggle_play()?; }, key!(KeyCode::Char('n')) => { self.rename_selected(); }, _ => return Ok(None) } diff --git a/crates/tek_sequencer/src/arranger_tui.rs b/crates/tek_sequencer/src/arranger_tui.rs index 2a39cc4c..7560bd03 100644 --- a/crates/tek_sequencer/src/arranger_tui.rs +++ b/crates/tek_sequencer/src/arranger_tui.rs @@ -139,7 +139,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> { //let border_bg = Color::Rgb(40, 50, 30); //let border_fg = if self.0.focused { border_hi } else { border_lo }; //let border = Lozenge(Style::default().bg(border_bg).fg(border_fg)); - let track_title_h = 5u16; + let track_title_h = 3u16;//5u16; let scene_title_w = 3 + Scene::longest_name(scenes) as u16; // x of 1st track let clock = &self.0.clock; let arrangement = Layers::new(move |add|{ @@ -210,7 +210,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> { .map(|port|port.short_name()) .transpose()? .unwrap_or("(none)".into())); - col!(name, input, output, until_next, elapsed) + col!(name, /*input, output,*/ until_next, elapsed) .min_xy(w as u16, track_title_h) .bg(track.color.rgb) .push_x(scene_title_w) @@ -230,14 +230,11 @@ impl<'a> Content for VerticalArranger<'a, Tui> { let max_w = name.len().min((w as usize).saturating_sub(2)); let color = phrase.read().unwrap().color; add(&name.as_str()[0..max_w].push_x(1).fixed_x(w))?; - bg = if let Some((_, Some(ref playing))) = track.player.phrase { + bg = color.dark.rgb; + if let Some((_, Some(ref playing))) = track.player.phrase { if *playing.read().unwrap() == *phrase.read().unwrap() { - color.light.rgb - } else { - color.dark.rgb + bg = color.light.rgb } - } else { - color.dark.rgb }; }, _ => {} diff --git a/crates/tek_sequencer/src/sequencer.rs b/crates/tek_sequencer/src/sequencer.rs index 5a85e6e3..ce270725 100644 --- a/crates/tek_sequencer/src/sequencer.rs +++ b/crates/tek_sequencer/src/sequencer.rs @@ -393,9 +393,11 @@ impl Eq for Phrase {} impl PhrasePlayer { pub fn new ( jack: &Arc>, - clock: &Arc - ) -> Self { - Self { + clock: &Arc, + name: &str + ) -> Usually { + let jack = jack.read().unwrap(); + Ok(Self { clock: clock.clone(), phrase: None, next_phrase: None, @@ -404,11 +406,15 @@ impl PhrasePlayer { monitoring: false, recording: false, overdub: true, - midi_inputs: vec![], - midi_outputs: vec![], + midi_inputs: vec![ + jack.client().register_port(format!("{name}_in0").as_str(), MidiIn::default())? + ], + midi_outputs: vec![ + jack.client().register_port(format!("{name}_out0").as_str(), MidiOut::default())? + ], midi_out_buf: vec![Vec::with_capacity(16);16384], reset: true, - } + }) } pub fn toggle_monitor (&mut self) { self.monitoring = !self.monitoring; } pub fn toggle_record (&mut self) { self.recording = !self.recording; } diff --git a/crates/tek_sequencer/src/sequencer_cli.rs b/crates/tek_sequencer/src/sequencer_cli.rs index 14a9c758..09d425a1 100644 --- a/crates/tek_sequencer/src/sequencer_cli.rs +++ b/crates/tek_sequencer/src/sequencer_cli.rs @@ -26,7 +26,7 @@ impl SequencerCli { phrases: Arc::new(RwLock::new(PhrasePool::new())), editor: PhraseEditor::new(), clock: transport.clock.clone(), - player: PhrasePlayer::new(jack, &transport.clock), + player: PhrasePlayer::new(jack, &transport.clock, "tek_sequencer")?, transport: self.transport.then_some(Arc::new(RwLock::new(transport))), }; if let Some(_) = self.name.as_ref() { diff --git a/crates/tek_sequencer/src/sequencer_cmd.rs b/crates/tek_sequencer/src/sequencer_cmd.rs index 1c7c06b4..7d9ee33c 100644 --- a/crates/tek_sequencer/src/sequencer_cmd.rs +++ b/crates/tek_sequencer/src/sequencer_cmd.rs @@ -92,8 +92,8 @@ impl Handle for PhraseEditor { key!(KeyCode::Esc) => { self.entered = false; }, key!(KeyCode::Char('[')) => if self.entered { self.note_length_dec() }, key!(KeyCode::Char(']')) => if self.entered { self.note_length_inc() }, - key!(KeyCode::Char('a')) => if self.entered { self.put(); self.time_cursor_advance() }, - key!(KeyCode::Char('s')) => if self.entered { self.put() }, + key!(KeyCode::Char('a')) => if self.entered { self.put(); self.time_cursor_advance(); }, + key!(KeyCode::Char('s')) => if self.entered { self.put(); }, key!(KeyCode::Char('-')) => self.time_zoom_out(), key!(KeyCode::Char('_')) => self.time_zoom_out(), key!(KeyCode::Char('=')) => self.time_zoom_in(),