mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56: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::*;
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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