mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
sequencer: extract get_sample_offset, get_pulses
Some checks are pending
/ build (push) Waiting to run
Some checks are pending
/ build (push) Waiting to run
This commit is contained in:
parent
329da026d7
commit
997d67a487
1 changed files with 57 additions and 38 deletions
|
|
@ -163,9 +163,64 @@ pub trait MidiPlayer: HasPlayClip + HasClock + HasMidiOuts {
|
||||||
}
|
}
|
||||||
// If a clip is playing, write a chunk of MIDI events from it to the output buffer.
|
// If a clip is playing, write a chunk of MIDI events from it to the output buffer.
|
||||||
// If no clip is playing, prepare for switchover immediately.
|
// If no clip is playing, prepare for switchover immediately.
|
||||||
self.play_clip().as_ref().map_or(true, |(started, clip)|{
|
if let Some((started, clip)) = self.play_clip() {
|
||||||
self.play_chunk(scope, note_buf, out, started, clip)
|
self.play_chunk(scope, note_buf, out, started, clip)
|
||||||
})
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_chunk (
|
||||||
|
&self,
|
||||||
|
scope: &ProcessScope,
|
||||||
|
note_buf: &mut Vec<u8>,
|
||||||
|
out: &mut [Vec<Vec<u8>>],
|
||||||
|
started: &Moment,
|
||||||
|
clip: &Option<Arc<RwLock<MidiClip>>>
|
||||||
|
) -> bool {
|
||||||
|
// Index of first sample to populate.
|
||||||
|
let offset = self.get_sample_offset(scope, started);
|
||||||
|
// Notes active during current chunk.
|
||||||
|
let notes = &mut self.notes_out().write().unwrap();
|
||||||
|
// Length of clip.
|
||||||
|
let length = clip.as_ref().map_or(0, |p|p.read().unwrap().length);
|
||||||
|
// Write MIDI events from clip at sample offsets corresponding to pulses.
|
||||||
|
for (sample, pulse) in self.get_pulses(scope, offset) {
|
||||||
|
// If a next clip is enqueued, and we're past the end of the current one,
|
||||||
|
// break the loop here (FIXME count pulse correctly)
|
||||||
|
let past_end = if clip.is_some() { pulse >= length } else { true };
|
||||||
|
// Is it time for switchover?
|
||||||
|
if self.next_clip().is_some() && past_end {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If there's a currently playing clip, output notes from it to buffer:
|
||||||
|
if let Some(ref clip) = clip {
|
||||||
|
Self::play_pulse(clip, pulse, sample, note_buf, out, notes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get index of first sample to populate.
|
||||||
|
///
|
||||||
|
/// Greater than 0 means that the first pulse of the clip
|
||||||
|
/// falls somewhere in the middle of the chunk.
|
||||||
|
fn get_sample_offset (&self, scope: &ProcessScope, started: &Moment) -> usize{
|
||||||
|
(scope.last_frame_time() as usize).saturating_sub(
|
||||||
|
started.sample.get() as usize +
|
||||||
|
self.clock().started.read().unwrap().as_ref().unwrap().sample.get() as usize
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get iterator that emits sample paired with pulse.
|
||||||
|
//
|
||||||
|
// * Sample: index into output buffer at which to write MIDI event
|
||||||
|
// * Pulse: index into clip from which to take the MIDI event
|
||||||
|
//
|
||||||
|
// Emitted for each sample of the output buffer that corresponds to a MIDI pulse.
|
||||||
|
fn get_pulses (&self, scope: &ProcessScope, offset: usize) -> TicksIterator {
|
||||||
|
self.clock().timebase().pulses_between_samples(
|
||||||
|
offset, offset + scope.n_frames() as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle switchover from current to next playing clip.
|
/// Handle switchover from current to next playing clip.
|
||||||
|
|
@ -197,42 +252,6 @@ pub trait MidiPlayer: HasPlayClip + HasClock + HasMidiOuts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play_chunk (
|
|
||||||
&self,
|
|
||||||
scope: &ProcessScope,
|
|
||||||
note_buf: &mut Vec<u8>,
|
|
||||||
out: &mut [Vec<Vec<u8>>],
|
|
||||||
started: &Moment,
|
|
||||||
clip: &Option<Arc<RwLock<MidiClip>>>
|
|
||||||
) -> bool {
|
|
||||||
// First sample to populate. Greater than 0 means that the first
|
|
||||||
// pulse of the clip falls somewhere in the middle of the chunk.
|
|
||||||
let sample = (scope.last_frame_time() as usize).saturating_sub(
|
|
||||||
started.sample.get() as usize +
|
|
||||||
self.clock().started.read().unwrap().as_ref().unwrap().sample.get() as usize
|
|
||||||
);
|
|
||||||
// Iterator that emits sample (index into output buffer at which to write MIDI event)
|
|
||||||
// paired with pulse (index into clip from which to take the MIDI event) for each
|
|
||||||
// sample of the output buffer that corresponds to a MIDI pulse.
|
|
||||||
let pulses = self.clock().timebase().pulses_between_samples(sample, sample + scope.n_frames() as usize);
|
|
||||||
// Notes active during current chunk.
|
|
||||||
let notes = &mut self.notes_out().write().unwrap();
|
|
||||||
let length = clip.as_ref().map_or(0, |p|p.read().unwrap().length);
|
|
||||||
for (sample, pulse) in pulses {
|
|
||||||
// If a next clip is enqueued, and we're past the end of the current one,
|
|
||||||
// break the loop here (FIXME count pulse correctly)
|
|
||||||
let past_end = if clip.is_some() { pulse >= length } else { true };
|
|
||||||
if self.next_clip().is_some() && past_end {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// If there's a currently playing clip, output notes from it to buffer:
|
|
||||||
if let Some(ref clip) = clip {
|
|
||||||
Self::play_pulse(clip, pulse, sample, note_buf, out, notes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play_pulse (
|
fn play_pulse (
|
||||||
clip: &RwLock<MidiClip>,
|
clip: &RwLock<MidiClip>,
|
||||||
pulse: usize,
|
pulse: usize,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue