mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
launch countdown/switchover, pt.2
This commit is contained in:
parent
3df8e87840
commit
97a7bf5b1d
3 changed files with 31 additions and 12 deletions
|
|
@ -236,12 +236,20 @@ impl<E: Engine> Arrangement<E> {
|
||||||
size: Measure::new(),
|
size: Measure::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn is_stopped (&self) -> bool {
|
||||||
|
*self.clock.playing.read().unwrap() == Some(TransportState::Stopped)
|
||||||
|
}
|
||||||
pub fn activate (&mut self) {
|
pub fn activate (&mut self) {
|
||||||
match self.selected {
|
match self.selected {
|
||||||
ArrangementFocus::Scene(s) => {
|
ArrangementFocus::Scene(s) => {
|
||||||
for (t, track) in self.tracks.iter_mut().enumerate() {
|
for (t, track) in self.tracks.iter_mut().enumerate() {
|
||||||
track.player.enqueue_next(self.scenes[s].clips[t].as_ref());
|
track.player.enqueue_next(self.scenes[s].clips[t].as_ref());
|
||||||
}
|
}
|
||||||
|
// TODO make transport available here, so that
|
||||||
|
// activating a scene when stopped starts playback
|
||||||
|
//if self.is_stopped() {
|
||||||
|
//self.transport.toggle_play()
|
||||||
|
//}
|
||||||
},
|
},
|
||||||
ArrangementFocus::Clip(t, s) => {
|
ArrangementFocus::Clip(t, s) => {
|
||||||
self.tracks[t].player.enqueue_next(self.scenes[s].clips[t].as_ref());
|
self.tracks[t].player.enqueue_next(self.scenes[s].clips[t].as_ref());
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl<E: Engine> Audio for Sequencer<E> {
|
||||||
impl Audio for PhrasePlayer {
|
impl Audio for PhrasePlayer {
|
||||||
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
|
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
|
||||||
let has_midi_outputs = self.has_midi_outputs();
|
let has_midi_outputs = self.has_midi_outputs();
|
||||||
let has_midi_inputs = self.has_midi_inputs();
|
let has_midi_inputs = self.has_midi_inputs();
|
||||||
if has_midi_outputs {
|
if has_midi_outputs {
|
||||||
// Clear output buffer(s)
|
// Clear output buffer(s)
|
||||||
self.clear(scope, false);
|
self.clear(scope, false);
|
||||||
|
|
@ -45,11 +45,12 @@ impl PhrasePlayer {
|
||||||
all_notes_off(&mut self.midi_out_buf); self.reset = false;
|
all_notes_off(&mut self.midi_out_buf); self.reset = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn is_rolling (&self) -> bool {
|
||||||
|
*self.clock.playing.read().unwrap() == Some(TransportState::Rolling)
|
||||||
|
}
|
||||||
/// Return playing phrase with starting point
|
/// Return playing phrase with starting point
|
||||||
fn playing (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
|
fn playing (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
|
||||||
if let (
|
if let (true, Some((started, Some(ref phrase)))) = (self.is_rolling(), &self.phrase) {
|
||||||
Some(TransportState::Rolling), Some((started, Some(ref phrase)))
|
|
||||||
) = (*self.clock.playing.read().unwrap(), &self.phrase) {
|
|
||||||
Some((started.sample().get() as usize, phrase.clone()))
|
Some((started.sample().get() as usize, phrase.clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -57,9 +58,7 @@ impl PhrasePlayer {
|
||||||
}
|
}
|
||||||
/// Return next phrase with starting point
|
/// Return next phrase with starting point
|
||||||
fn enqueued (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
|
fn enqueued (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
|
||||||
if let (
|
if let (true, Some((start_at, Some(ref phrase)))) = (self.is_rolling(), &self.next_phrase) {
|
||||||
Some(TransportState::Rolling), Some((start_at, Some(ref phrase)))
|
|
||||||
) = (*self.clock.playing.read().unwrap(), &self.next_phrase) {
|
|
||||||
Some((start_at.sample().get() as usize, phrase.clone()))
|
Some((start_at.sample().get() as usize, phrase.clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -76,6 +75,10 @@ impl PhrasePlayer {
|
||||||
let notes_on = &mut self.notes_out.write().unwrap();
|
let notes_on = &mut self.notes_out.write().unwrap();
|
||||||
let mut buf = Vec::with_capacity(8);
|
let mut buf = Vec::with_capacity(8);
|
||||||
for (sample, tick) in ticks {
|
for (sample, tick) in ticks {
|
||||||
|
// If a next phrase is enqueued, and we're past the end of the current one,
|
||||||
|
// break the loop here (FIXME count tick correctly)
|
||||||
|
if self.next_phrase.is_some() && tick >= phrase.length { break }
|
||||||
|
// Output events from phrase at appropriate frames of output buffer
|
||||||
let tick = tick % phrase.length;
|
let tick = tick % phrase.length;
|
||||||
for message in phrase.notes[tick].iter() {
|
for message in phrase.notes[tick].iter() {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
|
@ -88,6 +91,9 @@ impl PhrasePlayer {
|
||||||
}
|
}
|
||||||
}).unwrap()
|
}).unwrap()
|
||||||
}
|
}
|
||||||
|
if let Some((start, ref phrase)) = self.enqueued() {
|
||||||
|
// TODO switch to next phrase and fill in remaining ticks from it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn record (&mut self, scope: &ProcessScope) {
|
fn record (&mut self, scope: &ProcessScope) {
|
||||||
let sample0 = scope.last_frame_time() as usize;
|
let sample0 = scope.last_frame_time() as usize;
|
||||||
|
|
@ -101,7 +107,9 @@ impl PhrasePlayer {
|
||||||
for input in self.midi_inputs.iter() {
|
for input in self.midi_inputs.iter() {
|
||||||
for (sample, event, bytes) in parse_midi_input(input.iter(scope)) {
|
for (sample, event, bytes) in parse_midi_input(input.iter(scope)) {
|
||||||
if let LiveEvent::Midi { message, .. } = event {
|
if let LiveEvent::Midi { message, .. } = event {
|
||||||
if self.monitoring { self.midi_out_buf[sample].push(bytes.to_vec()) }
|
if self.monitoring {
|
||||||
|
self.midi_out_buf[sample].push(bytes.to_vec())
|
||||||
|
}
|
||||||
if self.recording {
|
if self.recording {
|
||||||
phrase.record_event({
|
phrase.record_event({
|
||||||
let pulse = self.clock.timebase().samples_to_pulse(
|
let pulse = self.clock.timebase().samples_to_pulse(
|
||||||
|
|
@ -117,6 +125,9 @@ impl PhrasePlayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some((start, ref phrase)) = self.enqueued() {
|
||||||
|
// TODO switch to next phrase and record into it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn monitor (&mut self, scope: &ProcessScope) {
|
fn monitor (&mut self, scope: &ProcessScope) {
|
||||||
let mut notes_in = self.notes_in.write().unwrap();
|
let mut notes_in = self.notes_in.write().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ use crate::*;
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TransportTime {
|
pub struct TransportTime {
|
||||||
/// Current moment in time
|
/// Current moment in time
|
||||||
pub instant: Instant,
|
pub instant: Instant,
|
||||||
/// Note quantization factor
|
/// Note quantization factor
|
||||||
pub quant: TimeUnit,
|
pub quant: TimeUnit,
|
||||||
/// Launch quantization factor
|
/// Launch quantization factor
|
||||||
pub sync: TimeUnit,
|
pub sync: TimeUnit,
|
||||||
/// Playback state
|
/// Playback state
|
||||||
pub playing: RwLock<Option<TransportState>>,
|
pub playing: RwLock<Option<TransportState>>,
|
||||||
}
|
}
|
||||||
impl TransportTime {
|
impl TransportTime {
|
||||||
pub fn timebase (&self) -> &Arc<Timebase> { &self.instant.timebase }
|
pub fn timebase (&self) -> &Arc<Timebase> { &self.instant.timebase }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue