class_name AlarmPlayer extends AudioStreamPlayer var _last_severity := 0 var _repeat_timer := 0.0 func update_alerts(delta: float, alerts: Array[int]) -> void: var severity := 0 for alert in alerts: severity = maxi(severity, alert) _repeat_timer = maxf(0.0, _repeat_timer - delta) if severity > _last_severity: _play_alarm(severity) _repeat_timer = _repeat_delay(severity) elif severity >= SurvivalModel.AlertLevel.RETURN and _repeat_timer <= 0.0: _play_alarm(severity) _repeat_timer = _repeat_delay(severity) _last_severity = severity func reset() -> void: _last_severity = 0 _repeat_timer = 0.0 stop() func _repeat_delay(severity: int) -> float: match severity: SurvivalModel.AlertLevel.EMPTY: return 0.75 SurvivalModel.AlertLevel.CRITICAL: return 1.25 SurvivalModel.AlertLevel.RETURN: return 2.5 SurvivalModel.AlertLevel.CAUTION: return 5.0 _: return 999.0 func _play_alarm(severity: int) -> void: if severity <= SurvivalModel.AlertLevel.NORMAL: return var generator := AudioStreamGenerator.new() generator.mix_rate = 22050.0 generator.buffer_length = 0.45 stream = generator play() var playback := get_stream_playback() as AudioStreamGeneratorPlayback if playback == null: return var frequency := 520.0 + float(severity) * 110.0 var duration := 0.35 var frame_count := int(generator.mix_rate * duration) var pulse_count := 1 if severity == SurvivalModel.AlertLevel.CAUTION else 2 if severity >= SurvivalModel.AlertLevel.CRITICAL: pulse_count = 3 for frame_index in frame_count: var time := float(frame_index) / generator.mix_rate var phase_in_pulse := fmod(time * float(pulse_count), duration) / duration var gate := 1.0 if phase_in_pulse < 0.62 else 0.0 var envelope := minf(time * 30.0, 1.0) * minf((duration - time) * 30.0, 1.0) var sample := sin(TAU * frequency * time) * 0.16 * gate * envelope playback.push_frame(Vector2(sample, sample))