"""Hop energy gate so neighboring C920s do not publish bleed.""" import numpy as np from audio_gate import HopGate, gate_enabled_for, rms_dbfs def _sine(n=1600, amp=8000): return (np.sin(2 * np.pi * 440 * np.arange(n) / 16000) * amp).astype(np.int16) def test_rms_dbfs_silence_is_floor(): assert rms_dbfs(np.zeros(1600, dtype=np.int16)) <= -120.0 def test_rms_dbfs_sine_is_near_minus_15(): db = rms_dbfs(_sine()) assert -16.5 < db < -14.0 def test_gate_silences_quiet_hop(): g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3) quiet = (np.random.randn(1600) * 80).astype(np.int16) out = g.apply(quiet) assert int(np.max(np.abs(out))) == 0 assert g.open is False def test_gate_passes_loud_hop(): g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3) loud = _sine() out = g.apply(loud) assert int(np.max(np.abs(out))) > 1000 assert g.open is True def test_gate_hold_then_closes(): g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=2) g.apply(_sine()) quiet = np.zeros(1600, dtype=np.int16) assert int(np.max(np.abs(g.apply(quiet)))) == 0 or g.open is True g.apply(quiet) g.apply(quiet) assert g.open is False assert int(np.max(np.abs(g.apply(quiet)))) == 0 def test_gate_skips_rally(): assert gate_enabled_for("rally", "rally", True) is False assert gate_enabled_for("cam-07", "rally", True) is True assert gate_enabled_for("cam-07", "rally", False) is False def test_cleaner_gates_quiet_after_dsp(): from audio_cleanup import AudioCleaner c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1)) quiet = (np.random.randn(1600) * 80).astype(np.int16) out = c.process(quiet) assert out.shape == (1600,) assert int(np.max(np.abs(out))) == 0 loud = _sine(1600, 8000) out = c.process(loud) assert int(np.max(np.abs(out))) > 1000 def test_cleaner_gate_uses_raw_energy_not_dsp_makeup(): """Room floor ~-34 dBFS must stay closed even though DSP makeup is ~+3 dB.""" from audio_cleanup import AudioCleaner c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1)) # sine RMS -34 dBFS => amplitude ~924 floor = _sine(1600, 924) assert -35.5 < rms_dbfs(floor) < -32.5 out = c.process(floor) assert int(np.max(np.abs(out))) == 0