mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 04:36:45 +01:00
197 lines
7.1 KiB
Rust
197 lines
7.1 KiB
Rust
use crate::*
|
|
/// A [AudioComponent] bound to a JACK client and a set of ports.
|
|
pub struct JackDevice<E: Engine> {
|
|
/// The active JACK client of this device.
|
|
pub client: DynamicAsyncClient,
|
|
/// The device state, encapsulated for sharing between threads.
|
|
pub state: Arc<RwLock<Box<dyn AudioComponent<E>>>>,
|
|
/// Unowned copies of the device's JACK ports, for connecting to the device.
|
|
/// The "real" readable/writable `Port`s are owned by the `state`.
|
|
pub ports: UnownedJackPorts,
|
|
}
|
|
impl<E: Engine> std::fmt::Debug for JackDevice<E> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("JackDevice")
|
|
.field("ports", &self.ports)
|
|
.finish()
|
|
}
|
|
}
|
|
impl<E: Engine> Render for JackDevice<E> {
|
|
type Engine = E;
|
|
fn min_size(&self, to: E::Size) -> Perhaps<E::Size> {
|
|
self.state.read().unwrap().layout(to)
|
|
}
|
|
fn render(&self, to: &mut E::Output) -> Usually<()> {
|
|
self.state.read().unwrap().render(to)
|
|
}
|
|
}
|
|
impl<E: Engine> Handle<E> for JackDevice<E> {
|
|
fn handle(&mut self, from: &E::Input) -> Perhaps<E::Handled> {
|
|
self.state.write().unwrap().handle(from)
|
|
}
|
|
}
|
|
impl<E: Engine> Ports for JackDevice<E> {
|
|
fn audio_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
|
|
Ok(self.ports.audio_ins.values().collect())
|
|
}
|
|
fn audio_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
|
|
Ok(self.ports.audio_outs.values().collect())
|
|
}
|
|
fn midi_ins(&self) -> Usually<Vec<&Port<Unowned>>> {
|
|
Ok(self.ports.midi_ins.values().collect())
|
|
}
|
|
fn midi_outs(&self) -> Usually<Vec<&Port<Unowned>>> {
|
|
Ok(self.ports.midi_outs.values().collect())
|
|
}
|
|
}
|
|
impl<E: Engine> JackDevice<E> {
|
|
/// Returns a locked mutex of the state's contents.
|
|
pub fn state(&self) -> LockResult<RwLockReadGuard<Box<dyn AudioComponent<E>>>> {
|
|
self.state.read()
|
|
}
|
|
/// Returns a locked mutex of the state's contents.
|
|
pub fn state_mut(&self) -> LockResult<RwLockWriteGuard<Box<dyn AudioComponent<E>>>> {
|
|
self.state.write()
|
|
}
|
|
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)?)
|
|
}
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
|
///// and activation, and encapsulates a `AudioComponent` into a `JackDevice`.
|
|
//pub struct Jack {
|
|
//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> {
|
|
//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<'a: 'static, D, E>(
|
|
//self,
|
|
//state: impl FnOnce(JackPorts) -> Box<D>,
|
|
//) -> Usually<JackDevice<E>>
|
|
//where
|
|
//D: AudioComponent<E> + Sized + 'static,
|
|
//E: Engine + 'static,
|
|
//{
|
|
//let owned_ports = JackPorts {
|
|
//audio_ins: register_ports(&self.client, self.audio_ins, AudioIn::default())?,
|
|
//audio_outs: register_ports(&self.client, self.audio_outs, AudioOut::default())?,
|
|
//midi_ins: register_ports(&self.client, self.midi_ins, MidiIn::default())?,
|
|
//midi_outs: register_ports(&self.client, self.midi_outs, MidiOut::default())?,
|
|
//};
|
|
//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(RwLock::new(state(owned_ports) as Box<dyn AudioComponent<E>>));
|
|
//let client = self.client.activate_async(
|
|
//Notifications(Box::new({
|
|
//let _state = state.clone();
|
|
//move |_event| {
|
|
//// FIXME: this deadlocks
|
|
////state.lock().unwrap().handle(&event).unwrap();
|
|
//}
|
|
//}) as Box<dyn Fn(JackEvent) + Send + Sync>),
|
|
//ClosureProcessHandler::new(Box::new({
|
|
//let state = state.clone();
|
|
//move |c: &Client, s: &ProcessScope| state.write().unwrap().process(c, s)
|
|
//}) as BoxedAudioHandler),
|
|
//)?;
|
|
//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 audio_in(mut self, name: &str) -> Self {
|
|
//self.audio_ins.push(name.to_string());
|
|
//self
|
|
//}
|
|
//pub fn audio_out(mut self, name: &str) -> Self {
|
|
//self.audio_outs.push(name.to_string());
|
|
//self
|
|
//}
|
|
//pub fn midi_in(mut self, name: &str) -> Self {
|
|
//self.midi_ins.push(name.to_string());
|
|
//self
|
|
//}
|
|
//pub fn midi_out(mut self, name: &str) -> Self {
|
|
//self.midi_outs.push(name.to_string());
|
|
//self
|
|
//}
|
|
//}
|
|
|
|
///// A UI component that may be associated with a JACK client by the `Jack` factory.
|
|
//pub trait AudioComponent<E: Engine>: Component<E> + Audio {
|
|
///// Perform type erasure for collecting heterogeneous devices.
|
|
//fn boxed(self) -> Box<dyn AudioComponent<E>>
|
|
//where
|
|
//Self: Sized + 'static,
|
|
//{
|
|
//Box::new(self)
|
|
//}
|
|
//}
|
|
|
|
///// All things that implement the required traits can be treated as `AudioComponent`.
|
|
//impl<E: Engine, W: Component<E> + Audio> AudioComponent<E> for W {}
|
|
|
|
/////////
|
|
|
|
/*
|
|
*/
|