//! Audio engine. use crate::core::*; submod!( device event factory ports ); pub(crate) use ::_jack::{ AsyncClient, AudioIn, AudioOut, Client, ClientOptions, ClientStatus, ClosureProcessHandler, Control, CycleTimes, Frames, MidiIn, MidiIter, MidiOut, NotificationHandler, Port, PortFlags, PortId, PortSpec, ProcessScope, RawMidi, Transport, TransportState, Unowned }; /// Wraps [Client] or [DynamicAsyncClient] in place. pub enum JackClient { Inactive(Client), Active(DynamicAsyncClient), } impl JackClient { pub fn client (&self) -> &Client { match self { Self::Inactive(ref client) => client, Self::Active(ref client) => client.as_client(), } } pub fn transport (&self) -> Transport { self.client().transport() } pub fn port_by_name (&self, name: &str) -> Option> { self.client().port_by_name(name) } pub fn register_port (&self, name: &str, spec: PS) -> Usually> { Ok(self.client().register_port(name, spec)?) } pub fn activate ( self, state: &Arc>, mut process: impl FnMut(&Arc>, &Client, &ProcessScope)->Control + Send + 'static ) -> Usually { Ok(match self { Self::Active(_) => self, Self::Inactive(client) => Self::Active(client.activate_async( Notifications(Box::new(move|_|{/*TODO*/}) as Box), ClosureProcessHandler::new(Box::new({ let state = state.clone(); move|c: &Client, s: &ProcessScope|process(&state, c, s) }) as BoxedProcessHandler) )?) }) } } pub type DynamicAsyncClient = AsyncClient; type DynamicProcessHandler = ClosureProcessHandler; pub type BoxedProcessHandler = Box Control + Send>; /// Trait for things that have a JACK process callback. pub trait Process { fn process (&mut self, _: &Client, _: &ProcessScope) -> Control { Control::Continue } } /// Define the JACK process callback associated with a struct. #[macro_export] macro_rules! process { ($T:ty) => { impl Process for $T {} }; ($T:ty |$self:ident, $c:ident, $s:ident|$block:tt) => { impl Process for $T { fn process (&mut $self, $c: &Client, $s: &ProcessScope) -> Control { $block } } }; ($T:ty = $process:path) => { impl Process for $T { fn process (&mut self, c: &Client, s: &ProcessScope) -> Control { $process(self, c, s) } } } } /// Just run thing with JACK. Returns the activated client. pub fn jack_run (name: &str, app: &Arc>) -> Usually where T: Handle + Process + Send + 'static { let options = ClientOptions::NO_START_SERVER; let (client, _status) = Client::new(name, options)?; Ok(client.activate_async( Notifications(Box::new({ let _app = app.clone(); move|_event|{ // FIXME: this deadlocks //app.lock().unwrap().handle(&event).unwrap(); } }) as Box), ClosureProcessHandler::new(Box::new({ let app = app.clone(); move|c: &Client, s: &ProcessScope|{ app.write().unwrap().process(c, s) //Control::Continue } }) as BoxedProcessHandler) )?) }