use crate::*; pub struct JackPort { pub port: Port, pub connect: Vec } impl JackPort { //pub fn new (jack: &impl RegisterPort } #[derive(Clone, PartialEq)] pub enum PortConnect { Exact(Arc), Wildcard(Arc), RegExp(Arc), } /// This is a utility trait for things that may register or connect [Port]s. /// It contains shorthand methods to this purpose. It's implemented for /// `Arc>` for terse port registration in the /// `init` callback of [JackClient::activate_with]. pub trait RegisterPort { fn midi_in (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually>; fn midi_out (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually>; fn audio_in (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually>; fn audio_out (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually>; } impl RegisterPort for Arc> { fn midi_in (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually> { let jack = self.read().unwrap(); let input = jack.client().register_port(name.as_ref(), MidiIn::default())?; for port in connect.iter() { let port = port.as_ref(); if let Some(output) = jack.port_by_name(port).as_ref() { jack.client().connect_ports(output, &input)?; } else { panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names."); } } Ok(input) } fn midi_out (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually> { let jack = self.read().unwrap(); let output = jack.client().register_port(name.as_ref(), MidiOut::default())?; for port in connect.iter() { let port = port.as_ref(); if let Some(input) = jack.port_by_name(port).as_ref() { jack.client().connect_ports(&output, input)?; } else { panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names."); } } Ok(output) } fn audio_in (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually> { let jack = self.read().unwrap(); let input = jack.client().register_port(name.as_ref(), AudioIn::default())?; for port in connect.iter() { let port = port.as_ref(); if let Some(output) = jack.port_by_name(port).as_ref() { jack.client().connect_ports(output, &input)?; } else { panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names."); } } Ok(input) } fn audio_out (&self, name: impl AsRef, connect: &[impl AsRef]) -> Usually> { let jack = self.read().unwrap(); let output = jack.client().register_port(name.as_ref(), AudioOut::default())?; for port in connect.iter() { let port = port.as_ref(); if let Some(input) = jack.port_by_name(port).as_ref() { jack.client().connect_ports(&output, input)?; } else { panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names."); } } Ok(output) } } ///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut]. //#[derive(Default, Debug)] //pub struct JackPorts { //pub audio_ins: BTreeMap>, //pub midi_ins: BTreeMap>, //pub audio_outs: BTreeMap>, //pub midi_outs: BTreeMap>, //} ///// Collection of JACK ports as [Unowned]. //#[derive(Default, Debug)] //pub struct UnownedJackPorts { //pub audio_ins: BTreeMap>, //pub midi_ins: BTreeMap>, //pub audio_outs: BTreeMap>, //pub midi_outs: BTreeMap>, //} //impl JackPorts { //pub fn clone_unowned(&self) -> UnownedJackPorts { //let mut unowned = UnownedJackPorts::default(); //for (name, port) in self.midi_ins.iter() { //unowned.midi_ins.insert(name.clone(), port.clone_unowned()); //} //for (name, port) in self.midi_outs.iter() { //unowned.midi_outs.insert(name.clone(), port.clone_unowned()); //} //for (name, port) in self.audio_ins.iter() { //unowned.audio_ins.insert(name.clone(), port.clone_unowned()); //} //for (name, port) in self.audio_outs.iter() { //unowned //.audio_outs //.insert(name.clone(), port.clone_unowned()); //} //unowned //} //} ///// Implement the `Ports` trait. //#[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) //})? //)? //)?} //}; //} /// Trait for things that may expose JACK ports. pub trait Ports { fn audio_ins(&self) -> Usually>> { Ok(vec![]) } fn audio_outs(&self) -> Usually>> { Ok(vec![]) } fn midi_ins(&self) -> Usually>> { Ok(vec![]) } fn midi_outs(&self) -> Usually>> { Ok(vec![]) } } fn register_ports( client: &Client, names: Vec, spec: T, ) -> Usually>> { names .into_iter() .try_fold(BTreeMap::new(), |mut ports, name| { let port = client.register_port(&name, spec)?; ports.insert(name, port); Ok(ports) }) } fn query_ports(client: &Client, names: Vec) -> BTreeMap> { names.into_iter().fold(BTreeMap::new(), |mut ports, name| { let port = client.port_by_name(&name).unwrap(); ports.insert(name, port); ports }) }