Files
seeding-planets/common/audio_manager/scripts/audio_manager.gd

420 lines
14 KiB
GDScript

extends Node
class_name AudioManagerInstance
const MIN_VOLUME = -60.
const MAX_VOLUME = 24.
const DEFAULT_FADE_TIME : float = 5.0
const REGION_FIRST_PHASE = [
"RegionForestPhase1",
"RegionForestPhase2",
"RegionMinePhase1",
"RegionMinePhase2"
]
const REGION_LOOP_PHASE = [
"RegionForestLoop",
"RegionForestLoop",
"RegionMineLoop",
"RegionMineLoop"
]
@onready var settings : SettingsData = GameInfo.settings_data
var music_actions : Array[AudioAction]
var ambiance_actions : Array[AudioAction]
var playing_musics : Array[String] = []
var playing_ambiances : Array[String] = []
var default_volumes := {}
# ----------------- Partie Fonctionnelle ----------------
# Fonction s'exécutant à chaque changement de scène
func _on_change_scene(scene : Scene):
stop_all_ambiances()
match scene.scene_id:
"TITLE":
play_music_alone("Title", false, 1.0)
"INTRO":
stop_all_musics()
"REGION":
play_ambiance("Exterior", false)
var region_level = GameInfo.game_data.current_region_data.region_level
var first_phase = REGION_FIRST_PHASE[region_level % len(REGION_FIRST_PHASE)]
var loop_phase = REGION_LOOP_PHASE[region_level % len(REGION_LOOP_PHASE)]
print(first_phase)
play_music_alone(first_phase)
queue_music(loop_phase, first_phase)
"COCKPIT":
stop_all_musics()
play_ambiance_alone("Ship", true, 1.0)
"ASTRA":
stop_all_musics()
play_ambiance_alone("Astra", false)
"GARAGE":
stop_all_musics()
play_ambiance_alone("Astra", false)
"BOREA":
stop_all_musics()
play_ambiance_alone("Borea", false)
# Fonction s'exécutant à chaque début de timeline
func _on_timeline_started():
var timeline_name = Dialogic.current_timeline.resource_path.split("/")[-1].trim_suffix(".dtl")
change_ambiances_volume(-10)
match timeline_name:
"demeter_astra_failed":
play_ambiance("Demeter")
"demeter_ship_presentation":
play_ambiance("Demeter")
"demeter_intro":
play_ambiance("Demeter")
"demeter_introV2":
play_ambiance("Demeter")
"demeter_post_tutorial":
play_ambiance("Demeter")
"failure":
play_ambiance("Demeter")
# Fonction s'exécutant à chaque fin de timeline
func _on_timeline_ended():
stop_ambiance("Demeter")
if SceneManager.actual_scene:
change_ambiances_volume()
# Joue la musique définie par player_name, arrête toute les autres musiques immédiatement
# - player_name : Nom de la Node dans la scène Godot sous la node Musics à jouer
# - from_random_time : joue depuis un temps aléatoire (true) ou non (false)
# - fade_time : durée du fondu d'arrivée
func play_music_alone(
player_name : String = "",
from_random_time := false,
fade_time := DEFAULT_FADE_TIME
):
stop_all_musics()
play_music(player_name,from_random_time,fade_time)
# Joue la musique définie par player_name
# - player_name : Nom de la Node dans la scène Godot sous la node Musics à jouer
# - from_random_time : joue depuis un temps aléatoire (true) ou non (false)
# - fade_time : durée du fondu d'arrivée
func play_music(
player_name : String = "",
from_random_time := false,
fade_time := DEFAULT_FADE_TIME
):
music_actions.append(AudioLaunch.new(
player_name,
from_random_time,
fade_time
))
# Joue la musique définie par player_name juste après la fin de la musique after_player_name, stoppe cette dernière à ce moment
# - player_name : Nom de la Node dans la scène Godot sous la node Musics à jouer
# - after_player_name : Nom de la Node dans la scène Godot à attendre, puis à stopper
# - from_random_time : joue depuis un temps aléatoire (true) ou non (false)
# - fade_time : durée du fondu d'arrivée
func queue_music(
player_name : String,
after_player_name : String,
from_random_time := false,
fade_time := DEFAULT_FADE_TIME
):
var player : AudioStreamPlayer = get_player_from_node(after_player_name, %Musics)
if player:
await player.finished
music_actions.append(AudioStop.new(after_player_name))
music_actions.append(AudioLaunch.new(
player_name,
from_random_time,
fade_time
))
# Stoppe la musique définie par player_name
# - player_name : Nom de la Node dans la scène Godot sous la node Musics à jouer
# - fade_time : durée du fondu de départ
func stop_music(player_name : String, fade := DEFAULT_FADE_TIME):
music_actions.append(AudioStop.new(player_name, fade))
# Stoppe toutes les musiques
# - fade_time : durée du fondu de départ
func stop_all_musics(fade := DEFAULT_FADE_TIME):
music_actions.append(AudioStopAll.new(fade))
# Joue l'ambiance définie par player_name, arrête toute les autres musiques immédiatement
# - player_name : Nom de la Node dans la scène Godot sous la node Ambiances à jouer
# - from_random_time : joue depuis un temps aléatoire (true) ou non (false)
# - fade_time : durée du fondu d'arrivée
func play_ambiance_alone(
player_name : String = "",
from_random_time := false,
fade_time := DEFAULT_FADE_TIME
):
stop_all_ambiances()
play_ambiance(player_name,from_random_time,fade_time)
# Joue l'ambiance définie par player_name
# - player_name : Nom de la Node dans la scène Godot sous la node Ambiances à jouer
# - from_random_time : joue depuis un temps aléatoire (true) ou non (false)
# - fade_time : durée du fondu d'arrivée
func play_ambiance(
player_name : String = "",
from_random_time := false,
fade_time := DEFAULT_FADE_TIME
):
ambiance_actions.append(AudioLaunch.new(
player_name,
from_random_time,
fade_time
))
# Stoppe l'ambiance définie par player_name
# - player_name : Nom de la Node dans la scène Godot sous la node Ambiances à jouer
# - fade_time : durée du fondu de départ
func stop_ambiance(player_name : String, fade := DEFAULT_FADE_TIME):
ambiance_actions.append(AudioStop.new(player_name, fade))
# Stoppe toutes les ambiances
# - fade_time : durée du fondu de départ
func stop_all_ambiances(fade := DEFAULT_FADE_TIME):
ambiance_actions.append(AudioStopAll.new(fade))
# Change le volume de toutes les ambiances qui jouent
# - db_change : changement du volume en décibel, mettre à 0 pour reset le volume
# - fade_time : durée du fondu de départ
func change_ambiances_volume(db_change := 0., fade := DEFAULT_FADE_TIME):
ambiance_actions.append(
AudioChangeVolumeAll.new(
db_change,
fade
)
)
# Joue un
# - player_name : Nom de la Node dans la scène Godot à jouer
func play_sfx(sfx_name : String):
var player := %Sfx.find_child(sfx_name) as AudioStreamPlayer
if player:
player.play()
else:
printerr("Sfx %s not found" % sfx_name)
# ----------------- Partie Technique (pas touche Niels ;D) ----------------
func _ready():
for player in get_all_players():
player.stop()
fetch_default_volumes()
# setup_players_bus()
settings.sound_changed.connect(
func(_s) : setup_players_bus()
)
SceneManager.scene_loaded.connect(_on_change_scene)
Dialogic.timeline_started.connect(_on_timeline_started)
Dialogic.timeline_ended.connect(_on_timeline_ended)
func _process(_d):
if len(music_actions) > 0:
playing_musics = process_audio_actions_for_node(music_actions, %Musics, playing_musics)
music_actions = []
if len(ambiance_actions) > 0:
playing_ambiances = process_audio_actions_for_node(ambiance_actions, %Ambiances, playing_ambiances)
ambiance_actions = []
func process_audio_actions_for_node(
audio_actions : Array[AudioAction],
parent_node : Node,
current_players: Array[String]
):
var players : Array[String] = current_players.duplicate()
for audio_action in audio_actions:
players = audio_action.process(
self,
parent_node,
players
)
return players
func get_player_from_node(player_name : String, parent_node : Node) -> AudioStreamPlayer:
var player = parent_node.find_child(player_name)
if not player:
printerr("Player %s not found in category %s" % [player_name, parent_node.name])
return null
return player
func fetch_default_volumes():
var all_players := get_all_players()
for player in all_players:
default_volumes[player] = player.volume_db
func setup_players_bus():
for player in get_all_players():
if player.get_parent() == %Musics:
player.bus = (AudioServer.get_bus_name(SettingsData.MUSIC_BUS_ID))
elif player.get_parent() == %Sfx:
player.bus = (AudioServer.get_bus_name(SettingsData.SFX_BUS_ID))
elif player.get_parent() == %Ambiances:
player.bus = (AudioServer.get_bus_name(SettingsData.AMBIANCE_BUS_ID))
func get_volume(player : AudioStreamPlayer) -> float:
return default_volumes[player]
func get_all_players() -> Array[AudioStreamPlayer]:
var players : Array[AudioStreamPlayer] = []
players.append_array(get_players_from_node(%Musics))
players.append_array(get_players_from_node(%Ambiances))
players.append_array(get_players_from_node(%Sfx))
return players
static func get_players_from_node(node : Node) -> Array[AudioStreamPlayer]:
var streams : Array[AudioStreamPlayer] = []
for c in node.get_children():
if c is AudioStreamPlayer:
streams.append(c)
return streams
func set_volume(player : AudioStreamPlayer, to : float, fade_time = DEFAULT_FADE_TIME) -> Tween:
var fade_tween : Tween = get_tree().create_tween()
fade_tween.tween_property(player, "volume_db", to, fade_time)
return fade_tween
func start_player(player: AudioStreamPlayer, from_random_time = false, fade_time = DEFAULT_FADE_TIME):
if player and not player.playing:
player.play(
0.0 if not from_random_time
else randf_range(0.0, player.stream.get_length())
)
if fade_time > 0.0:
player.volume_db = MIN_VOLUME
await set_volume(player, get_volume(player), fade_time).finished
func stop_player(player : AudioStreamPlayer, fade_time = DEFAULT_FADE_TIME):
if player and player.playing:
if fade_time > 0.0:
await set_volume(player, MIN_VOLUME, fade_time).finished
player.stop()
player.volume_db = get_volume(player)
func reset_volume(player : AudioStreamPlayer):
player.volume_db = get_volume(player)
@abstract class AudioAction:
@abstract func process(
manager: AudioManagerInstance,
parent_node : Node,
current_players : Array[String]
) -> Array[String]
class AudioLaunch extends AudioAction:
var player_name : String
var from_random_time : bool
var fade_time : float
var alone : bool
func _init(
_player_name : String,
_from_random_time := false,
_fade_time := DEFAULT_FADE_TIME,
_alone := true,
):
player_name = _player_name
from_random_time = _from_random_time
fade_time = _fade_time
func process(
manager: AudioManagerInstance,
parent_node : Node,
current_players : Array[String]
) -> Array[String]:
print("%s Launching %s" % [parent_node.name, player_name])
var player = manager.get_player_from_node(player_name,parent_node)
if player and not player in current_players:
manager.start_player(player, from_random_time, fade_time)
current_players.append(player_name)
return current_players
class AudioStop extends AudioAction:
var player_name : String
var fade_time : float
func _init(
_player_name : String,
_fade_time := DEFAULT_FADE_TIME,
):
player_name = _player_name
fade_time = fade_time
func process(
manager: AudioManagerInstance,
parent_node : Node,
current_players : Array[String]
) -> Array[String]:
print("%s Stopping %s" % [parent_node.name, player_name])
var player = manager.get_player_from_node(player_name,parent_node)
if player and player in current_players:
manager.stop_player(player, fade_time)
current_players.erase(player_name)
return current_players
class AudioStopAll extends AudioAction:
var fade_time : float
func _init(
_fade_time := DEFAULT_FADE_TIME,
):
fade_time = fade_time
func process(
manager: AudioManagerInstance,
parent_node : Node,
current_players : Array[String]
) -> Array[String]:
print("%s Stopping All" % parent_node.name)
for player_name in current_players:
var player := manager.get_player_from_node(player_name,parent_node)
if player:
manager.stop_player(player, fade_time)
return []
class AudioChangeVolumeAll extends AudioAction:
var db_change : float
var fade_time : float
func _init(
_db_change := 1.0,
_fade_time := DEFAULT_FADE_TIME,
):
db_change = _db_change
fade_time = fade_time
func process(
manager: AudioManagerInstance,
parent_node : Node,
current_players : Array[String]
) -> Array[String]:
print("%d Change volume all" % parent_node.name)
for player_name in current_players:
var player := manager.get_player_from_node(player_name,parent_node)
if player:
manager.set_volume(
player,
manager.get_volume(player) + db_change,
fade_time
)
return current_players