flatten jack module

This commit is contained in:
🪞👃🪞 2024-12-29 18:58:06 +01:00
parent b78b55faa2
commit e8b97bed37
3 changed files with 182 additions and 186 deletions

View file

@ -1,5 +1,4 @@
use crate::*;
pub use ::jack as libjack;
pub use ::jack::{
contrib::ClosureProcessHandler, NotificationHandler,
@ -9,13 +8,6 @@ pub use ::jack::{
Transport, TransportState, MidiIter, MidiWriter, RawMidi,
};
pub mod jack_event;
pub(crate) use self::jack_event::*;
pub mod ports;
pub(crate) use self::ports::*;
pub use self::ports::RegisterPort;
/// Implement [TryFrom<&Arc<RwLock<JackConnection>>>]: create app state from wrapped JACK handle.
#[macro_export] macro_rules! from_jack {
(|$jack:ident|$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)? $cb:expr) => {
@ -148,6 +140,144 @@ impl JackConnection {
}
}
pub trait RegisterPort {
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>>;
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>>;
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>>;
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>>;
fn connect_midi_from (&self, my_input: &Port<MidiIn>, ports: &[String]) -> Usually<()>;
fn connect_midi_to (&self, my_output: &Port<MidiOut>, ports: &[String]) -> Usually<()>;
fn connect_audio_from (&self, my_input: &Port<AudioIn>, ports: &[String]) -> Usually<()>;
fn connect_audio_to (&self, my_output: &Port<AudioOut>, ports: &[String]) -> Usually<()>;
}
impl RegisterPort for Arc<RwLock<JackConnection>> {
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>> {
Ok(self.read().unwrap().client().register_port(name, MidiIn::default())?)
}
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>> {
Ok(self.read().unwrap().client().register_port(name, MidiOut::default())?)
}
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>> {
Ok(self.read().unwrap().client().register_port(name, AudioOut::default())?)
}
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>> {
Ok(self.read().unwrap().client().register_port(name, AudioIn::default())?)
}
fn connect_midi_from (&self, input: &Port<MidiIn>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_midi_to (&self, output: &Port<MidiOut>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_from (&self, input: &Port<AudioIn>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_to (&self, output: &Port<AudioOut>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
/// Event enum for JACK events.
pub enum JackEvent {
ThreadInit,
Shutdown(ClientStatus, String),
Freewheel(bool),
SampleRate(Frames),
ClientRegistration(String, bool),
PortRegistration(PortId, bool),
PortRename(PortId, String, String),
PortsConnected(PortId, PortId, bool),
GraphReorder,
XRun,
}
/// Notification handler used by the [Jack] factory
/// when constructing [JackDevice]s.
pub type DynamicNotifications = Notifications<Box<dyn Fn(JackEvent) + Send + Sync>>;
/// Generic notification handler that emits [JackEvent]
pub struct Notifications<T: Fn(JackEvent) + Send>(pub T);
impl<T: Fn(JackEvent) + Send> NotificationHandler for Notifications<T> {
fn thread_init(&self, _: &Client) {
self.0(JackEvent::ThreadInit);
}
unsafe fn shutdown(&mut self, status: ClientStatus, reason: &str) {
self.0(JackEvent::Shutdown(status, reason.into()));
}
fn freewheel(&mut self, _: &Client, enabled: bool) {
self.0(JackEvent::Freewheel(enabled));
}
fn sample_rate(&mut self, _: &Client, frames: Frames) -> Control {
self.0(JackEvent::SampleRate(frames));
Control::Quit
}
fn client_registration(&mut self, _: &Client, name: &str, reg: bool) {
self.0(JackEvent::ClientRegistration(name.into(), reg));
}
fn port_registration(&mut self, _: &Client, id: PortId, reg: bool) {
self.0(JackEvent::PortRegistration(id, reg));
}
fn port_rename(&mut self, _: &Client, id: PortId, old: &str, new: &str) -> Control {
self.0(JackEvent::PortRename(id, old.into(), new.into()));
Control::Continue
}
fn ports_connected(&mut self, _: &Client, a: PortId, b: PortId, are: bool) {
self.0(JackEvent::PortsConnected(a, b, are));
}
fn graph_reorder(&mut self, _: &Client) -> Control {
self.0(JackEvent::GraphReorder);
Control::Continue
}
fn xrun(&mut self, _: &Client) -> Control {
self.0(JackEvent::XRun);
Control::Continue
}
}
////////////////////////////////////////////////////////////////////////////////////
///// A [AudioComponent] bound to a JACK client and a set of ports.
@ -424,3 +554,47 @@ impl JackConnection {
///// All things that implement the required traits can be treated as `AudioComponent`.
//impl<E: Engine, W: Component<E> + Audio> AudioComponent<E> for W {}
/////////
/*
/// Trait for things that may expose JACK ports.
pub trait Ports {
fn audio_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn audio_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn midi_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn midi_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
}
fn register_ports<T: PortSpec + Copy>(
client: &Client,
names: Vec<String>,
spec: T,
) -> Usually<BTreeMap<String, Port<T>>> {
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<String>) -> BTreeMap<String, Port<Unowned>> {
names.into_iter().fold(BTreeMap::new(), |mut ports, name| {
let port = client.port_by_name(&name).unwrap();
ports.insert(name, port);
ports
})
}
*/

View file

@ -1,69 +0,0 @@
use crate::*;
#[derive(Debug, Clone, PartialEq)]
/// Event enum for JACK events.
pub enum JackEvent {
ThreadInit,
Shutdown(ClientStatus, String),
Freewheel(bool),
SampleRate(Frames),
ClientRegistration(String, bool),
PortRegistration(PortId, bool),
PortRename(PortId, String, String),
PortsConnected(PortId, PortId, bool),
GraphReorder,
XRun,
}
/// Notification handler used by the [Jack] factory
/// when constructing [JackDevice]s.
pub type DynamicNotifications = Notifications<Box<dyn Fn(JackEvent) + Send + Sync>>;
/// Generic notification handler that emits [JackEvent]
pub struct Notifications<T: Fn(JackEvent) + Send>(pub T);
impl<T: Fn(JackEvent) + Send> NotificationHandler for Notifications<T> {
fn thread_init(&self, _: &Client) {
self.0(JackEvent::ThreadInit);
}
unsafe fn shutdown(&mut self, status: ClientStatus, reason: &str) {
self.0(JackEvent::Shutdown(status, reason.into()));
}
fn freewheel(&mut self, _: &Client, enabled: bool) {
self.0(JackEvent::Freewheel(enabled));
}
fn sample_rate(&mut self, _: &Client, frames: Frames) -> Control {
self.0(JackEvent::SampleRate(frames));
Control::Quit
}
fn client_registration(&mut self, _: &Client, name: &str, reg: bool) {
self.0(JackEvent::ClientRegistration(name.into(), reg));
}
fn port_registration(&mut self, _: &Client, id: PortId, reg: bool) {
self.0(JackEvent::PortRegistration(id, reg));
}
fn port_rename(&mut self, _: &Client, id: PortId, old: &str, new: &str) -> Control {
self.0(JackEvent::PortRename(id, old.into(), new.into()));
Control::Continue
}
fn ports_connected(&mut self, _: &Client, a: PortId, b: PortId, are: bool) {
self.0(JackEvent::PortsConnected(a, b, are));
}
fn graph_reorder(&mut self, _: &Client) -> Control {
self.0(JackEvent::GraphReorder);
Control::Continue
}
fn xrun(&mut self, _: &Client) -> Control {
self.0(JackEvent::XRun);
Control::Continue
}
}

View file

@ -1,109 +0,0 @@
use crate::*;
pub trait RegisterPort {
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>>;
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>>;
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>>;
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>>;
fn connect_midi_from (&self, my_input: &Port<MidiIn>, ports: &[String]) -> Usually<()>;
fn connect_midi_to (&self, my_output: &Port<MidiOut>, ports: &[String]) -> Usually<()>;
fn connect_audio_from (&self, my_input: &Port<AudioIn>, ports: &[String]) -> Usually<()>;
fn connect_audio_to (&self, my_output: &Port<AudioOut>, ports: &[String]) -> Usually<()>;
}
impl RegisterPort for Arc<RwLock<JackConnection>> {
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>> {
Ok(self.read().unwrap().client().register_port(name, MidiIn::default())?)
}
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>> {
Ok(self.read().unwrap().client().register_port(name, MidiOut::default())?)
}
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>> {
Ok(self.read().unwrap().client().register_port(name, AudioOut::default())?)
}
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>> {
Ok(self.read().unwrap().client().register_port(name, AudioIn::default())?)
}
fn connect_midi_from (&self, input: &Port<MidiIn>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_midi_to (&self, output: &Port<MidiOut>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_from (&self, input: &Port<AudioIn>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_to (&self, output: &Port<AudioOut>, ports: &[String]) -> Usually<()> {
let jack = self.read().unwrap();
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
}
/// Trait for things that may expose JACK ports.
pub trait Ports {
fn audio_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn audio_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn midi_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
fn midi_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
Ok(vec![])
}
}
fn register_ports<T: PortSpec + Copy>(
client: &Client,
names: Vec<String>,
spec: T,
) -> Usually<BTreeMap<String, Port<T>>> {
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<String>) -> BTreeMap<String, Port<Unowned>> {
names.into_iter().fold(BTreeMap::new(), |mut ports, name| {
let port = client.port_by_name(&name).unwrap();
ports.insert(name, port);
ports
})
}