big ass refactor (rip client)

This commit is contained in:
🪞👃🪞 2024-07-03 14:51:48 +03:00
parent 94c1f83ef2
commit 8c3cf53c67
56 changed files with 2232 additions and 1891 deletions

72
src/control/chain.rs Normal file
View file

@ -0,0 +1,72 @@
use crate::{core::*, model::*};
use super::focus::*;
pub fn handle (state: &mut Chain, event: &AppEvent) -> Usually<bool> {
Ok(handle_focus(state, event, keymap!(Chain {
[Up, NONE, "focus_up", "focus row above",
|s: &mut Chain|s.handle_focus(&FocusEvent::Backward)],
[Down, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Outward)],
}))? || handle_keymap(state, event, keymap!(Chain {
[Char('a'), NONE, "add_device", "add a device", add_device]
}))?)
}
fn add_device (state: &mut Chain) -> Usually<bool> {
state.adding = true;
Ok(true)
}
impl Focus for Chain {
fn unfocus (&mut self) {
self.focused = false
}
fn focused (&self) -> Option<&Box<dyn Device>> {
match self.focused {
true => self.items.get(self.focus),
false => None
}
}
fn focused_mut (&mut self) -> Option<&mut Box<dyn Device>> {
match self.focused {
true => self.items.get_mut(self.focus),
false => None
}
}
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool> {
Ok(match event {
FocusEvent::Backward => {
if self.focus == 0 {
self.focus = self.items.len();
}
self.focus = self.focus - 1;
true
},
FocusEvent::Forward => {
self.focus = self.focus + 1;
if self.focus >= self.items.len() {
self.focus = 0;
}
true
},
FocusEvent::Inward => {
self.focused = true;
self.items[self.focus].handle(&AppEvent::Focus)?;
true
},
FocusEvent::Outward => {
if self.focused {
self.focused = false;
self.items[self.focus].handle(&AppEvent::Blur)?;
true
} else {
false
}
},
})
}
}

189
src/control/focus.rs Normal file
View file

@ -0,0 +1,189 @@
use crate::{core::*, view::*};
pub trait Focus {
fn unfocus (&mut self);
fn focused (&self) -> Option<&Box<dyn Device>>;
fn focused_mut (&mut self) -> Option<&mut Box<dyn Device>>;
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool>;
}
pub enum FocusEvent { Forward, Backward, Inward, Outward, }
pub fn handle_focus <T: Focus> (
state: &mut T,
event: &AppEvent,
keymap: &[KeyBinding<T>]
) -> Usually<bool> {
let handled = if let Some(focused) = state.focused_mut() {
focused.handle(event)
} else {
Ok(false)
};
return Ok(handled? || handle_keymap(
state, event, keymap
)?)
}
pub struct FocusColumn(pub Option<usize>, pub Column);
impl Handle for FocusColumn {
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
handle_focus(self, event, KEYMAP_FOCUS_COLUMN)
}
}
impl Render for FocusColumn {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let (rect, _rects) = Column::draw(buf, area, self.1.0.as_ref(), 0)?;
//if i == self.focus {
//if self.focused {
//draw_box_styled(buf, result, Some(Style::default().white().not_dim()))
//} else {
//draw_box_styled_dotted(buf, result, Some(Style::default().white().dim()))
//};
//};
Ok(rect)
}
}
const KEYMAP_FOCUS_COLUMN: &'static [KeyBinding<FocusColumn>] = keymap!(FocusColumn {
[Up, NONE, "focus_up", "focus row above",
|s: &mut FocusColumn|s.handle_focus(&FocusEvent::Backward)],
[Down, NONE, "focus_down", "focus row below",
|s: &mut FocusColumn|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut FocusColumn|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut FocusColumn|s.handle_focus(&FocusEvent::Outward)]
});
impl Focus for FocusColumn {
fn unfocus (&mut self) {
self.0 = None
}
fn focused (&self) -> Option<&Box<dyn Device>> {
self.0.map(|index|self.1.0.get(index))?
}
fn focused_mut (&mut self) -> Option<&mut Box<dyn Device>> {
self.0.map(|index|self.1.0.get_mut(index))?
}
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool> {
Ok(match event {
FocusEvent::Backward => match self.0 {
Some(i) => {
self.0 = Some(if i == 0 {
self.1.0.len() - 1
} else {
i - 1
});
true
},
_ => false
},
FocusEvent::Forward => match self.0 {
Some(i) => {
self.0 = Some(if i >= self.1.0.len() {
0
} else {
i + 1
});
true
},
_ => false
},
FocusEvent::Inward => match self.0 {
None => {
self.0 = Some(0);
true
},
_ => false
},
FocusEvent::Outward => match self.0 {
Some(_i) => {
self.0 = None;
true
},
_ => false
},
})
}
}
pub struct FocusRow(pub Option<usize>, pub Row);
impl Handle for FocusRow {
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
handle_focus(self, event, KEYMAP_FOCUS_ROW)
}
}
impl Render for FocusRow {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let (rect, _rects) = Row::draw(buf, area, &self.1.0, 0)?;
Ok(rect)
}
}
const KEYMAP_FOCUS_ROW: &'static [KeyBinding<FocusRow>] = keymap!(FocusRow {
[Left, NONE, "focus_up", "focus row above",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Backward)],
[Right, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Outward)]
});
impl Focus for FocusRow {
fn unfocus (&mut self) {
self.0 = None
}
fn focused (&self) -> Option<&Box<dyn Device>> {
self.0.map(|index|self.1.0.get(index))?
}
fn focused_mut (&mut self) -> Option<&mut Box<dyn Device>> {
self.0.map(|index|self.1.0.get_mut(index))?
}
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool> {
Ok(match event {
FocusEvent::Backward => match self.0 {
Some(i) => {
self.0 = Some(if i == 0 {
self.1.0.len() - 1
} else {
i - 1
});
true
},
_ => false
},
FocusEvent::Forward => match self.0 {
Some(i) => {
self.0 = Some(if i >= self.1.0.len() {
0
} else {
i + 1
});
true
},
_ => false
},
FocusEvent::Inward => match self.0 {
None => {
self.0 = Some(0);
true
},
_ => false
},
FocusEvent::Outward => match self.0 {
Some(_i) => {
self.0 = None;
true
},
_ => false
},
})
}
}

