mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-26 19:46:47 -06:00
It cut the new clip at MAX_RENDER_SAMPLES / channels without a word, after allocating up to 2 GiB for it. Refuse such a selection up front, as #326 does for other renders, before anything is generated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
2.8 KiB
Rust
58 lines
2.8 KiB
Rust
//! Renders longer than one offline buffer holds are refused, rather than cut short and kept.
|
|
|
|
use serde_json::{Value, json};
|
|
use soundcraft_audio_io::{AudioBuffer, FileFormat};
|
|
use soundcraft_dsp::offline::MAX_OFFLINE_SAMPLES;
|
|
use soundcraft_engine::Engine;
|
|
use soundcraft_mix::MAX_RENDER_SAMPLES;
|
|
use soundcraft_model::{ChannelFormat, Clip, ClipId, Session, TrackKind};
|
|
|
|
/// A stereo track "Talk" with one clip `frames` long. Its source is one second: the commands
|
|
/// refuse on the clip's length before they render anything.
|
|
fn long_clip(frames: usize) -> (Engine, ClipId) {
|
|
let mut s = Session::default();
|
|
let t = s.add_track(TrackKind::Audio, ChannelFormat::Stereo, Some("Talk"));
|
|
let buf = AudioBuffer { sample_rate: 48_000, channels: vec![vec![0.25; 48_000]; 2] };
|
|
let src = soundcraft_engine::io::add_source(&mut s, "talk", buf, None, FileFormat::Wav);
|
|
let id = s.new_clip_id();
|
|
soundcraft_engine::edit::place_clip(&mut s, t, Clip::audio(id, "Talk", src, 0, 0, frames as i64));
|
|
(Engine::new(s), id)
|
|
}
|
|
|
|
fn refused(e: &mut Engine, cmd: &str, params: &Value) {
|
|
let before = serde_json::to_value(e.session()).unwrap();
|
|
let err = e.execute(cmd, params).expect_err(cmd).to_string();
|
|
assert!(err.contains("is too long to"), "{cmd}: {err}");
|
|
assert_eq!(serde_json::to_value(e.session()).unwrap(), before, "{cmd} changed the session");
|
|
}
|
|
|
|
#[test]
|
|
fn clips_longer_than_one_render_are_refused() {
|
|
let (mut e, id) = long_clip(MAX_RENDER_SAMPLES / 2 + 1);
|
|
let dir = std::env::temp_dir().join(format!("soundcraft-long-renders-{}", std::process::id()));
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
refused(&mut e, "clip.gain_render", &json!({"clips": [id.0]}));
|
|
refused(&mut e, "clip.effects_render", &json!({"clips": [id.0]}));
|
|
refused(&mut e, "audiosuite.process", &json!({"process": "reverse", "clips": [id.0]}));
|
|
refused(&mut e, "track.commit", &json!({"tracks": ["Talk"]}));
|
|
refused(&mut e, "file.export_clips", &json!({"dir": dir.to_string_lossy(), "clips": [id.0]}));
|
|
assert!(!dir.exists(), "Export Clips started writing before it refused");
|
|
}
|
|
|
|
#[test]
|
|
fn audiosuite_refuses_results_longer_than_one_render() {
|
|
let (mut e, id) = long_clip(MAX_OFFLINE_SAMPLES / 4 + 1);
|
|
let fourfold = [("time_stretch", json!({"ratio": 4.0})), ("pitch_shift", json!({"semitones": 24.0})), ("varispeed", json!({"speed": 0.25}))];
|
|
for (process, params) in fourfold {
|
|
refused(&mut e, "audiosuite.process", &json!({"process": process, "params": params, "clips": [id.0]}));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn signal_generator_refuses_a_selection_longer_than_one_render() {
|
|
let (mut e, _) = long_clip(48_000);
|
|
let end = (MAX_RENDER_SAMPLES / 2 + 1) as i64;
|
|
e.execute("edit.select", &json!({"tracks": ["Talk"], "start": 0, "end": end})).unwrap();
|
|
refused(&mut e, "audiosuite.process", &json!({"process": "signal_generator"}));
|
|
}
|