64 lines
2.5 KiB
GDScript
64 lines
2.5 KiB
GDScript
class_name MusicDirector
|
|||
|
|
extends Node
|
||
|
|
|
||
|
|
static var volume := 0.65
|
||
|
|
var layers: Array[AudioStreamPlayer] = []
|
||
|
|
var state := ""
|
||
|
|
var transition: Tween
|
||
|
|
var game: Node
|
||
|
|
var cue: AudioStreamPlayer
|
||
|
|
const ROOT := "res://assets/audio/assault/"
|
||
|
|
|
||
|
|
func _ready() -> void:
|
||
|
|
if DisplayServer.get_name() == "headless":
|
||
|
|
set_process(false)
|
||
|
|
return
|
||
|
|
if AudioServer.get_bus_index("Music") < 0:
|
||
|
|
AudioServer.add_bus()
|
||
|
|
AudioServer.set_bus_name(AudioServer.bus_count-1,"Music")
|
||
|
|
for instrument in ["Synth","Strings","Percussion","Guitar"]:
|
||
|
|
var path := ROOT+"Stems/Incoming/MUS_Combat_Incoming_Loop_%s_100BPM.wav" % instrument
|
||
|
|
if not ResourceLoader.exists(path): continue
|
||
|
|
var stream := load(path).duplicate() as AudioStreamWAV
|
||
|
|
stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
|
||
|
|
stream.loop_begin = 0
|
||
|
|
stream.loop_end = int(round(stream.get_length()*stream.mix_rate))
|
||
|
|
var player := AudioStreamPlayer.new()
|
||
|
|
player.stream = stream
|
||
|
|
player.bus = "Music"
|
||
|
|
player.volume_db = -60
|
||
|
|
add_child(player)
|
||
|
|
layers.append(player)
|
||
|
|
# All stems use the same audio mix boundary and keep playing through UI changes.
|
||
|
|
for player in layers: player.play()
|
||
|
|
cue = AudioStreamPlayer.new()
|
||
|
|
cue.bus = "Music"
|
||
|
|
cue.volume_db = -20
|
||
|
|
add_child(cue)
|
||
|
|
|
||
|
|
func _process(_delta: float) -> void:
|
||
|
|
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Music"),linear_to_db(maxf(volume,0.0001)))
|
||
|
|
AudioServer.set_bus_mute(AudioServer.get_bus_index("Music"),volume <= 0)
|
||
|
|
var next := "menu"
|
||
|
|
if is_instance_valid(game):
|
||
|
|
if game.match_over: next = "results"
|
||
|
|
elif game.active: next = "pause" if game.paused else "combat"
|
||
|
|
elif game.connecting: next = "lobby"
|
||
|
|
if next == state: return
|
||
|
|
var previous := state
|
||
|
|
state = next
|
||
|
|
if state == "combat" and previous != "pause":
|
||
|
|
play_cue("Loops/Combat_Incoming_Modular/MUS_Combat_Incoming_Intro_Transition_100BPM.wav")
|
||
|
|
elif state == "results":
|
||
|
|
var ending := "01" if not is_instance_valid(game) or game.winner != "DRAW" else "02"
|
||
|
|
play_cue("Loops/Combat_Incoming_Modular/MUS_Combat_Incoming_Outro_Resolve_%s_100BPM.wav" % ending)
|
||
|
|
if transition: transition.kill()
|
||
|
|
transition = create_tween().set_parallel(true)
|
||
|
|
var levels: Array = {"menu":[-16,-23,-60,-60],"lobby":[-16,-20,-28,-60],"combat":[-23,-23,-23,-26],"pause":[-25,-30,-60,-60],"results":[-19,-18,-60,-60]}[state]
|
||
|
|
for i in layers.size(): transition.tween_property(layers[i],"volume_db",float(levels[i]),1.5)
|
||
|
|
|
||
|
|
func play_cue(relative: String) -> void:
|
||
|
|
if cue and ResourceLoader.exists(ROOT+relative):
|
||
|
|
cue.stream = load(ROOT+relative)
|
||
|
|
cue.play()
|