convert all def_command! to #[commands]
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
i do not exist 2026-08-10 12:11:17 +03:00
parent 7fcab73b04
commit 62f30daac6
6 changed files with 295 additions and 195 deletions

View file

@ -46,40 +46,83 @@ pub struct Arrangement {
#[cfg(feature = "scene")] pub scene_scroll: usize,
}
def_command!(TrackCommand: |track: Track| {
Stop => { track.sequencer.enqueue_next(None); Ok(None) },
SetRec { rec: Option<bool> } => toggle_bool(&mut track.sequencer.recording, rec, |rec|Self::SetRec { rec }),
SetMon { mon: Option<bool> } => toggle_bool(&mut track.sequencer.monitoring, mon, |mon|Self::SetMon { mon }),
SetMute { mute: Option<bool> } => todo!(),
SetSolo { solo: Option<bool> } => todo!(),
SetSize { size: usize } => todo!(),
SetZoom { zoom: usize } => todo!(),
SetName { name: Arc<str> } => swap_value(&mut track.name, name, |name|Self::SetName { name }),
SetColor { color: ItemTheme } => swap_value(&mut track.color, color, |color|Self::SetColor { color }),
});
#[tek_proc::commands(TrackCommand = "track")]
impl Track {
#[command(Stop = "stop")]
fn stop (&mut self) -> Perhaps<TrackCommand> {
self.sequencer.enqueue_next(None);
Ok(None)
}
#[command(SetRec = "rec")]
fn set_rec (&mut self, rec: Option<bool>) -> Perhaps<TrackCommand> {
toggle_bool(&mut self.sequencer.recording, &rec, |rec|TrackCommand::SetRec { rec })
}
#[command(SetMon = "mon")]
fn set_mon (&mut self, mon: Option<bool>) -> Perhaps<TrackCommand> {
toggle_bool(&mut self.sequencer.monitoring, &mon, |mon|TrackCommand::SetMon { mon })
}
#[command(SetMute = "mute")]
fn set_mute (&mut self, mute: Option<bool>) -> Perhaps<TrackCommand> {
todo!()
}
#[command(SetSolo = "solo")]
fn set_solo (&mut self, solo: Option<bool>) -> Perhaps<TrackCommand> {
todo!()
}
#[command(SetSize = "size")]
fn set_size (&mut self, size: usize) -> Perhaps<TrackCommand> {
todo!()
}
#[command(SetZoom = "zoom")]
fn set_zoom (&mut self, zoom: usize) -> Perhaps<TrackCommand> {
todo!()
}
#[command(SetName = "name")]
fn set_name (&mut self, name: Arc<str>) -> Perhaps<TrackCommand> {
swap_value(&mut self.name, &name, |name|TrackCommand::SetName { name })
}
#[command(SetColor = "color")]
fn set_color (&mut self, color: ItemTheme) -> Perhaps<TrackCommand> {
swap_value(&mut self.color, &color, |color|TrackCommand::SetColor { color })
}
}
def_command!(SceneCommand: |scene: Scene| {
SetSize { size: usize } => { todo!() },
SetZoom { size: usize } => { todo!() },
SetName { name: Arc<str> } =>
swap_value(&mut scene.name, name, |name|Self::SetName{name}),
SetColor { color: ItemTheme } =>
swap_value(&mut scene.color, color, |color|Self::SetColor{color}),
});
#[tek_proc::commands(SceneCommand = "scene")]
impl Scene {
#[command(SetSize = "size")]
fn set_size (&mut self, size: usize) -> Perhaps<SceneCommand> {
todo!()
}
#[command(SetZoom = "zoom")]
fn set_zoom (&mut self, size: usize) -> Perhaps<SceneCommand> {
todo!()
}
#[command(SetName = "name")]
fn set_name (&mut self, name: Arc<str>) -> Perhaps<SceneCommand> {
swap_value(&mut self.name, &name, |name|SceneCommand::SetName{name})
}
#[command(SetColor = "color")]
fn set_color (&mut self, color: ItemTheme) -> Perhaps<SceneCommand> {
swap_value(&mut self.color, &color, |color|SceneCommand::SetColor{color})
}
}
def_command!(ClipCommand: |clip: MidiClip| {
SetColor { color: Option<ItemTheme> } => {
#[tek_proc::commands(ClipCommand = "clip")]
impl MidiClip {
#[command(SetColor = "color")]
fn set_color (&mut self, color: Option<ItemTheme>) -> Perhaps<ClipCommand> {
//(SetColor [t: usize, s: usize, c: ItemTheme]
//clip.clip_set_color(t, s, c).map(|o|Self::SetColor(t, s, o)))));
//("color" [a: usize, b: usize] Some(Self::SetColor(a.unwrap(), b.unwrap(), ItemTheme::random())))
todo!()
},
SetLoop { looping: Option<bool> } => {
}
#[command(SetLoop = "loop")]
fn set_loop (&mut self, looping: Option<bool>) -> Perhaps<ClipCommand> {
//(SetLoop [t: usize, s: usize, l: bool] cmd_todo!("\n\rtodo: {self:?}"))
//("loop" [a: usize, b: usize, c: bool] Some(Self::SetLoop(a.unwrap(), b.unwrap(), c.unwrap())))
todo!()
}
});
}
/// Represents the current user selection in the arranger
#[derive(PartialEq, Clone, Copy, Debug, Default)]
@ -1068,3 +1111,27 @@ macro_rules! def_sizes_iter {
def_sizes_iter!(PortsSizes => Arc<str>, [Connect]);
def_sizes_iter!(ScenesSizes => Scene);
def_sizes_iter!(TracksSizes => Track);
fn swap_value <T: Clone + PartialEq, U> (
target: &mut T, value: &T, returned: impl Fn(T)->U
) -> Perhaps<U> {
if *target == *value {
Ok(None)
} else {
let mut value = value.clone();
std::mem::swap(target, &mut value);
Ok(Some(returned(value)))
}
}
fn toggle_bool <U> (
target: &mut bool, value: &Option<bool>, returned: impl Fn(Option<bool>)->U
) -> Perhaps<U> {
let mut value = value.unwrap_or(!*target);
if value == *target {
Ok(None)
} else {
std::mem::swap(target, &mut value);
Ok(Some(returned(Some(value))))
}
}

View file

@ -19,8 +19,8 @@ impl Browse {
todo!()
}
/// Set current directory
#[command(SetPath = "set-path")]
fn set_path (&mut self, _path: PathBuf) -> Perhaps<BrowseCommand> {
#[command(Chdir = "chdir")]
fn chdir (&mut self, _path: PathBuf) -> Perhaps<BrowseCommand> {
todo!()
}
/// Set current filter
@ -35,15 +35,6 @@ impl Browse {
}
}
def_command!(FileBrowserCommand: |_browse: Browse|{
//("begin" [] Some(Self::Begin))
//("cancel" [] Some(Self::Cancel))
//("confirm" [] Some(Self::Confirm))
//("select" [i: usize] Some(Self::Select(i.expect("no index"))))
//("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path"))))
//("filter" [f: Arc<str>] Some(Self::Filter(f.expect("no filter")))))
});
/// Browses for files to load/save.
///
/// ```
@ -104,7 +95,7 @@ impl Browse {
}
Ok(Self { cwd, dirs, files, ..Default::default() })
}
pub fn chdir (&self) -> Usually<Self> { Self::new(Some(self.path())) }
pub fn to_chdir (&self) -> Usually<Self> { Self::new(Some(self.path())) }
pub fn len (&self) -> usize { self.dirs.len() + self.files.len() }
pub fn is_dir (&self) -> bool { self.index < self.dirs.len() }
pub fn is_file (&self) -> bool { self.index >= self.dirs.len() }

View file

@ -20,36 +20,61 @@ impl App {
}
}
def_command!(ClockCommand: |clock: Clock| {
SeekUsec { usec: f64 } => {
clock.playhead.update_from_usec(*usec); Ok(None) },
SeekSample { sample: f64 } => {
clock.playhead.update_from_sample(*sample); Ok(None) },
SeekPulse { pulse: f64 } => {
clock.playhead.update_from_pulse(*pulse); Ok(None) },
SetBpm { bpm: f64 } => Ok(Some(
Self::SetBpm { bpm: clock.timebase().bpm.set(*bpm) })),
SetQuant { quant: f64 } => Ok(Some(
Self::SetQuant { quant: clock.quant.set(*quant) })),
SetSync { sync: f64 } => Ok(Some(
Self::SetSync { sync: clock.sync.set(*sync) })),
#[tek_proc::commands(ClockCommand = "clock")]
impl Clock {
#[command(SeekUsec = "usec")]
fn seek_usec (&mut self, usec: f64) -> Perhaps<ClockCommand> {
self.playhead.update_from_usec(usec);
Ok(None)
}
Play { position: Option<u32> } => {
clock.play_from(*position)?; Ok(None) /* TODO Some(Pause(previousPosition)) */ },
Pause { position: Option<u32> } => {
clock.pause_at(*position)?; Ok(None) },
#[command(SeekSample = "sample")]
fn seek_sample (&mut self, sample: f64) -> Perhaps<ClockCommand> {
self.playhead.update_from_sample(sample);
Ok(None)
}
TogglePlayback { position: u32 } => Ok(if clock.is_rolling() {
clock.pause_at(Some(*position))?; None
} else {
clock.play_from(Some(*position))?; None
}),
});
#[command(SeekPulse = "pulse")]
fn seek_pulse (&mut self, pulse: f64) -> Perhaps<ClockCommand> {
self.playhead.update_from_pulse(pulse);
Ok(None)
}
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
fn clock (&self) -> &Clock { self.as_ref() }
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
#[command(SetBpm = "bpm")]
fn set_bpm (&mut self, bpm: f64) -> Perhaps<ClockCommand> {
Ok(Some(ClockCommand::SetBpm { bpm: self.timebase().bpm.set(bpm) }))
}
#[command(SetQuant = "quant")]
fn set_quant (&mut self, quant: f64) -> Perhaps<ClockCommand> {
Ok(Some(ClockCommand::SetQuant { quant: self.quant.set(quant) }))
}
#[command(SetSync = "sync")]
fn set_sync (&mut self, sync: f64) -> Perhaps<ClockCommand> {
Ok(Some(ClockCommand::SetSync { sync: self.sync.set(sync) }))
}
#[command(Play = "play")]
fn play (&mut self, position: Option<u32>) -> Perhaps<ClockCommand> {
self.play_from(position)?;
Ok(None) /* TODO Some(Pause(previousPosition)) */
}
#[command(Pause = "pause")]
fn pause (&mut self, position: Option<u32>) -> Perhaps<ClockCommand> {
self.pause_at(position)?;
Ok(None)
}
#[command(TogglePlayback = "toggle")]
fn toggle (&mut self, position: u32) -> Perhaps<ClockCommand> {
Ok(if self.is_rolling() {
self.pause_at(Some(position))?; None
} else {
self.play_from(Some(position))?; None
})
}
}
/// The source of time.
@ -86,6 +111,23 @@ pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
#[cfg(feature = "port")] pub click_out: Arc<RwLock<Option<AudioOutput>>>,
}
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
fn clock (&self) -> &Clock {
self.as_ref()
}
fn clock_mut (&mut self) -> &mut Clock {
self.as_mut()
}
}
impl<T: HasClock> Act<T> for ClockCommand {
fn act (&self, state: &mut T) -> Perhaps<Self> {
self.act(state.clock_mut()) // awesome
}
}
/// Quantization setting for launching clips
///
/// ```
@ -183,35 +225,6 @@ impl Quantize {
}
}
/// Define and implement a unit of time
#[macro_export] macro_rules! impl_time_unit {
($T:ident) => {
impl Gettable<f64> for $T {
fn get (&self) -> f64 { self.0.load(Relaxed) }
}
impl InteriorMutable<f64> for $T {
fn set (&self, value: f64) -> f64 {
let old = self.get();
self.0.store(value, Relaxed);
old
}
}
impl TimeUnit for $T {}
impl_op!($T, Add, add, |a, b|{a + b});
impl_op!($T, Sub, sub, |a, b|{a - b});
impl_op!($T, Mul, mul, |a, b|{a * b});
impl_op!($T, Div, div, |a, b|{a / b});
impl_op!($T, Rem, rem, |a, b|{a % b});
impl From<f64> for $T { fn from (value: f64) -> Self { Self(value.into()) } }
impl From<usize> for $T { fn from (value: usize) -> Self { Self((value as f64).into()) } }
impl From<$T> for f64 { fn from (value: $T) -> Self { value.get() } }
impl From<$T> for usize { fn from (value: $T) -> Self { value.get() as usize } }
impl From<&$T> for f64 { fn from (value: &$T) -> Self { value.get() } }
impl From<&$T> for usize { fn from (value: &$T) -> Self { value.get() as usize } }
impl Clone for $T { fn clone (&self) -> Self { Self(self.get().into()) } }
}
}
impl std::fmt::Debug for Clock {
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("Clock")
@ -397,14 +410,38 @@ impl Clock {
}
}
impl<T: HasClock> Act<T> for ClockCommand {
fn act (&self, state: &mut T) -> Perhaps<Self> {
self.act(state.clock_mut()) // awesome
impl_has!(Clock: |self: Track|self.sequencer.clock);
impl_default!(Timebase: Self::new(48000f64, 150f64, DEFAULT_PPQ));
/// Define and implement a unit of time
#[macro_export] macro_rules! impl_time_unit {
($T:ident) => {
impl Gettable<f64> for $T {
fn get (&self) -> f64 { self.0.load(Relaxed) }
}
impl InteriorMutable<f64> for $T {
fn set (&self, value: f64) -> f64 {
let old = self.get();
self.0.store(value, Relaxed);
old
}
}
impl TimeUnit for $T {}
impl_op!($T, Add, add, |a, b|{a + b});
impl_op!($T, Sub, sub, |a, b|{a - b});
impl_op!($T, Mul, mul, |a, b|{a * b});
impl_op!($T, Div, div, |a, b|{a / b});
impl_op!($T, Rem, rem, |a, b|{a % b});
impl From<f64> for $T { fn from (value: f64) -> Self { Self(value.into()) } }
impl From<usize> for $T { fn from (value: usize) -> Self { Self((value as f64).into()) } }
impl From<$T> for f64 { fn from (value: $T) -> Self { value.get() } }
impl From<$T> for usize { fn from (value: $T) -> Self { value.get() as usize } }
impl From<&$T> for f64 { fn from (value: &$T) -> Self { value.get() } }
impl From<&$T> for usize { fn from (value: &$T) -> Self { value.get() as usize } }
impl Clone for $T { fn clone (&self) -> Self { Self(self.get().into()) } }
}
}
#[cfg(feature = "clock")] impl_has!(Clock: |self: Track|self.sequencer.clock);
impl_default!(Timebase: Self::new(48000f64, 150f64, DEFAULT_PPQ));
impl_time_unit!(SampleCount);
impl_time_unit!(SampleRate);
impl_time_unit!(Microsecond);

View file

@ -56,29 +56,69 @@ impl App {
}
}
def_command!(MidiEditCommand: |editor: MidiEditor| {
Show { clip: Option<Arc<RwLock<MidiClip>>> } => {
editor.set_clip(clip.as_ref()); editor.redraw(); Ok(None) },
DeleteNote => {
editor.redraw(); todo!() },
AppendNote { advance: bool } => {
editor.put_note(*advance); editor.redraw(); Ok(None) },
SetNotePos { pos: usize } => {
editor.set_note_pos((*pos).min(127)); editor.redraw(); Ok(None) },
SetNoteLen { len: usize } => {
editor.set_note_len(*len); editor.redraw(); Ok(None) },
SetNoteScroll { scroll: usize } => {
editor.set_note_lo((*scroll).min(127)); editor.redraw(); Ok(None) },
SetTimePos { pos: usize } => {
editor.set_time_pos(*pos); editor.redraw(); Ok(None) },
SetTimeScroll { scroll: usize } => {
editor.set_time_start(*scroll); editor.redraw(); Ok(None) },
SetTimeZoom { zoom: usize } => {
editor.set_time_zoom(*zoom); editor.redraw(); Ok(None) },
SetTimeLock { lock: bool } => {
editor.set_time_lock(*lock); editor.redraw(); Ok(None) },
#[tek_proc::commands(MidiEditCommand = "edit")]
impl MidiEditor {
#[command(Show = "show")]
fn show (&mut self, clip: Option<Arc<RwLock<MidiClip>>>) -> Perhaps<MidiEditCommand> {
self.set_clip(clip.as_ref());
self.redraw();
Ok(None)
}
#[command(DeleteNote = "delete")]
fn note_delete (&mut self) -> Perhaps<MidiEditCommand> {
self.redraw();
todo!()
}
#[command(AppendNote = "append")]
fn note_append (&mut self, advance: bool) -> Perhaps<MidiEditCommand> {
self.put_note(advance);
self.redraw();
Ok(None)
}
#[command(SetNotePos = "note-pos")]
fn note_set_pos (&mut self, pos: usize) -> Perhaps<MidiEditCommand> {
self.set_note_pos((pos).min(127));
self.redraw();
Ok(None)
}
#[command(SetNoteLen = "note-len")]
fn note_set_len (&mut self, len: usize) -> Perhaps<MidiEditCommand> {
self.set_note_len(len);
self.redraw();
Ok(None)
}
#[command(SetNoteScroll = "note-scroll")]
fn note_set_scroll (&mut self, scroll: usize) -> Perhaps<MidiEditCommand> {
self.set_note_lo((scroll).min(127));
self.redraw();
Ok(None)
}
#[command(SetTimePos = "time-pos")]
fn time_set_pos (&mut self, pos: usize) -> Perhaps<MidiEditCommand> {
self.set_time_pos(pos);
self.redraw();
Ok(None)
}
#[command(SetTimeScroll = "time-scroll")]
fn time_set_scroll (&mut self, scroll: usize) -> Perhaps<MidiEditCommand> {
self.set_time_start(scroll);
self.redraw();
Ok(None)
}
#[command(SetTimeZoom = "time-zoom")]
fn time_set_zoom (&mut self, zoom: usize) -> Perhaps<MidiEditCommand> {
self.set_time_zoom(zoom);
self.redraw();
Ok(None)
}
#[command(SetTimeLock = "time-lock")]
fn time_set_lock (&mut self, lock: bool) -> Perhaps<MidiEditCommand> {
self.set_time_lock(lock);
self.redraw();
Ok(None)
}
// TODO: 1-9 seek markers that by default start every 8th of the clip
});
}
/// Contains state for viewing and editing a clip.
///

