diff --git a/crates/engine/src/io.rs b/crates/engine/src/io.rs index 1d4864d0..56d3d211 100644 --- a/crates/engine/src/io.rs +++ b/crates/engine/src/io.rs @@ -1454,13 +1454,18 @@ fn add_recording_in( if s.track(tid).is_none() { continue; } - let resampled = buf.sample_rate != s.sample_rate.hz(); + let hz = s.sample_rate.hz(); + let resampled = buf.sample_rate != hz; + let mut buf = buf; + if resampled && buf.sample_rate > 0 { + buf.channels = soundcraft_dsp::offline::resample(&buf.channels, buf.sample_rate, hz); + buf.sample_rate = hz; + } let name = path.file_stem().and_then(OsStr::to_str).unwrap_or("Take"); - let src = add_source(s, name, buf, Some(&path.to_string_lossy()), FileFormat::Wav); - let Some(x) = s.sources.last_mut() else { continue }; - x.unsaved = resampled; - let len = i64::try_from(x.frames).unwrap_or(0); + let len = i64::try_from(buf.frames()).unwrap_or(0); let pass = pass.unwrap_or(len).max(1); + // Work out what each pass keeps first, so a take nothing is placed from isn't registered. + let mut kept_passes = Vec::new(); for offset in (0..len).step_by(usize::try_from(pass).unwrap_or(usize::MAX)).take(1_000) { let n = pass.min(len - offset); if offset > 0 && n < pass / 8 { @@ -1473,6 +1478,16 @@ fn add_recording_in( } None => (start, 0, n), }; + kept_passes.push((offset, clip_start, cut, clip_len)); + } + if kept_passes.is_empty() { + continue; + } + let src = add_source(s, name, buf, Some(&path.to_string_lossy()), FileFormat::Wav); + if let Some(x) = s.sources.last_mut() { + x.unsaved = resampled; + } + for (offset, clip_start, cut, clip_len) in kept_passes { if offset > 0 && let Some(t) = s.track_mut(tid) { @@ -1586,6 +1601,39 @@ mod record_tests { let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn a_punch_that_misses_the_take_leaves_the_session_alone() { + let dir = std::env::temp_dir().join(format!("soundcraft-punch-miss-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + let mut e = Engine::default(); + let vox = armed(&mut e, "Vox", "mono", "In 1"); + let take = dir.join("Audio Files/Take.wav"); + write_take(&take, 1_000); + let shared = add_source( + e.session_mut(), + "Take", + AudioBuffer { sample_rate: 48_000, channels: vec![vec![0.0; 100]] }, + Some(&take.to_string_lossy()), + FileFormat::Wav, + ); + let sources = e.session().sources.len(); + let pool = e.session().pool.len(); + let plan = Recording { + start: 1_000, + pass: None, + punch: Some(Range::new(5_000, 6_000)), + rate: 48_000, + takes: vec![Take { track: vox, path: take.clone(), channels: 1 }], + }; + let placed = place_recording(&mut e, &plan, vec![(vox, take)]); + assert!(placed.is_empty()); + assert_eq!(e.session().sources.len(), sources); + assert_eq!(e.session().pool.len(), pool); + assert!(e.session().sources.iter().any(|x| x.id == shared)); + assert!(e.session().pool.contains(shared)); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn a_take_shows_the_pass_under_way_within_the_punch_while_it_records() { assert_eq!(live_span(1_000, None, None, 0), None);