mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
support multiple midi ins in PhrasePlayer::process
This commit is contained in:
parent
325492ec42
commit
02f691c494
3 changed files with 51 additions and 66 deletions
|
|
@ -179,7 +179,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
|||
.map(|port|port.short_name())
|
||||
.transpose()?
|
||||
.unwrap_or("(none)".into());
|
||||
let input = format!("▎i {}", input_name);
|
||||
let input = format!("▎>{}", input_name);
|
||||
col!(name, input)
|
||||
.min_xy(w as u16, track_title_h)
|
||||
.bg(track.color)
|
||||
|
|
@ -201,7 +201,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
|||
.map(|port|port.short_name())
|
||||
.transpose()?
|
||||
.unwrap_or("(none)".into());
|
||||
let output = format!("▎o {}", output_name);
|
||||
let output = format!("▎<{}", output_name);
|
||||
col!(until_next, elapsed, output)
|
||||
.min_xy(w as u16, tracks_footer)
|
||||
.bg(track.color)
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ impl<E: Engine> PhrasePlayer<E> {
|
|||
pub fn toggle_monitor (&mut self) { self.monitoring = !self.monitoring; }
|
||||
pub fn toggle_record (&mut self) { self.recording = !self.recording; }
|
||||
pub fn toggle_overdub (&mut self) { self.overdub = !self.overdub; }
|
||||
pub fn enqueue_next (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) {
|
||||
pub fn enqueue_next (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) {
|
||||
let start = self.clock.next_launch_pulse();
|
||||
self.next_phrase = Some((start.into(), phrase.map(|p|p.clone())));
|
||||
self.reset = true;
|
||||
|
|
@ -433,6 +433,21 @@ impl<E: Engine> PhrasePlayer<E> {
|
|||
.map(|(started,_)|started.load(Ordering::Relaxed))
|
||||
.map(|started|started - self.clock.sample())
|
||||
}
|
||||
pub fn playing_phrase (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
|
||||
if let (
|
||||
Some(TransportState::Rolling),
|
||||
Some((start_frame, _)),
|
||||
Some((_started, Some(ref phrase)))
|
||||
) = (
|
||||
*self.clock.playing.read().unwrap(),
|
||||
self.started,
|
||||
&self.phrase
|
||||
) {
|
||||
Some((start_frame, phrase.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Displays and edits phrase length
|
||||
pub struct PhraseLength<E: Engine> {
|
||||
|
|
|
|||
|
|
@ -10,47 +10,37 @@ impl<E: Engine> Audio for Sequencer<E> {
|
|||
impl<E: Engine> PhrasePlayer<E> {
|
||||
pub fn process (
|
||||
&mut self,
|
||||
input: Option<MidiIter>,
|
||||
scope: &ProcessScope,
|
||||
(frame0, frames): (usize, usize),
|
||||
(_usec0, _usecs): (usize, usize),
|
||||
period: f64,
|
||||
) {
|
||||
let has_midi_inputs = self.has_midi_inputs();
|
||||
let has_midi_outputs = self.has_midi_outputs();
|
||||
let quant = self.clock.quant();
|
||||
if has_midi_outputs {
|
||||
self.clear_midi_out_buf(frames);
|
||||
self.reset_midi_out_buf(false /* FIXME where did force-reset come from? */);
|
||||
}
|
||||
if let (
|
||||
Some(TransportState::Rolling),
|
||||
Some((start_frame, _)),
|
||||
Some((_started, Some(ref phrase)))
|
||||
) = (
|
||||
*self.clock.playing.read().unwrap(),
|
||||
self.started,
|
||||
&self.phrase
|
||||
) {
|
||||
let has_midi_inputs = self.has_midi_inputs();
|
||||
let quant = self.clock.quant();
|
||||
if let Some((start_frame, phrase)) = self.playing_phrase() {
|
||||
phrase.read().map(|phrase|{
|
||||
if has_midi_outputs {
|
||||
phrase.process_out(
|
||||
&mut self.midi_out_buf,
|
||||
&mut self.notes_out.write().unwrap(),
|
||||
&self.clock.timebase,
|
||||
(frame0.saturating_sub(start_frame), frames, period)
|
||||
&mut self.midi_out_buf, &mut self.notes_out.write().unwrap(),
|
||||
&self.clock.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) {
|
||||
if has_midi_inputs && (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, .. } => {
|
||||
// Record from each input
|
||||
for input in self.midi_inputs.iter() {
|
||||
for (frame, event, bytes) in parse_midi_input(input.iter(scope)) {
|
||||
if let LiveEvent::Midi { message, .. } = event {
|
||||
if self.monitoring {
|
||||
self.midi_out_buf[frame].push(bytes.to_vec())
|
||||
}
|
||||
|
|
@ -66,37 +56,20 @@ impl<E: Engine> PhrasePlayer<E> {
|
|||
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;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
update_keys(&mut notes_in, &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if input.is_some() && has_midi_outputs && self.monitoring {
|
||||
} else if has_midi_inputs && has_midi_outputs && 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, .. } => {
|
||||
for input in self.midi_inputs.iter() {
|
||||
// Monitor each input
|
||||
for (frame, event, bytes) in parse_midi_input(input.iter(scope)) {
|
||||
if let LiveEvent::Midi { message, .. } = event {
|
||||
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;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
update_keys(&mut notes_in, &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,17 +85,11 @@ impl<E: Engine> PhrasePlayer<E> {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn has_midi_inputs (&self) -> bool {
|
||||
self.midi_inputs.len() > 0
|
||||
}
|
||||
pub fn has_midi_outputs (&self) -> bool {
|
||||
self.midi_outputs.len() > 0
|
||||
}
|
||||
pub fn has_midi_inputs (&self) -> bool { self.midi_inputs.len() > 0 }
|
||||
pub fn has_midi_outputs (&self) -> bool { self.midi_outputs.len() > 0 }
|
||||
/// Clear the section of the output buffer that we will be using
|
||||
pub fn clear_midi_out_buf (&mut self, frames: usize) {
|
||||
for frame in &mut self.midi_out_buf[0..frames] {
|
||||
frame.clear();
|
||||
}
|
||||
for frame in &mut self.midi_out_buf[0..frames] { frame.clear(); }
|
||||
}
|
||||
/// Emit "all notes off" at start of buffer if requested
|
||||
pub fn reset_midi_out_buf (&mut self, force_reset: bool) {
|
||||
|
|
@ -144,9 +111,8 @@ impl Phrase {
|
|||
(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 ticks = Ticks(timebase.pulses_per_sample()).between_samples(frame0, frame0 + frames);
|
||||
for (time, tick) in ticks {
|
||||
let tick = tick % self.length;
|
||||
for message in self.notes[tick].iter() {
|
||||
buf.clear();
|
||||
|
|
@ -154,11 +120,7 @@ impl Phrase {
|
|||
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,
|
||||
_ => {}
|
||||
}
|
||||
update_keys(notes_on, &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -179,3 +141,11 @@ pub fn parse_midi_input (input: MidiIter) -> Box<dyn Iterator<Item=(usize, LiveE
|
|||
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; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue