wip: rebinding commands...

This commit is contained in:
🪞👃🪞 2025-01-11 23:48:20 +01:00
parent 4fb703d05d
commit 744ce21e24
3 changed files with 171 additions and 122 deletions

View file

@ -25,6 +25,54 @@ pub trait HasClips {
}
}
#[derive(Debug)]
pub struct PoolModel {
pub visible: bool,
/// Collection of clips
pub clips: Arc<RwLock<Vec<Arc<RwLock<MidiClip>>>>>,
/// Selected clip
pub clip: AtomicUsize,
/// Mode switch
pub mode: Option<PoolMode>,
}
impl Default for PoolModel {
fn default () -> Self {
Self {
visible: true,
clips: Arc::from(RwLock::from(vec![])),
clip: 0.into(),
mode: None,
}
}
}
from!(|clip:&Arc<RwLock<MidiClip>>|PoolModel = {
let model = Self::default();
model.clips.write().unwrap().push(clip.clone());
model.clip.store(1, Relaxed);
model
});
#[derive(Clone, PartialEq, Debug)]
pub enum PoolCommand {
Show(bool),
/// Update the contents of the clip pool
Clip(MidiPoolCommand),
/// Select a clip from the clip pool
Select(usize),
/// Rename a clip
Rename(ClipRenameCommand),
/// Change the length of a clip
Length(ClipLengthCommand),
/// Import from file
Import(FileBrowserCommand),
/// Export to file
Export(FileBrowserCommand),
}
impl PoolCommand {
pub fn from_edn <'a> (head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> Self {
todo!()
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum MidiPoolCommand {
Add(usize, MidiClip),
@ -42,6 +90,20 @@ impl MidiPoolCommand {
}
}
/// Modes for clip pool
#[derive(Debug, Clone)]
pub enum PoolMode {
/// Renaming a pattern
Rename(usize, Arc<str>),
/// Editing the length of a pattern
Length(usize, usize, ClipLengthFocus),
/// Load clip from disk
Import(usize, FileBrowser),
/// Save clip to disk
Export(usize, FileBrowser),
}
impl<T: HasClips> Command<T> for MidiPoolCommand {
fn execute (self, model: &mut T) -> Perhaps<Self> {
use MidiPoolCommand::*;
@ -108,38 +170,6 @@ impl<T: HasClips> Command<T> for MidiPoolCommand {
}
}
#[derive(Debug)]
pub struct PoolModel {
pub visible: bool,
/// Collection of clips
pub clips: Arc<RwLock<Vec<Arc<RwLock<MidiClip>>>>>,
/// Selected clip
pub clip: AtomicUsize,
/// Mode switch
pub mode: Option<PoolMode>,
/// Rendered size
size: Measure<TuiOut>,
/// Scroll offset
scroll: usize,
}
impl Default for PoolModel {
fn default () -> Self {
Self {
visible: true,
clips: Arc::from(RwLock::from(vec![])),
clip: 0.into(),
scroll: 0,
mode: None,
size: Measure::new(),
}
}
}
from!(|clip:&Arc<RwLock<MidiClip>>|PoolModel = {
let mut model = Self::default();
model.clips.write().unwrap().push(clip.clone());
model.clip.store(1, Relaxed);
model
});
pub struct PoolView<'a>(pub bool, pub &'a PoolModel);
render!(TuiOut: (self: PoolView<'a>) => {
@ -167,41 +197,6 @@ render!(TuiOut: (self: PoolView<'a>) => {
})))))
});
/// Modes for clip pool
#[derive(Debug, Clone)]
pub enum PoolMode {
/// Renaming a pattern
Rename(usize, Arc<str>),
/// Editing the length of a pattern
Length(usize, usize, ClipLengthFocus),
/// Load clip from disk
Import(usize, FileBrowser),
/// Save clip to disk
Export(usize, FileBrowser),
}
#[derive(Clone, PartialEq, Debug)]
pub enum PoolCommand {
Show(bool),
/// Update the contents of the clip pool
Clip(MidiPoolCommand),
/// Select a clip from the clip pool
Select(usize),
/// Rename a clip
Rename(ClipRenameCommand),
/// Change the length of a clip
Length(ClipLengthCommand),
/// Import from file
Import(FileBrowserCommand),
/// Export to file
Export(FileBrowserCommand),
}
impl PoolCommand {
pub fn from_edn <'a> (head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> Self {
todo!()
}
}
command!(|self:PoolCommand, state: PoolModel|{
use PoolCommand::*;
match self {

View file

@ -151,7 +151,54 @@ impl TrackCommand {
StopAll,
Clear,
}
command!(|self: AppCommand, state: App|match self {
Self::Clear => { todo!() },
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
Self::History(delta) => { todo!("undo/redo") },
Self::Select(s) => { state.selected = s; None },
Self::Scene(cmd) => cmd.delegate(state, Self::Scene)?,
Self::Track(cmd) => cmd.delegate(state, Self::Track)?,
Self::Zoom(_) => { todo!(); },
Self::Editor(cmd) =>
state.editor.as_mut().map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(),
Self::Sampler(cmd) =>
state.sampler.as_mut().map(|sampler|cmd.delegate(sampler, Self::Sampler)).transpose()?.flatten(),
Self::Enqueue(clip) =>
state.player.as_mut().map(|player|{player.enqueue_next(clip.as_ref());None}).flatten(),
Self::StopAll => {
for track in 0..state.tracks.len() { state.tracks[track].player.enqueue_next(None); }
None
},
Self::Color(palette) => {
let old = state.color;
state.color = palette;
Some(Self::Color(old))
},
Self::Pool(cmd) => match cmd {
// autoselect: automatically load selected clip in editor
PoolCommand::Select(_) => {
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
state.editor.set_clip(state.pool.clip().as_ref());
undo
},
// update color in all places simultaneously
PoolCommand::Clip(PoolCmd::SetColor(index, _)) => {
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
state.editor.set_clip(state.pool.clip().as_ref());
undo
},
_ => cmd.delegate(&mut state.pool, Self::Pool)?
},
Self::Compact(compact) => if state.compact != compact {
state.compact = compact;
Some(Self::Compact(!compact))
} else {
None
},
});
command!(|self: SequencerCommand, state: Sequencer|match self {
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,

View file

@ -86,62 +86,11 @@ impl App {
}
}
}
#[derive(Default)] pub struct Sequencer {
pub jack: Arc<RwLock<JackConnection>>,
pub compact: bool,
pub editor: MidiEditor,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub player: MidiPlayer,
pub pool: PoolModel,
pub selectors: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub transport: bool,
}
has_size!(<TuiOut>|self:Sequencer|&self.size);
has_clock!(|self:Sequencer|&self.player.clock);
has_clips!(|self:Sequencer|self.pool.clips);
has_editor!(|self:Sequencer|self.editor);
has_size!(<TuiOut>|self: App|&self.size);
has_clock!(|self: App|&self.clock);
has_clips!(|self: App|self.pool.clips);
has_editor!(|self: App|self.editor);
#[derive(Default)] pub struct Groovebox {
pub jack: Arc<RwLock<JackConnection>>,
pub compact: bool,
pub editor: MidiEditor,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub player: MidiPlayer,
pub pool: PoolModel,
pub sampler: Sampler,
pub size: Measure<TuiOut>,
pub status: bool,
}
has_clock!(|self: Groovebox|self.player.clock());
#[derive(Default)] pub struct Arranger {
pub clock: Clock,
pub color: ItemPalette,
pub compact: bool,
pub editing: AtomicBool,
pub editor: MidiEditor,
pub jack: Arc<RwLock<JackConnection>>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub midi_ins: Vec<JackPort<MidiIn>>,
pub midi_outs: Vec<JackPort<MidiOut>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub pool: PoolModel,
pub scenes: Vec<ArrangerScene>,
pub selected: ArrangerSelection,
pub size: Measure<TuiOut>,
pub splits: [u16;2],
pub tracks: Vec<ArrangerTrack>,
}
has_clock!(|self: Arranger|&self.clock);
has_clips!(|self: Arranger|self.pool.clips);
has_editor!(|self: Arranger|self.editor);
#[derive(Debug)] pub struct ArrangerTrack {
/// Name of track
pub name: Arc<str>,
@ -217,3 +166,61 @@ impl ArrangerSelection {
}
}
}
#[derive(Default)] pub struct Sequencer {
pub jack: Arc<RwLock<JackConnection>>,
pub compact: bool,
pub editor: MidiEditor,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub player: MidiPlayer,
pub pool: PoolModel,
pub selectors: bool,
pub size: Measure<TuiOut>,
pub status: bool,
pub transport: bool,
}
has_size!(<TuiOut>|self:Sequencer|&self.size);
has_clock!(|self:Sequencer|&self.player.clock);
has_clips!(|self:Sequencer|self.pool.clips);
has_editor!(|self:Sequencer|self.editor);
has_player!(|self:Sequencer|self.player);
#[derive(Default)] pub struct Groovebox {
pub jack: Arc<RwLock<JackConnection>>,
pub compact: bool,
pub editor: MidiEditor,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub player: MidiPlayer,
pub pool: PoolModel,
pub sampler: Sampler,
pub size: Measure<TuiOut>,
pub status: bool,
}
has_clock!(|self: Groovebox|self.player.clock());
#[derive(Default)] pub struct Arranger {
pub clock: Clock,
pub color: ItemPalette,
pub compact: bool,
pub editing: AtomicBool,
pub editor: MidiEditor,
pub jack: Arc<RwLock<JackConnection>>,
pub midi_buf: Vec<Vec<Vec<u8>>>,
pub midi_ins: Vec<JackPort<MidiIn>>,
pub midi_outs: Vec<JackPort<MidiOut>>,
pub note_buf: Vec<u8>,
pub perf: PerfModel,
pub pool: PoolModel,
pub scenes: Vec<ArrangerScene>,
pub selected: ArrangerSelection,
pub size: Measure<TuiOut>,
pub splits: [u16;2],
pub tracks: Vec<ArrangerTrack>,
}
has_clock!(|self: Arranger|&self.clock);
has_clips!(|self: Arranger|self.pool.clips);
has_editor!(|self: Arranger|self.editor);