use crate::*; pub trait MidiPlayerApi: MidiRecordApi + MidiPlaybackApi + Send + Sync {} impl MidiPlayerApi for MidiPlayer {} pub trait HasPlayer { fn player (&self) -> &impl MidiPlayerApi; fn player_mut (&mut self) -> &mut impl MidiPlayerApi; } #[macro_export] macro_rules! has_player { (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { impl $(<$($L),*$($T $(: $U)?),*>)? HasPlayer for $Struct $(<$($L),*$($T),*>)? { fn player (&$self) -> &impl MidiPlayerApi { &$cb } fn player_mut (&mut $self) -> &mut impl MidiPlayerApi { &mut$cb } } } } /// Contains state for playing a phrase pub struct MidiPlayer { /// State of clock and playhead pub clock: Clock, /// Start time and phrase being played pub play_phrase: Option<(Moment, Option>>)>, /// Start time and next phrase pub next_phrase: Option<(Moment, Option>>)>, /// Play input through output. pub monitoring: bool, /// Write input to sequence. pub recording: bool, /// Overdub input to sequence. pub overdub: bool, /// Send all notes off pub reset: bool, // TODO?: after Some(nframes) /// Record from MIDI ports to current sequence. pub midi_ins: Vec>, /// Play from current sequence to MIDI ports pub midi_outs: Vec>, /// Notes currently held at input pub notes_in: Arc>, /// Notes currently held at output pub notes_out: Arc>, /// MIDI output buffer pub note_buf: Vec, } impl MidiPlayer { pub fn new ( jack: &Arc>, name: impl AsRef, clip: Option<&Arc>>, midi_from: &[PortConnection], midi_to: &[PortConnection], ) -> Usually { let name = name.as_ref(); let clock = Clock::from(jack); Ok(Self { play_phrase: Some((Moment::zero(&clock.timebase), clip.cloned())), next_phrase: None, recording: false, monitoring: false, overdub: false, notes_in: RwLock::new([false;128]).into(), notes_out: RwLock::new([false;128]).into(), note_buf: vec![0;8], reset: true, midi_ins: vec![JackPort::::new(jack, format!("M/{name}"), midi_from)?,], midi_outs: vec![JackPort::::new(jack, format!("{name}/M"), midi_to)?, ], clock, }) } pub fn play_status (&self) -> impl Content { ClipSelected::play_phrase(self) } pub fn next_status (&self) -> impl Content { ClipSelected::next_phrase(self) } } impl std::fmt::Debug for MidiPlayer { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("MidiPlayer") .field("clock", &self.clock) .field("play_phrase", &self.play_phrase) .field("next_phrase", &self.next_phrase) .finish() } } from!(|clock: &Clock| MidiPlayer = Self { clock: clock.clone(), midi_ins: vec![], midi_outs: vec![], note_buf: vec![0;8], reset: true, recording: false, monitoring: false, overdub: false, play_phrase: None, next_phrase: None, notes_in: RwLock::new([false;128]).into(), notes_out: RwLock::new([false;128]).into(), }); from!(|state: (&Clock, &Arc>)|MidiPlayer = { let (clock, phrase) = state; let mut model = Self::from(clock); model.play_phrase = Some((Moment::zero(&clock.timebase), Some(phrase.clone()))); model }); has_clock!(|self: MidiPlayer|&self.clock); impl HasMidiIns for MidiPlayer { fn midi_ins (&self) -> &Vec> { &self.midi_ins } fn midi_ins_mut (&mut self) -> &mut Vec> { &mut self.midi_ins } } impl HasMidiOuts for MidiPlayer { fn midi_outs (&self) -> &Vec> { &self.midi_outs } fn midi_outs_mut (&mut self) -> &mut Vec> { &mut self.midi_outs } fn midi_note (&mut self) -> &mut Vec { &mut self.note_buf } } /// Hosts the JACK callback for a single MIDI player pub struct PlayerAudio<'a, T: MidiPlayerApi>( /// Player pub &'a mut T, /// Note buffer pub &'a mut Vec, /// Note chunk buffer pub &'a mut Vec>>, ); /// JACK process callback for a sequencer's phrase player/recorder. impl Audio for PlayerAudio<'_, T> { fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { let model = &mut self.0; let note_buf = &mut self.1; let midi_buf = &mut self.2; // Clear output buffer(s) model.clear(scope, midi_buf, false); // Write chunk of phrase to output, handle switchover if model.play(scope, note_buf, midi_buf) { model.switchover(scope, note_buf, midi_buf); } if model.has_midi_ins() { if model.recording() || model.monitoring() { // Record and/or monitor input model.record(scope, midi_buf) } else if model.has_midi_outs() && model.monitoring() { // Monitor input to output model.monitor(scope, midi_buf) } } // Write to output port(s) model.write(scope, midi_buf); Control::Continue } } impl MidiRecordApi for MidiPlayer { fn recording (&self) -> bool { self.recording } fn recording_mut (&mut self) -> &mut bool { &mut self.recording } fn monitoring (&self) -> bool { self.monitoring } fn monitoring_mut (&mut self) -> &mut bool { &mut self.monitoring } fn overdub (&self) -> bool { self.overdub } fn overdub_mut (&mut self) -> &mut bool { &mut self.overdub } fn notes_in (&self) -> &Arc> { &self.notes_in } } impl MidiPlaybackApi for MidiPlayer { fn notes_out (&self) -> &Arc> { &self.notes_out } } impl HasPlayPhrase for MidiPlayer { fn reset (&self) -> bool { self.reset } fn reset_mut (&mut self) -> &mut bool { &mut self.reset } fn play_phrase (&self) -> &Option<(Moment, Option>>)> { &self.play_phrase } fn play_phrase_mut (&mut self) -> &mut Option<(Moment, Option>>)> { &mut self.play_phrase } fn next_phrase (&self) -> &Option<(Moment, Option>>)> { &self.next_phrase } fn next_phrase_mut (&mut self) -> &mut Option<(Moment, Option>>)> { &mut self.next_phrase } } //#[derive(Debug)] //pub struct MIDIPlayer { ///// Global timebase //pub clock: Arc, ///// Start time and phrase being played //pub play_phrase: Option<(Moment, Option>>)>, ///// Start time and next phrase //pub next_phrase: Option<(Moment, Option>>)>, ///// Play input through output. //pub monitoring: bool, ///// Write input to sequence. //pub recording: bool, ///// Overdub input to sequence. //pub overdub: bool, ///// Send all notes off //pub reset: bool, // TODO?: after Some(nframes) ///// Record from MIDI ports to current sequence. //pub midi_inputs: Vec>, ///// Play from current sequence to MIDI ports //pub midi_outputs: Vec>, ///// MIDI output buffer //pub midi_note: Vec, ///// MIDI output buffer //pub midi_chunk: Vec>>, ///// Notes currently held at input //pub notes_in: Arc>, ///// Notes currently held at output //pub notes_out: Arc>, //} ///// Methods used primarily by the process callback //impl MIDIPlayer { //pub fn new ( //jack: &Arc>, //clock: &Arc, //name: &str //) -> Usually { //let jack = jack.read().unwrap(); //Ok(Self { //clock: clock.clone(), //phrase: None, //next_phrase: None, //notes_in: Arc::new(RwLock::new([false;128])), //notes_out: Arc::new(RwLock::new([false;128])), //monitoring: false, //recording: false, //overdub: true, //reset: true, //midi_note: Vec::with_capacity(8), //midi_chunk: vec![Vec::with_capacity(16);16384], //midi_outputs: vec![ //jack.client().register_port(format!("{name}_out0").as_str(), MidiOut::default())? //], //midi_inputs: vec![ //jack.client().register_port(format!("{name}_in0").as_str(), MidiIn::default())? //], //}) //} //}