236
src/control/launcher.rs Normal file
View file

@ -0,0 +1,236 @@
use crate::{core::*,model::*};
pub fn handle (state: &mut Launcher, event: &AppEvent) -> Usually<bool> {
Ok(handle_keymap(state, event, KEYMAP)? || match state.view {
LauncherMode::Tracks => {
handle_keymap(state, event, KEYMAP_TRACKS)?
},
LauncherMode::Sequencer => {
let i = state.col().saturating_sub(1);
if let Some(track) = state.tracks.get_mut(i) {
crate::control::sequencer::handle(&mut track.sequencer, event)?
} else {
true
}
},
LauncherMode::Chains => {
let i = state.col().saturating_sub(1);
if let Some(track) = state.tracks.get_mut(i) {
crate::control::chain::handle(&mut track.chain, event)?
} else {
true
}
}
})
}
pub const KEYMAP: &'static [KeyBinding<Launcher>] = keymap!(Launcher {
[F(1), NONE, "toggle_help", "toggle help", toggle_help],
[Tab, SHIFT, "focus_prev", "focus previous area", focus_prev],
[Tab, NONE, "focus_next", "focus next area", focus_next],
[Char(' '), NONE, "play_toggle", "play or pause", play_toggle],
[Char('r'), NONE, "record_toggle", "toggle recording", record_toggle],
[Char('d'), NONE, "overdub_toggle", "toggle overdub", overdub_toggle],
[Char('m'), NONE, "monitor_toggle", "toggle input monitoring", monitor_toggle],
[Char('r'), CONTROL, "rename", "rename current element", rename],
[Char('t'), CONTROL, "add_track", "add a new track", add_track],
//[Char(' '), SHIFT, "play_start", "play from start", play_start],
});
pub const KEYMAP_TRACKS: &'static [KeyBinding<Launcher>] = keymap!(Launcher {
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Left, NONE, "cursor_left", "move cursor left", cursor_left],
[Right, NONE, "cursor_right", "move cursor right", cursor_right],
[Char('.'), NONE, "clip_next", "set clip to next phrase", clip_next],
[Char(','), NONE, "clip_prev", "set clip to last phrase", clip_prev],
[Delete, CONTROL, "delete_track", "delete track", delete_track],
[Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate],
[Enter, NONE, "activate", "activate item at cursor", activate],
});
fn duplicate (_: &mut Launcher) -> Usually<bool> {
unimplemented!();
Ok(true)
}
fn activate (_: &mut Launcher) -> Usually<bool> {
unimplemented!();
//if let (
//Some((_scene_id, scene)),
//Some((track_id, track)),
//) = (state.scene_mut(), state.track_mut()) {
//// Launch clip
//if let Some(phrase_id) = scene.clips.get(track_id) {
//track.sequencer.sequence = *phrase_id;
//}
//if state.playing == TransportState::Stopped {
//state.transport.start()?;
//state.playing = TransportState::Starting;
//}
//} else if let Some((_scene_id, scene)) = state.scene() {
//// Launch scene
//for (track_id, track) in state.tracks.iter().enumerate() {
//if let Some(phrase_id) = scene.clips.get(track_id) {
//track.sequencer.sequence = *phrase_id;
//}
//}
//if state.playing == TransportState::Stopped {
//state.transport.start()?;
//state.playing = TransportState::Starting;
//}
//} else if let Some((_track_id, _track)) = state.track() {
//// Rename track?
//}
//let track = state.active_track().unwrap();
//let scene = state.active_scene();
//if state.cursor.1 >= 2 {
//if let Some(Some(index)) = scene.clips.get(state.cursor.1 - 2) {
//track.enqueue(index)
//} else {
//}
//}
//if state.cursor.0 >= 1 {
//let sequencer = state.tracks.get_mut(state.cursor.0 - 1);
//if state.cursor.1 >= 2 {
//let scene = state.scenes.get_mut(state.cursor.1 - 2);
//if let Some(index) = scene.get(state.cursor.0 - 1) {
//let phrase = sequencer.phrases.get(index);
//} else {
//let index = sequencer.phrases.len();
//let phrase = Phrase::new(&format!("Phrase#{index}"));
//sequencer.phrases.push(phrase);
//scene[state.cursor.0 - 1] = Some(index);
//}
//}
//}
Ok(true)
}
fn rename (_: &mut Launcher) -> Usually<bool> {
Ok(true)
}
fn add_track (state: &mut Launcher) -> Usually<bool> {
let name = format!("Track {}", state.tracks.len() + 1);
state.tracks.push(Track::new(&name, &state.timebase, None, None)?);
state.cursor.0 = state.tracks.len();
Ok(true)
}
fn delete_track (state: &mut Launcher) -> Usually<bool> {
if state.tracks.len() > 0 && state.cursor.0 >= 1 {
state.tracks.remove(state.cursor.0 - 1);
state.cursor.0 = state.cursor.0.min(state.tracks.len());
}
Ok(true)
}
fn cursor_up (state: &mut Launcher) -> Usually<bool> {
state.dec_row();
Ok(true)
}
fn cursor_down (state: &mut Launcher) -> Usually<bool> {
state.inc_row();
Ok(true)
}
fn cursor_left (state: &mut Launcher) -> Usually<bool> {
state.dec_col();
Ok(true)
}
fn cursor_right (state: &mut Launcher) -> Usually<bool> {
state.inc_col();
Ok(true)
}
fn toggle_help (state: &mut Launcher) -> Usually<bool> {
state.show_help = !state.show_help;
Ok(true)
}
fn focus_next (state: &mut Launcher) -> Usually<bool> {
match state.view {
LauncherMode::Tracks => { state.view = LauncherMode::Sequencer; },
LauncherMode::Sequencer => { state.view = LauncherMode::Chains; },
LauncherMode::Chains => { state.view = LauncherMode::Tracks; },
};
Ok(true)
}
fn focus_prev (state: &mut Launcher) -> Usually<bool> {
match state.view {
LauncherMode::Tracks => { state.view = LauncherMode::Chains; },
LauncherMode::Chains => { state.view = LauncherMode::Sequencer; },
LauncherMode::Sequencer => { state.view = LauncherMode::Tracks; },
};
Ok(true)
}
fn clip_next (state: &mut Launcher) -> Usually<bool> {
if state.cursor.0 >= 1 && state.cursor.1 >= 1 {
let scene_id = state.cursor.1 - 1;
let clip_id = state.cursor.0 - 1;
let scene = &mut state.scenes[scene_id];
scene.clips[clip_id] = match scene.clips[clip_id] {
None => Some(0),
Some(i) => if i >= state.tracks[clip_id].sequencer.phrases.len().saturating_sub(1) {
None
} else {
Some(i + 1)
}
};
}
Ok(true)
}
fn clip_prev (state: &mut Launcher) -> Usually<bool> {
if state.cursor.0 >= 1 && state.cursor.1 >= 1 {
let scene_id = state.cursor.1 - 1;
let clip_id = state.cursor.0 - 1;
let scene = &mut state.scenes[scene_id];
scene.clips[clip_id] = match scene.clips[clip_id] {
None => Some(state.tracks[clip_id].sequencer.phrases.len().saturating_sub(1)),
Some(i) => if i == 0 {
None
} else {
Some(i - 1)
}
};
}
Ok(true)
}
fn play_toggle (s: &mut Launcher) -> Usually<bool> {
s.playing = match s.playing {
TransportState::Stopped => {
s.transport.start()?;
TransportState::Starting
},
_ => {
s.transport.stop()?;
s.transport.locate(0)?;
TransportState::Stopped
},
};
Ok(true)
}
//fn play_start (_: &mut Launcher) -> Usually<bool> {
//unimplemented!()
//}
fn record_toggle (s: &mut Launcher) -> Usually<bool> {
s.sequencer_mut().map(|s|s.recording = !s.recording);
Ok(true)
}
fn overdub_toggle (s: &mut Launcher) -> Usually<bool> {
s.sequencer_mut().map(|s|s.overdub = !s.overdub);
Ok(true)
}
fn monitor_toggle (s: &mut Launcher) -> Usually<bool> {
s.sequencer_mut().map(|s|s.monitoring = !s.monitoring);
Ok(true)
}

