big worky on sequencer and launcher

This commit is contained in:
🪞👃🪞 2024-06-28 23:19:25 +03:00
parent a4c3593840
commit 8a8d7b8704
14 changed files with 852 additions and 680 deletions

View file

@ -1,21 +1,25 @@
use crate::prelude::*;
use ratatui::style::Stylize;
mod keys;
use keys::*;
use self::keys::*;
mod handle;
pub use self::handle::*;
pub mod horizontal;
pub mod vertical;
pub struct Sequence {
pub name: String,
pub notes: std::collections::BTreeMap<u32, Vec<::midly::MidiMessage>>
type PhraseData = BTreeMap<u32, Vec<MidiMessage>>;
pub struct Phrase {
pub name: String,
pub length: u32,
pub notes: PhraseData,
}
impl Sequence {
pub fn new (name: &str) -> Self {
Self { name: name.to_string(), notes: std::collections::BTreeMap::new() }
impl Phrase {
pub fn new (name: &str, length: u32, notes: Option<PhraseData>) -> Self {
Self { name: name.to_string(), length, notes: notes.unwrap_or(BTreeMap::new()) }
}
}
@ -36,10 +40,10 @@ pub struct Sequencer {
/// Steps in sequence, e.g. 64 16ths = 4 beat loop.
/// FIXME: play start / end / loop in ppm
steps: usize,
/// Sequence selector
/// Phrase selector
sequence: usize,
/// Map: tick -> MIDI events at tick
pub sequences: Vec<Sequence>,
pub sequences: Vec<Phrase>,
/// Red keys on piano roll.
notes_on: Vec<bool>,
@ -76,20 +80,21 @@ impl Sequencer {
pub fn new (
name: &str,
timebase: &Arc<Timebase>,
sequences: Option<Vec<Sequence>>,
sequences: Option<Vec<Phrase>>,
) -> Usually<DynamicDevice<Self>> {
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
let transport = client.transport();
let ppq = timebase.ppq() as u32;
DynamicDevice::new(render, handle, Self::process, Self {
name: name.into(),
midi_in: client.register_port("in", MidiIn::default())?,
midi_out: client.register_port("out", MidiOut::default())?,
timebase: timebase.clone(),
steps: 64,
steps: 16,
resolution: 4,
sequence: 0,
sequences: sequences.unwrap_or(vec![Sequence::new("")]),
sequences: sequences.unwrap_or(vec![]),
notes_on: vec![false;128],
playing: TransportState::Starting,
@ -108,6 +113,10 @@ impl Sequencer {
pub fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
// Prepare output buffer
let frames = scope.n_frames() as usize;
let mut output: Vec<Option<Vec<Vec<u8>>>> = vec![None;frames];
// Update time
let sequence = self.sequences.get_mut(self.sequence);
if sequence.is_none() {
@ -115,6 +124,18 @@ impl Sequencer {
}
let sequence = &mut sequence.unwrap().notes;
let transport = self.transport.query().unwrap();
// If starting or stopping, send "all notes off":
if transport.state != self.playing {
output[0] = Some(vec![]);
if let Some(Some(frame)) = output.get_mut(0) {
let mut buf = vec![];
LiveEvent::Midi {
channel: 0.into(),
message: MidiMessage::Controller { controller: 123.into(), value: 0.into() }
}.write(&mut buf).unwrap();
frame.push(buf);
}
}
self.playing = transport.state;
let pos = &transport.pos;
let usecs = self.timebase.frame_to_usec(pos.frame() as usize);
@ -122,10 +143,6 @@ impl Sequencer {
let step = steps % self.steps;
let tick = step * self.timebase.ppq() / self.resolution;
// Prepare output buffer
let frames = scope.n_frames() as usize;
let mut output: Vec<Option<Vec<Vec<u8>>>> = vec![None;frames];
// Read from sequence into output buffer
if self.playing == TransportState::Rolling {
let frame = transport.pos.frame() as usize;
@ -137,9 +154,7 @@ impl Sequencer {
let mut buf = vec![];
let channel = 0.into();
let message = *message;
::midly::live::LiveEvent::Midi { channel, message }
.write(&mut buf)
.unwrap();
LiveEvent::Midi { channel, message }.write(&mut buf).unwrap();
let t = *time as usize;
if output[t].is_none() {
output[t] = Some(vec![]);
@ -337,11 +352,11 @@ fn draw_clips (s: &Sequencer, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
}
Ok(Rect { x, y, width: 14, height: 14 })
}
pub fn contains_note_on (sequence: &Sequence, k: ::midly::num::u7, start: u32, end: u32) -> bool {
pub fn contains_note_on (sequence: &Phrase, k: u7, start: u32, end: u32) -> bool {
for (_, (_, events)) in sequence.notes.range(start..end).enumerate() {
for event in events.iter() {
match event {
::midly::MidiMessage::NoteOn {key,..} => {
MidiMessage::NoteOn {key,..} => {
if *key == k {
return true
}
@ -352,193 +367,6 @@ pub fn contains_note_on (sequence: &Sequence, k: ::midly::num::u7, start: u32, e
}
return false
}
pub fn handle (s: &mut Sequencer, event: &AppEvent) -> Usually<bool> {
handle_keymap(s, 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", nop],
[Char('-'), NONE, "zoom_out", "Zoom out", nop],
[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", "Sequence 1", focus_seq(0)],
[Char('2'), NONE, "seq_2", "Sequence 2", focus_seq(1)],
[Char('3'), NONE, "seq_3", "Sequence 3", focus_seq(2)],
[Char('4'), NONE, "seq_4", "Sequence 4", focus_seq(3)],
[Char('5'), NONE, "seq_5", "Sequence 5", focus_seq(4)],
[Char('6'), NONE, "seq_6", "Sequence 6", focus_seq(5)],
[Char('7'), NONE, "seq_7", "Sequence 7", focus_seq(6)],
[Char('8'), NONE, "seq_8", "Sequence 8", focus_seq(7)],
});
const fn focus_seq (i: usize) -> impl Fn(&mut Sequencer)->Usually<bool> {
move |s: &mut Sequencer| {
s.sequence = i;
Ok(true)
}
}
fn nop (_: &mut Sequencer) -> Usually<bool> {
Ok(false)
}
fn note_add (s: &mut Sequencer) -> Usually<bool> {
let step = (s.time_axis.0 + s.time_cursor) as u32;
let start = (step as usize * s.timebase.ppq() / s.resolution) as u32;
let end = ((step + 1) as usize * s.timebase.ppq() / s.resolution) as u32;
let key = ::midly::num::u7::from_int_lossy((s.note_cursor + s.note_axis.0) as u8);
let note_on = ::midly::MidiMessage::NoteOn { key, vel: 100.into() };
let note_off = ::midly::MidiMessage::NoteOff { key, vel: 100.into() };
let sequence = &mut s.sequences[s.sequence].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> {
let time = s.time_axis.1 - s.time_axis.0;
s.time_cursor = ((time + s.time_cursor) + 1) % time;
Ok(true)
}
fn time_cursor_dec (s: &mut Sequencer) -> Usually<bool> {
let time = s.time_axis.1 - s.time_axis.0;
s.time_cursor = ((time + s.time_cursor) - 1) % time;
Ok(true)
}
fn note_cursor_inc (s: &mut Sequencer) -> Usually<bool> {
let note = s.note_axis.1 - s.note_axis.0;
s.note_cursor = ((note + s.note_cursor) + 1) % note;
Ok(true)
}
fn note_cursor_dec (s: &mut Sequencer) -> Usually<bool> {
let note = s.note_axis.1 - s.note_axis.0;
s.note_cursor = ((note + s.note_cursor) - 1) % note;
Ok(true)
}
fn cursor_up (s: &mut Sequencer) -> Usually<bool> {
match s.mode {
SequencerView::Vertical => time_cursor_dec(s),
SequencerView::Horizontal => note_cursor_dec(s),
_ => Ok(false)
};
Ok(true)
}
fn cursor_down (s: &mut Sequencer) -> Usually<bool> {
match s.mode {
SequencerView::Vertical => time_cursor_inc(s),
SequencerView::Horizontal => note_cursor_inc(s),
_ => Ok(false)
};
Ok(true)
}
fn cursor_left (s: &mut Sequencer) -> Usually<bool> {
match s.mode {
SequencerView::Vertical => note_cursor_dec(s),
SequencerView::Horizontal => time_cursor_dec(s),
_ => Ok(false)
};
Ok(true)
}
fn cursor_right (s: &mut Sequencer) -> Usually<bool> {
match s.mode {
SequencerView::Vertical => note_cursor_inc(s),
SequencerView::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.mode = s.mode.next();
Ok(true)
}
impl SequencerView {
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.resolution < 64 {
s.resolution = s.resolution * 2;
}
Ok(true)
}
fn quantize_prev (s: &mut Sequencer) -> Usually<bool> {
if s.resolution > 1 {
s.resolution = s.resolution / 2;
}
Ok(true)
}
#[cfg(test)] mod test {
use super::*;