use crate::*; impl App { /// FIXME: generalize. Set picked device in device pick dialog. /// /// ``` /// tek::App::default().device_pick(0); /// ``` pub fn device_pick (&mut self, index: usize) { self.dialog = Dialog::Device(index); } /// FIXME: generalize. Add device to current track. pub fn add_device (&mut self, index: usize) -> Usually<()> { match index { 0 => { let name = self.jack.with_client(|c|c.name().to_string()); let midi = self.project.track().expect("no active track").sequencer.midi_outs[0].port_name(); let track = self.track().expect("no active track"); let port = format!("{}/Sampler", &track.name); let connect = Connect::exact(format!("{name}:{midi}")); let sampler = if let Ok(sampler) = Sampler::new( &self.jack, &port, &[connect], &[&[], &[]], &[&[], &[]] ) { self.dialog = Dialog::None; Device::Sampler(sampler) } else { self.dialog = Dialog::Message("Failed to add device.".into()); return Err("failed to add device".into()) }; let track = self.track_mut().expect("no active track"); track.devices.push(sampler); Ok(()) }, 1 => { todo!(); //Ok(()) }, _ => unreachable!(), } } } impl HasJack<'static> for App { fn jack (&self) -> &Jack<'static> { &self.jack } } impl_audio!(App: tek_jack_process, tek_jack_event); fn tek_jack_process (state: &mut App, client: &Client, scope: &ProcessScope) -> Control { let t0 = state.perf.get_t0(); state.clock().update_from_scope(scope).unwrap(); let midi_in = state.project.midi_input_collect(scope); if let Some(editor) = &state.editor() { let mut pitch: Option = None; for port in midi_in.iter() { for event in port.iter() { if let (_, Ok(LiveEvent::Midi {message: MidiMessage::NoteOn {key, ..}, ..})) = event { pitch = Some(key.clone()); } } } if let Some(pitch) = pitch { editor.set_note_pos(pitch.as_int() as usize); } } let result = state.project.tracks_jack_process(client, scope); state.perf.update_from_jack_scope(t0, scope); result } fn tek_jack_event (state: &mut App, event: JackEvent) { use JackEvent::*; match event { SampleRate(sr) => { state.clock().timebase.sr.set(sr as f64); }, PortRegistration(_id, true) => { //let port = self.jack().port_by_id(id); //println!("\rport add: {id} {port:?}"); //println!("\rport add: {id}"); }, PortRegistration(_id, false) => { /*println!("\rport del: {id}")*/ }, PortsConnected(_a, _b, true) => { /*println!("\rport conn: {a} {b}")*/ }, PortsConnected(_a, _b, false) => { /*println!("\rport disc: {a} {b}")*/ }, ClientRegistration(_id, true) => {}, ClientRegistration(_id, false) => {}, ThreadInit => {}, XRun => {}, GraphReorder => {}, _ => { panic!("{event:?}"); } } } #[tek_proc::command(Device)] #[tek_proc::keyword(Device)] #[derive(Debug)] pub enum DeviceCmd {} impl Device { pub fn name (&self) -> &str { match self { Self::Sampler(sampler) => sampler.name.as_ref(), _ => todo!(), } } pub fn midi_ins (&self) -> &[MidiInput] { match self { //Self::Sampler(Sampler { midi_in, .. }) => &[midi_in], _ => todo!() } } pub fn midi_outs (&self) -> &[MidiOutput] { match self { Self::Sampler(_) => &[], _ => todo!() } } pub fn audio_ins (&self) -> &[AudioInput] { match self { Self::Sampler(Sampler { audio_ins, .. }) => audio_ins.as_slice(), _ => todo!() } } pub fn audio_outs (&self) -> &[AudioOutput] { match self { Self::Sampler(Sampler { audio_outs, .. }) => audio_outs.as_slice(), _ => todo!() } } } /// A device that can be plugged into the chain. /// /// ``` /// let device = tek::Device::default(); /// ``` #[derive(Debug, Default)] pub enum Device { #[default] Bypass, Mute, #[cfg(feature = "sampler")] Sampler(Sampler), #[cfg(feature = "lv2")] // TODO Lv2(Lv2), #[cfg(feature = "vst2")] // TODO Vst2, #[cfg(feature = "vst3")] // TODO Vst3, #[cfg(feature = "clap")] // TODO Clap, #[cfg(feature = "sf2")] // TODO Sf2, } /// Some sort of wrapper? pub struct DeviceAudio<'a>(pub &'a mut Device); impl_audio!(|self: DeviceAudio<'a>, client, scope|{ use Device::*; match self.0 { Mute => { Control::Continue }, Bypass => { /*TODO*/ Control::Continue }, #[cfg(feature = "sampler")] Sampler(sampler) => sampler.process(client, scope), #[cfg(feature = "lv2")] Lv2(lv2) => lv2.process(client, scope), #[cfg(feature = "vst2")] Vst2 => { todo!() }, // TODO #[cfg(feature = "vst3")] Vst3 => { todo!() }, // TODO #[cfg(feature = "clap")] Clap => { todo!() }, // TODO #[cfg(feature = "sf2")] Sf2 => { todo!() }, // TODO } }); pub fn device_kinds () -> &'static [&'static str] { &[ #[cfg(feature = "sampler")] "Sampler", #[cfg(feature = "lv2")] "Plugin (LV2)", ] } impl> + AsMut>> HasDevices for T { fn devices (&self) -> &Vec { self.as_ref() } fn devices_mut (&mut self) -> &mut Vec { self.as_mut() } }