fix(dsp): chorus and flanger tails follow their feedback (#242)

This commit is contained in:
Marco Arnulfo
2026-10-12 14:44:57 +02:00
parent df0c4790b7
commit 96ea49c7f6
2 changed files with 26 additions and 1 deletions
+9 -1
View File
@@ -316,7 +316,15 @@ impl Plugin for ModFx {
}
fn tail_samples(&self) -> usize {
ms_to_samples(200.0, self.sr) as usize
// Time for feedback to fall by 60 dB at the longest delay of the sweep, as for the delay
// above; never shorter than the 200 ms this used to report.
let longest = match self.kind {
ModKind::Chorus => self.p.v(2) + self.p.v(1) / 100.0 * 6.0,
ModKind::Flanger => self.p.v(2),
};
let fb = (self.p.v(3).abs() / 100.0).clamp(0.0, 0.99);
let repeats = if fb < 1e-3 { 1.0 } else { (-60.0 / (20.0 * fb.log10())).min(500.0) + 1.0 };
ms_to_samples((longest * repeats).max(200.0), self.sr) as usize
}
}
+17
View File
@@ -329,6 +329,23 @@ fn delay_repeats_at_time() {
assert!((pos as i64 - 4800).abs() <= 2, "echo at {pos}");
}
#[test]
fn modulation_tail_covers_feedback_echoes() {
for (id, delay, feedback) in [("chorus", 30.0, 90.0), ("flanger", 10.0, 95.0), ("flanger", 10.0, -95.0)] {
let mut p = prepared(id);
for (param, v) in [("delay", delay), ("feedback", feedback), ("depth", 0.0), ("mix", 100.0)] {
assert!(p.set_param(param, v));
}
p.reset();
let mut x = vec![0.0f32; 48_000 * 5];
x[0] = 0.5;
let out = run(p.as_mut(), &[x]);
let floor = peak(&out[0]) * 1e-3;
let last = out[0].iter().rposition(|v| v.abs() > floor).unwrap();
assert!(last < p.tail_samples(), "{id} feedback {feedback}: echo at {last}, tail {}", p.tail_samples());
}
}
#[test]
fn trim_and_invert() {
let mut p = prepared("invert");