59
src/control/mixer.rs Normal file
View file

@ -0,0 +1,59 @@
use crate::{core::*, model::*};
pub fn handle (state: &mut Mixer, event: &AppEvent) -> Usually<bool> {
if let AppEvent::Input(crossterm::event::Event::Key(event)) = event {
match event.code {
//KeyCode::Char('c') => {
//if event.modifiers == KeyModifiers::CONTROL {
//state.exit();
//}
//},
KeyCode::Down => {
state.selected_track = (state.selected_track + 1) % state.tracks.len();
println!("{}", state.selected_track);
return Ok(true)
},
KeyCode::Up => {
if state.selected_track == 0 {
state.selected_track = state.tracks.len() - 1;
} else {
state.selected_track = state.selected_track - 1;
}
println!("{}", state.selected_track);
return Ok(true)
},
KeyCode::Left => {
if state.selected_column == 0 {
state.selected_column = 6
} else {
state.selected_column = state.selected_column - 1;
}
return Ok(true)
},
KeyCode::Right => {
if state.selected_column == 6 {
state.selected_column = 0
} else {
state.selected_column = state.selected_column + 1;
}
return Ok(true)
},
_ => {
println!("\n{event:?}");
}
}
}
Ok(false)
}
// TODO:
// - Meters: propagate clipping:
// - If one stage clips, all stages after it are marked red
// - If one track clips, all tracks that feed from it are marked red?
pub const ACTIONS: [(&'static str, &'static str);2] = [
("+/-", "Adjust"),
("Ins/Del", "Add/remove track"),
];

69
src/control/plugin.rs Normal file
View file

@ -0,0 +1,69 @@
use crate::{core::*, model::*};
pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
handle_keymap(s, event, keymap!(Plugin {
[Up, NONE, "cursor_up", "move cursor up",
|s: &mut Plugin|{
if s.selected > 0 {
s.selected = s.selected - 1
} else {
s.selected = match &s.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
_ => 0
}
}
Ok(true)
}],
[Down, NONE, "cursor_down", "move cursor down",
|s: &mut Plugin|{
s.selected = s.selected + 1;
match &s.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => {
if s.selected >= port_list.len() {
s.selected = 0;
}
},
_ => {}
}
Ok(true)
}],
[Char(','), NONE, "decrement", "decrement value",
|s: &mut Plugin|{
match s.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[s.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value - 0.01);
}
},
_ => {}
}
Ok(true)
}],
[Char('.'), NONE, "increment", "increment value",
|s: &mut Plugin|{
match s.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[s.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value + 0.01);
}
},
_ => {}
}
Ok(true)
}],
[Char('m'), NONE, "toggle_midi_map", "toggle midi map mode",
|s: &mut Plugin|{
s.mapping = !s.mapping;
Ok(true)
}]
}))
}

45
src/control/sampler.rs Normal file
View file

@ -0,0 +1,45 @@
use crate::{core::*, model::*};
pub fn handle (state: &mut Sampler, event: &AppEvent) -> Usually<bool> {
Ok(handle_keymap(state, event, KEYMAP)?)
}
pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Char('t'), NONE, "trigger", "play current sample", trigger],
[Enter, NONE, "select", "select item under cursor", select],
});
fn cursor_up (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = if state.cursor.0 == 0 {
state.samples.len() - 1
} else {
state.cursor.0 - 1
};
Ok(true)
}
fn cursor_down (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = (state.cursor.0 + 1) % state.samples.len();
Ok(true)
}
fn trigger (state: &mut Sampler) -> Usually<bool> {
for (i, sample) in state.samples.values().enumerate() {
if i == state.cursor.0 {
state.voices.push(sample.play(0))
}
}
Ok(true)
}
fn select (state: &mut Sampler) -> Usually<bool> {
for (i, _sample) in state.samples.values().enumerate() {
if i == state.cursor.0 {
//state.voices.push(sample.play(0))
}
}
Ok(true)
}

222
src/control/sequencer.rs Normal file
View file

@ -0,0 +1,222 @@
use crate::{core::*, model::*};
pub fn handle (state: &mut Sequencer, event: &AppEvent) -> Usually<bool> {
handle_keymap(state, event, KEYMAP)
}
pub const KEYMAP: &'static [KeyBinding<Sequencer>] = keymap!(Sequencer {
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Left, NONE, "cursor_left", "move cursor left", cursor_left],
[Right, NONE, "cursor_right", "move cursor right", cursor_right],
[Char('.'), NONE, "cursor_inc", "increase note duration", cursor_duration_inc],
[Char(','), NONE, "cursor_dec", "decrease note duration", cursor_duration_dec],
[Char('`'), NONE, "mode_next", "Next view mode", mode_next],
[Char('='), NONE, "zoom_in", "Zoom in", zoom_in],
[Char('-'), NONE, "zoom_out", "Zoom out", zoom_out],
[Char('a'), NONE, "note_add", "Add note", note_add],
[Char('z'), NONE, "note_del", "Delete note", note_del],
[CapsLock, NONE, "advance", "Toggle auto advance", nop],
[Char('w'), NONE, "rest", "Advance by note duration", nop],
[Char(' '), NONE, "toggle_play", "Toggle play/pause", toggle_play],
[Char('r'), NONE, "toggle_record", "Toggle recording", toggle_record],
[Char('d'), NONE, "toggle_overdub", "Toggle overdub", toggle_overdub],
[Char('m'), NONE, "toggle_monitor", "Toggle input monitoring", toggle_monitor],
[Char('s'), NONE, "stop_and_rewind", "Stop and rewind", stop_and_rewind],
[Char('q'), NONE, "quantize_next", "Next quantize value", quantize_next],
[Char('Q'), SHIFT, "quantize_prev", "Previous quantize value", quantize_prev],
[Char('n'), NONE, "note_axis", "Focus note axis", nop],
[Char('t'), NONE, "time_axis", "Focus time axis", nop],
[Char('v'), NONE, "variations", "Focus variation selector", nop],
[Char('s'), SHIFT, "sync", "Focus sync selector", nop],
[Char('1'), NONE, "seq_1", "Phrase 1", focus_seq(0)],
[Char('2'), NONE, "seq_2", "Phrase 2", focus_seq(1)],
[Char('3'), NONE, "seq_3", "Phrase 3", focus_seq(2)],
[Char('4'), NONE, "seq_4", "Phrase 4", focus_seq(3)],
[Char('5'), NONE, "seq_5", "Phrase 5", focus_seq(4)],
[Char('6'), NONE, "seq_6", "Phrase 6", focus_seq(5)],
[Char('7'), NONE, "seq_7", "Phrase 7", focus_seq(6)],
[Char('8'), NONE, "seq_8", "Phrase 8", focus_seq(7)],
});
const fn focus_seq (i: usize) -> impl Fn(&mut Sequencer)->Usually<bool> {
move |s: &mut Sequencer| {
s.sequence = Some(i);
Ok(true)
}
}
fn nop (_: &mut Sequencer) -> Usually<bool> {
Ok(false)
}
fn note_add (s: &mut Sequencer) -> Usually<bool> {
if s.sequence.is_none() {
return Ok(false)
}
let ppq = s.timebase.ppq() as usize;
let step = s.time_start + s.time_cursor;
let start = step as usize * ppq / s.time_zoom;
let end = (step + 1) as usize * ppq / s.time_zoom;
let key = u7::from_int_lossy((s.note_cursor + s.note_start) as u8);
let note_on = MidiMessage::NoteOn { key, vel: 100.into() };
let note_off = MidiMessage::NoteOff { key, vel: 100.into() };
let sequence = &mut s.phrases[s.sequence.unwrap()].notes;
if sequence.contains_key(&start) {
sequence.get_mut(&start).unwrap().push(note_on.clone());
} else {
sequence.insert(start, vec![note_on]);
}
if sequence.contains_key(&end) {
sequence.get_mut(&end).unwrap().push(note_off.clone());
} else {
sequence.insert(end, vec![note_off]);
};
Ok(true)
}
fn note_del (_: &mut Sequencer) -> Usually<bool> {
Ok(true)
}
fn time_cursor_inc (s: &mut Sequencer) -> Usually<bool> {
s.time_cursor = s.time_cursor + 1;
Ok(true)
}
fn time_cursor_dec (s: &mut Sequencer) -> Usually<bool> {
s.time_cursor = s.time_cursor.saturating_sub(1);
Ok(true)
}
fn note_cursor_inc (s: &mut Sequencer) -> Usually<bool> {
s.note_cursor = s.note_cursor + 1;
Ok(true)
}
fn note_cursor_dec (s: &mut Sequencer) -> Usually<bool> {
s.note_cursor = s.note_cursor.saturating_sub(1);
Ok(true)
}
fn cursor_up (s: &mut Sequencer) -> Usually<bool> {
match s.view {
SequencerMode::Vertical => time_cursor_dec(s),
SequencerMode::Horizontal => note_cursor_dec(s),
_ => Ok(false)
}?;
Ok(true)
}
fn cursor_down (s: &mut Sequencer) -> Usually<bool> {
match s.view {
SequencerMode::Vertical => time_cursor_inc(s),
SequencerMode::Horizontal => note_cursor_inc(s),
_ => Ok(false)
}?;
Ok(true)
}
fn cursor_left (s: &mut Sequencer) -> Usually<bool> {
match s.view {
SequencerMode::Vertical => note_cursor_dec(s),
SequencerMode::Horizontal => time_cursor_dec(s),
_ => Ok(false)
}?;
Ok(true)
}
fn cursor_right (s: &mut Sequencer) -> Usually<bool> {
match s.view {
SequencerMode::Vertical => note_cursor_inc(s),
SequencerMode::Horizontal => time_cursor_inc(s),
_ => Ok(false)
}?;
Ok(true)
}
fn cursor_duration_inc (_: &mut Sequencer) -> Usually<bool> {
//s.cursor.2 = s.cursor.2 + 1
Ok(true)
}
fn cursor_duration_dec (_: &mut Sequencer) -> Usually<bool> {
//if s.cursor.2 > 0 { s.cursor.2 = s.cursor.2 - 1 }
Ok(true)
}
fn mode_next (s: &mut Sequencer) -> Usually<bool> {
s.view = s.view.next();
Ok(true)
}
impl SequencerMode {
fn next (&self) -> Self {
match self {
Self::Horizontal => Self::Vertical,
Self::Vertical => Self::Tiny,
Self::Tiny => Self::Horizontal,
_ => self.clone()
}
}
}
fn stop_and_rewind (s: &mut Sequencer) -> Usually<bool> {
s.transport.stop()?;
s.transport.locate(0)?;
s.playing = TransportState::Stopped;
Ok(true)
}
fn toggle_play (s: &mut Sequencer) -> Usually<bool> {
s.playing = match s.playing {
TransportState::Stopped => {
s.transport.start()?;
TransportState::Starting
},
_ => {
s.transport.stop()?;
s.transport.locate(0)?;
TransportState::Stopped
},
};
Ok(true)
}
fn toggle_record (s: &mut Sequencer) -> Usually<bool> {
s.recording = !s.recording;
Ok(true)
}
fn toggle_overdub (s: &mut Sequencer) -> Usually<bool> {
s.overdub = !s.overdub;
Ok(true)
}
fn toggle_monitor (s: &mut Sequencer) -> Usually<bool> {
s.monitoring = !s.monitoring;
Ok(true)
}
fn quantize_next (s: &mut Sequencer) -> Usually<bool> {
if s.time_zoom < 64 {
s.time_zoom = s.time_zoom * 2;
}
Ok(true)
}
fn quantize_prev (s: &mut Sequencer) -> Usually<bool> {
if s.time_zoom > 1 {
s.time_zoom = s.time_zoom / 2;
}
Ok(true)
}
fn zoom_in (s: &mut Sequencer) -> Usually<bool> {
s.time_zoom = s.time_zoom / 2;
Ok(true)
}
fn zoom_out (s: &mut Sequencer) -> Usually<bool> {
s.time_zoom = s.time_zoom * 2;
Ok(true)
}