use crate::*; /// Audio input port. #[derive(Debug)] pub struct AudioInput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, } /// Audio output port. #[derive(Debug)] pub struct AudioOutput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, } /// MIDI input port. #[derive(Debug)] pub struct MidiInput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of currently held notes. pub held: Arc>, /// List of ports to connect to. pub connections: Vec, } /// MIDI output port. #[derive(Debug)] pub struct MidiOutput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, /// List of currently held notes. pub held: Arc>, /// Buffer pub note_buffer: Vec, /// Buffer pub output_buffer: Vec>>, } #[derive(Clone, Debug, PartialEq)] pub enum ConnectName { /** Exact match */ Exact(Arc), /** Match regular expression */ RegExp(Arc), } #[derive(Clone, Copy, Debug, PartialEq)] pub enum ConnectScope { One, All } #[derive(Clone, Copy, Debug, PartialEq)] pub enum ConnectStatus { Missing, Disconnected, Connected, Mismatch, } /// Port connection manager. /// /// ``` /// let connect = tek::Connect::default(); /// ``` #[derive(Clone, Debug, Default)] pub struct Connect { pub name: Option, pub scope: Option, pub status: Arc, Arc, ConnectStatus)>>>, pub info: Arc, } impl Connect { pub fn collect (exact: &[impl AsRef], re: &[impl AsRef], re_all: &[impl AsRef]) -> Vec { let mut connections = vec![]; for port in exact.iter() { connections.push(Self::exact(port)) } for port in re.iter() { connections.push(Self::regexp(port)) } for port in re_all.iter() { connections.push(Self::regexp_all(port)) } connections } /// Connect to this exact port pub fn exact (name: impl AsRef) -> Self { let info = format!("=:{}", name.as_ref()).into(); let name = Some(Exact(name.as_ref().into())); Self { name, scope: Some(One), status: Arc::new(RwLock::new(vec![])), info } } pub fn regexp (name: impl AsRef) -> Self { let info = format!("~:{}", name.as_ref()).into(); let name = Some(RegExp(name.as_ref().into())); Self { name, scope: Some(One), status: Arc::new(RwLock::new(vec![])), info } } pub fn regexp_all (name: impl AsRef) -> Self { let info = format!("+:{}", name.as_ref()).into(); let name = Some(RegExp(name.as_ref().into())); Self { name, scope: Some(All), status: Arc::new(RwLock::new(vec![])), info } } pub fn info (&self) -> Arc { format!(" ({}) {} {}", { let status = self.status.read().unwrap(); let mut ok = 0; for (_, _, state) in status.iter() { if *state == Connected { ok += 1 } } format!("{ok}/{}", status.len()) }, match self.scope { None => "x", Some(One) => " ", Some(All) => "*", }, match &self.name { None => format!("x"), Some(Exact(name)) => format!("= {name}"), Some(RegExp(name)) => format!("~ {name}"), }).into() } } impl HasJack<'static> for MidiInput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl HasJack<'static> for MidiOutput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl HasJack<'static> for AudioInput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl HasJack<'static> for AudioOutput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl> RegisterPorts for J { fn midi_in (&self, name: &impl AsRef, connect: &[Connect]) -> Usually { MidiInput::new(self.jack(), name, connect) } fn midi_out (&self, name: &impl AsRef, connect: &[Connect]) -> Usually { MidiOutput::new(self.jack(), name, connect) } fn audio_in (&self, name: &impl AsRef, connect: &[Connect]) -> Usually { AudioInput::new(self.jack(), name, connect) } fn audio_out (&self, name: &impl AsRef, connect: &[Connect]) -> Usually { AudioOutput::new(self.jack(), name, connect) } } /// May create new MIDI input ports. pub trait AddMidiIn { fn midi_in_add (&mut self) -> Usually<()>; } /// May create new MIDI output ports. pub trait AddMidiOut { fn midi_out_add (&mut self) -> Usually<()>; } pub trait RegisterPorts: HasJack<'static> { /// Register a MIDI input port. fn midi_in (&self, name: &impl AsRef, connect: &[Connect]) -> Usually; /// Register a MIDI output port. fn midi_out (&self, name: &impl AsRef, connect: &[Connect]) -> Usually; /// Register an audio input port. fn audio_in (&self, name: &impl AsRef, connect: &[Connect]) -> Usually; /// Register an audio output port. fn audio_out (&self, name: &impl AsRef, connect: &[Connect]) -> Usually; } pub trait JackPort: HasJack<'static> { type Port: PortSpec + Default; type Pair: PortSpec + Default; fn new (jack: &Jack<'static>, name: &impl AsRef, connect: &[Connect]) -> Usually where Self: Sized; fn register (jack: &Jack<'static>, name: &impl AsRef) -> Usually> { jack.with_client(|c|c.register_port::(name.as_ref(), Default::default())) .map_err(|e|e.into()) } fn port_name (&self) -> &Arc; fn connections (&self) -> &[Connect]; fn port (&self) -> &Port; fn port_mut (&mut self) -> &mut Port; fn into_port (self) -> Port where Self: Sized; fn close (self) -> Usually<()> where Self: Sized { let jack = self.jack().clone(); Ok(jack.with_client(|c|c.unregister_port(self.into_port()))?) } fn ports (&self, re_name: Option<&str>, re_type: Option<&str>, flags: PortFlags) -> Vec { self.with_client(|c|c.ports(re_name, re_type, flags)) } fn port_by_id (&self, id: u32) -> Option> { self.with_client(|c|c.port_by_id(id)) } fn port_by_name (&self, name: impl AsRef) -> Option> { self.with_client(|c|c.port_by_name(name.as_ref())) } fn connect_to_matching <'k> (&'k self) -> Usually<()> { for connect in self.connections().iter() { match &connect.name { Some(Exact(name)) => { *connect.status.write().unwrap() = self.connect_exact(name)?; }, Some(RegExp(re)) => { *connect.status.write().unwrap() = self.connect_regexp(re, connect.scope)?; }, _ => {}, }; } Ok(()) } fn connect_exact <'k> (&'k self, name: &str) -> Usually, Arc, ConnectStatus)>> { self.with_client(move|c|{ let mut status = vec![]; for port in c.ports(None, None, PortFlags::empty()).iter() { if port.as_str() == &*name { if let Some(port) = c.port_by_name(port.as_str()) { let port_status = self.connect_to_unowned(&port)?; let name = port.name()?.into(); status.push((port, name, port_status)); if port_status == Connected { break } } } } Ok(status) }) } fn connect_regexp <'k> ( &'k self, re: &str, scope: Option ) -> Usually, Arc, ConnectStatus)>> { self.with_client(move|c|{ let mut status = vec![]; let ports = c.ports(Some(&re), None, PortFlags::empty()); for port in ports.iter() { if let Some(port) = c.port_by_name(port.as_str()) { let port_status = self.connect_to_unowned(&port)?; let name = port.name()?.into(); status.push((port, name, port_status)); if port_status == Connected && scope == Some(One) { break } } } Ok(status) }) } /** Connect to a matching port by name. */ fn connect_to_name (&self, name: impl AsRef) -> Usually { self.with_client(|c|if let Some(ref port) = c.port_by_name(name.as_ref()) { self.connect_to_unowned(port) } else { Ok(Missing) }) } /** Connect to a matching port by reference. */ fn connect_to_unowned (&self, port: &Port) -> Usually { self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(self.port(), port) { Connected } else if let Ok(_) = c.connect_ports(port, self.port()) { Connected } else { Mismatch })) } /** Connect to an owned matching port by reference. */ fn connect_to_owned (&self, port: &Port) -> Usually { self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(self.port(), port) { Connected } else if let Ok(_) = c.connect_ports(port, self.port()) { Connected } else { Mismatch })) } }