mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 12:46:42 +01:00
flatten jack module
This commit is contained in:
parent
b78b55faa2
commit
e8b97bed37
3 changed files with 182 additions and 186 deletions
190
src/jack.rs
190
src/jack.rs
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub use ::jack as libjack;
|
pub use ::jack as libjack;
|
||||||
pub use ::jack::{
|
pub use ::jack::{
|
||||||
contrib::ClosureProcessHandler, NotificationHandler,
|
contrib::ClosureProcessHandler, NotificationHandler,
|
||||||
|
|
@ -9,13 +8,6 @@ pub use ::jack::{
|
||||||
Transport, TransportState, MidiIter, MidiWriter, RawMidi,
|
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.
|
/// Implement [TryFrom<&Arc<RwLock<JackConnection>>>]: create app state from wrapped JACK handle.
|
||||||
#[macro_export] macro_rules! from_jack {
|
#[macro_export] macro_rules! from_jack {
|
||||||
(|$jack:ident|$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)? $cb:expr) => {
|
(|$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.
|
///// 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`.
|
///// All things that implement the required traits can be treated as `AudioComponent`.
|
||||||
//impl<E: Engine, W: Component<E> + Audio> AudioComponent<E> for W {}
|
//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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue