mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
remove those two pesky status widgets to the trait
This commit is contained in:
parent
acfaf757ec
commit
efbabe6248
13 changed files with 145 additions and 162 deletions
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Note;
|
||||
|
||||
impl Note {
|
||||
|
|
|
|||
|
|
@ -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())?
|
||||
//],
|
||||
//})
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
@ -102,7 +109,7 @@ impl<T: HasClips> Command<T> for PoolClipCommand {
|
|||
})
|
||||
}
|
||||
}
|
||||
command!(|self:PoolCommand, state: MidiPool|{
|
||||
command!(|self: PoolCommand, state: MidiPool|{
|
||||
use PoolCommand::*;
|
||||
match self {
|
||||
Show(visible) => {
|
||||
|
|
|
|||
13
midi/src/midi_pool_keys.edn
Normal file
13
midi/src/midi_pool_keys.edn
Normal 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)
|
||||
0
midi/src/midi_pool_view.edn
Normal file
0
midi/src/midi_pool_view.edn
Normal 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, }
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue