use crate::*; def_sizes_iter!(InputsSizes => MidiInput); def_sizes_iter!(OutputsSizes => MidiOutput); def_sizes_iter!(PortsSizes => Arc, [Connect]); pub(crate) use ConnectName::*; pub(crate) use ConnectScope::*; pub(crate) use ConnectStatus::*; #[derive(Debug)] pub struct AudioInput { /// Handle to JACK client, for receiving reconnect events. jack: Jack<'static>, /// Port name name: Arc, /// Port handle. port: Port, /// List of ports to connect to. pub connections: Vec, } #[derive(Debug)] pub struct AudioOutput { /// Handle to JACK client, for receiving reconnect events. jack: Jack<'static>, /// Port name name: Arc, /// Port handle. port: Port, /// List of ports to connect to. pub connections: Vec, } #[derive(Debug)] pub struct MidiInput { /// Handle to JACK client, for receiving reconnect events. jack: Jack<'static>, /// Port name name: Arc, /// Port handle. port: Port, /// List of currently held notes. held: Arc>, /// List of ports to connect to. pub connections: Vec, } #[derive(Debug)] pub struct MidiOutput { /// Handle to JACK client, for receiving reconnect events. jack: Jack<'static>, /// Port name name: Arc, /// Port handle. port: Port, /// List of ports to connect to. pub connections: Vec, /// List of currently held notes. held: Arc>, /// Buffer note_buffer: Vec, /// Buffer output_buffer: Vec>>, } 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; } 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) } } //take!(MidiInputCommand |state: Arrangement, iter|state.selected_midi_in().as_ref() //.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); //take!(MidiOutputCommand |state: Arrangement, iter|state.selected_midi_out().as_ref() //.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); 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() { //panic!("{connect:?}"); let status = match &connect.name { Exact(name) => self.connect_exact(name), RegExp(re) => self.connect_regexp(re, connect.scope), }?; *connect.status.write().unwrap() = status; } 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: ConnectScope ) -> 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 == 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 })) } } #[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, } #[derive(Clone, Debug)] pub struct Connect { pub name: ConnectName, pub scope: ConnectScope, 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 = Exact(name.as_ref().into()); Self { name, scope: One, status: Arc::new(RwLock::new(vec![])), info } } pub fn regexp (name: impl AsRef) -> Self { let info = format!("~:{}", name.as_ref()).into(); let name = RegExp(name.as_ref().into()); Self { name, scope: 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 = RegExp(name.as_ref().into()); Self { name, scope: All, status: Arc::new(RwLock::new(vec![])), info } } pub fn info (&self) -> Arc { let status = { let status = self.status.read().unwrap(); let mut ok = 0; for (_, _, state) in status.iter() { if *state == Connected { ok += 1 } } format!("{ok}/{}", status.len()) }; let scope = match self.scope { One => " ", All => "*", }; let name = match &self.name { Exact(name) => format!("= {name}"), RegExp(name) => format!("~ {name}"), }; format!(" ({}) {} {}", status, scope, name).into() } } def_command!(MidiInputCommand: |port: MidiInput| { Close => todo!(), Connect { midi_out: Arc } => todo!(), }); def_command!(MidiOutputCommand: |port: MidiOutput| { Close => todo!(), Connect { midi_in: Arc } => todo!(), }); def_command!(AudioInputCommand: |port: AudioInput| { Close => todo!(), Connect { audio_out: Arc } => todo!(), }); def_command!(AudioOutputCommand: |port: AudioOutput| { Close => todo!(), Connect { audio_in: Arc } => todo!(), }); impl HasJack<'static> for MidiInput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl JackPort for MidiInput { type Port = MidiIn; type Pair = MidiOut; fn port_name (&self) -> &Arc { &self.name } fn port (&self) -> &Port { &self.port } fn port_mut (&mut self) -> &mut Port { &mut self.port } fn into_port (self) -> Port { self.port } fn connections (&self) -> &[Connect] { self.connections.as_slice() } fn new (jack: &Jack<'static>, name: &impl AsRef, connect: &[Connect]) -> Usually where Self: Sized { let port = Self { port: Self::register(jack, name)?, jack: jack.clone(), name: name.as_ref().into(), connections: connect.to_vec(), held: Arc::new(RwLock::new([false;128])) }; port.connect_to_matching()?; Ok(port) } } impl MidiInput { pub fn parsed <'a> (&'a self, scope: &'a ProcessScope) -> impl Iterator, &'a [u8])> { parse_midi_input(self.port().iter(scope)) } } impl>> HasMidiIns for T { fn midi_ins (&self) -> &Vec { self.get() } fn midi_ins_mut (&mut self) -> &mut Vec { self.get_mut() } } /// Trait for thing that may receive MIDI. pub trait HasMidiIns { fn midi_ins (&self) -> &Vec; fn midi_ins_mut (&mut self) -> &mut Vec; /// Collect MIDI input from app ports (TODO preallocate large buffers) fn midi_input_collect <'a> (&'a self, scope: &'a ProcessScope) -> CollectedMidiInput<'a> { self.midi_ins().iter() .map(|port|port.port().iter(scope) .map(|RawMidi { time, bytes }|(time, LiveEvent::parse(bytes))) .collect::>()) .collect::>() } fn midi_ins_with_sizes <'a> (&'a self) -> impl Iterator, &'a [Connect], usize, usize)> + Send + Sync + 'a { let mut y = 0; self.midi_ins().iter().enumerate().map(move|(i, input)|{ let height = 1 + input.connections().len(); let data = (i, input.port_name(), input.connections(), y, y + height); y += height; data }) } } pub type CollectedMidiInput<'a> = Vec, MidiError>)>>; impl> AddMidiIn for T { fn midi_in_add (&mut self) -> Usually<()> { let index = self.midi_ins().len(); let port = MidiInput::new(self.jack(), &format!("M/{index}"), &[])?; self.midi_ins_mut().push(port); Ok(()) } } /// May create new MIDI input ports. pub trait AddMidiIn { fn midi_in_add (&mut self) -> Usually<()>; } impl HasJack<'static> for MidiOutput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl JackPort for MidiOutput { type Port = MidiOut; type Pair = MidiIn; fn port_name (&self) -> &Arc { &self.name } fn port (&self) -> &Port { &self.port } fn port_mut (&mut self) -> &mut Port { &mut self.port } fn into_port (self) -> Port { self.port } fn connections (&self) -> &[Connect] { self.connections.as_slice() } fn new (jack: &Jack<'static>, name: &impl AsRef, connect: &[Connect]) -> Usually where Self: Sized { let port = Self::register(jack, name)?; let jack = jack.clone(); let name = name.as_ref().into(); let connections = connect.to_vec(); let port = Self { jack, port, name, connections, held: Arc::new([false;128].into()), note_buffer: vec![0;8], output_buffer: vec![vec![];65536], }; port.connect_to_matching()?; Ok(port) } } impl MidiOutput { /// Clear the section of the output buffer that we will be using, /// emitting "all notes off" at start of buffer if requested. pub fn buffer_clear (&mut self, scope: &ProcessScope, reset: bool) { let n_frames = (scope.n_frames() as usize).min(self.output_buffer.len()); for frame in &mut self.output_buffer[0..n_frames] { frame.clear(); } if reset { all_notes_off(&mut self.output_buffer); } } /// Write a note to the output buffer pub fn buffer_write <'a> ( &'a mut self, sample: usize, event: LiveEvent, ) { self.note_buffer.fill(0); event.write(&mut self.note_buffer).expect("failed to serialize MIDI event"); self.output_buffer[sample].push(self.note_buffer.clone()); // Update the list of currently held notes. if let LiveEvent::Midi { ref message, .. } = event { update_keys(&mut*self.held.write().unwrap(), message); } } /// Write a chunk of MIDI data from the output buffer to the output port. pub fn buffer_emit (&mut self, scope: &ProcessScope) { let samples = scope.n_frames() as usize; let mut writer = self.port.writer(scope); for (time, events) in self.output_buffer.iter().enumerate().take(samples) { for bytes in events.iter() { writer.write(&RawMidi { time: time as u32, bytes }).unwrap_or_else(|_|{ panic!("Failed to write MIDI data: {bytes:?}"); }); } } } } impl>> HasMidiOuts for T { fn midi_outs (&self) -> &Vec { self.get() } fn midi_outs_mut (&mut self) -> &mut Vec { self.get_mut() } } /// Trait for thing that may output MIDI. pub trait HasMidiOuts { fn midi_outs (&self) -> &Vec; fn midi_outs_mut (&mut self) -> &mut Vec; fn midi_outs_with_sizes <'a> (&'a self) -> impl Iterator, &'a [Connect], usize, usize)> + Send + Sync + 'a { let mut y = 0; self.midi_outs().iter().enumerate().map(move|(i, output)|{ let height = 1 + output.connections().len(); let data = (i, output.port_name(), output.connections(), y, y + height); y += height; data }) } fn midi_outs_emit (&mut self, scope: &ProcessScope) { for port in self.midi_outs_mut().iter_mut() { port.buffer_emit(scope) } } } /// Trail for thing that may gain new MIDI ports. impl> AddMidiOut for T { fn midi_out_add (&mut self) -> Usually<()> { let index = self.midi_outs().len(); let port = MidiOutput::new(self.jack(), &format!("{index}/M"), &[])?; self.midi_outs_mut().push(port); Ok(()) } } /// May create new MIDI output ports. pub trait AddMidiOut { fn midi_out_add (&mut self) -> Usually<()>; } impl HasJack<'static> for AudioInput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl JackPort for AudioInput { type Port = AudioIn; type Pair = AudioOut; fn port_name (&self) -> &Arc { &self.name } fn port (&self) -> &Port { &self.port } fn port_mut (&mut self) -> &mut Port { &mut self.port } fn into_port (self) -> Port { self.port } fn connections (&self) -> &[Connect] { self.connections.as_slice() } fn new (jack: &Jack<'static>, name: &impl AsRef, connect: &[Connect]) -> Usually where Self: Sized { let port = Self { port: Self::register(jack, name)?, jack: jack.clone(), name: name.as_ref().into(), connections: connect.to_vec() }; port.connect_to_matching()?; Ok(port) } } impl HasJack<'static> for AudioOutput { fn jack (&self) -> &Jack<'static> { &self.jack } } impl JackPort for AudioOutput { type Port = AudioOut; type Pair = AudioIn; fn port_name (&self) -> &Arc { &self.name } fn port (&self) -> &Port { &self.port } fn port_mut (&mut self) -> &mut Port { &mut self.port } fn into_port (self) -> Port { self.port } fn connections (&self) -> &[Connect] { self.connections.as_slice() } fn new (jack: &Jack<'static>, name: &impl AsRef, connect: &[Connect]) -> Usually where Self: Sized { let port = Self { port: Self::register(jack, name)?, jack: jack.clone(), name: name.as_ref().into(), connections: connect.to_vec() }; port.connect_to_matching()?; Ok(port) } }