mirror of
https://github.com/storytold/soundcraft.git
synced 2026-11-01 06:26:51 -06:00
Clear: lift clips removed by id in Shuffle so crossfade partners don't overlap
This commit is contained in:
+13
-20
@@ -177,28 +177,21 @@ pub fn clear_range(s: &mut Session, track: TrackId, range: Range, shuffle: bool)
|
||||
removed
|
||||
}
|
||||
|
||||
/// Remove the clips `ids` from every track. In Shuffle the later clips on each track close the gaps they leave,
|
||||
/// the latest gap first so the earlier ones stay where they were. Returns how many clips went.
|
||||
/// Remove the clips `ids` from every track. In Shuffle the later clips on each track close the holes the movable
|
||||
/// ones leave, as a Shuffle move lifts them (see [`lift_plan`]), so a crossfade partner keeps its material. Returns
|
||||
/// how many clips went.
|
||||
pub fn remove_clips(s: &mut Session, ids: &[ClipId], shuffle: bool) -> usize {
|
||||
let mut gaps: Vec<(TrackId, Range)> = Vec::new();
|
||||
for t in &mut s.tracks {
|
||||
let track = t.id;
|
||||
if let Some(pl) = t.playlist_mut() {
|
||||
pl.clips.retain(|c| {
|
||||
let gone = ids.contains(&c.id);
|
||||
if gone {
|
||||
gaps.push((track, c.range()));
|
||||
}
|
||||
!gone
|
||||
});
|
||||
let ids: HashSet<ClipId> = ids.iter().copied().collect();
|
||||
let mut n = 0;
|
||||
for track in s.tracks.iter().map(|t| t.id).collect::<Vec<_>>() {
|
||||
if shuffle {
|
||||
n += lift_all(s, track, &ids).len();
|
||||
}
|
||||
}
|
||||
let n = gaps.len();
|
||||
if shuffle {
|
||||
gaps.sort_by_key(|(t, r)| (t.0, std::cmp::Reverse(r.start)));
|
||||
for (track, r) in gaps {
|
||||
let moved = ripple(s, track, r.end, -r.len());
|
||||
follow_automation(s, track, r.end, moved);
|
||||
// Locked clips don't lift; they go without closing up, as everything does outside Shuffle.
|
||||
if let Some(pl) = s.track_mut(track).and_then(|t| t.playlist_mut()) {
|
||||
let before = pl.clips.len();
|
||||
pl.clips.retain(|c| !ids.contains(&c.id));
|
||||
n += before - pl.clips.len();
|
||||
}
|
||||
}
|
||||
n
|
||||
|
||||
@@ -175,6 +175,24 @@ fn remove_clips_closes_each_gap_in_shuffle_only() {
|
||||
assert_eq!(split(true), vec![(1000, 1000, 2000), (2000, 1000, 4000)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_clips_in_shuffle_keeps_crossfade_partners_apart() {
|
||||
// `(start, end)` of each clip; the second one goes.
|
||||
let remove_second = |spans: &[(Samples, Samples)]| {
|
||||
let (mut s, t) = session_with_clip();
|
||||
let ids: Vec<ClipId> = spans.iter().map(|_| s.new_clip_id()).collect();
|
||||
if let Some(pl) = s.track_mut(t).and_then(|t| t.playlist_mut()) {
|
||||
pl.clips = ids.iter().zip(spans).map(|(id, (a, b))| Clip::audio(*id, "c", SourceId(500), *a, *a, b - a)).collect();
|
||||
}
|
||||
assert_eq!(remove_clips(&mut s, &[ids[1]], true), 1);
|
||||
clips(&s, t).into_iter().map(|(start, len, _)| (start, start + len)).collect::<Vec<_>>()
|
||||
};
|
||||
// Crossfaded with the clip before: the hole starts where that one ends.
|
||||
assert_eq!(remove_second(&[(0, 1050), (950, 2000), (2000, 3000)]), vec![(0, 1050), (1050, 2050)]);
|
||||
// Crossfaded with the clip after: the hole ends where that one starts.
|
||||
assert_eq!(remove_second(&[(0, 1000), (1000, 2050), (1950, 3000), (4000, 5000)]), vec![(0, 1000), (1000, 2050), (3050, 4050)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_paste_overwrites() {
|
||||
let (mut s, t) = session_with_clip();
|
||||
|
||||
Reference in New Issue
Block a user