pub(crate) use tek_core::*; pub(crate) use tek_core::midly::{*, live::LiveEvent, num::u7}; pub(crate) use std::thread::JoinHandle; pub(crate) use std::fmt::{Debug, Formatter, Error}; pub(crate) use tek_core::jack::{ Client, ProcessScope, Control, CycleTimes, Port, MidiIn, MidiOut, AudioIn, AudioOut, Unowned, Transport, TransportState, MidiIter, RawMidi }; submod! { api_clip api_clock api_color api_jack api_phrase api_player api_scene api_track //api_mixer //api_channel //api_plugin //api_plugin_kind //api_plugin_lv2 //api_sampler //api_sampler_sample //api_sampler_voice } pub trait JackActivate: Sized { fn activate_with ( self, init: impl FnOnce(&Arc>)->Usually ) -> Usually>>; } impl JackActivate for JackClient { fn activate_with ( self, init: impl FnOnce(&Arc>)->Usually ) -> Usually>> { let client = Arc::new(RwLock::new(self)); let target = Arc::new(RwLock::new(init(&client)?)); let event = Box::new(move|_|{/*TODO*/}) as Box; let events = Notifications(event); let frame = Box::new({ let target = target.clone(); move|c: &_, s: &_|if let Ok(mut target) = target.write() { target.process(c, s) } else { Control::Quit } }); let frames = tek_core::jack::contrib::ClosureProcessHandler::new(frame as BoxedAudioHandler); let mut buffer = Self::Activating; std::mem::swap(&mut*client.write().unwrap(), &mut buffer); *client.write().unwrap() = Self::Active(Client::from(buffer).activate_async(events, frames)?); Ok(target) } } /// Trait for things that have a JACK process callback. pub trait Audio: Send + Sync { fn process(&mut self, _: &Client, _: &ProcessScope) -> Control { Control::Continue } fn callback( state: &Arc>, client: &Client, scope: &ProcessScope ) -> Control where Self: Sized { if let Ok(mut state) = state.write() { state.process(client, scope) } else { Control::Quit } } } /// A UI component that may be associated with a JACK client by the `Jack` factory. pub trait AudioComponent: Component + Audio { /// Perform type erasure for collecting heterogeneous devices. fn boxed(self) -> Box> where Self: Sized + 'static, { Box::new(self) } } /// All things that implement the required traits can be treated as `AudioComponent`. impl + Audio> AudioComponent for W {} /// Trait for things that may expose JACK ports. pub trait Ports { fn audio_ins(&self) -> Usually>> { Ok(vec![]) } fn audio_outs(&self) -> Usually>> { Ok(vec![]) } fn midi_ins(&self) -> Usually>> { Ok(vec![]) } fn midi_outs(&self) -> Usually>> { Ok(vec![]) } } fn register_ports( client: &Client, names: Vec, spec: T, ) -> Usually>> { 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) -> BTreeMap> { names.into_iter().fold(BTreeMap::new(), |mut ports, name| { let port = client.port_by_name(&name).unwrap(); ports.insert(name, port); ports }) } ///// A [AudioComponent] bound to a JACK client and a set of ports. //pub struct JackDevice { ///// The active JACK client of this device. //pub client: DynamicAsyncClient, ///// The device state, encapsulated for sharing between threads. //pub state: Arc>>>, ///// 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 std::fmt::Debug for JackDevice { //fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { //f.debug_struct("JackDevice") //.field("ports", &self.ports) //.finish() //} //} //impl Widget for JackDevice { //type Engine = E; //fn layout(&self, to: E::Size) -> Perhaps { //self.state.read().unwrap().layout(to) //} //fn render(&self, to: &mut E::Output) -> Usually<()> { //self.state.read().unwrap().render(to) //} //} //impl Handle for JackDevice { //fn handle(&mut self, from: &E::Input) -> Perhaps { //self.state.write().unwrap().handle(from) //} //} //impl Ports for JackDevice { //fn audio_ins(&self) -> Usually>> { //Ok(self.ports.audio_ins.values().collect()) //} //fn audio_outs(&self) -> Usually>> { //Ok(self.ports.audio_outs.values().collect()) //} //fn midi_ins(&self) -> Usually>> { //Ok(self.ports.midi_ins.values().collect()) //} //fn midi_outs(&self) -> Usually>> { //Ok(self.ports.midi_outs.values().collect()) //} //} //impl JackDevice { ///// Returns a locked mutex of the state's contents. //pub fn state(&self) -> LockResult>>> { //self.state.read() //} ///// Returns a locked mutex of the state's contents. //pub fn state_mut(&self) -> LockResult>>> { //self.state.write() //} //pub fn connect_midi_in(&self, index: usize, port: &Port) -> Usually<()> { //Ok(self //.client //.as_client() //.connect_ports(port, self.midi_ins()?[index])?) //} //pub fn connect_midi_out(&self, index: usize, port: &Port) -> Usually<()> { //Ok(self //.client //.as_client() //.connect_ports(self.midi_outs()?[index], port)?) //} //pub fn connect_audio_in(&self, index: usize, port: &Port) -> Usually<()> { //Ok(self //.client //.as_client() //.connect_ports(port, self.audio_ins()?[index])?) //} //pub fn connect_audio_out(&self, index: usize, port: &Port) -> Usually<()> { //Ok(self //.client //.as_client() //.connect_ports(self.audio_outs()?[index], port)?) //} //} ///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut]. //#[derive(Default, Debug)] //pub struct JackPorts { //pub audio_ins: BTreeMap>, //pub midi_ins: BTreeMap>, //pub audio_outs: BTreeMap>, //pub midi_outs: BTreeMap>, //} ///// Collection of JACK ports as [Unowned]. //#[derive(Default, Debug)] //pub struct UnownedJackPorts { //pub audio_ins: BTreeMap>, //pub midi_ins: BTreeMap>, //pub audio_outs: BTreeMap>, //pub midi_outs: BTreeMap>, //} //impl JackPorts { //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(), port.clone_unowned()); //} //for (name, port) in self.midi_outs.iter() { //unowned.midi_outs.insert(name.clone(), port.clone_unowned()); //} //for (name, port) in self.audio_ins.iter() { //unowned.audio_ins.insert(name.clone(), port.clone_unowned()); //} //for (name, port) in self.audio_outs.iter() { //unowned //.audio_outs //.insert(name.clone(), port.clone_unowned()); //} //unowned //} //} ///// Implement the `Ports` trait. //#[macro_export] //macro_rules! ports { //($T:ty $({ $(audio: { //$(ins: |$ai_arg:ident|$ai_impl:expr,)? //$(outs: |$ao_arg:ident|$ao_impl:expr,)? //})? $(midi: { //$(ins: |$mi_arg:ident|$mi_impl:expr,)? //$(outs: |$mo_arg:ident|$mo_impl:expr,)? //})?})?) => { //impl Ports for $T {$( //$( //$(fn audio_ins <'a> (&'a self) -> Usually>> { //let cb = |$ai_arg:&'a Self|$ai_impl; //cb(self) //})? //)? //$( //$(fn audio_outs <'a> (&'a self) -> Usually>> { //let cb = (|$ao_arg:&'a Self|$ao_impl); //cb(self) //})? //)? //)? $( //$( //$(fn midi_ins <'a> (&'a self) -> Usually>> { //let cb = (|$mi_arg:&'a Self|$mi_impl); //cb(self) //})? //)? //$( //$(fn midi_outs <'a> (&'a self) -> Usually>> { //let cb = (|$mo_arg:&'a Self|$mo_impl); //cb(self) //})? //)? //)?} //}; //} ///// `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, //pub audio_ins: Vec, //pub midi_outs: Vec, //pub audio_outs: Vec, //} //impl Jack { //pub fn new(name: &str) -> Usually { //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, //) -> Usually> //where //D: AudioComponent + 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::>>()?; //let midi_ins = owned_ports //.midi_ins //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let audio_outs = owned_ports //.audio_outs //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let audio_ins = owned_ports //.audio_ins //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); //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), //contrib::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 //} //} //impl Command for ArrangerSceneCommand { //} //Edit(phrase) => { state.state.phrase = phrase.clone() }, //ToggleViewMode => { state.state.mode.to_next(); }, //Delete => { state.state.delete(); }, //Activate => { state.state.activate(); }, //ZoomIn => { state.state.zoom_in(); }, //ZoomOut => { state.state.zoom_out(); }, //MoveBack => { state.state.move_back(); }, //MoveForward => { state.state.move_forward(); }, //RandomColor => { state.state.randomize_color(); }, //Put => { state.state.phrase_put(); }, //Get => { state.state.phrase_get(); }, //AddScene => { state.state.scene_add(None, None)?; }, //AddTrack => { state.state.track_add(None, None)?; }, //ToggleLoop => { state.state.toggle_loop() }, //pub fn zoom_in (&mut self) { //if let ArrangerEditorMode::Vertical(factor) = self.mode { //self.mode = ArrangerEditorMode::Vertical(factor + 1) //} //} //pub fn zoom_out (&mut self) { //if let ArrangerEditorMode::Vertical(factor) = self.mode { //self.mode = ArrangerEditorMode::Vertical(factor.saturating_sub(1)) //} //} //pub fn move_back (&mut self) { //match self.selected { //ArrangerEditorFocus::Scene(s) => { //if s > 0 { //self.scenes.swap(s, s - 1); //self.selected = ArrangerEditorFocus::Scene(s - 1); //} //}, //ArrangerEditorFocus::Track(t) => { //if t > 0 { //self.tracks.swap(t, t - 1); //self.selected = ArrangerEditorFocus::Track(t - 1); //// FIXME: also swap clip order in scenes //} //}, //_ => todo!("arrangement: move forward") //} //} //pub fn move_forward (&mut self) { //match self.selected { //ArrangerEditorFocus::Scene(s) => { //if s < self.scenes.len().saturating_sub(1) { //self.scenes.swap(s, s + 1); //self.selected = ArrangerEditorFocus::Scene(s + 1); //} //}, //ArrangerEditorFocus::Track(t) => { //if t < self.tracks.len().saturating_sub(1) { //self.tracks.swap(t, t + 1); //self.selected = ArrangerEditorFocus::Track(t + 1); //// FIXME: also swap clip order in scenes //} //}, //_ => todo!("arrangement: move forward") //} //} //impl From for Clock { //fn from (current: Instant) -> Self { //Self { //playing: Some(TransportState::Stopped).into(), //started: None.into(), //quant: 24.into(), //sync: (current.timebase.ppq.get() * 4.).into(), //current, //} //} //}