mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: rebinding commands...
This commit is contained in:
parent
4fb703d05d
commit
744ce21e24
3 changed files with 171 additions and 122 deletions
|
|
@ -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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum MidiPoolCommand {
|
pub enum MidiPoolCommand {
|
||||||
Add(usize, MidiClip),
|
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 {
|
impl<T: HasClips> Command<T> for MidiPoolCommand {
|
||||||
fn execute (self, model: &mut T) -> Perhaps<Self> {
|
fn execute (self, model: &mut T) -> Perhaps<Self> {
|
||||||
use MidiPoolCommand::*;
|
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);
|
pub struct PoolView<'a>(pub bool, pub &'a PoolModel);
|
||||||
render!(TuiOut: (self: PoolView<'a>) => {
|
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|{
|
command!(|self:PoolCommand, state: PoolModel|{
|
||||||
use PoolCommand::*;
|
use PoolCommand::*;
|
||||||
match self {
|
match self {
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,54 @@ impl TrackCommand {
|
||||||
StopAll,
|
StopAll,
|
||||||
Clear,
|
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 {
|
command!(|self: SequencerCommand, state: Sequencer|match self {
|
||||||
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||||
|
|
|
||||||
117
tek/src/model.rs
117
tek/src/model.rs
|
|
@ -86,62 +86,11 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Default)] pub struct Sequencer {
|
has_size!(<TuiOut>|self: App|&self.size);
|
||||||
pub jack: Arc<RwLock<JackConnection>>,
|
has_clock!(|self: App|&self.clock);
|
||||||
pub compact: bool,
|
has_clips!(|self: App|self.pool.clips);
|
||||||
pub editor: MidiEditor,
|
has_editor!(|self: App|self.editor);
|
||||||
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);
|
|
||||||
|
|
||||||
#[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 {
|
#[derive(Debug)] pub struct ArrangerTrack {
|
||||||
/// Name of track
|
/// Name of track
|
||||||
pub name: Arc<str>,
|
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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue