use crate::*; pub(crate) mod midi_pool; pub(crate) use midi_pool::*; pub(crate) mod midi_clip; pub(crate) use midi_clip::*; pub(crate) mod midi_launch; pub(crate) use midi_launch::*; pub(crate) mod midi_play; pub(crate) use midi_play::*; pub(crate) mod midi_rec; pub(crate) use midi_rec::*; pub(crate) mod midi_note; pub(crate) use midi_note::*; pub(crate) mod midi_range; pub(crate) use midi_range::*; pub(crate) mod midi_point; pub(crate) use midi_point::*; pub(crate) mod midi_view; pub(crate) use midi_view::*; pub(crate) mod midi_editor; pub(crate) use midi_editor::*; /// Trait for thing that may receive MIDI. pub trait HasMidiIns { fn midi_ins (&self) -> &Vec>; fn midi_ins_mut (&mut self) -> &mut Vec>; fn has_midi_ins (&self) -> bool { !self.midi_ins().is_empty() } } /// Trait for thing that may output MIDI. pub trait HasMidiOuts { fn midi_outs (&self) -> &Vec>; fn midi_outs_mut (&mut self) -> &mut Vec>; fn has_midi_outs (&self) -> bool { !self.midi_outs().is_empty() } /// Buffer for serializing a MIDI event. FIXME rename fn midi_note (&mut self) -> &mut Vec; } /// Add "all notes off" to the start of a buffer. pub fn all_notes_off (output: &mut [Vec>]) { 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(); output[0].push(buf); } /// Return boxed iterator of MIDI events pub fn parse_midi_input (input: MidiIter) -> Box + '_> { Box::new(input.map(|RawMidi { time, bytes }|( time as usize, LiveEvent::parse(bytes).unwrap(), bytes ))) } /// Update notes_in array pub fn update_keys (keys: &mut[bool;128], message: &MidiMessage) { match message { MidiMessage::NoteOn { key, .. } => { keys[key.as_int() as usize] = true; } MidiMessage::NoteOff { key, .. } => { keys[key.as_int() as usize] = false; }, _ => {} } } pub fn to_note_name (n: usize) -> &'static str { if n > 127 { panic!("to_note_name({n}): must be 0-127"); } MIDI_NOTE_NAMES[n] } pub const MIDI_NOTE_NAMES: [&str; 128] = [ "C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", "C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9", "C10", "C#10", "D10", "D#10", "E10", "F10", "F#10", "G10", ]; 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(crate) clock: ClockModel, /// Start time and phrase being played pub(crate) play_phrase: Option<(Moment, Option>>)>, /// Start time and next phrase pub(crate) next_phrase: Option<(Moment, Option>>)>, /// Play input through output. pub(crate) monitoring: bool, /// Write input to sequence. pub(crate) recording: bool, /// Overdub input to sequence. pub(crate) overdub: bool, /// Send all notes off pub(crate) 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(crate) notes_in: Arc>, /// Notes currently held at output pub(crate) notes_out: Arc>, /// MIDI output buffer pub note_buf: Vec, } impl MidiPlayer { pub fn new (jack: &Arc>, name: &str) -> Usually { Ok(Self { clock: ClockModel::from(jack), play_phrase: None, next_phrase: None, recording: false, monitoring: false, overdub: false, notes_in: RwLock::new([false;128]).into(), midi_ins: vec![ jack.midi_in(&format!("M/{name}"))?, ], midi_outs: vec![ jack.midi_out(&format!("{name}/M"))?, ], notes_out: RwLock::new([false;128]).into(), reset: true, note_buf: vec![0;8], }) } } 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: &ClockModel| 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: (&ClockModel, &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())? //], //}) //} //}