Merge branch 'gemini/gate-tests': noise gate edge-case unit tests

This commit is contained in:
2026-06-02 16:00:15 -04:00
+108
View File
@@ -227,4 +227,112 @@ mod tests {
let mut f = frame(0);
assert!(!g.process(&mut f, 0.05), "an unopened gate on silence must not transmit");
}
#[test]
fn frame_rms_known_values() {
assert_eq!(frame_rms(&[]), 0.0);
assert_eq!(frame_rms(&frame(0)), 0.0);
let f_high = frame(16384);
let rms_high = frame_rms(&f_high);
assert!((rms_high - 0.5).abs() < 1e-4, "rms_high was {}", rms_high);
let f_low = frame(3277);
let rms_low = frame_rms(&f_low);
assert!((rms_low - 0.1).abs() < 1e-3, "rms_low was {}", rms_low);
}
#[test]
fn empty_frame_transmit_follows_gate_state() {
let mut g = NoiseGate::new(SR);
// fresh gate (never opened)
assert!(!g.process(&mut [], 0.05));
// open it with loud signals
for _ in 0..3 {
let mut f = frame(10000);
assert!(g.process(&mut f, 0.05));
}
// now empty frame should transmit
assert!(g.process(&mut [], 0.05));
}
#[test]
fn disabled_parks_envelope_so_reenable_has_no_fade_in() {
let mut g = NoiseGate::new(SR);
let mut f1 = frame(5000);
assert!(g.process(&mut f1, 0.0)); // disabled
let mut f2 = frame(10000);
assert!(g.process(&mut f2, 0.05)); // enabled
assert!(f2[0].abs() > 9000, "expected first sample of enabled frame to have no fade-in, got {}", f2[0]);
}
#[test]
fn hold_keeps_open_through_window_then_releases_to_closed() {
let mut g = NoiseGate::new(SR);
// open it
for _ in 0..3 {
let mut f = frame(10000);
g.process(&mut f, 0.05);
}
let mut results = Vec::new();
for _ in 0..25 {
let mut f = frame(0);
results.push(g.process(&mut f, 0.05));
}
assert!(results[4], "should still transmit at the 5th silent frame");
assert!(!results[19], "should not transmit at the 20th silent frame");
}
#[test]
fn sustained_mid_level_refreshes_hold_and_stays_open() {
let mut g = NoiseGate::new(SR);
// open it loud
for _ in 0..3 {
let mut f = frame(10000);
g.process(&mut f, 0.05);
}
// feed 30x frame(1310) (rms ~0.04, between close 0.03 and open 0.05)
for _ in 0..30 {
let mut f = frame(1310);
assert!(g.process(&mut f, 0.05));
}
assert!(g.open, "gate must stay open (hold refreshed by mid-level input)");
}
#[test]
fn loud_signal_reopens_a_releasing_gate() {
let mut g = NoiseGate::new(SR);
// open it
for _ in 0..3 {
let mut f = frame(10000);
g.process(&mut f, 0.05);
}
// feed silent frames to fully close
let mut closed = false;
for _ in 0..40 {
let mut f = frame(0);
if !g.process(&mut f, 0.05) {
closed = true;
break;
}
}
assert!(closed);
// feed frame(10000) @ 0.05 a few times
let mut last_peak = 0;
for _ in 0..3 {
let mut f = frame(10000);
assert!(g.process(&mut f, 0.05));
last_peak = peak(&f);
}
assert!(g.open);
assert!(last_peak >= 9900, "peak of the 3rd reopened frame must be >= 9900, got {}", last_peak);
}
}