View file

@ -8,52 +8,61 @@ pub(crate) use symphonia::{
},
};
def_command!(SamplerCommand: |sampler: Sampler| {
RecordToggle { slot: usize } => {
let slot = *slot;
let recording = sampler.recording.as_ref().map(|x|x.0);
let _ = Self::RecordFinish.act(sampler)?;
#[tek_proc::commands(SamplerCommand = "sampler")]
impl Sampler {
#[command(RecordToggle = "rec-toggle")]
fn record_toggle (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
let recording = self.recording.as_ref().map(|x|x.0);
let _ = SamplerCommand::RecordFinish.act(self)?;
// autoslice: continue recording at next slot
if recording != Some(slot) {
Self::RecordBegin { slot }.act(sampler)
SamplerCommand::RecordBegin { slot }.act(self)
} else {
Ok(None)
}
},
RecordBegin { slot: usize } => {
let slot = *slot;
sampler.recording = Some((
}
#[command(RecordBegin = "rec-begin")]
fn record_begin (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
self.recording = Some((
slot,
Some(Arc::new(RwLock::new(Sample::new(
"Sample", 0, 0, vec![vec![];sampler.audio_ins.len()]
"Sample", 0, 0, vec![vec![];self.audio_ins.len()]
))))
));
Ok(None)
},
RecordFinish => {
let _prev_sample = sampler.recording.as_mut().map(|(index, sample)|{
std::mem::swap(sample, &mut sampler.samples.0[*index]);
}
#[command(RecordFinish = "rec-finish")]
fn record_finish (&mut self) -> Perhaps<SamplerCommand> {
let _prev_sample = self.recording.as_mut().map(|(index, sample)|{
std::mem::swap(sample, &mut self.samples.0[*index]);
sample
}); // TODO: undo
Ok(None)
},
RecordCancel => {
sampler.recording = None;
}
#[command(RecordCancel = "rec-cancel")]
fn record_cancel (&mut self) -> Perhaps<SamplerCommand> {
self.recording = None;
Ok(None)
},
PlaySample { slot: usize } => {
let slot = *slot;
if let Some(ref sample) = sampler.samples.0[slot] {
sampler.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
}
#[command(PlaySample = "sample-play")]
fn sample_play (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
if let Some(ref sample) = self.samples.0[slot] {
self.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
}
Ok(None)
},
StopSample { slot: usize } => {
let _slot = *slot;
}
#[command(StopSample = "sample-stop")]
fn sample_stop (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
todo!();
//Ok(None)
},
});
}
}
/// Plays [Voice]s from [Sample]s.
///