diff --git a/.old/tek.rs.old b/.old/tek.rs.old index b51b97ad..8c0fd9d1 100644 --- a/.old/tek.rs.old +++ b/.old/tek.rs.old @@ -1847,3 +1847,63 @@ from_edn!("mixer/track" => |jack: &Arc>, args| -> MixerTr //key(Char('<')) => todo!("transport seek beat"), //key(Char('>')) => todo!("transport seek beat"), //}); + +//#[derive(Debug)] +//pub struct MIDIPlayer { + ///// Global timebase + //pub clock: Arc, + ///// Start time and clip being played + //pub play_clip: Option<(Moment, Option>>)>, + ///// Start time and next clip + //pub next_clip: Option<(Moment, Option>>)>, + ///// Play input through output. + //pub monitoring: bool, + ///// Write input to sequence. + //pub recording: bool, + ///// Overdub input to sequence. + //pub overdub: bool, + ///// Send all notes off + //pub reset: bool, // TODO?: after Some(nframes) + ///// Record from MIDI ports to current sequence. + //pub midi_inputs: Vec>, + ///// Play from current sequence to MIDI ports + //pub midi_outputs: Vec>, + ///// MIDI output buffer + //pub midi_note: Vec, + ///// MIDI output buffer + //pub midi_chunk: Vec>>, + ///// Notes currently held at input + //pub notes_in: Arc>, + ///// Notes currently held at output + //pub notes_out: Arc>, +//} + +///// Methods used primarily by the process callback +//impl MIDIPlayer { + //pub fn new ( + //jack: &Arc>, + //clock: &Arc, + //name: &str + //) -> Usually { + //let jack = jack.read().unwrap(); + //Ok(Self { + //clock: clock.clone(), + //clip: None, + //next_clip: None, + //notes_in: Arc::new(RwLock::new([false;128])), + //notes_out: Arc::new(RwLock::new([false;128])), + //monitoring: false, + //recording: false, + //overdub: true, + //reset: true, + //midi_note: Vec::with_capacity(8), + //midi_chunk: vec![Vec::with_capacity(16);16384], + //midi_outputs: vec![ + //jack.client().register_port(format!("{name}_out0").as_str(), MidiOut::default())? + //], + //midi_inputs: vec![ + //jack.client().register_port(format!("{name}_in0").as_str(), MidiIn::default())? + //], + //}) + //} +//} diff --git a/midi/src/lib.rs b/midi/src/lib.rs index 666d402d..569aee85 100644 --- a/midi/src/lib.rs +++ b/midi/src/lib.rs @@ -8,13 +8,12 @@ mod midi_pitch; pub use midi_pitch::*; mod midi_range; pub use midi_range::*; mod midi_point; pub use midi_point::*; mod midi_view; pub use midi_view::*; -mod midi_select; pub use midi_select::*; mod midi_pool; pub use midi_pool::*; mod midi_pool_tui; pub use midi_pool_tui::*; mod midi_pool_cmd; pub use midi_pool_cmd::*; -mod midi_editor; pub use midi_editor::*; +mod midi_edit; pub use midi_edit::*; mod midi_edit_cmd; pub use midi_edit_cmd::*; mod midi_edit_tui; pub use midi_edit_tui::*; diff --git a/midi/src/midi_editor.rs b/midi/src/midi_edit.rs similarity index 100% rename from midi/src/midi_editor.rs rename to midi/src/midi_edit.rs diff --git a/midi/src/midi_editor_keys.edn b/midi/src/midi_edit_keys.edn similarity index 100% rename from midi/src/midi_editor_keys.edn rename to midi/src/midi_edit_keys.edn diff --git a/midi/src/midi-view.edn b/midi/src/midi_edit_view.edn similarity index 100% rename from midi/src/midi-view.edn rename to midi/src/midi_edit_view.edn diff --git a/midi/src/midi_launch.rs b/midi/src/midi_launch.rs index 6359ae5d..abf647eb 100644 --- a/midi/src/midi_launch.rs +++ b/midi/src/midi_launch.rs @@ -32,4 +32,53 @@ pub trait HasPlayClip: HasClock { *self.next_clip_mut() = Some((instant, clip.cloned())); *self.reset_mut() = true; } + fn play_status (&self) -> impl Content { + let (name, color): (Arc, ItemPalette) = if let Some((_, Some(clip))) = self.play_clip() { + let MidiClip { ref name, color, .. } = *clip.read().unwrap(); + (name.clone(), color) + } else { + ("".into(), TuiTheme::g(64).into()) + }; + let time: String = self.pulses_since_start_looped() + .map(|(times, time)|format!("{:>3}x {:>}", times+1.0, self.clock().timebase.format_beats_1(time))) + .unwrap_or_else(||String::from(" ")).into(); + FieldV(color, "Now:", format!("{} {}", time, name)) + } + fn next_status (&self) -> impl Content { + let mut time: Arc = String::from("--.-.--").into(); + let mut name: Arc = String::from("").into(); + let mut color = ItemPalette::from(TuiTheme::g(64)); + let clock = self.clock(); + if let Some((t, Some(clip))) = self.next_clip() { + let clip = clip.read().unwrap(); + name = clip.name.clone(); + color = clip.color.clone(); + time = { + let target = t.pulse.get(); + let current = clock.playhead.pulse.get(); + if target > current { + let remaining = target - current; + format!("-{:>}", clock.timebase.format_beats_1(remaining)) + } else { + String::new() + } + }.into() + } else if let Some((t, Some(clip))) = self.play_clip() { + let clip = clip.read().unwrap(); + if clip.looped { + name = clip.name.clone(); + color = clip.color.clone(); + let target = t.pulse.get() + clip.length as f64; + let current = clock.playhead.pulse.get(); + if target > current { + time = format!("-{:>}", clock.timebase.format_beats_0( + target - current + )).into() + } + } else { + name = "Stop".to_string().into(); + } + }; + FieldV(color, "Next:", format!("{} {}", time, name)) + } } diff --git a/midi/src/midi_pitch.rs b/midi/src/midi_pitch.rs index b0e1f4e2..00269cf6 100644 --- a/midi/src/midi_pitch.rs +++ b/midi/src/midi_pitch.rs @@ -1,5 +1,3 @@ -use crate::*; - pub struct Note; impl Note { diff --git a/midi/src/midi_player.rs b/midi/src/midi_player.rs index eeb1c96e..8d49f05b 100644 --- a/midi/src/midi_player.rs +++ b/midi/src/midi_player.rs @@ -217,63 +217,3 @@ impl HasPlayClip for MidiPlayer { &mut self.next_clip } } - -//#[derive(Debug)] -//pub struct MIDIPlayer { - ///// Global timebase - //pub clock: Arc, - ///// Start time and clip being played - //pub play_clip: Option<(Moment, Option>>)>, - ///// Start time and next clip - //pub next_clip: Option<(Moment, Option>>)>, - ///// Play input through output. - //pub monitoring: bool, - ///// Write input to sequence. - //pub recording: bool, - ///// Overdub input to sequence. - //pub overdub: bool, - ///// Send all notes off - //pub reset: bool, // TODO?: after Some(nframes) - ///// Record from MIDI ports to current sequence. - //pub midi_inputs: Vec>, - ///// Play from current sequence to MIDI ports - //pub midi_outputs: Vec>, - ///// MIDI output buffer - //pub midi_note: Vec, - ///// MIDI output buffer - //pub midi_chunk: Vec>>, - ///// Notes currently held at input - //pub notes_in: Arc>, - ///// Notes currently held at output - //pub notes_out: Arc>, -//} - -///// Methods used primarily by the process callback -//impl MIDIPlayer { - //pub fn new ( - //jack: &Arc>, - //clock: &Arc, - //name: &str - //) -> Usually { - //let jack = jack.read().unwrap(); - //Ok(Self { - //clock: clock.clone(), - //clip: None, - //next_clip: None, - //notes_in: Arc::new(RwLock::new([false;128])), - //notes_out: Arc::new(RwLock::new([false;128])), - //monitoring: false, - //recording: false, - //overdub: true, - //reset: true, - //midi_note: Vec::with_capacity(8), - //midi_chunk: vec![Vec::with_capacity(16);16384], - //midi_outputs: vec![ - //jack.client().register_port(format!("{name}_out0").as_str(), MidiOut::default())? - //], - //midi_inputs: vec![ - //jack.client().register_port(format!("{name}_in0").as_str(), MidiIn::default())? - //], - //}) - //} -//} diff --git a/midi/src/midi_pool_cmd.rs b/midi/src/midi_pool_cmd.rs index 0fe636a7..5f4bc048 100644 --- a/midi/src/midi_pool_cmd.rs +++ b/midi/src/midi_pool_cmd.rs @@ -1,7 +1,6 @@ use crate::*; use KeyCode::*; -#[derive(Clone, PartialEq, Debug)] -pub enum PoolCommand { +#[derive(Clone, PartialEq, Debug)] pub enum PoolCommand { Show(bool), /// Update the contents of the clip pool Clip(PoolClipCommand), @@ -16,13 +15,16 @@ pub enum PoolCommand { /// Export to file Export(FileBrowserCommand), } -impl EdnCommand for PoolCommand { - fn from_edn <'a> (state: &MidiPool, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { - todo!() - } -} -#[derive(Clone, Debug, PartialEq)] -pub enum PoolClipCommand { +edn_command!(PoolCommand: |state: MidiPool| { + ("show" [a: bool] Self::Show(a.expect("no flag"))) + ("select" [i: usize] Self::Select(i.expect("no index"))) + ("clip" [a, ..b] Self::Clip(PoolClipCommand::from_edn(state, &a.to_ref(), b))) + ("rename" [a, ..b] Self::Rename(ClipRenameCommand::from_edn(state, &a.to_ref(), b))) + ("length" [a, ..b] Self::Length(ClipRenameCommand::from_edn(state, &a.to_ref(), b))) + ("import" [a, ..b] Self::Import(FileBrowserCommand::from_edn(state, &a.to_ref(), b))) + ("export" [a, ..b] Self::Export(FileBrowserCommand::from_edn(state, &a.to_ref(), b))) +}); +#[derive(Clone, Debug, PartialEq)] pub enum PoolClipCommand { Add(usize, MidiClip), Delete(usize), Swap(usize, usize), @@ -32,11 +34,16 @@ pub enum PoolClipCommand { SetLength(usize, usize), SetColor(usize, ItemColor), } -impl PoolClipCommand { - pub fn from_edn <'a> (head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { - todo!() - } -} +edn_command!(PoolClipCommand: |state: MidiPool| { + ("add" [i: usize, c: MidiClip] Self::Add(i.expect("no index"), c.expect("no clip"))) + ("delete" [i: usize] Self::Delete(i.expect("no index"))) + ("swap" [a: usize, b: usize] Self::Swap(a.expect("no index"), b.expect("no index"))) + ("import" [i: usize, p: PathBuf] Self::Import(i.expect("no index"), p.expect("no path"))) + ("export" [i: usize, p: PathBuf] Self::Export(i.expect("no index"), p.expect("no path"))) + ("set-name" [i: usize, n: Arc] Self::SetName(i.expect("no index"), n.expect("no name"))) + ("set-length" [i: usize, l: usize] Self::SetLength(i.expect("no index"), l.expect("no length"))) + ("set-color" [i: usize, c: ItemColor] Self::SetColor(i.expect("no index"), c.expect("no color"))) +}); impl Command for PoolClipCommand { fn execute (self, model: &mut T) -> Perhaps { use PoolClipCommand::*; @@ -102,7 +109,7 @@ impl Command for PoolClipCommand { }) } } -command!(|self:PoolCommand, state: MidiPool|{ +command!(|self: PoolCommand, state: MidiPool|{ use PoolCommand::*; match self { Show(visible) => { diff --git a/midi/src/midi_pool_keys.edn b/midi/src/midi_pool_keys.edn new file mode 100644 index 00000000..cc4a01da --- /dev/null +++ b/midi/src/midi_pool_keys.edn @@ -0,0 +1,13 @@ +(:n clip/rename/begin) +(:t clip/length/begin) +(:m clip/import/begin) +(:x clip/export/begin) +(:c clip/color/random) +(:bracket-open clip/select/prev) +(:bracket-close clip/select/next) +(:lt clip/move/prev) +(:gt clip/move/next) +(:del clip/delete) +(:shift-a clip/add) +(:i clip/insert) +(:d clip/duplicate) diff --git a/midi/src/midi_pool_view.edn b/midi/src/midi_pool_view.edn new file mode 100644 index 00000000..e69de29b diff --git a/midi/src/midi_select.rs b/midi/src/midi_select.rs deleted file mode 100644 index 0073a8fd..00000000 --- a/midi/src/midi_select.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::*; -pub struct ClipSelected { - pub(crate) title: &'static str, - pub(crate) name: Arc, - pub(crate) color: ItemPalette, - pub(crate) time: Arc, -} -content!(TuiOut: |self: ClipSelected|FieldV( - self.color, - self.title, - format!("{} {}", self.time, self.name) -)); -impl ClipSelected { - /// Shows currently playing clip with beats elapsed - pub fn play_clip (state: &T) -> Self { - let (name, color) = if let Some((_, Some(clip))) = state.play_clip() { - let MidiClip { ref name, color, .. } = *clip.read().unwrap(); - (name.clone().into(), color) - } else { - ("".to_string().into(), TuiTheme::g(64).into()) - }; - Self { - title: "Now", - name, - color, - time: state.pulses_since_start_looped() - .map(|(times, time)|format!("{:>3}x {:>}", - times+1.0, - state.clock().timebase.format_beats_1(time))) - .unwrap_or_else(||String::from(" ")).into() - } - } - /// Shows next clip with beats remaining until switchover - pub fn next_clip (state: &T) -> Self { - let mut time: Arc = String::from("--.-.--").into(); - let mut name: Arc = String::from("").into(); - let mut color = ItemPalette::from(TuiTheme::g(64)); - if let Some((t, Some(clip))) = state.next_clip() { - let clip = clip.read().unwrap(); - name = clip.name.clone(); - color = clip.color.clone(); - time = { - let target = t.pulse.get(); - let current = state.clock().playhead.pulse.get(); - if target > current { - let remaining = target - current; - format!("-{:>}", state.clock().timebase.format_beats_1(remaining)) - } else { - String::new() - } - }.into() - } else if let Some((t, Some(clip))) = state.play_clip() { - let clip = clip.read().unwrap(); - if clip.looped { - name = clip.name.clone(); - color = clip.color.clone(); - let target = t.pulse.get() + clip.length as f64; - let current = state.clock().playhead.pulse.get(); - if target > current { - time = format!("-{:>}", state.clock().timebase.format_beats_0( - target - current - )).into() - } - } else { - name = "Stop".to_string().into(); - } - }; - Self { title: "Next", time, name, color, } - } -} diff --git a/midi/src/pool-keys.edn b/midi/src/pool-keys.edn index cc4a01da..e69de29b 100644 --- a/midi/src/pool-keys.edn +++ b/midi/src/pool-keys.edn @@ -1,13 +0,0 @@ -(:n clip/rename/begin) -(:t clip/length/begin) -(:m clip/import/begin) -(:x clip/export/begin) -(:c clip/color/random) -(:bracket-open clip/select/prev) -(:bracket-close clip/select/next) -(:lt clip/move/prev) -(:gt clip/move/next) -(:del clip/delete) -(:shift-a clip/add) -(:i clip/insert) -(:d clip/duplicate)