mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-02-21 08:19:03 +01:00
1078 lines
43 KiB
Rust
1078 lines
43 KiB
Rust
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//pub fn view_nil (_: &App) -> TuiCb {
|
|
//|to|to.place(&Fill::XY("·"))
|
|
//}
|
|
|
|
//Bsp::s("",
|
|
//Map::south(1,
|
|
//move||app.config.binds.layers.iter()
|
|
//.filter_map(|a|(a.0)(app).then_some(a.1))
|
|
//.flat_map(|a|a)
|
|
//.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None })
|
|
//.skip(offset)
|
|
//.take(20),
|
|
//|mut b,i|Fixed::X(60, Align::w(Bsp::e("(", Bsp::e(
|
|
//b.next().map(|t|Fixed::X(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))),
|
|
//Bsp::e(" ", Align::w(format!("{}", b.0.0.trim()))))))))))),
|
|
|
|
//Dialog::Browse(BrowseTarget::Load, browser) => {
|
|
//"bobcat".boxed()
|
|
////Bsp::s(
|
|
////Fill::X(Align::w(Margin::XY(1, 1, Bsp::e(
|
|
////Tui::bold(true, " Load project: "),
|
|
////Shrink::X(3, Fixed::Y(1, RepeatH("🭻"))))))),
|
|
////Outer(true, Style::default().fg(Tui::g(96)))
|
|
////.enclose(Fill::XY(browser)))
|
|
//},
|
|
//Dialog::Browse(BrowseTarget::Export, browser) => {
|
|
//"bobcat".boxed()
|
|
////Bsp::s(
|
|
////Fill::X(Align::w(Margin::XY(1, 1, Bsp::e(
|
|
////Tui::bold(true, " Export: "),
|
|
////Shrink::X(3, Fixed::Y(1, RepeatH("🭻"))))))),
|
|
////Outer(true, Style::default().fg(Tui::g(96)))
|
|
////.enclose(Fill::XY(browser)))
|
|
//},
|
|
//Dialog::Browse(BrowseTarget::Import, browser) => {
|
|
//"bobcat".boxed()
|
|
////Bsp::s(
|
|
////Fill::X(Align::w(Margin::XY(1, 1, Bsp::e(
|
|
////Tui::bold(true, " Import: "),
|
|
////Shrink::X(3, Fixed::Y(1, RepeatH("🭻"))))))),
|
|
////Outer(true, Style::default().fg(Tui::g(96)))
|
|
////.enclose(Fill::XY(browser)))
|
|
//},
|
|
//
|
|
//pub fn view_history (&self) -> impl Content<TuiOut> {
|
|
//Fixed::Y(1, Fill::X(Align::w(FieldH(self.color,
|
|
//format!("History ({})", self.history.len()),
|
|
//self.history.last().map(|last|Fill::X(Align::w(format!("{:?}", last.0))))))))
|
|
//}
|
|
//pub fn view_status_h2 (&self) -> impl Content<TuiOut> {
|
|
//self.update_clock();
|
|
//let theme = self.color;
|
|
//let clock = self.clock();
|
|
//let playing = clock.is_rolling();
|
|
//let cache = clock.view_cache.clone();
|
|
////let selection = self.selection().describe(self.tracks(), self.scenes());
|
|
//let hist_len = self.history.len();
|
|
//let hist_last = self.history.last();
|
|
//Fixed::Y(2, Stack::east(move|add: &mut dyn FnMut(&dyn Draw<TuiOut>)|{
|
|
//add(&Fixed::X(5, Tui::bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
|
|
//Either::new(false, // TODO
|
|
//Thunk::new(move||Fixed::X(9, Either::new(playing,
|
|
//Tui::fg(Rgb(0, 255, 0), " PLAYING "),
|
|
//Tui::fg(Rgb(255, 128, 0), " STOPPED ")))
|
|
//),
|
|
//Thunk::new(move||Fixed::X(5, Either::new(playing,
|
|
//Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
|
//Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))
|
|
//)
|
|
//)
|
|
//)));
|
|
//add(&" ");
|
|
//{
|
|
//let cache = cache.read().unwrap();
|
|
//add(&Fixed::X(15, Align::w(Bsp::s(
|
|
//FieldH(theme, "Beat", cache.beat.view.clone()),
|
|
//FieldH(theme, "Time", cache.time.view.clone()),
|
|
//))));
|
|
//add(&Fixed::X(13, Align::w(Bsp::s(
|
|
//Fill::X(Align::w(FieldH(theme, "BPM", cache.bpm.view.clone()))),
|
|
//Fill::X(Align::w(FieldH(theme, "SR ", cache.sr.view.clone()))),
|
|
//))));
|
|
//add(&Fixed::X(12, Align::w(Bsp::s(
|
|
//Fill::X(Align::w(FieldH(theme, "Buf", cache.buf.view.clone()))),
|
|
//Fill::X(Align::w(FieldH(theme, "Lat", cache.lat.view.clone()))),
|
|
//))));
|
|
////add(&Bsp::s(
|
|
//////Fill::X(Align::w(FieldH(theme, "Selected", Align::w(selection)))),
|
|
////Fill::X(Align::w(FieldH(theme, format!("History ({})", hist_len),
|
|
////hist_last.map(|last|Fill::X(Align::w(format!("{:?}", last.0))))))),
|
|
////""
|
|
////));
|
|
//////if let Some(last) = self.history.last() {
|
|
//////add(&FieldV(theme, format!("History ({})", self.history.len()),
|
|
//////Fill::X(Align::w(format!("{:?}", last.0)))));
|
|
//////}
|
|
//}
|
|
//}))
|
|
//}
|
|
//pub fn view_status_v (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.update_clock();
|
|
//let cache = self.project.clock.view_cache.read().unwrap();
|
|
//let theme = self.color;
|
|
//let playing = self.clock().is_rolling();
|
|
//Tui::bg(theme.darker.rgb, Fixed::XY(20, 5, Outer(true, Style::default().fg(Tui::g(96))).enclose(
|
|
//col!(
|
|
//Fill::X(Align::w(Bsp::e(
|
|
//Align::w(Tui::bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
|
|
//Either::new(false, // TODO
|
|
//Thunk::new(move||Fixed::X(9, Either::new(playing,
|
|
//Tui::fg(Rgb(0, 255, 0), " PLAYING "),
|
|
//Tui::fg(Rgb(255, 128, 0), " STOPPED ")))
|
|
//),
|
|
//Thunk::new(move||Fixed::X(5, Either::new(playing,
|
|
//Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
|
//Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))
|
|
//)
|
|
//)
|
|
//)),
|
|
//Bsp::s(
|
|
//FieldH(theme, "Beat", cache.beat.view.clone()),
|
|
//FieldH(theme, "Time", cache.time.view.clone()),
|
|
//),
|
|
//))),
|
|
//Fill::X(Align::w(FieldH(theme, "BPM", cache.bpm.view.clone()))),
|
|
//Fill::X(Align::w(FieldH(theme, "SR ", cache.sr.view.clone()))),
|
|
//Fill::X(Align::w(FieldH(theme, "Buf", Bsp::e(cache.buf.view.clone(), Bsp::e(" = ", cache.lat.view.clone()))))),
|
|
//))))
|
|
//}
|
|
//pub fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.update_clock();
|
|
//let cache = self.project.clock.view_cache.read().unwrap();
|
|
//view_status(Some(self.project.selection.describe(self.tracks(), self.scenes())),
|
|
//cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone())
|
|
//}
|
|
//pub fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.update_clock();
|
|
//let cache = self.project.clock.view_cache.read().unwrap();
|
|
//view_transport(self.project.clock.is_rolling(),
|
|
//cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone())
|
|
//}
|
|
//pub fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//let bg = self.editor()
|
|
//.and_then(|editor|editor.clip().clone())
|
|
//.map(|clip|clip.read().unwrap().color.darker)
|
|
//.unwrap_or(self.color.darker);
|
|
//Fill::XY(Tui::bg(bg.rgb, self.editor()))
|
|
//}
|
|
//pub fn view_editor_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.editor().map(|e|Fixed::X(20, Outer(true, Style::default().fg(Tui::g(96))).enclose(
|
|
//Fill::Y(Align::n(Bsp::s(e.clip_status(), e.edit_status()))))))
|
|
//}
|
|
//pub fn view_midi_ins_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_midi_ins_status(self.color)
|
|
//}
|
|
//pub fn view_midi_outs_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_midi_outs_status(self.color)
|
|
//}
|
|
//pub fn view_audio_ins_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_audio_ins_status(self.color)
|
|
//}
|
|
//pub fn view_audio_outs_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_audio_outs_status(self.color)
|
|
//}
|
|
//pub fn view_scenes (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//Bsp::e(
|
|
//Fixed::X(20, Align::nw(self.project.view_scenes_names())),
|
|
//self.project.view_scenes_clips(),
|
|
//)
|
|
//}
|
|
//pub fn view_scenes_names (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_scenes_names()
|
|
//}
|
|
//pub fn view_scenes_clips (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.view_scenes_clips()
|
|
//}
|
|
//pub fn view_tracks_inputs <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
|
//Fixed::Y(1 + self.project.midi_ins.len() as u16,
|
|
//self.project.view_inputs(self.color))
|
|
//}
|
|
//pub fn view_tracks_outputs <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
|
//self.project.view_outputs(self.color)
|
|
//}
|
|
//pub fn view_tracks_devices <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
|
//Fixed::Y(4, self.project.view_track_devices(self.color))
|
|
//}
|
|
//pub fn view_tracks_names <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
|
//Fixed::Y(2, self.project.view_track_names(self.color))
|
|
//}
|
|
//pub fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//Fixed::X(20, Bsp::s(
|
|
//Fill::X(Align::w(FieldH(self.color, "Clip pool:", ""))),
|
|
//Fill::Y(Align::n(Tui::bg(Rgb(0, 0, 0), Outer(true, Style::default().fg(Tui::g(96)))
|
|
//.enclose(PoolView(&self.pool)))))))
|
|
//}
|
|
//pub fn view_samples_keys (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.sampler().map(|s|s.view_list(true, self.editor().unwrap()))
|
|
//}
|
|
//pub fn view_samples_grid (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.sampler().map(|s|s.view_grid())
|
|
//}
|
|
//pub fn view_sample_viewer (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.sampler().map(|s|s.view_sample(self.editor().unwrap().get_note_pos()))
|
|
//}
|
|
//pub fn view_sample_info (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.sampler().map(|s|s.view_sample_info(self.editor().unwrap().get_note_pos()))
|
|
//}
|
|
//pub fn view_sample_status (&self) -> impl Content<TuiOut> + use<'_> {
|
|
//self.project.sampler().map(|s|Outer(true, Style::default().fg(Tui::g(96))).enclose(
|
|
//Fill::Y(Align::n(s.view_sample_status(self.editor().unwrap().get_note_pos())))))
|
|
//}
|
|
////let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
|
////let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
|
|
////Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
|
|
|
|
//AppCommand => {
|
|
//("x/inc" /
|
|
//("stop-all") => todo!(),//app.project.stop_all(),
|
|
//("enqueue", clip: Option<Arc<RwLock<MidiClip>>>) => todo!(),
|
|
//("history", delta: isize) => todo!(),
|
|
//("zoom", zoom: usize) => todo!(),
|
|
//("select", selection: Selection) => todo!(),
|
|
//("dialog" / command: DialogCommand) => todo!(),
|
|
//("project" / command: ArrangementCommand) => todo!(),
|
|
//("clock" / command: ClockCommand) => todo!(),
|
|
//("sampler" / command: SamplerCommand) => todo!(),
|
|
//("pool" / command: PoolCommand) => todo!(),
|
|
//("edit" / editor: MidiEditCommand) => todo!(),
|
|
//};
|
|
|
|
//DialogCommand;
|
|
|
|
//ArrangementCommand;
|
|
|
|
//ClockCommand;
|
|
|
|
//SamplerCommand;
|
|
|
|
//PoolCommand;
|
|
|
|
//MidiEditCommand;
|
|
|
|
|
|
//take!(DialogCommand |state: App, iter|Take::take(&state.dialog, iter));
|
|
//#[derive(Clone, Debug)]
|
|
//pub enum DialogCommand {
|
|
//Open { dialog: Dialog },
|
|
//Close
|
|
//}
|
|
|
|
//impl Command<Option<Dialog>> for DialogCommand {
|
|
//fn execute (self, state: &mut Option<Dialog>) -> Perhaps<Self> {
|
|
//match self {
|
|
//Self::Open { dialog } => {
|
|
//*state = Some(dialog);
|
|
//},
|
|
//Self::Close => {
|
|
//*state = None;
|
|
//}
|
|
//};
|
|
//Ok(None)
|
|
//}
|
|
//}
|
|
|
|
//dsl!(DialogCommand: |self: Dialog, iter|todo!());
|
|
//Dsl::take(&mut self.dialog, iter));
|
|
|
|
//#[tengri_proc::command(Option<Dialog>)]//Nope.
|
|
//impl DialogCommand {
|
|
//fn open (dialog: &mut Option<Dialog>, new: Dialog) -> Perhaps<Self> {
|
|
//*dialog = Some(new);
|
|
//Ok(None)
|
|
//}
|
|
//fn close (dialog: &mut Option<Dialog>) -> Perhaps<Self> {
|
|
//*dialog = None;
|
|
//Ok(None)
|
|
//}
|
|
//}
|
|
//
|
|
//dsl_bind!(AppCommand: App {
|
|
//enqueue = |app, clip: Option<Arc<RwLock<MidiClip>>>| { todo!() };
|
|
//history = |app, delta: isize| { todo!() };
|
|
//zoom = |app, zoom: usize| { todo!() };
|
|
//stop_all = |app| { app.tracks_stop_all(); Ok(None) };
|
|
////dialog = |app, command: DialogCommand|
|
|
////Ok(command.delegate(&mut app.dialog, |c|Self::Dialog{command: c})?);
|
|
//project = |app, command: ArrangementCommand|
|
|
//Ok(command.delegate(&mut app.project, |c|Self::Project{command: c})?);
|
|
//clock = |app, command: ClockCommand|
|
|
//Ok(command.execute(app.clock_mut())?.map(|c|Self::Clock{command: c}));
|
|
//sampler = |app, command: SamplerCommand|
|
|
//Ok(app.project.sampler_mut().map(|s|command.delegate(s, |command|Self::Sampler{command}))
|
|
//.transpose()?.flatten());
|
|
//pool = |app, command: PoolCommand| {
|
|
//let undo = command.clone().delegate(&mut app.pool, |command|AppCommand::Pool{command})?;
|
|
//// update linked editor after pool action
|
|
//match command {
|
|
//// autoselect: automatically load selected clip in editor
|
|
//PoolCommand::Select { .. } |
|
|
//// autocolor: update color in all places simultaneously
|
|
//PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } => {
|
|
//let clip = app.pool.clip().clone();
|
|
//app.editor_mut().map(|editor|editor.set_clip(clip.as_ref()))
|
|
//},
|
|
//_ => None
|
|
//};
|
|
//Ok(undo)
|
|
//};
|
|
//select = |app, selection: Selection| {
|
|
//*app.project.selection_mut() = selection;
|
|
////todo!
|
|
////if let Some(ref mut editor) = app.editor_mut() {
|
|
////editor.set_clip(match selection {
|
|
////Selection::TrackClip { track, scene } if let Some(Some(Some(clip))) = app
|
|
////.project
|
|
////.scenes.get(scene)
|
|
////.map(|s|s.clips.get(track))
|
|
////=>
|
|
////Some(clip),
|
|
////_ =>
|
|
////None
|
|
////});
|
|
////}
|
|
//Ok(None)
|
|
////("select" [t: usize, s: usize] Some(match (t.expect("no track"), s.expect("no scene")) {
|
|
////(0, 0) => Self::Select(Selection::Mix),
|
|
////(t, 0) => Self::Select(Selection::Track(t)),
|
|
////(0, s) => Self::Select(Selection::Scene(s)),
|
|
////(t, s) => Self::Select(Selection::TrackClip { track: t, scene: s }) })))
|
|
//// autoedit: load focused clip in editor.
|
|
//};
|
|
////fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
|
|
////Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
|
|
////}
|
|
////fn launch (app: &mut App) -> Perhaps<Self> {
|
|
////app.project.launch();
|
|
////Ok(None)
|
|
////}
|
|
//toggle_editor = |app, value: bool|{ app.toggle_editor(Some(value)); Ok(None) };
|
|
//editor = |app, command: MidiEditCommand| Ok(if let Some(editor) = app.editor_mut() {
|
|
//let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?;
|
|
//// update linked sampler after editor action
|
|
//app.project.sampler_mut().map(|sampler|match command {
|
|
//// autoselect: automatically select sample in sampler
|
|
//MidiEditCommand::SetNotePos { pos } => { sampler.set_note_pos(pos); },
|
|
//_ => {}
|
|
//});
|
|
//undo
|
|
//} else {
|
|
//None
|
|
//});
|
|
//});
|
|
//take!(ClockCommand |state: App, iter|Take::take(state.clock(), iter));
|
|
//take!(MidiEditCommand |state: App, iter|Ok(state.editor().map(|x|Take::take(x, iter)).transpose()?.flatten()));
|
|
//take!(PoolCommand |state: App, iter|Take::take(&state.pool, iter));
|
|
//take!(SamplerCommand |state: App, iter|Ok(state.project.sampler().map(|x|Take::take(x, iter)).transpose()?.flatten()));
|
|
//take!(ArrangementCommand |state: App, iter|Take::take(&state.project, iter));
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//has_editor!(|self: App|{
|
|
//editor = self.editor;
|
|
//editor_w = {
|
|
//let size = self.size.w();
|
|
//let editor = self.editor.as_ref().expect("missing editor");
|
|
//let time_len = editor.time_len().get();
|
|
//let time_zoom = editor.time_zoom().get().max(1);
|
|
//(5 + (time_len / time_zoom)).min(size.saturating_sub(20)).max(16)
|
|
//};
|
|
//editor_h = 15;
|
|
//is_editing = self.editor.is_some();
|
|
//});
|
|
|
|
|
|
|
|
//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<str>) => {
|
|
//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<ItemTheme> } => {
|
|
//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<Jack> {
|
|
//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<str> {
|
|
//todo!()
|
|
//}
|
|
//fn file_browser_path (&self) -> PathBuf {
|
|
//todo!();
|
|
//}
|
|
///// Immutable reference to sample at cursor.
|
|
//fn sample_selected (&self) -> Option<Arc<RwLock<Sample>>> {
|
|
//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> {
|
|
//Self::Select(state.set_note_pos(i))
|
|
//}
|
|
///// Assign sample to slot
|
|
//set (&self, slot: u7, sample: Option<Arc<RwLock<Sample>>>) -> Option<Self> {
|
|
//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<Self> {
|
|
//todo!()
|
|
//}
|
|
//set_gain (&self, state: &mut Sampler, slot: u7, g: f32) -> Option<Self> {
|
|
//todo!()
|
|
//}
|
|
//note_on (&self, state: &mut Sampler, slot: u7, v: u7) -> Option<Self> {
|
|
//todo!()
|
|
//}
|
|
//note_off (&self, state: &mut Sampler, slot: u7) -> Option<Self> {
|
|
//todo!()
|
|
//}
|
|
//set_sample (&self, state: &mut Sampler, slot: u7, s: Option<Arc<RwLock<Sample>>>) -> Option<Self> {
|
|
//Some(Self::SetSample(p, state.set_sample(p, s)))
|
|
//}
|
|
//import (&self, state: &mut Sampler, c: FileBrowserCommand) -> Option<Self> {
|
|
//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<Arc<RwLock<Sample>>>] 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<Arc<RwLock<Sample>>>]
|
|
////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<Item = (usize, &'a Arc<str>, &'a [Connect], usize, usize)>
|
|
//) -> impl Content<TuiOut> + '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()));
|
|
|
|
|
|
//macro_rules! impl_port {
|
|
//($Name:ident : $Spec:ident -> $Pair:ident |$jack:ident, $name:ident|$port:expr) => {
|
|
//#[derive(Debug)] pub struct $Name {
|
|
///// Handle to JACK client, for receiving reconnect events.
|
|
//jack: Jack<'static>,
|
|
///// Port name
|
|
//name: Arc<str>,
|
|
///// Port handle.
|
|
//port: Port<$Spec>,
|
|
///// List of ports to connect to.
|
|
//conn: Vec<PortConnect>
|
|
//}
|
|
//impl AsRef<Port<$Spec>> for $Name {
|
|
//fn as_ref (&self) -> &Port<$Spec> { &self.port }
|
|
//}
|
|
//impl $Name {
|
|
//pub fn new ($jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
|
//-> Usually<Self>
|
|
//{
|
|
//let $name = name.as_ref();
|
|
//let jack = $jack.clone();
|
|
//let port = $port?;
|
|
//let name = $name.into();
|
|
//let conn = connect.to_vec();
|
|
//let port = Self { jack, port, name, conn };
|
|
//port.connect_to_matching()?;
|
|
//Ok(port)
|
|
//}
|
|
//pub fn name (&self) -> &Arc<str> { &self.name }
|
|
//pub fn port (&self) -> &Port<$Spec> { &self.port }
|
|
//pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port }
|
|
//pub fn into_port (self) -> Port<$Spec> { self.port }
|
|
//pub fn close (self) -> Usually<()> {
|
|
//let Self { jack, port, .. } = self;
|
|
//Ok(jack.with_client(|client|client.unregister_port(port))?)
|
|
//}
|
|
//}
|
|
//impl HasJack<'static> for $Name {
|
|
//fn jack (&self) -> &'static Jack<'static> { &self.jack }
|
|
//}
|
|
//impl JackPort<'static> for $Name {
|
|
//type Port = $Spec;
|
|
//type Pair = $Pair;
|
|
//fn port (&self) -> &Port<$Spec> { &self.port }
|
|
//}
|
|
//impl ConnectTo<'static, &str> for $Name {
|
|
//fn connect_to (&self, to: &str) -> Usually<PortConnectStatus> {
|
|
//self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) {
|
|
//self.connect_to(port)
|
|
//} else {
|
|
//Ok(Missing)
|
|
//})
|
|
//}
|
|
//}
|
|
//impl ConnectTo<'static, &Port<Unowned>> for $Name {
|
|
//fn connect_to (&self, port: &Port<Unowned>) -> Usually<PortConnectStatus> {
|
|
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
|
//Connected
|
|
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
|
//Connected
|
|
//} else {
|
|
//Mismatch
|
|
//}))
|
|
//}
|
|
//}
|
|
//impl ConnectTo<'static, &Port<$Pair>> for $Name {
|
|
//fn connect_to (&self, port: &Port<$Pair>) -> Usually<PortConnectStatus> {
|
|
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
|
//Connected
|
|
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
|
//Connected
|
|
//} else {
|
|
//Mismatch
|
|
//}))
|
|
//}
|
|
//}
|
|
//impl ConnectAuto<'static> for $Name {
|
|
//fn connections (&self) -> &[PortConnect] {
|
|
//&self.conn
|
|
//}
|
|
//}
|
|
//};
|
|
//}
|