mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-08-28 12:56:57 +02:00
This commit is contained in:
parent
7fcab73b04
commit
62f30daac6
6 changed files with 295 additions and 195 deletions
|
|
@ -46,40 +46,83 @@ pub struct Arrangement {
|
||||||
#[cfg(feature = "scene")] pub scene_scroll: usize,
|
#[cfg(feature = "scene")] pub scene_scroll: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_command!(TrackCommand: |track: Track| {
|
#[tek_proc::commands(TrackCommand = "track")]
|
||||||
Stop => { track.sequencer.enqueue_next(None); Ok(None) },
|
impl Track {
|
||||||
SetRec { rec: Option<bool> } => toggle_bool(&mut track.sequencer.recording, rec, |rec|Self::SetRec { rec }),
|
#[command(Stop = "stop")]
|
||||||
SetMon { mon: Option<bool> } => toggle_bool(&mut track.sequencer.monitoring, mon, |mon|Self::SetMon { mon }),
|
fn stop (&mut self) -> Perhaps<TrackCommand> {
|
||||||
SetMute { mute: Option<bool> } => todo!(),
|
self.sequencer.enqueue_next(None);
|
||||||
SetSolo { solo: Option<bool> } => todo!(),
|
Ok(None)
|
||||||
SetSize { size: usize } => todo!(),
|
}
|
||||||
SetZoom { zoom: usize } => todo!(),
|
#[command(SetRec = "rec")]
|
||||||
SetName { name: Arc<str> } => swap_value(&mut track.name, name, |name|Self::SetName { name }),
|
fn set_rec (&mut self, rec: Option<bool>) -> Perhaps<TrackCommand> {
|
||||||
SetColor { color: ItemTheme } => swap_value(&mut track.color, color, |color|Self::SetColor { color }),
|
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| {
|
#[tek_proc::commands(SceneCommand = "scene")]
|
||||||
SetSize { size: usize } => { todo!() },
|
impl Scene {
|
||||||
SetZoom { size: usize } => { todo!() },
|
#[command(SetSize = "size")]
|
||||||
SetName { name: Arc<str> } =>
|
fn set_size (&mut self, size: usize) -> Perhaps<SceneCommand> {
|
||||||
swap_value(&mut scene.name, name, |name|Self::SetName{name}),
|
todo!()
|
||||||
SetColor { color: ItemTheme } =>
|
}
|
||||||
swap_value(&mut scene.color, color, |color|Self::SetColor{color}),
|
#[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| {
|
#[tek_proc::commands(ClipCommand = "clip")]
|
||||||
SetColor { color: Option<ItemTheme> } => {
|
impl MidiClip {
|
||||||
|
#[command(SetColor = "color")]
|
||||||
|
fn set_color (&mut self, color: Option<ItemTheme>) -> Perhaps<ClipCommand> {
|
||||||
//(SetColor [t: usize, s: usize, c: ItemTheme]
|
//(SetColor [t: usize, s: usize, c: ItemTheme]
|
||||||
//clip.clip_set_color(t, s, c).map(|o|Self::SetColor(t, s, o)))));
|
//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())))
|
//("color" [a: usize, b: usize] Some(Self::SetColor(a.unwrap(), b.unwrap(), ItemTheme::random())))
|
||||||
todo!()
|
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:?}"))
|
//(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())))
|
//("loop" [a: usize, b: usize, c: bool] Some(Self::SetLoop(a.unwrap(), b.unwrap(), c.unwrap())))
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/// Represents the current user selection in the arranger
|
/// Represents the current user selection in the arranger
|
||||||
#[derive(PartialEq, Clone, Copy, Debug, Default)]
|
#[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!(PortsSizes => Arc<str>, [Connect]);
|
||||||
def_sizes_iter!(ScenesSizes => Scene);
|
def_sizes_iter!(ScenesSizes => Scene);
|
||||||
def_sizes_iter!(TracksSizes => Track);
|
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))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ impl Browse {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
/// Set current directory
|
/// Set current directory
|
||||||
#[command(SetPath = "set-path")]
|
#[command(Chdir = "chdir")]
|
||||||
fn set_path (&mut self, _path: PathBuf) -> Perhaps<BrowseCommand> {
|
fn chdir (&mut self, _path: PathBuf) -> Perhaps<BrowseCommand> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
/// Set current filter
|
/// 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.
|
/// Browses for files to load/save.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -104,7 +95,7 @@ impl Browse {
|
||||||
}
|
}
|
||||||
Ok(Self { cwd, dirs, files, ..Default::default() })
|
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 len (&self) -> usize { self.dirs.len() + self.files.len() }
|
||||||
pub fn is_dir (&self) -> bool { self.index < self.dirs.len() }
|
pub fn is_dir (&self) -> bool { self.index < self.dirs.len() }
|
||||||
pub fn is_file (&self) -> bool { self.index >= self.dirs.len() }
|
pub fn is_file (&self) -> bool { self.index >= self.dirs.len() }
|
||||||
|
|
|
||||||
|
|
@ -20,36 +20,61 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_command!(ClockCommand: |clock: Clock| {
|
#[tek_proc::commands(ClockCommand = "clock")]
|
||||||
SeekUsec { usec: f64 } => {
|
impl Clock {
|
||||||
clock.playhead.update_from_usec(*usec); Ok(None) },
|
#[command(SeekUsec = "usec")]
|
||||||
SeekSample { sample: f64 } => {
|
fn seek_usec (&mut self, usec: f64) -> Perhaps<ClockCommand> {
|
||||||
clock.playhead.update_from_sample(*sample); Ok(None) },
|
self.playhead.update_from_usec(usec);
|
||||||
SeekPulse { pulse: f64 } => {
|
Ok(None)
|
||||||
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) })),
|
|
||||||
|
|
||||||
Play { position: Option<u32> } => {
|
#[command(SeekSample = "sample")]
|
||||||
clock.play_from(*position)?; Ok(None) /* TODO Some(Pause(previousPosition)) */ },
|
fn seek_sample (&mut self, sample: f64) -> Perhaps<ClockCommand> {
|
||||||
Pause { position: Option<u32> } => {
|
self.playhead.update_from_sample(sample);
|
||||||
clock.pause_at(*position)?; Ok(None) },
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
TogglePlayback { position: u32 } => Ok(if clock.is_rolling() {
|
#[command(SeekPulse = "pulse")]
|
||||||
clock.pause_at(Some(*position))?; None
|
fn seek_pulse (&mut self, pulse: f64) -> Perhaps<ClockCommand> {
|
||||||
} else {
|
self.playhead.update_from_pulse(pulse);
|
||||||
clock.play_from(Some(*position))?; None
|
Ok(None)
|
||||||
}),
|
}
|
||||||
});
|
|
||||||
|
|
||||||
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
|
#[command(SetBpm = "bpm")]
|
||||||
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
|
fn set_bpm (&mut self, bpm: f64) -> Perhaps<ClockCommand> {
|
||||||
fn clock (&self) -> &Clock { self.as_ref() }
|
Ok(Some(ClockCommand::SetBpm { bpm: self.timebase().bpm.set(bpm) }))
|
||||||
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
|
}
|
||||||
|
|
||||||
|
#[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.
|
/// 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>>>,
|
#[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
|
/// 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 {
|
impl std::fmt::Debug for Clock {
|
||||||
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||||
f.debug_struct("Clock")
|
f.debug_struct("Clock")
|
||||||
|
|
@ -397,14 +410,38 @@ impl Clock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: HasClock> Act<T> for ClockCommand {
|
impl_has!(Clock: |self: Track|self.sequencer.clock);
|
||||||
fn act (&self, state: &mut T) -> Perhaps<Self> {
|
impl_default!(Timebase: Self::new(48000f64, 150f64, DEFAULT_PPQ));
|
||||||
self.act(state.clock_mut()) // awesome
|
|
||||||
|
/// 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!(SampleCount);
|
||||||
impl_time_unit!(SampleRate);
|
impl_time_unit!(SampleRate);
|
||||||
impl_time_unit!(Microsecond);
|
impl_time_unit!(Microsecond);
|
||||||
|
|
|
||||||
|
|
@ -56,29 +56,69 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_command!(MidiEditCommand: |editor: MidiEditor| {
|
#[tek_proc::commands(MidiEditCommand = "edit")]
|
||||||
Show { clip: Option<Arc<RwLock<MidiClip>>> } => {
|
impl MidiEditor {
|
||||||
editor.set_clip(clip.as_ref()); editor.redraw(); Ok(None) },
|
#[command(Show = "show")]
|
||||||
DeleteNote => {
|
fn show (&mut self, clip: Option<Arc<RwLock<MidiClip>>>) -> Perhaps<MidiEditCommand> {
|
||||||
editor.redraw(); todo!() },
|
self.set_clip(clip.as_ref());
|
||||||
AppendNote { advance: bool } => {
|
self.redraw();
|
||||||
editor.put_note(*advance); editor.redraw(); Ok(None) },
|
Ok(None)
|
||||||
SetNotePos { pos: usize } => {
|
}
|
||||||
editor.set_note_pos((*pos).min(127)); editor.redraw(); Ok(None) },
|
#[command(DeleteNote = "delete")]
|
||||||
SetNoteLen { len: usize } => {
|
fn note_delete (&mut self) -> Perhaps<MidiEditCommand> {
|
||||||
editor.set_note_len(*len); editor.redraw(); Ok(None) },
|
self.redraw();
|
||||||
SetNoteScroll { scroll: usize } => {
|
todo!()
|
||||||
editor.set_note_lo((*scroll).min(127)); editor.redraw(); Ok(None) },
|
}
|
||||||
SetTimePos { pos: usize } => {
|
#[command(AppendNote = "append")]
|
||||||
editor.set_time_pos(*pos); editor.redraw(); Ok(None) },
|
fn note_append (&mut self, advance: bool) -> Perhaps<MidiEditCommand> {
|
||||||
SetTimeScroll { scroll: usize } => {
|
self.put_note(advance);
|
||||||
editor.set_time_start(*scroll); editor.redraw(); Ok(None) },
|
self.redraw();
|
||||||
SetTimeZoom { zoom: usize } => {
|
Ok(None)
|
||||||
editor.set_time_zoom(*zoom); editor.redraw(); Ok(None) },
|
}
|
||||||
SetTimeLock { lock: bool } => {
|
#[command(SetNotePos = "note-pos")]
|
||||||
editor.set_time_lock(*lock); editor.redraw(); Ok(None) },
|
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
|
// TODO: 1-9 seek markers that by default start every 8th of the clip
|
||||||
});
|
}
|
||||||
|
|
||||||
/// Contains state for viewing and editing a clip.
|
/// Contains state for viewing and editing a clip.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -8,52 +8,61 @@ pub(crate) use symphonia::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
def_command!(SamplerCommand: |sampler: Sampler| {
|
#[tek_proc::commands(SamplerCommand = "sampler")]
|
||||||
RecordToggle { slot: usize } => {
|
impl Sampler {
|
||||||
let slot = *slot;
|
|
||||||
let recording = sampler.recording.as_ref().map(|x|x.0);
|
#[command(RecordToggle = "rec-toggle")]
|
||||||
let _ = Self::RecordFinish.act(sampler)?;
|
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
|
// autoslice: continue recording at next slot
|
||||||
if recording != Some(slot) {
|
if recording != Some(slot) {
|
||||||
Self::RecordBegin { slot }.act(sampler)
|
SamplerCommand::RecordBegin { slot }.act(self)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
RecordBegin { slot: usize } => {
|
|
||||||
let slot = *slot;
|
#[command(RecordBegin = "rec-begin")]
|
||||||
sampler.recording = Some((
|
fn record_begin (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
|
||||||
|
self.recording = Some((
|
||||||
slot,
|
slot,
|
||||||
Some(Arc::new(RwLock::new(Sample::new(
|
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)
|
Ok(None)
|
||||||
},
|
}
|
||||||
RecordFinish => {
|
|
||||||
let _prev_sample = sampler.recording.as_mut().map(|(index, sample)|{
|
#[command(RecordFinish = "rec-finish")]
|
||||||
std::mem::swap(sample, &mut sampler.samples.0[*index]);
|
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
|
sample
|
||||||
}); // TODO: undo
|
}); // TODO: undo
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
}
|
||||||
RecordCancel => {
|
|
||||||
sampler.recording = None;
|
#[command(RecordCancel = "rec-cancel")]
|
||||||
|
fn record_cancel (&mut self) -> Perhaps<SamplerCommand> {
|
||||||
|
self.recording = None;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
}
|
||||||
PlaySample { slot: usize } => {
|
|
||||||
let slot = *slot;
|
#[command(PlaySample = "sample-play")]
|
||||||
if let Some(ref sample) = sampler.samples.0[slot] {
|
fn sample_play (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
|
||||||
sampler.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
|
if let Some(ref sample) = self.samples.0[slot] {
|
||||||
|
self.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
}
|
||||||
StopSample { slot: usize } => {
|
|
||||||
let _slot = *slot;
|
#[command(StopSample = "sample-stop")]
|
||||||
|
fn sample_stop (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
|
||||||
todo!();
|
todo!();
|
||||||
//Ok(None)
|
//Ok(None)
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/// Plays [Voice]s from [Sample]s.
|
/// Plays [Voice]s from [Sample]s.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
52
src/tek.rs
52
src/tek.rs
|
|
@ -877,58 +877,14 @@ pub use self::bind::*;
|
||||||
mod bind {
|
mod bind {
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Define an enum containing commands, and implement [Command] trait for over given `State`.
|
|
||||||
#[macro_export] macro_rules! def_command (
|
|
||||||
($Command:ident: |$state:ident: $State:ty| {
|
|
||||||
// FIXME: support attrs (docstrings)
|
|
||||||
$($Variant:ident$({$($arg:ident:$Arg:ty),+ $(,)?})?=>$body:expr),* $(,)?
|
|
||||||
})=>{
|
|
||||||
#[derive(Debug)] pub enum $Command {
|
|
||||||
// FIXME: support attrs (docstrings)
|
|
||||||
$($Variant $({ $($arg: $Arg),* })?),*
|
|
||||||
}
|
|
||||||
impl ::tengri::dizzle::Act<$State> for $Command {
|
|
||||||
fn act (&self, $state: &mut $State) -> Perhaps<Self> {
|
|
||||||
match self {
|
|
||||||
$(Self::$Variant $({ $($arg),* })? => $body,)*
|
|
||||||
_ => unimplemented!("Act<{}>: {self:?}", stringify!($State)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pub 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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_keys!(self: App, input {
|
tui_keys!(self: App, input {
|
||||||
let commands = tek_commands_collect(self, input)?;
|
let commands = collect_commands(self, input)?;
|
||||||
let results = tek_commands_execute(self, commands)?;
|
let results = execute_commands(self, commands)?;
|
||||||
self.history.extend(results.into_iter());
|
self.history.extend(results.into_iter());
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
fn tek_commands_collect (app: &App, input: &TuiEvent)
|
fn collect_commands (app: &App, input: &TuiEvent)
|
||||||
-> Usually<Vec<AppCommand>>
|
-> Usually<Vec<AppCommand>>
|
||||||
{
|
{
|
||||||
let mut commands = vec![];
|
let mut commands = vec![];
|
||||||
|
|
@ -953,7 +909,7 @@ mod bind {
|
||||||
Ok(commands)
|
Ok(commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tek_commands_execute (app: &mut App, commands: Vec<AppCommand>)
|
fn execute_commands (app: &mut App, commands: Vec<AppCommand>)
|
||||||
-> Usually<Vec<(AppCommand, Option<AppCommand>)>>
|
-> Usually<Vec<(AppCommand, Option<AppCommand>)>>
|
||||||
{
|
{
|
||||||
let mut history = vec![];
|
let mut history = vec![];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue