remove those two pesky status widgets to the trait

This commit is contained in:
🪞👃🪞 2025-01-14 17:23:25 +01:00
parent acfaf757ec
commit efbabe6248
13 changed files with 145 additions and 162 deletions

View file

@ -1847,3 +1847,63 @@ from_edn!("mixer/track" => |jack: &Arc<RwLock<JackConnection>>, args| -> MixerTr
//key(Char('<')) => todo!("transport seek beat"),
//key(Char('>')) => todo!("transport seek beat"),
//});
//#[derive(Debug)]
//pub struct MIDIPlayer {
///// Global timebase
//pub clock: Arc<Clock>,
///// Start time and clip being played
//pub play_clip: Option<(Moment, Option<Arc<RwLock<Clip>>>)>,
///// Start time and next clip
//pub next_clip: Option<(Moment, Option<Arc<RwLock<Clip>>>)>,
///// 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<Port<MidiIn>>,
///// Play from current sequence to MIDI ports
//pub midi_outputs: Vec<Port<MidiOut>>,
///// MIDI output buffer
//pub midi_note: Vec<u8>,
///// MIDI output buffer
//pub midi_chunk: Vec<Vec<Vec<u8>>>,
///// Notes currently held at input
//pub notes_in: Arc<RwLock<[bool; 128]>>,
///// Notes currently held at output
//pub notes_out: Arc<RwLock<[bool; 128]>>,
//}
///// Methods used primarily by the process callback
//impl MIDIPlayer {
//pub fn new (
//jack: &Arc<RwLock<JackConnection>>,
//clock: &Arc<Clock>,
//name: &str
//) -> Usually<Self> {
//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())?
//],
//})
//}
//}

View file

@ -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::*;

View file

@ -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<TuiOut> {
let (name, color): (Arc<str>, 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<TuiOut> {
let mut time: Arc<str> = String::from("--.-.--").into();
let mut name: Arc<str> = 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))
}
}

View file

@ -1,5 +1,3 @@
use crate::*;
pub struct Note;
impl Note {

View file

@ -217,63 +217,3 @@ impl HasPlayClip for MidiPlayer {
&mut self.next_clip
}
}
//#[derive(Debug)]
//pub struct MIDIPlayer {
///// Global timebase
//pub clock: Arc<Clock>,
///// Start time and clip being played
//pub play_clip: Option<(Moment, Option<Arc<RwLock<Clip>>>)>,
///// Start time and next clip
//pub next_clip: Option<(Moment, Option<Arc<RwLock<Clip>>>)>,
///// 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<Port<MidiIn>>,
///// Play from current sequence to MIDI ports
//pub midi_outputs: Vec<Port<MidiOut>>,
///// MIDI output buffer
//pub midi_note: Vec<u8>,
///// MIDI output buffer
//pub midi_chunk: Vec<Vec<Vec<u8>>>,
///// Notes currently held at input
//pub notes_in: Arc<RwLock<[bool; 128]>>,
///// Notes currently held at output
//pub notes_out: Arc<RwLock<[bool; 128]>>,
//}
///// Methods used primarily by the process callback
//impl MIDIPlayer {
//pub fn new (
//jack: &Arc<RwLock<JackConnection>>,
//clock: &Arc<Clock>,
//name: &str
//) -> Usually<Self> {
//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())?
//],
//})
//}
//}

View file

@ -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<MidiPool> for PoolCommand {
fn from_edn <'a> (state: &MidiPool, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> 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<String>]) -> 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<str>] 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<T: HasClips> Command<T> for PoolClipCommand {
fn execute (self, model: &mut T) -> Perhaps<Self> {
use PoolClipCommand::*;

View file

@ -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)

View file

View file

@ -1,70 +0,0 @@
use crate::*;
pub struct ClipSelected {
pub(crate) title: &'static str,
pub(crate) name: Arc<str>,
pub(crate) color: ItemPalette,
pub(crate) time: Arc<str>,
}
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 <T: HasPlayClip + HasClock> (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 <T: HasPlayClip> (state: &T) -> Self {
let mut time: Arc<str> = String::from("--.-.--").into();
let mut name: Arc<str> = 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, }
}
}

View file

@ -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)