nice (and working) port connect api

This commit is contained in:
🪞👃🪞 2024-07-05 00:49:24 +03:00
parent f928b026ed
commit 3ed9ebddd4
7 changed files with 209 additions and 190 deletions

View file

@ -25,4 +25,16 @@ impl JackDevice {
pub fn state (&self) -> MutexGuard<Box<dyn Device>> {
self.state.lock().unwrap()
}
pub fn connect_midi_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
Ok(self.client.as_client().connect_ports(port, self.midi_ins()?[index])?)
}
pub fn connect_midi_out (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
Ok(self.client.as_client().connect_ports(self.midi_outs()?[index], port)?)
}
pub fn connect_audio_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
Ok(self.client.as_client().connect_ports(port, self.audio_ins()?[index])?)
}
pub fn connect_audio_out (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
Ok(self.client.as_client().connect_ports(self.audio_outs()?[index], port)?)
}
}

View file

@ -3,22 +3,44 @@ use super::*;
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
/// and activation, and encapsulates a `Device` into a `JackDevice`.
pub struct Jack {
pub client: Client,
pub ports: JackPorts,
pub client: Client,
pub midi_ins: Vec<String>,
pub audio_ins: Vec<String>,
pub midi_outs: Vec<String>,
pub audio_outs: Vec<String>,
}
impl Jack {
pub fn new (name: &str) -> Usually<Self> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
Ok(Self { client, ports: JackPorts::default() })
Ok(Self {
midi_ins: vec![],
audio_ins: vec![],
midi_outs: vec![],
audio_outs: vec![],
client: Client::new(
name,
ClientOptions::NO_START_SERVER
)?.0,
})
}
pub fn run <T: Device + Process + Sized + 'static> (
mut self, state: impl FnOnce(JackPorts)->Box<T>
self, state: impl FnOnce(JackPorts)->Box<T>
)
-> Usually<JackDevice>
{
let mut owned_ports = JackPorts::default();
std::mem::swap(&mut self.ports, &mut owned_ports);
let unowned_ports = owned_ports.clone_unowned(&self.client);
let owned_ports = JackPorts {
audio_ins: register_ports(&self.client, self.audio_ins, AudioIn)?,
audio_outs: register_ports(&self.client, self.audio_outs, AudioOut)?,
midi_ins: register_ports(&self.client, self.midi_ins, MidiIn)?,
midi_outs: register_ports(&self.client, self.midi_outs, MidiOut)?,
};
let midi_outs = owned_ports.midi_outs.values()
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
let midi_ins = owned_ports.midi_ins.values()
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
let audio_outs = owned_ports.audio_outs.values()
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
let audio_ins = owned_ports.audio_ins.values()
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
let state = Arc::new(Mutex::new(state(owned_ports) as Box<dyn Device>));
let client = self.client.activate_async(
Notifications(Box::new({
@ -35,44 +57,68 @@ impl Jack {
}
}) as BoxedProcessHandler)
)?;
Ok(JackDevice { client, state, ports: unowned_ports })
Ok(JackDevice {
ports: UnownedJackPorts {
audio_ins: query_ports(&client.as_client(), audio_ins),
audio_outs: query_ports(&client.as_client(), audio_outs),
midi_ins: query_ports(&client.as_client(), midi_ins),
midi_outs: query_ports(&client.as_client(), midi_outs),
},
client,
state,
})
}
pub fn ports_from_lv2 (self, plugin: &::livi::Plugin) -> Usually<Self> {
pub fn ports_from_lv2 (self, plugin: &::livi::Plugin) -> Self {
let counts = plugin.port_counts();
let mut jack = self;
for i in 0..counts.atom_sequence_inputs {
jack = jack.register_midi_in(&format!("midi-in-{i}"))?
jack = jack.midi_in(&format!("midi-in-{i}"))
}
for i in 0..counts.atom_sequence_outputs {
jack = jack.register_midi_out(&format!("midi-out-{i}"))?;
jack = jack.midi_out(&format!("midi-out-{i}"));
}
for i in 0..counts.audio_inputs {
jack = jack.register_audio_in(&format!("audio-in-{i}"))?
jack = jack.audio_in(&format!("audio-in-{i}"));
}
for i in 0..counts.audio_outputs {
jack = jack.register_audio_out(&format!("audio-out-{i}"))?;
jack = jack.audio_out(&format!("audio-out-{i}"));
}
Ok(jack)
jack
}
pub fn register_midi_out (mut self, name: &str) -> Usually<Self> {
let port = self.client.register_port(name, MidiOut::default())?;
self.ports.midi_outs.insert(name.to_string(), port);
Ok(self)
pub fn audio_in (mut self, name: &str) -> Self {
self.audio_ins.push(name.to_string());
self
}
pub fn register_midi_in (mut self, name: &str) -> Usually<Self> {
let port = self.client.register_port(name, MidiIn::default())?;
self.ports.midi_ins.insert(name.to_string(), port);
Ok(self)
pub fn audio_out (mut self, name: &str) -> Self {
self.audio_outs.push(name.to_string());
self
}
pub fn register_audio_out (mut self, name: &str) -> Usually<Self> {
let port = self.client.register_port(name, AudioOut::default())?;
self.ports.audio_outs.insert(name.to_string(), port);
Ok(self)
pub fn midi_in (mut self, name: &str) -> Self {
self.midi_ins.push(name.to_string());
self
}
pub fn register_audio_in (mut self, name: &str) -> Usually<Self> {
let port = self.client.register_port(name, AudioIn::default())?;
self.ports.audio_ins.insert(name.to_string(), port);
Ok(self)
pub fn midi_out (mut self, name: &str) -> Self {
self.midi_outs.push(name.to_string());
self
}
}
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

@ -2,7 +2,6 @@ use super::*;
#[derive(Default)]
pub struct JackPorts {
lifesaver: Arc<()>,
pub audio_ins: BTreeMap<String, Port<AudioIn>>,
pub midi_ins: BTreeMap<String, Port<MidiIn>>,
pub audio_outs: BTreeMap<String, Port<AudioOut>>,
@ -18,27 +17,19 @@ pub struct UnownedJackPorts {
}
impl JackPorts {
pub fn clone_unowned (&self, client: &Client) -> UnownedJackPorts {
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(), unsafe {
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
});
unowned.midi_ins.insert(name.clone(), port.clone_unowned());
}
for (name, port) in self.midi_outs.iter() {
unowned.midi_outs.insert(name.clone(), unsafe {
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
});
unowned.midi_outs.insert(name.clone(), port.clone_unowned());
}
for (name, port) in self.audio_ins.iter() {
unowned.audio_ins.insert(name.clone(), unsafe {
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
});
unowned.audio_ins.insert(name.clone(), port.clone_unowned());
}
for (name, port) in self.audio_outs.iter() {
unowned.audio_outs.insert(name.clone(), unsafe {
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
});
unowned.audio_outs.insert(name.clone(), port.clone_unowned());
}
unowned
}