diff --git a/src/core/midi.rs b/src/core/midi.rs index be8715ed..6caada72 100644 --- a/src/core/midi.rs +++ b/src/core/midi.rs @@ -7,18 +7,15 @@ pub type MIDIMessage = Vec; pub type MIDIChunk = - [Option>]; + [Vec]; /// 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); - } + 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); } pub fn parse_midi_input (input: MidiIter) -> Box + '_> { @@ -32,11 +29,9 @@ pub fn parse_midi_input (input: MidiIter) -> Box, /// Output from current sequence. pub midi_out: Port, + midi_out_buf: Vec>>, /// Red keys on piano roll. pub notes_on: Vec, /// Device chain @@ -39,89 +40,30 @@ impl Track { devices: Option>, ) -> Usually { Ok(Self { - name: name.to_string(), - midi_out: jack.register_port(name, MidiOut)?, - notes_on: vec![], - monitoring: false, - recording: false, - overdub: true, - sequence: None, - phrases: phrases.unwrap_or_else(||Vec::with_capacity(16)), - devices: devices.unwrap_or_else(||Vec::with_capacity(16)), - device: 0, + name: name.to_string(), + midi_out: jack.register_port(name, MidiOut)?, + midi_out_buf: vec![vec![];1024], + notes_on: vec![false;128], + monitoring: false, + recording: false, + overdub: true, + sequence: None, + phrases: phrases.unwrap_or_else(||Vec::with_capacity(16)), + devices: devices.unwrap_or_else(||Vec::with_capacity(16)), + 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 conditionals? - 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 - if self.recording || self.monitoring { - let phrase = &mut self.phrase_mut(); - for (time, event, bytes) in parse_midi_input(input) { - 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 pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; - let pulse = pulse % phrase.length; - 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 device (&self) -> Option>> { + self.get_device(self.device) + } + pub fn first_device (&self) -> Option>> { + self.get_device(0) + } + pub fn last_device (&self) -> Option>> { + self.get_device(self.devices.len().saturating_sub(1)) + } + pub fn get_device (&self, i: usize) -> Option>> { + self.devices.get(i).map(|d|d.state.lock().unwrap()) } pub fn add_device (&mut self, device: JackDevice) -> Usually<&mut JackDevice> { self.devices.push(device); @@ -138,18 +80,6 @@ impl Track { let index = self.devices.len() - 1; Ok(&mut self.devices[index]) } - pub fn get_device (&self, i: usize) -> Option>> { - self.devices.get(i).map(|d|d.state.lock().unwrap()) - } - pub fn device (&self) -> Option>> { - self.get_device(self.device) - } - pub fn first_device (&self) -> Option>> { - self.get_device(0) - } - pub fn last_device (&self) -> Option>> { - self.get_device(self.devices.len().saturating_sub(1)) - } pub fn phrase (&self) -> Option<&Phrase> { if let Some(phrase) = self.sequence { return self.phrases.get(phrase) @@ -180,4 +110,80 @@ impl Track { pub fn toggle_overdub (&mut self) { self.overdub = !self.overdub; } + 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 conditionals? + let recording = self.recording; + let monitoring = self.monitoring; + // Clear the section of the output buffer that we will be using + for frame in &mut self.midi_out_buf[0..frames] { + frame.clear(); + } + // Emit "all notes off" at start of buffer if requested + if panic { + all_notes_off(&mut self.midi_out_buf); + } + // Play from phrase into output buffer + if let Some(Some(phrase)) = self.sequence.map(|id|self.phrases.get(id)) { + if playing == Some(TransportState::Rolling) { + phrase.process_out( + &mut self.midi_out_buf, + &mut self.notes_on, + timebase, + frame0, + frames + ); + } + } + // Monitor and record input + if self.recording || self.monitoring { + // For highlighting keys + let notes_on = &mut self.notes_on; + let phrase = &mut self.sequence.map(|id|self.phrases.get_mut(id)); + for (time, event, bytes) in parse_midi_input(input) { + match event { + LiveEvent::Midi { message, .. } => { + if monitoring { + self.midi_out_buf[time].push(bytes.to_vec()) + } + if recording { + if let Some(Some(phrase)) = phrase { + let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; + let pulse = pulse % phrase.length; + 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; + }, + _ => {} + } + }, + _ => {} + } + } + } + write_midi_output( + &mut self.midi_out.writer(scope), + &self.midi_out_buf, + frames + ); + } }