use crate::*; tui_keys!(self: App, input { #[cfg(feature = "prof2")] profiling::scope!("App::tui_keys!"); self.input_cmds(input) }); impl App { fn input_cmds (&mut self, input: &TuiEvent) -> Usually<()> { if let Some(bindings) = Self::input_cmds_find(self, input) { return Self::input_cmds_exec(self, bindings) } Ok(()) } fn input_cmds_find (state: &Self, input: &TuiEvent) -> Option>]>> { for name in state.modes.read().iter().rev() { let mode = state.config.get_mode(name).as_ref().map(Arc::clone); if let Some(mode) = mode { let binds = state.config.binds.clone(); for id in mode.keys.iter() { if let Some(event_map) = binds.find(id) && let Some(bindings) = event_map.query(input) { return Some(bindings.into()) } } } } None } fn input_cmds_exec (state: &mut Self, bindings: Arc<[Binding>]>) -> Usually<()> { for binding in bindings.iter() { for src in binding.commands.iter() { if let Some(command) = Namespace::::namespace(state, &src)? { Self::cmd_dispatch(state, command)?; } } } Ok(()) } fn cmd_dispatch (state: &mut Self, command: AppCmd) -> Usually<()> { match command.clone().dispatch(state) { Ok(undo) => { state.history.push((command, undo)); Ok(()) }, Err(err) => { state.history.push((command, None)); Err(err) } } } } impl_from!(AppCmd: |x: AxisCmd| AppCmd::Axis { command: x }); impl_from!(AppCmd: |x: BrowseCmd| AppCmd::Browse { command: x }); impl_from!(AppCmd: |x: MidiClipCmd| AppCmd::MidiClip { command: x }); impl_from!(AppCmd: |x: MidiEditCmd| AppCmd::MidiEdit { command: x }); impl_from!(AppCmd: |x: ProjectCmd| AppCmd::Project { command: x }); impl_from!(AppCmd: |x: SceneCmd| AppCmd::Scene { command: x }); impl_from!(AppCmd: |x: ScenesCmd| AppCmd::Scenes { command: x }); impl_from!(AppCmd: |x: TrackCmd| AppCmd::Track { command: x }); impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x }); #[tek_proc::commands(AppCmd)] impl App { /// Exit the application. #[command(Exit = "exit")] pub fn cmd_exit (&mut self) -> Perhaps { self.exit.exit(); Ok(None) } /// Switch to another set of contextual modes. #[command(Mode = "mode")] pub fn cmd_mode (&mut self, modes: Vec>) -> Perhaps { *self.modes_mut() = modes.into(); Ok(None) } /// Enter a contextual mode. #[command(Enter = "enter")] pub fn enter_mode (&mut self, mode: Arc) -> Perhaps { let mut modes = self.modes_mut(); Ok(if modes.last() != Some(&mode) { modes.push(mode); Some(AppCmd::Leave) } else { None }) } /// Leave a contextual mode. #[command(Leave = "leave")] fn leave_mode (&mut self) -> Perhaps { let mut modes = self.modes_mut(); if modes.len() > 1 { let mode = modes.pop(); Ok(mode.map(|mode|AppCmd::Enter { mode })) } else { Ok(None) } } /// Navigate along a contextual axis. #[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } /// Cancel current selection. #[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps { todo!("cancel") } /// Confirm current selection. #[command(Confirm = "confirm")] pub fn cmd_confirm (&mut self) -> Perhaps { Ok(match self.dialog.clone() { Dialog::Menu(index, items) => { for command in items[index].1.iter() { App::cmd_dispatch(self, command.clone())?; } None } _ => todo!(), }) } /// Swap currently active modal dialog. /// /// ``` /// let _ = tek::App::default().cmd_dialog(tek::Dialog::welcome()); /// ``` #[command(Dialog = "dialog")] pub fn cmd_dialog (&mut self, dialog: Dialog) -> Perhaps { let mut dialog = dialog.clone(); std::mem::swap(&mut self.dialog, &mut dialog); Ok(Some(AppCmd::Dialog { dialog })) } /// Command the file browser. #[command(Browse = "browse")] pub fn cmd_browse (&mut self, command: BrowseCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } /// Commands that alter the current session. #[command(Project = "session")] pub fn cmd_session (&mut self, command: ProjectCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } /// Commands pertaining to MIDI clips. #[command(MidiClip = "clip")] pub fn cmd_midi_clip (&mut self, command: MidiClipCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } /// Commands pertaining to the MIDI clip editor. #[command(MidiEdit = "edit")] pub fn cmd_midi_edit (&mut self, command: MidiEditCmd) -> Perhaps { if matches!(command, MidiEditCmd::Toggle) { if self.is_editing() { self.leave_mode()?; } else { self.enter_mode("Edit".into())?; } } Ok(command.dispatch(self)?.map(Into::into)) } #[command(Scene = "scene")] pub fn cmd_scene (&mut self, command: SceneCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Scenes = "scenes")] pub fn cmd_scenes (&mut self, command: ScenesCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Track = "track")] pub fn cmd_track (&mut self, command: TrackCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Tracks = "tracks")] pub fn cmd_tracks (&mut self, command: TracksCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } //#[command(Pool = "pool")] pub fn cmd_pool (&mut self, command: PoolCmd) -> Perhaps { //Ok(command.dispatch(self)?.map(Into::into)) //} } impl ProjectControl for T {} #[tek_proc::commands(ProjectCmd)] pub trait ProjectControl: HasProject { #[command(LoadLast = "load-last")] fn load_last (&mut self) -> Perhaps { todo!() } #[command(Load = "load")] fn load (&mut self) -> Perhaps { todo!() } } impl ClockControl for T where T: HasClock + Namespace + Namespace + Namespace> {} #[tek_proc::commands(ClockCmd = "clock")] pub trait ClockControl: HasClock + Namespace + Namespace + Namespace> { #[command(SeekUsec = "usec")] fn seek_usec (&mut self, usec: f64) -> Perhaps { self.clock().playhead.update_from_usec(usec); Ok(None) } #[command(SeekSample = "sample")] fn seek_sample (&mut self, sample: f64) -> Perhaps { self.clock().playhead.update_from_sample(sample); Ok(None) } #[command(SeekPulse = "pulse")] fn seek_pulse (&mut self, pulse: f64) -> Perhaps { self.clock().playhead.update_from_pulse(pulse); Ok(None) } #[command(SetBpm = "bpm")] fn set_bpm (&mut self, bpm: f64) -> Perhaps { Ok(Some(ClockCmd::SetBpm { bpm: self.clock().timebase().bpm.set(bpm) })) } #[command(SetQuant = "quant")] fn set_quant (&mut self, quant: f64) -> Perhaps { Ok(Some(ClockCmd::SetQuant { quant: self.clock().quant.set(quant) })) } #[command(SetSync = "sync")] fn set_sync (&mut self, sync: f64) -> Perhaps { Ok(Some(ClockCmd::SetSync { sync: self.clock().sync.set(sync) })) } #[command(Play = "play")] fn play (&mut self, position: Option) -> Perhaps { self.clock().play_from(position)?; Ok(None) /* TODO Some(Pause(previousPosition)) */ } #[command(Pause = "pause")] fn pause (&mut self, position: Option) -> Perhaps { self.clock().pause_at(position)?; Ok(None) } #[command(TogglePlayback = "toggle")] fn toggle (&mut self, position: u32) -> Perhaps { Ok(if self.clock().is_rolling() { self.clock().pause_at(Some(position))?; None } else { self.clock().play_from(Some(position))?; None }) } } impl TracksControl for T where T: HasTracks + HasScenes + HasSelection + HasJack<'static> + Namespace {} #[tek_proc::commands(TracksCmd)] pub trait TracksControl: HasTracks + HasScenes + HasSelection + HasJack<'static> + Namespace { /// Stop all playing clips #[command(Stop = "stop")] fn tracks_stop_all (&mut self) -> Perhaps { for track in self.tracks_mut().iter_mut() { track.sequencer.enqueue_next(None); } Ok(None) } /// Launch multiple clips #[command(Launch = "launch")] fn tracks_launch (&mut self, clips: ClipPool) -> Perhaps { if clips.len() == 0 { for track in self.tracks_mut().iter_mut() { track.sequencer.enqueue_next(None); } return Ok(None) } for (clip, track) in clips.0.read().iter().zip(self.tracks_mut()) { track.sequencer.enqueue_next(clip.read().as_ref()); } Ok(None) } #[command(Add = "add")] fn tracks_add (&mut self) -> Perhaps where Self: HasScenes + HasJack<'static> + Sized { let (_index, _) = self.tracks_add_one(None, None, [].into(), [].into())?; Ok(None) } #[command(Select = "select")] fn track_select (&mut self) -> Perhaps { let tracks = self.tracks().len(); let select = self.selection_mut().select_track(tracks); *self.selection_mut() = select; Ok(None) } #[command(Next = "next")] fn track_select_next (&mut self) -> Perhaps { let tracks = self.tracks().len(); let select = self.selection().select_track_next(tracks); *self.selection_mut() = select; Ok(None) } #[command(Prev = "prev")] fn track_select_prev (&mut self) -> Perhaps { let select = self.selection_mut().select_track_prev(); *self.selection_mut() = select; Ok(None) } /// Run audio callbacks for every track and every device fn tracks_jack_process (&mut self, client: &Client, scope: &ProcessScope) -> Control where Self: HasJack<'static> { for track in self.tracks_mut().iter_mut() { if Control::Quit == Audio::process(&mut track.sequencer, client, scope) { return Control::Quit } for device in track.devices.iter_mut() { if Control::Quit == DeviceAudio(device).process(client, scope) { return Control::Quit } } } Control::Continue } /// Add multiple tracks fn tracks_add_many ( &mut self, count: usize, width: Option, mins: Arc<[Connect]>, mouts: Arc<[Connect]>, ) -> Usually<()> where Self: HasJack<'static> + HasScenes { let track_color_1 = ItemColor::random(); let track_color_2 = ItemColor::random(); for i in 0..count { let color = track_color_1.mix(track_color_2, i as f32 / count as f32).into(); let track = self.tracks_add_one(None, Some(color), mins.clone(), mouts.clone())?.1; if let Some(width) = width { track.width = width; } } Ok(()) } /// Add a track fn tracks_add_one ( &mut self, name: Option>, color: Option, mins: Arc<[Connect]>, mouts: Arc<[Connect]>, ) -> Usually<(usize, &mut Track)> where Self: HasJack<'static> + HasScenes { let name: Arc = name.map_or_else( ||format!("trk{}", self.tracks_last()).into(), |x|x.to_string().into() ); *self.tracks_last_mut() += 1; let track = Track::new_added(self.jack(), Some(self.clock()), &name, color, None, mins, mouts)?; self.tracks_mut().push(track); let len = self.tracks().len(); let index = len - 1; for scene in self.scenes_mut().iter_mut() { while scene.clips.len() < len { scene.clips.append(None); } } Ok((index, &mut self.tracks_mut()[index])) } fn track_longest_name (&self) -> usize { self.tracks().iter().map(|s|s.name.len()).fold(0, usize::max) } } impl + Namespace> + Namespace + Namespace> > TrackControl for T {} #[tek_proc::commands(TrackCmd)] pub trait TrackControl: HasTrack + Namespace + Namespace> + Namespace + Namespace> { #[command(Stop = "track/stop")] fn track_stop (&mut self) -> Perhaps { self.track_mut().map(|track|track.sequencer.enqueue_next(None)); Ok(None) } #[command(SetMute = "track/mute")] fn track_set_mute (&mut self, _mute: Option) -> Perhaps { todo!() } #[command(SetSolo = "track/solo")] fn track_set_solo (&mut self, _solo: Option) -> Perhaps { todo!() } #[command(SetSize = "track/size")] fn track_set_size (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetZoom = "track/zoom")] fn track_set_zoom (&mut self, _zoom: usize) -> Perhaps { todo!() } #[command(SetName = "track/name")] fn track_set_name (&mut self, name: Arc) -> Perhaps { self.track_mut() .map(|track|swap_value(&mut track.name, &name, |name|TrackCmd::SetName { name })) .transpose() .map(Option::flatten) } #[command(SetColor = "track/color")] fn track_set_color (&mut self, color: ItemTheme) -> Perhaps { self.track_mut() .map(|track|swap_value(&mut track.color, &color, |color|TrackCmd::SetColor { color })) .transpose() .map(Option::flatten) } #[command(SetRec = "track/rec")] fn track_set_rec (&mut self, rec: Option) -> Perhaps { self.track_mut() .map(|track|toggle_bool(&mut track.sequencer.recording, &rec, |rec|TrackCmd::SetRec { rec })) .transpose() .map(Option::flatten) } #[command(SetMon = "track/mon")] fn track_set_mon (&mut self, mon: Option) -> Perhaps { self.track_mut() .map(|track|toggle_bool(&mut track.sequencer.monitoring, &mon, |mon|TrackCmd::SetMon { mon })) .transpose() .map(Option::flatten) } } impl > ScenesControl for T {} #[tek_proc::commands(ScenesCmd)] pub trait ScenesControl: HasScenes + HasTracks + HasTrackScroll + HasSelection + HasJack<'static> { #[command(Add = "add")] fn scenes_add (&mut self) -> Perhaps where Self: Sized { let (_index, _) = self.scenes_add_one(None, None)?; Ok(None) } #[command(Select = "select")] fn scene_select (&mut self) -> Perhaps { let scenes = self.scenes().len(); let select = self.selection_mut().select_scene(scenes); *self.selection_mut() = select; Ok(None) } #[command(Next = "next")] fn scene_select_next (&mut self) -> Perhaps { let scenes = self.scenes().len(); let select = self.selection().select_scene_next(scenes); *self.selection_mut() = select; Ok(None) } #[command(Prev = "prev")] fn scene_select_prev (&mut self) -> Perhaps { let select = self.selection_mut().select_scene_prev(); *self.selection_mut() = select; Ok(None) } /// Generate the default name for a new scene fn scenes_default_name (&self) -> Arc { format!("s{:3>}", self.scenes().len() + 1).into() } fn scenes_longest_name (&self) -> usize { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) } /// Add multiple scenes fn scenes_add_many (&mut self, n: usize) -> Usually<()> where Self: HasTracks { let scene_color_1 = ItemColor::random(); let scene_color_2 = ItemColor::random(); for i in 0..n { let _ = self.scenes_add_one(None, Some( scene_color_1.mix(scene_color_2, i as f32 / n as f32).into() ))?; } Ok(()) } /// Add a scene fn scenes_add_one (&mut self, name: Option>, color: Option) -> Usually<(usize, &mut Scene)> where Self: HasTracks { let scene = Scene { name: name.map_or_else(||self.scenes_default_name(), |x|x.to_string().into()), clips: Pool::from(vec![None;self.tracks().len()]), color: color.unwrap_or_else(ItemTheme::random), }; self.scenes_mut().push(scene); let index = self.scenes().len() - 1; Ok((index, &mut self.scenes_mut()[index])) } } impl + Namespace> + Namespace > SceneControl for T {} #[tek_proc::commands(SceneCmd)] pub trait SceneControl: HasScene + Namespace + Namespace> + Namespace { #[command(SetSize = "size")] fn scene_set_size (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetZoom = "zoom")] fn scene_set_zoom (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetName = "name")] fn scene_set_name (&mut self, name: Arc) -> Perhaps { Ok(self.scene_mut().map(|scene|swap_value( &mut scene.name, &name, |name|SceneCmd::SetName { name } )).transpose()?.flatten()) } #[command(SetColor = "color")] fn scene_set_color (&mut self, color: ItemTheme) -> Perhaps { Ok(self.scene_mut().map(|scene|swap_value( &mut scene.color, &color, |color|SceneCmd::SetColor { color } )).transpose()?.flatten()) } } #[tek_proc::commands(SamplerCmd = "sampler")] pub trait SamplerControl: HasSampler + Namespace { #[command(RecToggle = "rec-toggle")] fn record_toggle (&mut self, slot: usize) -> Perhaps where Self: Sized { let sampler = self.sampler_mut(); let recording = sampler.recording.as_ref().map(|x|x.0); let _ = SamplerCmd::RecFinish.dispatch(self)?; // autoslice: continue recording at next slot if recording != Some(slot) { SamplerCmd::RecBegin { slot }.dispatch(self) } else { Ok(None) } } #[command(RecBegin = "rec-begin")] fn record_begin (&mut self, slot: usize) -> Perhaps { let sampler = self.sampler_mut(); sampler.recording = Some(( slot, Some(Arc::new(RwLock::new(Sample::new( "Sample", 0, 0, vec![vec![]; sampler.audio_ins.len()] )))) )); Ok(None) } #[command(RecFinish = "rec-finish")] fn record_finish (&mut self) -> Perhaps { let sampler = self.sampler_mut(); let _prev_sample = sampler.recording.as_mut().map(|(index, sample)|{ std::mem::swap(sample, &mut sampler.samples.0[*index]); sample }); // TODO: undo Ok(None) } #[command(RecCancel = "rec-cancel")] fn record_cancel (&mut self) -> Perhaps { self.sampler_mut().recording = None; Ok(None) } #[command(PlaySample = "sample-play")] fn sample_play (&mut self, slot: usize) -> Perhaps { let sampler = self.sampler_mut(); if let Some(ref sample) = sampler.samples.0[slot] { sampler.voices.write().push(Sample::play(sample, 0, &u7::from(128))); } Ok(None) } #[command(StopSample = "sample-stop")] fn sample_stop (&mut self, slot: usize) -> Perhaps { todo!(); //Ok(None) } } impl + Namespace + Namespace + Namespace + Namespace> + Namespace > MidiEditControl for T {} #[tek_proc::commands(MidiEditCmd)] pub trait MidiEditControl: HasClip + HasEditor + Namespace + Namespace + Namespace + Namespace + Namespace> + Namespace { #[command(Toggle = "toggle")] fn edit_toggle (&mut self) -> Perhaps { if self.is_editing() { *self.editor_mut() = None; } else if let Some(clip) = self.clip() { let editor = MidiEditor::new(); *editor.mode.clip.0.write() = clip.clone(); editor.redraw(); *self.editor_mut() = Some(editor); } else { return Ok(None) } Ok(Some(MidiEditCmd::Toggle)) } #[command(Show = "show")] fn edit_show (&mut self, clip: ClipSlot) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.mode.clip.0 = clip.0; editor.redraw(); None }).flatten()) } #[command(DeleteNote = "delete")] fn edit_note_delete (&mut self) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.redraw(); todo!() }).flatten()) } #[command(AppendNote = "append")] fn edit_note_append (&mut self, advance: bool) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.put_note(advance); editor.redraw(); None }).flatten()) } #[command(SetNotePos = "note-pos")] fn edit_note_set_pos (&mut self, pos: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_pos((pos).min(127)); editor.redraw(); None }).flatten()) } #[command(SetNoteLen = "note-len")] fn edit_note_set_len (&mut self, len: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_len(len); editor.redraw(); None }).flatten()) } #[command(SetNoteScroll = "note-scroll")] fn edit_note_set_scroll (&mut self, scroll: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_lo((scroll).min(127)); editor.redraw(); None }).flatten()) } #[command(SetTimePos = "time-pos")] fn edit_time_set_pos (&mut self, pos: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_pos(pos); editor.redraw(); None }).flatten()) } #[command(SetTimeScroll = "time-scroll")] fn edit_time_set_scroll (&mut self, scroll: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_start(scroll); editor.redraw(); None }).flatten()) } #[command(SetTimeZoom = "time-zoom")] fn edit_time_set_zoom (&mut self, zoom: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_zoom(zoom); editor.redraw(); None }).flatten()) } #[command(SetTimeLock = "time-lock")] fn edit_time_set_lock (&mut self, lock: bool) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_lock(lock); editor.redraw(); None }).flatten()) } // TODO: 1-9 seek markers that by default start every 8th of the clip } impl MidiClipControl for T where T: HasClip + Namespace> + Namespace> {} #[tek_proc::commands(MidiClipCmd)] pub trait MidiClipControl: HasClip + Namespace> + Namespace> { /// Create a clip at the current position if it does not already exist. #[command(Upsert = "upsert")] fn clip_upsert ( &mut self ) -> Perhaps { Ok(self.clip_mut().map(|mut clip|if clip.is_none() { *clip = Some(Arc::new(RwLock::new(MidiClip { ppq: 24, length: 96, color: ItemTheme::random(), ..Default::default() }))); None // TODO undo } else { None }).flatten()) } #[command(SetColor = "color")] fn clip_set_color ( &mut self, color: Option ) -> Perhaps { Ok(self.clip_slot().map_inner_mut(|clip|MidiClipCmd::SetColor { color: Some(clip.set_color(color)) })) } /// Toggle looping for the active clip #[command(SetLoop = "loop")] fn clip_toggle_loop ( &mut self, looping: Option ) -> Perhaps { Ok(self.clip_slot().map_inner_mut(|clip|MidiClipCmd::SetLoop { looping: Some(clip.toggle_loop(looping)) })) } } impl BrowseControl for T where T: Namespace + Namespace + Namespace> {} #[tek_proc::commands(BrowseCmd = "browse")] pub trait BrowseControl: Namespace + Namespace + Namespace> { /// Toggle visibility of browser #[command(Show = "show")] fn show (&mut self) -> Perhaps { todo!() } /// Set current directory #[command(Chdir = "chdir")] fn chdir (&mut self, _path: PathBuf) -> Perhaps { todo!() } /// Set current filter #[command(SetSearch = "set-search")] fn set_search (&mut self, _filter: Arc) -> Perhaps { todo!() } /// Set selected item #[command(SetCursor = "set-cursor")] fn set_cursor (&mut self, _index: usize) -> Perhaps { todo!() } } #[tek_proc::commands(AxisCmd)] impl App { /// Increment the given data axis. #[command(Inc = "inc")] pub fn inc (&mut self, axis: ControlAxis) -> Perhaps { panic!("inc {axis:?}"); Ok(match (&self.dialog, axis) { (Dialog::None, _) => todo!(), (Dialog::Menu(_, _), ControlAxis::Y) => { AppCmd::Dialog { dialog: self.dialog.menu_next() }.dispatch(self)?; None }, _ => todo!() }) } /// Decrement the given data axis. #[command(Dec = "dec")] pub fn dec (&mut self, axis: ControlAxis) -> Perhaps { panic!("dec {axis:?}"); Ok(match (&self.dialog, axis) { (Dialog::None, _) => None, (Dialog::Menu(_, _), ControlAxis::Y) => { AppCmd::Dialog { dialog: self.dialog.menu_prev() }.dispatch(self)?; None }, _ => todo!() }) } } #[tek_proc::command(AudioInput)] #[tek_proc::keyword(AudioInput)] #[derive(Debug)] pub enum AudioInputCmd { Close, Connect(Arc), } #[tek_proc::command(AudioOutput)] #[tek_proc::keyword(AudioOutput)] #[derive(Debug)] pub enum AudioOutputCmd { Close, Connect(Arc), } #[tek_proc::command(MidiInput)] #[tek_proc::keyword(MidiInput)] #[derive(Debug)] pub enum MidiInputCmd { Close, Connect(Arc), } #[tek_proc::command(MidiOutput)] #[tek_proc::keyword(MidiOutput)] #[derive(Debug)] pub enum MidiOutputCmd { Close, Connect(Arc), } //impl //+ Namespace //+ Namespace> //+ Namespace //+ Namespace //+ Namespace //+ Namespace //> PoolControl for T {} //#[tek_proc::commands(PolCmd = "pool")] pub trait PoolControl: HasPool //+ Namespace //+ Namespace //+ Namespace> //+ Namespace //+ Namespace //+ Namespace //+ Namespace //{ ///// Toggle visibility of pool //#[command(Show = "show")] fn show (&mut self, visible: bool) -> Perhaps { //self.pool_mut().visible = visible; //Ok(Some(PoolCmd::Show { visible: !visible })) //} ///// Set selected clip //#[command(Select = "select")] fn select (&mut self, index: usize) -> Perhaps { //self.pool_mut().set_clip_index(index); //Ok(None) //} ///// Delete a clip from the pool //#[command(Delete = "delete")] fn delete (&mut self, index: usize) -> Perhaps { //let clip = self.pool_mut().remove(index).read().clone(); //Ok(Some(PoolCmd::Add { index, clip })) //} ///// Switch places of two clips in pool //#[command(Swap = "swap")] fn swap (&mut self, index: usize, other: usize) -> Perhaps { //self.pool_mut().swap(index, other); //Ok(Some(PoolCmd::Swap { index, other })) //} ///// Add clip to pool //#[command(Add = "add")] fn clip_add (&mut self, index: usize, clip: MidiClip) -> Perhaps { //let mut index = index; //let clip = Arc::new(RwLock::new(clip.clone())); //let mut clips = self.pool_mut().clips_mut(); //if index >= clips.len() { //index = clips.len(); //clips.push(clip) //} else { //clips.insert(index, clip); //} //Ok(Some(PoolCmd::Delete { index })) //} ///// Set name of clip //#[command(SetName = "set-name")] fn clip_set_name (&mut self, index: usize, name: Arc) -> Perhaps { //Ok(self.pool_mut().clips.read().get(index).map(|clip|{ //let old_name = clip.read().name.clone(); //clip.write().name = name.clone(); //PoolCmd::SetName { index, name: old_name } //})) //} ///// Set length of clip //#[command(SetLength = "set-length")] fn clip_set_length (&mut self, index: usize, length: usize) -> Perhaps { //Ok(self.pool_mut().clips.read().get(index).map(|clip|{ //let old_len = clip.read().length; //clip.write().length = length; //PoolCmd::SetLength { index, length: old_len } //})) //} ///// Set color of clip //#[command(SetColor = "set-color")] fn clip_set_color (&mut self, index: usize, color: ItemColor) -> Perhaps { //let mut color = ItemTheme::from(color); //std::mem::swap(&mut color, &mut self.pool().clips.read()[index].write().color); //Ok(Some(PoolCmd::SetColor { index, color: color.base })) //} ///// Enter crop mode //#[command(CropBegin = "crop/begin")] fn crop_begin (&mut self) -> Perhaps { //let index = self.pool().clip_index(); //let length = self.pool().clips.read()[index].read().length; //*self.pool_mut().mode_mut() = Some(PoolMode::Length(index, length, ClipLengthFocus::Bar)); //Ok(None) //} ///// Exit crop mode, discard //#[command(CropCancel = "crop/cancel")] fn crop_cancel (&mut self) -> Perhaps { //if let Some(PoolMode::Length(..)) = self.pool_mut().mode_mut().clone() { //*self.pool_mut().mode_mut() = None; //} //Ok(None) //} //#[command(CropSet = "crop/set")] fn crop_set (&mut self, _length: usize) -> Perhaps { //if let Some(PoolMode::Length(clip, ref mut length, ref mut _focus)) //= self.pool_mut().mode_mut().clone() //{ //let old_length; //{ //let clip = self.pool().clips.read()[clip].clone();//.write(); //old_length = Some(clip.read().length); //clip.write().length = *length; //} //*self.pool_mut().mode_mut() = None; //return Ok(old_length.map(|l|PoolCmd::CropSet { _length: l })) //} //Ok(None) //} //#[command(CropNext = "crop/next")] fn crop_next (&mut self) -> Perhaps { //if let Some(PoolMode::Length( //_clip, ref mut _length, ref mut focus //)) = self.pool_mut().mode_mut().clone() { //focus.next() //}; //Ok(None) //} //#[command(CropPrev = "crop/prev")] fn crop_prev (&mut self) -> Perhaps { //if let Some(PoolMode::Length( //_clip, ref mut _length, ref mut focus //)) = self.pool_mut().mode_mut().clone() { //focus.prev() //}; //Ok(None) //} //#[command(CropInc = "crop/inc")] fn crop_inc (&mut self) -> Perhaps { //if let Some(PoolMode::Length( //_clip, ref mut length, ref mut focus //)) = self.pool_mut().mode_mut().clone() { //match focus { //ClipLengthFocus::Bar => { *length += 4 * PPQ }, //ClipLengthFocus::Beat => { *length += PPQ }, //ClipLengthFocus::Tick => { *length += 1 }, //} //} //Ok(None) //} //#[command(CropDec = "crop/dec")] fn crop_dec (&mut self) -> Perhaps { //if let Some(PoolMode::Length( //_clip, ref mut length, ref mut focus //)) = self.pool_mut().mode_mut().clone() { //match focus { //ClipLengthFocus::Bar => { *length = length.saturating_sub(4 * PPQ) }, //ClipLengthFocus::Beat => { *length = length.saturating_sub(PPQ) }, //ClipLengthFocus::Tick => { *length = length.saturating_sub(1) }, //} //} //Ok(None) //} ///// Enter rename mode //#[command(RenameBegin = "rename/begin")] fn rename_begin (&mut self) -> Perhaps { //let index = self.pool().clip_index(); //let name = self.pool().clips.read()[index].read().name.clone(); //*self.pool_mut().mode_mut() = Some(PoolMode::Rename(index, name)); //Ok(None) //} ///// Exit rename mode, discard //#[command(RenameCancel = "rename/cancel")] fn rename_cancel (&mut self) -> Perhaps { //if let Some(PoolMode::Rename(clip, ref mut old_name)) = self.pool_mut().mode_mut().clone() { //self.pool().clips.read()[clip].write().name = old_name.clone().into(); //} //Ok(None) //} ///// Exit rename mode, update name //#[command(RenameConfirm = "rename/confirm")] fn rename_confirm (&mut self) -> Perhaps { //Ok(if let Some(PoolMode::Rename(_clip, ref mut old_name)) = self.pool_mut().mode_mut().clone() { //let old_name = old_name.clone(); //*self.pool_mut().mode_mut() = None; //Some(PoolCmd::RenameSet { value: old_name }) //} else { //None //}) //} //#[command(RenameSet = "rename/set")] fn rename_set (&mut self, value: Arc) -> Perhaps { //if let Some(PoolMode::Rename(clip, ref mut _old_name)) = self.pool_mut().mode_mut().clone() { //self.pool().clips.read()[clip].write().name = value.clone(); //} //Ok(None) //} /////// Import from file ////#[command(Browse = "browse")] ////fn browse (&mut self, command: BrowseCmd) -> Perhaps { ////Ok(if let Some(browse) = self.pool_mut().browse.as_mut() { ////command.act(browse)?.map(|command|PoolCmd::Browse{command}) ////} else { ////None ////}) ////} ///// Import clip to pool from file //#[command(Import = "import")] //fn clip_import (&mut self, index: usize, path: PathBuf) -> Perhaps //where Self: Sized //{ //let bytes = std::fs::read(&path)?; //let smf = Smf::parse(bytes.as_slice())?; //let mut t = 0u32; //let mut events = vec![]; //for track in smf.tracks.iter() { //for event in track.iter() { //t += event.delta.as_int(); //if let TrackEventKind::Midi { channel, message } = event.kind { //events.push((t, channel.as_int(), message)); //} //} //} //let mut clip = MidiClip::new("imported", true, t as usize + 1, None, None); //for event in events.iter() { //clip.notes[event.0 as usize].push(event.2); //} //Ok(PoolCmd::Add { index, clip }.dispatch(self)?) //} /////// Export to file ////#[command(Export = "export")] ////fn export (&mut self, command: BrowseCmd) -> Perhaps { ////Ok(if let Some(browse) = self.pool_mut().browse.as_mut() { ////command.act(browse)?.map(|command|PoolCmd::Export{command}) ////} else { ////None ////}) ////} //}