extends Node ## Separate effects from ambience so pellet sounds never restart the siren. ## Tune this to the end of the fourth wah in death_0.wav. const DEATH_INTRO_SECONDS := 1.35 var death_cutoff: Timer var effects: Array[AudioStreamPlayer] = [] var ambience: AudioStreamPlayer var streams := {} var background := "" var effect_cursor := 0 var death_tail := false var intro_pending := false func _ready() -> void: death_cutoff = Timer.new() death_cutoff.one_shot = true add_child(death_cutoff) death_cutoff.timeout.connect(_death_finished) for i in range(4): var voice := AudioStreamPlayer.new() voice.volume_db = -10.0 add_child(voice) effects.append(voice) ambience = AudioStreamPlayer.new() ambience.volume_db = -15.0 add_child(ambience) ambience.finished.connect(_ambient_finished) effects[3].finished.connect(_death_finished) func stream(name: String) -> AudioStream: if not streams.has(name): var path := "res://games/pacman/audio/%s.wav" % name if not ResourceLoader.exists(path): return null streams[name] = load(path) return streams[name] func play_effect(name: String) -> void: if name == "death": stop_all() death_tail = true effects[3].stream = stream("death_0") effects[3].play() death_cutoff.start(DEATH_INTRO_SECONDS) return var voice: AudioStreamPlayer = effects[0] if name.begins_with("eat_dot") else effects[1 + effect_cursor % 2] if not name.begins_with("eat_dot"): effect_cursor += 1 voice.stream = stream(name) if voice.stream != null: voice.play() func _death_finished() -> void: if not death_tail: return death_tail = false death_cutoff.stop() effects[3].stop() effects[3].stream = stream("death_1") effects[3].play() func set_background(name: String) -> void: if name == background: return background = name ambience.stop() intro_pending = false if name.is_empty(): return var intro := stream(name + "_firstloop") # Join PCM samples before playback: no finished-signal gap at the intro seam. ambience.stream = _loop_stream(name, intro) if ambience.stream != null: ambience.play() func _loop_stream(name: String, intro: AudioStream = null) -> AudioStream: var source := stream(name) if source is AudioStreamWAV: var loop: AudioStreamWAV = source.duplicate() loop.loop_mode = AudioStreamWAV.LOOP_FORWARD loop.loop_begin = 0 loop.loop_end = roundi(loop.get_length() * loop.mix_rate) if intro is AudioStreamWAV and intro.format == loop.format and intro.mix_rate == loop.mix_rate and intro.stereo == loop.stereo: var intro_frames := roundi(intro.get_length() * intro.mix_rate) loop.data = intro.data + loop.data loop.loop_begin = intro_frames loop.loop_end += intro_frames return loop return source func _ambient_finished() -> void: if background.is_empty(): return intro_pending = false ambience.stream = _loop_stream(background) if ambience.stream != null: ambience.play() func stop_all() -> void: background = "" death_tail = false intro_pending = false if death_cutoff != null: death_cutoff.stop() if ambience != null: ambience.stop() for voice in effects: voice.stop()