Implement NPC perception, returning trespassers, responder dispatch, wand screening, and accessibility polish
CI / headless-tests (push) Successful in 2m11s
CI / headless-tests (push) Successful in 2m11s
This commit is contained in:
1 parent
439e0a4281
commit
81b5d5ce5a
22 files changed
+879
-73
No files matched your search
@@ -0,0 +1,60 @@
|
||||
class_name AudioFeedback
|
||||
extends Node
|
||||
## Procedural audio feedback (PLAN.md: Polish and Accessibility). Generates
|
||||
## short tones for confirmation prompts, radio responses, and escalation
|
||||
## feedback without requiring audio assets. Headless-safe: in headless mode
|
||||
## the AudioServer is a dummy and playback is a no-op.
|
||||
|
||||
const SAMPLE_RATE := 22050.0
|
||||
|
||||
var _players: Array[AudioStreamPlayer] = []
|
||||
|
||||
func _ready() -> void:
|
||||
# Pre-create a few players so overlapping cues don't cut each other off.
|
||||
for i in 4:
|
||||
var player := AudioStreamPlayer.new()
|
||||
add_child(player)
|
||||
_players.append(player)
|
||||
|
||||
## Play a short confirmation beep (single high tone).
|
||||
func play_confirm() -> void:
|
||||
_play_tone(880.0, 0.12, 0.5)
|
||||
|
||||
## Play a radio-response cue (two quick tones).
|
||||
func play_radio_response() -> void:
|
||||
_play_tone(660.0, 0.10, 0.5)
|
||||
_play_tone(990.0, 0.10, 0.5, 0.12)
|
||||
|
||||
## Play an escalation warning cue (low descending tone).
|
||||
func play_escalation(level: int) -> void:
|
||||
var freq := 440.0 - float(level) * 40.0
|
||||
_play_tone(maxf(freq, 180.0), 0.18, 0.6)
|
||||
|
||||
## Play a denial/error cue (low buzz).
|
||||
func play_deny() -> void:
|
||||
_play_tone(220.0, 0.20, 0.5)
|
||||
|
||||
## Generate a sine-wave tone and play it on a free player.
|
||||
func _play_tone(freq: float, duration: float, volume: float, delay: float = 0.0) -> void:
|
||||
var player := _free_player()
|
||||
if player == null:
|
||||
return
|
||||
var stream := AudioStreamGenerator.new()
|
||||
stream.mix_rate = SAMPLE_RATE
|
||||
stream.buffer_length = duration + 0.05
|
||||
player.stream = stream
|
||||
player.volume_db = linear_to_db(volume)
|
||||
player.play()
|
||||
# Fill the generator buffer with a sine wave.
|
||||
var playback: AudioStreamGeneratorPlayback = player.get_stream_playback()
|
||||
var frames := int(SAMPLE_RATE * duration)
|
||||
for i in frames:
|
||||
var t := float(i) / SAMPLE_RATE
|
||||
var sample := sin(TAU * freq * t) * 0.6
|
||||
playback.push_frame(Vector2(sample, sample))
|
||||
|
||||
func _free_player() -> AudioStreamPlayer:
|
||||
for player in _players:
|
||||
if not player.playing:
|
||||
return player
|
||||
return _players[0]
|
||||
Reference in new issue
Block a user