use crate::*; impl Audio for Sequencer { fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { if let Some(ref transport) = self.transport { transport.write().unwrap().process(client, scope); } todo!("sequencer process") } } impl Phrase { /// Write a chunk of MIDI events to an output port. pub fn process_out ( &self, output: &mut PhraseChunk, notes_on: &mut [bool;128], timebase: &Arc, (frame0, frames, _): (usize, usize, f64), ) { let mut buf = Vec::with_capacity(8); for (time, tick) in Ticks(timebase.pulses_per_sample()).between_samples( frame0, frame0 + frames ) { let tick = tick % self.length; for message in self.notes[tick].iter() { buf.clear(); let channel = 0.into(); let message = *message; LiveEvent::Midi { channel, message }.write(&mut buf).unwrap(); output[time as usize].push(buf.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, _ => {} } } } } } impl PhrasePlayer { pub fn process ( &mut self, input: Option, timebase: &Arc, playing: Option, started: Option<(usize, usize)>, quant: usize, reset: bool, scope: &ProcessScope, (frame0, frames): (usize, usize), (_usec0, _usecs): (usize, usize), period: f64, ) { if self.midi_out.is_some() { // 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 self.reset { all_notes_off(&mut self.midi_out_buf); self.reset = false; } else if reset { all_notes_off(&mut self.midi_out_buf); } } if let ( Some(TransportState::Rolling), Some((start_frame, _)), Some((_started, Some(ref phrase))) ) = (playing, started, &self.phrase) { phrase.read().map(|phrase|{ if self.midi_out.is_some() { phrase.process_out( &mut self.midi_out_buf, &mut self.notes_out.write().unwrap(), timebase, (frame0.saturating_sub(start_frame), frames, period) ); } }).unwrap(); let mut phrase = phrase.write().unwrap(); let length = phrase.length; // Monitor and record input if input.is_some() && (self.recording || self.monitoring) { // For highlighting keys and note repeat let mut notes_in = self.notes_in.write().unwrap(); for (frame, event, bytes) in parse_midi_input(input.unwrap()) { match event { LiveEvent::Midi { message, .. } => { if self.monitoring { self.midi_out_buf[frame].push(bytes.to_vec()) } if self.recording { phrase.record_event({ let pulse = timebase.samples_to_pulse( (frame0 + frame - start_frame) as f64 ); let quantized = ( pulse / quant as f64 ).round() as usize * quant; let looped = quantized % length; looped }, message); } match message { MidiMessage::NoteOn { key, .. } => { notes_in[key.as_int() as usize] = true; } MidiMessage::NoteOff { key, .. } => { notes_in[key.as_int() as usize] = false; }, _ => {} } }, _ => {} } } } } else if input.is_some() && self.midi_out.is_some() && self.monitoring { let mut notes_in = self.notes_in.write().unwrap(); for (frame, event, bytes) in parse_midi_input(input.unwrap()) { match event { LiveEvent::Midi { message, .. } => { self.midi_out_buf[frame].push(bytes.to_vec()); match message { MidiMessage::NoteOn { key, .. } => { notes_in[key.as_int() as usize] = true; } MidiMessage::NoteOff { key, .. } => { notes_in[key.as_int() as usize] = false; }, _ => {} } }, _ => {} } } } if let Some(out) = &mut self.midi_out { let writer = &mut out.writer(scope); let output = &self.midi_out_buf; for time in 0..frames { for event in output[time].iter() { writer.write(&RawMidi { time: time as u32, bytes: &event }) .expect(&format!("{event:?}")); } } } } } /// Add "all notes off" to the start of a buffer. pub fn all_notes_off (output: &mut PhraseChunk) { 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 ))) }