Merge branch 'gemini/gate-tests': noise gate edge-case unit tests
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user