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

141
src/model/sequencer.rs Normal file
View file

@ -0,0 +1,141 @@
use crate::core::*;
use crate::model::*;
#[derive(Debug, Clone)]
pub enum SequencerMode { Tiny, Compact, Horizontal, Vertical, }
pub struct Sequencer {
pub name: String,
/// JACK transport handle.
pub transport: ::jack::Transport,
/// JACK MIDI input port that will be created.
pub midi_in: Port<MidiIn>,
/// JACK MIDI output port that will be created.
pub midi_out: Port<MidiOut>,
/// Holds info about tempo
pub timebase: Arc<Timebase>,
/// Phrase selector
pub sequence: Option<usize>,
/// Map: tick -> MIDI events at tick
pub phrases: Vec<Phrase>,
/// Red keys on piano roll.
pub notes_on: Vec<bool>,
/// Play sequence to output.
pub playing: TransportState,
/// Play input through output.
pub monitoring: bool,
/// Write input to sequence.
pub recording: bool,
/// Don't delete when recording.
pub overdub: bool,
/// Display mode
pub view: SequencerMode,
/// Range of notes to display
pub note_start: usize,
/// Position of cursor within note range
pub note_cursor: usize,
/// PPM per display unit
pub time_zoom: usize,
/// Range of time steps to display
pub time_start: usize,
/// Position of cursor within time range
pub time_cursor: usize,
}
render!(Sequencer = crate::view::sequencer::render);
handle!(Sequencer = crate::control::sequencer::handle);
process!(Sequencer |self, _client, scope| {
if self.sequence.is_none() { return Control::Continue }
let phrase = self.phrases.get_mut(self.sequence.unwrap());
if phrase.is_none() { return Control::Continue }
let phrase = phrase.unwrap();
let frame = scope.last_frame_time() as usize;
let frames = scope.n_frames() as usize;
let mut output: Vec<Option<Vec<Vec<u8>>>> = vec![None;frames];
let transport = self.transport.query().unwrap();
if transport.state != self.playing {
all_notes_off(&mut output);
}
self.playing = transport.state;
// Play from phrase into output buffer
if self.playing == TransportState::Rolling {
phrase.process_out(
&mut output,
&mut self.notes_on,
&self.timebase,
frame,
frames
);
}
// Play from input to monitor, and record into phrase.
phrase.process_in(
self.midi_in.iter(scope),
&mut self.notes_on,
if self.monitoring { Some(&mut output) } else { None },
self.recording && self.playing == TransportState::Rolling,
&self.timebase,
frame,
);
write_output(&mut self.midi_out.writer(scope), &mut output, frames);
Control::Continue
});
impl Sequencer {
pub fn new (
name: &str,
timebase: &Arc<Timebase>,
phrases: Option<Vec<Phrase>>,
) -> Usually<Self> {
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
let transport = client.transport();
Ok(Self {
name: name.into(),
timebase: timebase.clone(),
phrases: phrases.unwrap_or_else(||vec![Phrase::default()]),
sequence: Some(0),
transport,
midi_in: client.register_port("in", MidiIn::default())?,
monitoring: true,
recording: true,
midi_out: client.register_port("out", MidiOut::default())?,
playing: TransportState::Starting,
overdub: true,
view: SequencerMode::Horizontal,
notes_on: vec![false;128],
note_start: 12,
note_cursor: 0,
time_zoom: 24,
time_start: 0,
time_cursor: 0,
})
}
pub fn phrase <'a> (&'a self) -> Option<&'a Phrase> {
self.phrases.get(self.sequence?)
}
}
impl PortList for Sequencer {
fn midi_ins (&self) -> Usually<Vec<String>> { Ok(vec![self.midi_in.name()?]) }
fn midi_outs (&self) -> Usually<Vec<String>> { Ok(vec![self.midi_out.name()?]) }
}
/// Add "all notes off" to the start of a buffer.
pub fn all_notes_off (output: &mut MIDIChunk) {
output[0] = Some(vec![]);
if let Some(Some(frame)) = output.get_mut(0) {
let mut buf = vec![];
let msg = MidiMessage::Controller { controller: 123.into(), value: 0.into() };
let evt = LiveEvent::Midi { channel: 0.into(), message: msg };
evt.write(&mut buf).unwrap();
frame.push(buf);
}
}
/// Write to JACK port from output buffer (containing notes from sequence and/or monitor)
fn write_output (writer: &mut ::jack::MidiWriter, output: &mut MIDIChunk, frames: usize) {
for time in 0..frames {
if let Some(Some(frame)) = output.get_mut(time ) {
for event in frame.iter() {
writer.write(&::jack::RawMidi { time: time as u32, bytes: &event })
.expect(&format!("{event:?}"));
}
}
}
}