//fn begin (browse: &mut Browse) => { //unreachable!(); //} //fn cancel (browse: &mut Browse) => { //todo!() ////browse.mode = None; ////Ok(None) //} //fn confirm (browse: &mut Browse) => { //todo!() ////Ok(match browse.mode { ////Some(PoolMode::Import(index, ref mut browse)) => { ////if browse.is_file() { ////let path = browse.path(); ////browse.mode = None; ////let _undo = PoolClipCommand::import(browse, index, path)?; ////None ////} else if browse.is_dir() { ////browse.mode = Some(PoolMode::Import(index, browse.chdir()?)); ////None ////} else { ////None ////} ////}, ////Some(PoolMode::Export(index, ref mut browse)) => { ////todo!() ////}, ////_ => unreachable!(), ////}) //} //fn select (browse: &mut Browse, index: usize) => { //todo!() ////Ok(match browse.mode { ////Some(PoolMode::Import(index, ref mut browse)) => { ////browse.index = index; ////None ////}, ////Some(PoolMode::Export(index, ref mut browse)) => { ////browse.index = index; ////None ////}, ////_ => unreachable!(), ////}) //} //fn chdir (browse: &mut Browse, dir: PathBuf) => { //todo!() ////Ok(match browse.mode { ////Some(PoolMode::Import(index, ref mut browse)) => { ////browse.mode = Some(PoolMode::Import(index, Browse::new(Some(dir))?)); ////None ////}, ////Some(PoolMode::Export(index, ref mut browse)) => { ////browse.mode = Some(PoolMode::Export(index, Browse::new(Some(dir))?)); ////None ////}, ////_ => unreachable!(), ////}) //} //fn filter (browse: &mut Browse, filter: Arc) => { //todo!() //} //def_command!(ArrangementCommand: |arranger: Arrangement| { //Home => { arranger.editor = None; Ok(None) }, //Edit => { //let selection = arranger.selection().clone(); //arranger.editor = if arranger.editor.is_some() { //None //} else { //match selection { //Selection::TrackClip { track, scene } => { //let clip = &mut arranger.scenes_mut()[scene].clips[track]; //if clip.is_none() { ////app.clip_auto_create(); //*clip = Some(Arc::new(RwLock::new(MidiClip::new( //&format!("t{track:02}s{scene:02}"), //false, 384, None, Some(ItemTheme::random()) //)))); //} //clip.as_ref().map(|c|c.into()) //} //_ => { //None //} //} //}; //if let Some(editor) = arranger.editor.as_mut() { //if let Some(clip) = editor.clip() { //let length = clip.read().unwrap().length.max(1); //let width = arranger.size_inner.w().saturating_sub(20).max(1); //editor.set_time_zoom(length / width); //editor.redraw(); //} //} //Ok(None) //}, ////// Set the selection //Select { selection: Selection } => { *arranger.selection_mut() = *selection; Ok(None) }, ////// Launch the selected clip or scene //Launch => { //match *arranger.selection() { //Selection::Track(t) => { //arranger.tracks[t].sequencer.enqueue_next(None) //}, //Selection::TrackClip { track, scene } => { //arranger.tracks[track].sequencer.enqueue_next(arranger.scenes[scene].clips[track].as_ref()) //}, //Selection::Scene(s) => { //for t in 0..arranger.tracks.len() { //arranger.tracks[t].sequencer.enqueue_next(arranger.scenes[s].clips[t].as_ref()) //} //}, //_ => {} //}; //Ok(None) //}, ////// Set the color of the selected entity //SetColor { palette: Option } => { //let mut palette = palette.unwrap_or_else(||ItemTheme::random()); //let selection = *arranger.selection(); //Ok(Some(Self::SetColor { palette: Some(match selection { //Selection::Mix => { //std::mem::swap(&mut palette, &mut arranger.color); //palette //}, //Selection::Scene(s) => { //std::mem::swap(&mut palette, &mut arranger.scenes[s].color); //palette //} //Selection::Track(t) => { //std::mem::swap(&mut palette, &mut arranger.tracks[t].color); //palette //} //Selection::TrackClip { track, scene } => { //if let Some(ref clip) = arranger.scenes[scene].clips[track] { //let mut clip = clip.write().unwrap(); //std::mem::swap(&mut palette, &mut clip.color); //palette //} else { //return Ok(None) //} //}, //_ => todo!() //}) })) //}, //Track { track: TrackCommand } => { todo!("delegate") }, //TrackAdd => { //let index = arranger.track_add(None, None, &[], &[])?.0; //*arranger.selection_mut() = match arranger.selection() { //Selection::Track(_) => Selection::Track(index), //Selection::TrackClip { track: _, scene } => Selection::TrackClip { //track: index, scene: *scene //}, //_ => *arranger.selection() //}; //Ok(Some(Self::TrackDelete { index })) //}, //TrackSwap { index: usize, other: usize } => { //let index = *index; //let other = *other; //Ok(Some(Self::TrackSwap { index, other })) //}, //TrackDelete { index: usize } => { //let index = *index; //let exists = arranger.tracks().get(index).is_some(); //if exists { //let track = arranger.tracks_mut().remove(index); //let Track { sequencer: Sequencer { midi_ins, midi_outs, .. }, .. } = track; //for port in midi_ins.into_iter() { //port.close()?; //} //for port in midi_outs.into_iter() { //port.close()?; //} //for scene in arranger.scenes_mut().iter_mut() { //scene.clips.remove(index); //} //} //Ok(None) ////TODO:Ok(Some(Self::TrackAdd ( index, track: Some(deleted_track) }) //}, //MidiIn { input: MidiInputCommand } => { //todo!("delegate"); Ok(None) //}, //MidiInAdd => { //arranger.midi_in_add()?; //Ok(None) //}, //MidiOut { output: MidiOutputCommand } => { //todo!("delegate"); //Ok(None) //}, //MidiOutAdd => { //arranger.midi_out_add()?; //Ok(None) //}, //Device { command: DeviceCommand } => { //todo!("delegate"); //Ok(None) //}, //DeviceAdd { index: usize } => { //todo!("delegate"); //Ok(None) //}, //Scene { scene: SceneCommand } => { //todo!("delegate"); //Ok(None) //}, //OutputAdd => { //arranger.midi_outs.push(MidiOutput::new( //arranger.jack(), //&format!("/M{}", arranger.midi_outs.len() + 1), //&[] //)?); //Ok(None) //}, //InputAdd => { //arranger.midi_ins.push(MidiInput::new( //arranger.jack(), //&format!("M{}/", arranger.midi_ins.len() + 1), //&[] //)?); //Ok(None) //}, //SceneAdd => { //let index = arranger.scene_add(None, None)?.0; //*arranger.selection_mut() = match arranger.selection() { //Selection::Scene(_) => Selection::Scene(index), //Selection::TrackClip { track, scene } => Selection::TrackClip { //track: *track, //scene: index //}, //_ => *arranger.selection() //}; //Ok(None) // TODO //}, //SceneSwap { index: usize, other: usize } => { //let index = *index; //let other = *other; //Ok(Some(Self::SceneSwap { index, other })) //}, //SceneDelete { index: usize } => { //let index = *index; //let scenes = arranger.scenes_mut(); //Ok(if scenes.get(index).is_some() { //let _scene = scenes.remove(index); //None //} else { //None //}) //}, //SceneLaunch { index: usize } => { //let index = *index; //for track in 0..arranger.tracks.len() { //let clip = arranger.scenes[index].clips[track].as_ref(); //arranger.tracks[track].sequencer.enqueue_next(clip); //} //Ok(None) //}, //Clip { scene: ClipCommand } => { //todo!("delegate") //}, //ClipGet { a: usize, b: usize } => { ////(Get [a: usize, b: usize] cmd_todo!("\n\rtodo: clip: get: {a} {b}")) ////("get" [a: usize, b: usize] Some(Self::Get(a.unwrap(), b.unwrap()))) //todo!() //}, //ClipPut { a: usize, b: usize } => { ////(Put [t: usize, s: usize, c: MaybeClip] ////Some(Self::Put(t, s, arranger.clip_put(t, s, c)))) ////("put" [a: usize, b: usize, c: MaybeClip] Some(Self::Put(a.unwrap(), b.unwrap(), c.unwrap()))) //todo!() //}, //ClipDel { a: usize, b: usize } => { ////("delete" [a: usize, b: usize] Some(Self::Put(a.unwrap(), b.unwrap(), None)))) //todo!() //}, //ClipEnqueue { a: usize, b: usize } => { ////(Enqueue [t: usize, s: usize] ////cmd!(arranger.tracks[t].sequencer.enqueue_next(arranger.scenes[s].clips[t].as_ref()))) ////("enqueue" [a: usize, b: usize] Some(Self::Enqueue(a.unwrap(), b.unwrap()))) //todo!() //}, //ClipSwap { a: usize, b: usize }=> { ////(Edit [clip: MaybeClip] cmd_todo!("\n\rtodo: clip: edit: {clip:?}")) ////("edit" [a: MaybeClip] Some(Self::Edit(a.unwrap()))) //todo!() //}, //}); // Update sequencer playhead indicator //self.now().set(0.); //if let Some((ref started_at, Some(ref playing))) = self.sequencer.play_clip { //let clip = clip.read().unwrap(); //if *playing.read().unwrap() == *clip { //let pulse = self.current().pulse.get(); //let start = started_at.pulse.get(); //let now = (pulse - start) % clip.length as f64; //self.now().set(now); //} //} //fn jack_from_lv2 (name: &str, plugin: &::livi::Plugin) -> Usually { //let counts = plugin.port_counts(); //let mut jack = Jack::new(name)?; //for i in 0..counts.atom_sequence_inputs { //jack = jack.midi_in(&format!("midi-in-{i}")) //} //for i in 0..counts.atom_sequence_outputs { //jack = jack.midi_out(&format!("midi-out-{i}")); //} //for i in 0..counts.audio_inputs { //jack = jack.audio_in(&format!("audio-in-{i}")); //} //for i in 0..counts.audio_outputs { //jack = jack.audio_out(&format!("audio-out-{i}")); //} //Ok(jack) //} //handle!(TuiIn: |self:Plugin, from|{ //match from.event() { //kpat!(KeyCode::Up) => { //self.selected = self.selected.saturating_sub(1); //Ok(Some(true)) //}, //kpat!(KeyCode::Down) => { //self.selected = (self.selected + 1).min(match &self.plugin { //Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1, //_ => unimplemented!() //}); //Ok(Some(true)) //}, //kpat!(KeyCode::PageUp) => { //self.selected = self.selected.saturating_sub(8); //Ok(Some(true)) //}, //kpat!(KeyCode::PageDown) => { //self.selected = (self.selected + 10).min(match &self.plugin { //Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1, //_ => unimplemented!() //}); //Ok(Some(true)) //}, //kpat!(KeyCode::Char(',')) => { //match self.plugin.as_mut() { //Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => { //let index = port_list[self.selected].index; //if let Some(value) = instance.control_input(index) { //instance.set_control_input(index, value - 0.01); //} //}, //_ => {} //} //Ok(Some(true)) //}, //kpat!(KeyCode::Char('.')) => { //match self.plugin.as_mut() { //Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => { //let index = port_list[self.selected].index; //if let Some(value) = instance.control_input(index) { //instance.set_control_input(index, value + 0.01); //} //}, //_ => {} //} //Ok(Some(true)) //}, //kpat!(KeyCode::Char('g')) => { //match self.plugin { ////Some(PluginKind::LV2(ref mut plugin)) => { ////plugin.ui_thread = Some(run_lv2_ui(LV2PluginUI::new()?)?); ////}, //Some(_) => unreachable!(), //None => {} //} //Ok(Some(true)) //}, //_ => Ok(None) //} //}); //from_atom!("plugin/lv2" => |jack: &Jack, args| -> Plugin { //let mut name = String::new(); //let mut path = String::new(); //atom!(atom in args { //Atom::Map(map) => { //if let Some(Atom::Str(n)) = map.get(&Atom::Key(":name")) { //name = String::from(*n); //} //if let Some(Atom::Str(p)) = map.get(&Atom::Key(":path")) { //path = String::from(*p); //} //}, //_ => panic!("unexpected in lv2 '{name}'"), //}); //Plugin::new_lv2(jack, &name, &path) //}); //pub struct LV2PluginUI { //write: (), //controller: (), //widget: (), //features: (), //transfer: (), //} //take!(BrowseCommand |state: Pool, iter|Ok(state.browse.as_ref() //.map(|p|Take::take(p, iter)) //.transpose()? //.flatten())); //fn file_browser_filter (&self) -> Arc { //todo!() //} //fn file_browser_path (&self) -> PathBuf { //todo!(); //} ///// Immutable reference to sample at cursor. //fn sample_selected (&self) -> Option>> { //for (i, sample) in self.mapped.iter().enumerate() { //if i == self.cursor().0 { //return sample.as_ref() //} //} //for (i, sample) in self.unmapped.iter().enumerate() { //if i + self.mapped.len() == self.cursor().0 { //return Some(sample) //} //} //None //} //fn sample_gain (&self) -> f32 { //todo!() //} //fn sample_above () -> usize { //self.note_pos().min(119) + 8 //} //fn sample_below () -> usize { //self.note_pos().max(8) - 8 //} //fn sample_to_left () -> usize { //self.note_pos().min(126) + 1 //} //fn sample_to_right () -> usize { //self.note_pos().max(1) - 1 //} //fn selected_pitch () -> u7 { //(self.note_pos() as u8).into() // TODO //} //select (&self, state: &mut Sampler, i: usize) -> Option { //Self::Select(state.set_note_pos(i)) //} ///// Assign sample to slot //set (&self, slot: u7, sample: Option>>) -> Option { //let i = slot.as_int() as usize; //let old = self.mapped[i].clone(); //self.mapped[i] = sample; //Some(Self::Set(old)) //} //set_start (&self, state: &mut Sampler, slot: u7, frame: usize) -> Option { //todo!() //} //set_gain (&self, state: &mut Sampler, slot: u7, g: f32) -> Option { //todo!() //} //note_on (&self, state: &mut Sampler, slot: u7, v: u7) -> Option { //todo!() //} //note_off (&self, state: &mut Sampler, slot: u7) -> Option { //todo!() //} //set_sample (&self, state: &mut Sampler, slot: u7, s: Option>>) -> Option { //Some(Self::SetSample(p, state.set_sample(p, s))) //} //import (&self, state: &mut Sampler, c: FileBrowserCommand) -> Option { //match c { //FileBrowserCommand::Begin => { ////let voices = &state.state.voices; ////let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![]))); //state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?)); //None //}, //_ => { //println!("\n\rtodo: import: filebrowser: {c:?}"); //None //} //} //} ////(Select [i: usize] Some(Self::Select(state.set_note_pos(i)))) ////(RecordBegin [p: u7] cmd!(state.begin_recording(p.as_int() as usize))) ////(RecordCancel [] cmd!(state.cancel_recording())) ////(RecordFinish [] cmd!(state.finish_recording())) ////(SetStart [p: u7, frame: usize] cmd_todo!("\n\rtodo: {self:?}")) ////(SetGain [p: u7, gain: f32] cmd_todo!("\n\rtodo: {self:?}")) ////(NoteOn [p: u7, velocity: u7] cmd_todo!("\n\rtodo: {self:?}")) ////(NoteOff [p: u7] cmd_todo!("\n\rtodo: {self:?}")) ////(SetSample [p: u7, s: Option>>] Some(Self::SetSample(p, state.set_sample(p, s)))) ////(Import [c: FileBrowserCommand] match c { ////FileBrowserCommand::Begin => { //////let voices = &state.state.voices; //////let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![]))); ////state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?)); ////None ////}, ////_ => { ////println!("\n\rtodo: import: filebrowser: {c:?}"); ////None ////} ////}))); ////("import" [,..a] ////FileBrowserCommand::try_from_expr(state, a).map(Self::Import)) ////("select" [i: usize] ////Some(Self::Select(i.expect("no index")))) ////("record/begin" [i: u7] ////Some(Self::RecordBegin(i.expect("no index")))) ////("record/cancel" [] ////Some(Self::RecordCancel)) ////("record/finish" [] ////Some(Self::RecordFinish)) ////("set/sample" [i: u7, s: Option>>] ////Some(Self::SetSample(i.expect("no index"), s.expect("no sampler")))) ////("set/start" [i: u7, s: usize] ////Some(Self::SetStart(i.expect("no index"), s.expect("no start")))) ////("set/gain" [i: u7, g: f32] ////Some(Self::SetGain(i.expect("no index"), g.expect("no gain")))) ////("note/on" [p: u7, v: u7] ////Some(Self::NoteOn(p.expect("no slot"), v.expect("no velocity")))) ////("note/off" [p: u7] ////Some(Self::NoteOff(p.expect("no slot")))))); // TODO: //for port in midi_in.iter() { //for event in port.iter() { //match event { //(time, Ok(LiveEvent::Midi {message, ..})) => match message { //MidiMessage::NoteOn {ref key, ..} if let Some(editor) = self.editor.as_ref() => { //editor.set_note_pos(key.as_int() as usize); //}, //MidiMessage::Controller {controller, value} if let (Some(editor), Some(sampler)) = ( //self.editor.as_ref(), //self.sampler.as_ref(), //) => { //// TODO: give sampler its own cursor //if let Some(sample) = &sampler.mapped[editor.note_pos()] { //sample.write().unwrap().handle_cc(*controller, *value) //} //} //_ =>{} //}, //_ =>{} //} //} //} //scene_scroll: Fill::Y(Fixed::X(1, ScrollbarV { //offset: arrangement.scene_scroll, //length: h_scenes_area as usize, //total: h_scenes as usize, //})), //take!(SceneCommand |state: Arrangement, iter|state.selected_scene().as_ref() //.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); //pub(crate) fn io_conns <'a, T: PortsSizes<'a>> ( //fg: Color, bg: Color, iter: &mut impl Iterator, &'a [Connect], usize, usize)> //) -> impl Content + 'a { //Fill::XY(Thunk::new(move|to: &mut TuiOut|for (_, _, connections, y, y2) in &mut *iter { //to.place(&map_south(y as u16, (y2-y) as u16, Bsp::s( //Fill::Y(Tui::bold(true, wrap(bg, fg, Fill::Y(Align::w(&"▞▞▞▞ ▞▞▞▞"))))), //Thunk::new(|to: &mut TuiOut|for (index, _connection) in connections.iter().enumerate() { //to.place(&map_south(index as u16, 1, Fill::Y(Align::w(Tui::bold(false, //wrap(bg, fg, Fill::Y(&""))))))) //}) //))) //})) //} //track_scroll: Fill::Y(Fixed::Y(1, ScrollbarH { //offset: arrangement.track_scroll, //length: h_tracks_area as usize, //total: h_scenes as usize, //})), //take!(TrackCommand |state: Arrangement, iter|state.selected_track().as_ref() //.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));