Skip to content

Commit

Permalink
Playtime: Clear slot in main thread synchronously
Browse files Browse the repository at this point in the history
better because immediate feedback to Playtime app and lead-follow-principle
intact
  • Loading branch information
helgoboss committed Jun 9, 2023
1 parent 46c81aa commit 9d742cc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
10 changes: 8 additions & 2 deletions playtime-clip-engine/src/base/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,15 @@ impl Column {
change_events
}

/// Asynchronously clears the given slot.
pub fn clear_slot(&self, slot_index: usize) {
/// Clears the given slot.
///
/// # Errors
///
/// Returns an error if the slot doesn't exist.
pub fn clear_slot(&mut self, slot_index: usize) -> ClipEngineResult<()> {
self.get_slot_mut(slot_index)?.clear();
self.rt_command_sender.clear_slot(slot_index);
Ok(())
}

/// Freezes the complete column.
Expand Down
31 changes: 22 additions & 9 deletions playtime-clip-engine/src/base/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,15 +408,20 @@ impl<H: ClipMatrixHandler> Matrix<H> {

/// Clears the slots of all scene-following columns.
pub fn clear_scene(&mut self, row_index: usize) -> ClipEngineResult<()> {
self.clear_scene_internal(row_index)
self.undoable("Clear scene", |matrix| {
matrix.clear_scene_internal(row_index)?;
matrix.notify_everything_changed();
Ok(())
})
}

fn clear_scene_internal(&mut self, row_index: usize) -> ClipEngineResult<()> {
if row_index >= self.row_count() {
return Err("row doesn't exist");
}
for column in self.scene_columns() {
column.clear_slot(row_index);
for column in self.scene_columns_mut() {
// If the slot doesn't exist in that column, it's okay.
let _ = column.clear_slot(row_index);
}
Ok(())
}
Expand All @@ -432,6 +437,11 @@ impl<H: ClipMatrixHandler> Matrix<H> {
self.columns.iter().filter(|c| c.follows_scene())
}

/// Returns a mutable iterator over all scene-following columns.
fn scene_columns_mut(&mut self) -> impl Iterator<Item = &mut Column> {
self.columns.iter_mut().filter(|c| c.follows_scene())
}

/// Cuts the given slot's clips to the matrix clipboard.
pub fn cut_slot(&mut self, address: ClipSlotAddress) -> ClipEngineResult<()> {
self.copy_slot(address)?;
Expand Down Expand Up @@ -463,14 +473,17 @@ impl<H: ClipMatrixHandler> Matrix<H> {

/// Clears the given slot.
pub fn clear_slot(&mut self, address: ClipSlotAddress) -> ClipEngineResult<()> {
// The undo point after clip removal is created later, in response to the upcoming event
// that indicates that the slot has actually been cleared.
self.clear_slot_internal(address)?;
Ok(())
self.undoable("Clear slot", move |matrix| {
matrix.clear_slot_internal(address)?;
let event = SlotChangeEvent::Clips("");
matrix.emit(ClipMatrixEvent::slot_changed(address, event));
Ok(())
})
}

fn clear_slot_internal(&mut self, address: ClipSlotAddress) -> ClipEngineResult<()> {
self.get_column(address.column)?.clear_slot(address.row);
self.get_column_mut(address.column)?
.clear_slot(address.row)?;
Ok(())
}

Expand Down Expand Up @@ -599,8 +612,8 @@ impl<H: ClipMatrixHandler> Matrix<H> {
.get_slot(source_address)?
.api_clips(self.permanent_project());
self.undoable("Move slot to", |matrix| {
matrix.add_clips_to_slot(dest_address, clips_in_slot)?;
matrix.clear_slot_internal(source_address)?;
matrix.add_clips_to_slot(dest_address, clips_in_slot)?;
matrix.notify_everything_changed();
Ok(())
})?;
Expand Down
4 changes: 4 additions & 0 deletions playtime-clip-engine/src/base/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,10 @@ impl Slot {
Ok(SlotChangeEvent::Clips("MIDI overdub finished"))
}

pub fn clear(&mut self) {
self.contents.clear();
}

pub fn slot_cleared(&mut self) -> Option<SlotChangeEvent> {
if self.is_empty() {
return None;
Expand Down
3 changes: 3 additions & 0 deletions playtime-clip-engine/src/rt/supplier/fade_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ enum BlockLocation {
}

// 240 frames = 5ms at 48 kHz
// TODO-high-clip-engine That's not enough. Take some pad/organ sound and it will click!
// And this, gentlemen, is why the stop process needs to be asynchronous = needs to cover
// multiple audio callback cycles.
const FADE_LENGTH: usize = 240;
pub const SECTION_FADE_LENGTH: usize = FADE_LENGTH;
pub const INTERACTION_FADE_LENGTH: usize = FADE_LENGTH;
Expand Down

0 comments on commit 9d742cc

Please sign in to comment.