collective

Browse / github.com/storytold/soundcraft / patch

Keep crossfade overlaps when pasting clips

Keep crossfade overlaps when pasting clips Found while testing `crates/engine/src/edit.rs:235-248 (paste, via place_clip at :252-258)` (no existing issue): Pasting a crossfaded clip pair destroys the crossfade overlap. ## Cause `paste` placed each clip with `place_clip`, which runs `clear_range` over that clip's range first. When the second clip of a crossfaded pair was placed, this split the first pasted clip at the second clip's start and deleted the overlapping tail. The first clip ended up shorter, and the split reset its fade-out to 0. ## Fix `paste` now builds every pasted clip first and hands them all to `put_clips`, the same

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #1137, open)
Base
60087e0f46032118bf309ed9ea161a9b4a872713
Size
+25 −1 in 2 files
Review
pending
Shared
2026-10-28
Id
81500ac9cc3aba2f5fc14d67

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/edit.rs crates/engine/src/edit/tests.rs

diff --git a/crates/engine/src/edit.rs b/crates/engine/src/edit.rs--- a/crates/engine/src/edit.rs+++ b/crates/engine/src/edit.rs@@ -238,13 +238,16 @@ pub fn paste(s: &mut Session, track: TrackId, at: Samples, clips: &[Clip], lengt         make_room(s, track, at, length)?;     }     let mut ids = Vec::new();+    let mut placed = Vec::new();     for c in clips {         let mut nc = c.clone();         nc.id = s.new_clip_id();         nc.start += at;         ids.push(nc.id);-        place_clip(s, track, nc);+        placed.push((track, nc));     }+    // Clear every destination first, so pasted clips that overlap (crossfades) keep each other.+    put_clips(s, placed);     Ok(ids) } diff --git a/crates/engine/src/edit/tests.rs b/crates/engine/src/edit/tests.rs--- a/crates/engine/src/edit/tests.rs+++ b/crates/engine/src/edit/tests.rs@@ -343,3 +343,24 @@ fn delete_fades_leaves_unrelated_overlaps_alone() {     let c = s.track(t).unwrap().clips();     assert_eq!((c[1].fade_in.len, c[2].fade_out.len, c[3].fade_in.len), (0, 100, 100)); }++#[test]+fn paste_keeps_crossfade_overlap() {+    let (mut s, t) = session_with_clip();+    let (a, b) = (s.new_clip_id(), s.new_clip_id());+    if let Some(pl) = s.track_mut(t).and_then(|t| t.playlist_mut()) {+        pl.clips.clear();+        let mut ca = Clip::audio(a, "a", SourceId(500), 0, 1000, 2000);+        ca.fade_out = Fade { len: 500, shape: FadeShape::Linear, curvature: 0.0 };+        let mut cb = Clip::audio(b, "b", SourceId(500), 0, 2500, 2500);+        cb.fade_in = Fade { len: 500, shape: FadeShape::Linear, curvature: 0.0 };+        pl.clips.push(ca);+        pl.clips.push(cb);+        pl.sort();+    }+    let copied = copy_range(&s, t, Range::new(0, 6000));+    paste(&mut s, t, 20_000, &copied, 6000, false).unwrap();+    let pasted: Vec<_> =+        s.track(t).unwrap().clips().iter().filter(|c| c.start >= 20_000).map(|c| (c.start, c.length, c.fade_out.len, c.fade_in.len)).collect();+    assert_eq!(pasted, vec![(21_000, 2000, 500, 0), (22_500, 2500, 0, 500)]);+}