From e86be4facc5bc0b5f004be9ef7c5c7d511bdd01e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Wed, 3 Jul 2024 20:56:17 +0300 Subject: [PATCH] ports macro --- src/control.rs | 6 +++-- src/core.rs | 3 ++- src/core/device.rs | 19 +++---------- src/core/port.rs | 62 ++++++++++++++++++++++++++++++------------- src/main.rs | 6 +++++ src/model/plugin.rs | 36 ++++++------------------- src/model/sampler.rs | 24 +++++------------ src/model/track.rs | 40 +++++++++++++++++----------- src/view/chain.rs | 8 +++--- src/view/sequencer.rs | 2 +- 10 files changed, 104 insertions(+), 102 deletions(-) diff --git a/src/control.rs b/src/control.rs index 086314e0..c8fb4f6b 100644 --- a/src/control.rs +++ b/src/control.rs @@ -49,10 +49,11 @@ const KEYMAP: &'static [KeyBinding] = keymap!(App { false => {app.scene_cursor = app.scene_cursor.saturating_sub(1); Ok(true)}, true => {app.track_cursor = app.track_cursor.saturating_sub(1); Ok(true)}, }, + 2 => { app.note_cursor = app.note_cursor.saturating_sub(1); Ok(true) } _ => Ok(false) } } else { - focus_prev(app) + focus_next(app) } }], [Down, NONE, "cursor_down", "move cursor down", |app: &mut App| { @@ -62,10 +63,11 @@ const KEYMAP: &'static [KeyBinding] = keymap!(App { false => {app.scene_cursor = app.scenes.len().min(app.scene_cursor + 1); Ok(true)}, true => {app.track_cursor = app.tracks.len().min(app.track_cursor + 1); Ok(true)}, }, + 2 => { app.note_cursor = app.note_cursor + 1; Ok(true) } _ => Ok(false) } } else { - focus_next(app) + focus_prev(app) } }], [Left, NONE, "cursor_left", "move cursor left", |app: &mut App| { diff --git a/src/core.rs b/src/core.rs index dc193765..459f0869 100644 --- a/src/core.rs +++ b/src/core.rs @@ -26,5 +26,6 @@ pub use crate::{ process, phrase, keymap, - key + key, + ports }; diff --git a/src/core/device.rs b/src/core/device.rs index 3465c9f3..1663a64e 100644 --- a/src/core/device.rs +++ b/src/core/device.rs @@ -5,14 +5,14 @@ pub trait Component: Render + Handle {} impl Component for T {} /// A UI component that may have presence on the JACK grap. -pub trait Device: Render + Handle + PortList + Send + Sync { +pub trait Device: Render + Handle + Ports + Send + Sync { fn boxed (self) -> Box where Self: Sized + 'static { Box::new(self) } } /// All things that implement the required traits can be treated as `Device`. -impl Device for T {} +impl Device for T {} /// A device dynamicammy composed of state and handlers. pub struct DynamicDevice { @@ -35,20 +35,7 @@ impl Render for DynamicDevice { } } -impl PortList for DynamicDevice { - fn audio_ins (&self) -> Usually> { - self.state().audio_ins() - } - fn audio_outs (&self) -> Usually> { - self.state().audio_outs() - } - fn midi_ins (&self) -> Usually> { - self.state().midi_ins() - } - fn midi_outs (&self) -> Usually> { - self.state().midi_outs() - } -} +impl Ports for DynamicDevice {} impl DynamicDevice { pub fn new <'a, R, H, P> (render: R, handle: H, process: P, state: T) -> Self where diff --git a/src/core/port.rs b/src/core/port.rs index ee6b7243..e39eedd3 100644 --- a/src/core/port.rs +++ b/src/core/port.rs @@ -1,32 +1,58 @@ use crate::core::*; /// Trait for things that may expose JACK ports. -pub trait PortList { - fn audio_ins (&self) -> Usually> { +pub trait Ports { + fn audio_ins (&self) -> Usually>> { Ok(vec![]) } - fn audio_outs (&self) -> Usually> { + fn audio_outs (&self) -> Usually>> { Ok(vec![]) } - fn midi_ins (&self) -> Usually> { + fn midi_ins <'a> (&'a self) -> Usually>> { Ok(vec![]) } - fn midi_outs (&self) -> Usually> { + fn midi_outs <'a> (&'a self) -> Usually>> { Ok(vec![]) } - fn connect (&mut self, _connect: bool, _source: &str, _target: &str) - -> Usually<()> - { - Ok(()) - } - fn connect_all (&mut self, connections: &[(bool, &str, &str)]) - -> Usually<()> - { - for (connect, source, target) in connections.iter() { - self.connect(*connect, source, target)?; - } - Ok(()) - } +} + +#[macro_export] macro_rules! ports { + ($T:ty $({ $(audio: { + $(ins: |$ai_arg:ident|$ai_impl:expr,)? + $(outs: |$ao_arg:ident|$ao_impl:expr,)? + })? $(midi: { + $(ins: |$mi_arg:ident|$mi_impl:expr,)? + $(outs: |$mo_arg:ident|$mo_impl:expr,)? + })?})?) => { + impl Ports for $T {$( + $( + $(fn audio_ins <'a> (&'a self) -> Usually>> { + let cb = |$ai_arg:&'a Self|$ai_impl; + cb(self) + })? + )? + $( + $(fn audio_outs <'a> (&'a self) -> Usually>> { + let cb = (|$ao_arg:&'a Self|$ao_impl); + cb(self) + })? + )? + )? $( + $( + $(fn midi_ins <'a> (&'a self) -> Usually>> { + let cb = (|$mi_arg:&'a Self|$mi_impl); + cb(self) + })? + )? + $( + $(fn midi_outs <'a> (&'a self) -> Usually>> { + let cb = (|$mo_arg:&'a Self|$mo_impl); + cb(self) + })? + )? + )?} + }; + } pub struct DevicePort { diff --git a/src/main.rs b/src/main.rs index c3279dc4..4caa57dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,7 +69,13 @@ pub fn main () -> Usually<()> { ]; state.track_cursor = 1; state.scene_cursor = 1; + state.note_start = 12; let client = jack.as_client(); + for track in state.tracks.iter() { + if let Some(port) = track.midi_ins()?.get(0) { + client.connect_ports(&track.midi_out, port)?; + } + } state.midi_in = Some(client.register_port("midi-in", MidiIn)?); state.transport = Some(client.transport()); state.playing = Some(TransportState::Stopped); diff --git a/src/model/plugin.rs b/src/model/plugin.rs index 305988cb..df7baeec 100644 --- a/src/model/plugin.rs +++ b/src/model/plugin.rs @@ -144,33 +144,13 @@ impl Plugin { } } -impl PortList for Plugin { - fn audio_ins (&self) -> Usually> { - let mut ports = vec![]; - for port in self.audio_ins.iter() { - ports.push(port.name()?); - } - Ok(ports) +ports!(Plugin { + audio: { + ins: |track|Ok(track.audio_ins.iter().collect()), + outs: |track|Ok(track.audio_outs.iter().collect()), } - fn audio_outs (&self) -> Usually> { - let mut ports = vec![]; - for port in self.audio_outs.iter() { - ports.push(port.name()?); - } - Ok(ports) + midi: { + ins: |track|Ok(track.midi_ins.iter().collect()), + outs: |track|Ok(track.midi_outs.iter().collect()), } - fn midi_ins (&self) -> Usually> { - let mut ports = vec![]; - for port in self.midi_ins.iter() { - ports.push(port.name()?); - } - Ok(ports) - } - fn midi_outs (&self) -> Usually> { - let mut ports = vec![]; - for port in self.midi_outs.iter() { - ports.push(port.name()?); - } - Ok(ports) - } -} +}); diff --git a/src/model/sampler.rs b/src/model/sampler.rs index e07fcc6a..d7613554 100644 --- a/src/model/sampler.rs +++ b/src/model/sampler.rs @@ -135,25 +135,15 @@ impl Sampler { fn load_sample (&mut self, _path: &str) {} } -impl PortList for Sampler { - fn midi_ins (&self) -> Usually> { - Ok(vec![self.midi_in.name()?]) +ports!(Sampler { + audio: { + ins: |sampler|Ok(sampler.audio_ins.iter().collect()), + outs: |sampler|Ok(sampler.audio_outs.iter().collect()), } - fn audio_ins (&self) -> Usually> { - let mut ports = vec![]; - for port in self.audio_ins.iter() { - ports.push(port.name()?); - } - Ok(ports) + midi: { + ins: |sampler|Ok(vec![&sampler.midi_in]), } - fn audio_outs (&self) -> Usually> { - let mut ports = vec![]; - for port in self.audio_outs.iter() { - ports.push(port.name()?); - } - Ok(ports) - } -} +}); #[macro_export] macro_rules! sample { ($note:expr, $name:expr, $src:expr) => { diff --git a/src/model/track.rs b/src/model/track.rs index 0f78dd4f..b56b2ae5 100644 --- a/src/model/track.rs +++ b/src/model/track.rs @@ -43,6 +43,15 @@ impl Track { device: 0, }) } + pub fn device (&self) -> Option<&Box> { + self.devices.get(self.device) + } + pub fn first_device (&self) -> Option<&Box> { + self.devices.get(0) + } + pub fn last_device (&self) -> Option<&Box> { + self.devices.get(self.devices.len().saturating_sub(1)) + } pub fn phrase (&self) -> Option<&Phrase> { if let Some(phrase) = self.sequence { return self.phrases.get(phrase) @@ -52,23 +61,24 @@ impl Track { } } -impl PortList for Track { - fn midi_outs (&self) -> Usually> { - Ok(vec![self.midi_out.name()?]) +ports!(Track { + audio: { + outs: |track|{ + if let Some(device) = track.last_device() { + device.audio_outs() + } else { + Ok(vec![]) + } + }, } - fn midi_ins (&self) -> Usually> { - if let Some(device) = self.devices.get(0) { + midi: { + ins: |track|if let Some(device) = track.first_device() { device.midi_ins() } else { Ok(vec![]) - } + }, + outs: |track|Ok(vec![ + &track.midi_out + ]), } - fn audio_outs (&self) -> Usually> { - if let Some(device) = self.devices.get(self.devices.len().saturating_sub(1)) { - device.audio_outs() - } else { - Ok(vec![]) - } - } -} - +}); diff --git a/src/view/chain.rs b/src/view/chain.rs index be06e8c1..0fa8984c 100644 --- a/src/view/chain.rs +++ b/src/view/chain.rs @@ -159,23 +159,23 @@ pub fn draw_as_column ( w = w.max(frame.width); y = y - midi_ins.len() as u16; for port in midi_ins.iter() { - buf.set_string(x + frame.width - 10, y, &format!(" MIDI {port} "), style_midi); + buf.set_string(x + frame.width - 10, y, &format!(" MIDI {} ", port.name()?), style_midi); y = y + 1; } y = y - audio_ins.len() as u16; for port in audio_ins.iter() { - buf.set_string(x + frame.width - 10, y, &format!(" MIDI {port} "), style_audio); + buf.set_string(x + frame.width - 10, y, &format!(" MIDI {} ", port.name()?), style_audio); y = y + 1; } y = y + frame.height - 1; y = y + midi_outs.len() as u16; for port in midi_outs.iter() { - buf.set_string(x + 2, y, &format!(" MIDI {port} "), style_midi); + buf.set_string(x + 2, y, &format!(" MIDI {} ", port.name()?), style_midi); y = y + 1; } y = y + audio_outs.len() as u16; for port in audio_outs.iter() { - buf.set_string(x + 2, y, &format!(" Audio {port} "), style_audio); + buf.set_string(x + 2, y, &format!(" Audio {} ", port.name()?), style_audio); y = y + 1; } } diff --git a/src/view/sequencer.rs b/src/view/sequencer.rs index f638eb7b..71f5024f 100644 --- a/src/view/sequencer.rs +++ b/src/view/sequencer.rs @@ -139,7 +139,7 @@ mod horizontal { //let time1 = time0 + width as usize; //let note1 = note0 + height as usize; let bg = Style::default(); - let (bw, wh) = (bg.dim(), bg.white()); + let (bw, wh) = (bg.dim(), bg.white().not_dim()); let offset = 5; for x in x+offset..x+width-offset { let step = (x-offset) as usize * time_z;