From 163ecaaed614197456b1293c590e1e73f3e0328e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 4 Jul 2024 18:24:08 +0300 Subject: [PATCH] move Phrase::process_in logic to Track::process --- src/core/midi.rs | 12 +++++- src/jack.rs | 1 + src/main.rs | 53 +++++++++------------------ src/model/phrase.rs | 55 ---------------------------- src/model/track.rs | 89 +++++++++++++++++++++++++++++++++++++++------ src/view.rs | 2 +- 6 files changed, 107 insertions(+), 105 deletions(-) diff --git a/src/core/midi.rs b/src/core/midi.rs index 2832a5c9..be8715ed 100644 --- a/src/core/midi.rs +++ b/src/core/midi.rs @@ -21,10 +21,18 @@ pub fn all_notes_off (output: &mut MIDIChunk) { } } +pub fn parse_midi_input (input: MidiIter) -> Box + '_> { + Box::new(input.map(|RawMidi { time, bytes }|( + time as usize, + LiveEvent::parse(bytes).unwrap(), + bytes + ))) +} + /// Write to JACK port from output buffer (containing notes from sequence and/or monitor) -pub fn write_output (writer: &mut ::jack::MidiWriter, output: &mut MIDIChunk, frames: usize) { +pub fn write_midi_output (writer: &mut ::jack::MidiWriter, output: &MIDIChunk, frames: usize) { for time in 0..frames { - if let Some(Some(frame)) = output.get_mut(time ) { + if let Some(Some(frame)) = output.get(time) { for event in frame.iter() { writer.write(&::jack::RawMidi { time: time as u32, bytes: &event }) .expect(&format!("{event:?}")); diff --git a/src/jack.rs b/src/jack.rs index 51fc6420..a33c946b 100644 --- a/src/jack.rs +++ b/src/jack.rs @@ -25,6 +25,7 @@ pub use ::_jack::{ Control, Frames, MidiIn, + MidiIter, MidiOut, NotificationHandler, Port, diff --git a/src/main.rs b/src/main.rs index ee65fcb7..c1aef4c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,6 +76,9 @@ pub fn main () -> Usually<()> { 12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, })); + // FIXME: + drums.sequence = Some(1); + let bass = state.add_track(Some("Bass"))?; bass.add_device(Plugin::lv2("Odin2", "file:///home/user/.lv2/Odin2.lv2")?); bass.add_phrase("Offbeat", ppq * 4, Some(phrase! { @@ -89,6 +92,9 @@ pub fn main () -> Usually<()> { 14 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, })); + // FIXME: + bass.sequence = Some(0); + Ok(()) })) } @@ -144,54 +150,29 @@ pub struct App { /// Collection of tracks pub tracks: Vec, } - process!(App |self, _client, scope| { let transport = self.transport.as_ref().unwrap().query().unwrap(); - let mut send_all_notes_off = false; + let mut panic = false; if Some(transport.state) != self.playing { - send_all_notes_off = true; + panic = true; } self.playing = Some(transport.state); self.playhead = transport.pos.frame() as usize; let frame = scope.last_frame_time() as usize; let frames = scope.n_frames() as usize; for track in self.tracks.iter_mut() { - // Output buffer - let mut output: Vec>>> = vec![None;frames]; - if send_all_notes_off { all_notes_off(&mut output); } - // For highlighting keys - let mut notes_on = vec![false;128]; - // Need to be borrowed outside the if - let recording = track.recording; - let monitoring = track.monitoring; - // If there's an active phrase, play/record - if let Some(phrase) = track.phrase_mut() { - // Play from phrase into output buffer - if self.playing == Some(TransportState::Rolling) { - phrase.process_out( - &mut output, - &mut notes_on, - &self.timebase, - frame, - frames - ); - } - // Play from input to monitor, and record into phrase. - phrase.process_in( - self.midi_in.as_ref().unwrap().iter(scope), - &mut notes_on, - if monitoring { Some(&mut output) } else { None }, - recording && self.playing == Some(TransportState::Rolling), - &self.timebase, - frame, - ); - } - track.notes_on = notes_on; - write_output(&mut track.midi_out.writer(scope), &mut output, frames); + track.process( + self.midi_in.as_ref().unwrap().iter(scope), + &self.timebase, + self.playing, + &scope, + frame, + frames, + panic, + ); } Control::Continue }); - impl App { pub fn toggle_play (&mut self) -> Usually<()> { self.playing = match self.playing.expect("after jack init") { diff --git a/src/model/phrase.rs b/src/model/phrase.rs index e1afccc3..704ff32c 100644 --- a/src/model/phrase.rs +++ b/src/model/phrase.rs @@ -77,61 +77,6 @@ impl Phrase { } } } - /// Read a chunk of MIDI events from an input port. - pub fn process_in ( - &mut self, - input: ::jack::MidiIter, - notes_on: &mut Vec, - mut monitor: Option<&mut MIDIChunk>, - record: bool, - timebase: &Arc, - frame0: usize, - ) { - for RawMidi { time, bytes } in input { - let time = time as usize; - let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; - if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() { - if let MidiMessage::NoteOn { key, vel: _ } = message { - notes_on[key.as_int() as usize] = true; - if let Some(ref mut monitor) = monitor { - if monitor[time].is_none() { - monitor[time] = Some(vec![]); - } - if let Some(Some(frame)) = monitor.get_mut(time) { - frame.push(bytes.into()) - } - } - if record { - let contains = self.notes.contains_key(&pulse); - if contains { - self.notes.get_mut(&pulse).unwrap().push(message.clone()); - } else { - self.notes.insert(pulse, vec![message.clone()]); - } - } - } else if let midly::MidiMessage::NoteOff { key, vel: _ } = message { - notes_on[key.as_int() as usize] = false; - if let Some(ref mut monitor) = monitor { - if monitor[time].is_none() { - monitor[time] = Some(vec![]); - } - if let Some(Some(frame)) = monitor.get_mut(time) { - frame.push(bytes.into()) - } - } - if record { - let contains = self.notes.contains_key(&pulse); - if contains { - self.notes.get_mut(&pulse).unwrap().push(message.clone()); - } else { - self.notes.insert(pulse, vec![message.clone()]); - } - } - } - } - } - } - } #[macro_export] macro_rules! phrase { diff --git a/src/model/track.rs b/src/model/track.rs index 10909b0e..7573c5e4 100644 --- a/src/model/track.rs +++ b/src/model/track.rs @@ -22,7 +22,15 @@ pub struct Track { /// Device selector pub device: usize, } - +ports!(Track { + audio: { + outs: |_t|Ok(vec![]), + } + midi: { + ins: |_t|Ok(vec![]), + outs: |_t|Ok(vec![]), + } +}); impl Track { pub fn new ( name: &str, @@ -43,6 +51,75 @@ impl Track { device: 0, }) } + pub fn process ( + &mut self, + input: MidiIter, + timebase: &Arc, + playing: Option, + scope: &ProcessScope, + frame0: usize, + frames: usize, + panic: bool, + ) { + // Need to be borrowed outside the conditional + let recording = self.recording; + let monitoring = self.monitoring; + // Output buffer + let mut output: Vec>>> = vec![None;frames]; + // For highlighting keys + let mut notes_on = vec![false;128]; + if panic { all_notes_off(&mut output); } + // Play from phrase into output buffer + if let Some(phrase) = self.phrase() { + if playing == Some(TransportState::Rolling) { + phrase.process_out( + &mut output, + &mut notes_on, + timebase, + frame0, + frames + ); + } + } + // Monitor and record input + let phrase = &mut self.phrase_mut(); + for (time, event, bytes) in parse_midi_input(input) { + let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; + match event { + LiveEvent::Midi { message, .. } => { + if monitoring { + if let Some(Some(frame)) = output.get_mut(time) { + frame.push(bytes.into()) + } else { + output[time] = Some(vec![bytes.into()]); + } + } + if recording { + if let Some(phrase) = phrase { + let contains = phrase.notes.contains_key(&pulse); + if contains { + phrase.notes.get_mut(&pulse).unwrap().push(message.clone()); + } else { + phrase.notes.insert(pulse, vec![message.clone()]); + } + }; + } + match message { + MidiMessage::NoteOn { key, .. } => { + notes_on[key.as_int() as usize] = true; + } + MidiMessage::NoteOff { key, .. } => { + notes_on[key.as_int() as usize] = false; + }, + _ => {} + } + }, + _ => {} + } + } + self.notes_on = notes_on; + write_midi_output(&mut self.midi_out.writer(scope), &output, frames); + } pub fn add_device ( &mut self, device: JackDevice ) -> &mut JackDevice { @@ -84,13 +161,3 @@ impl Track { &mut self.phrases[index] } } - -ports!(Track { - audio: { - outs: |_t|Ok(vec![]), - } - midi: { - ins: |_t|Ok(vec![]), - outs: |_t|Ok(vec![]), - } -}); diff --git a/src/view.rs b/src/view.rs index 55d76d93..ba4be97b 100644 --- a/src/view.rs +++ b/src/view.rs @@ -85,7 +85,7 @@ render!(App |self, buf, area| { track: Some(track), vertical: true, } - .render(buf, Rect { x, y: y + 1, width, height: height / 3 })? + .render(buf, Rect { x, y: y + 1, width, height: height - y - 1 })? .width .max(track.name.len() as u16); }