121 lines
4.0 KiB
GDScript
121 lines
4.0 KiB
GDScript
class_name Sfx
|
|
extends Node
|
|
## Kurze, zur Laufzeit erzeugte Töne (keine Audiodateien nötig).
|
|
|
|
var streams := {}
|
|
var players: Array[AudioStreamPlayer] = []
|
|
var volume := 0.8
|
|
var music_player: AudioStreamPlayer
|
|
var music_volume := 0.5
|
|
var music_task := -1 # die Musik wird im Hintergrund berechnet (spart ~150 ms beim Start)
|
|
var music_box := {}
|
|
|
|
|
|
func _ready() -> void:
|
|
streams["click"] = _tone(880, 0.05, "sine")
|
|
streams["play"] = _tone(440, 0.14, "sine", 660)
|
|
streams["attack"] = _tone(220, 0.16, "square", 90)
|
|
streams["damage"] = _tone(140, 0.12, "square")
|
|
streams["heal"] = _tone(523, 0.22, "sine", 784)
|
|
streams["combo"] = _tone(660, 0.2, "sine", 1100)
|
|
streams["win"] = _tone(400, 0.6, "sine", 1200)
|
|
streams["lose"] = _tone(320, 0.7, "square", 90)
|
|
for i in 4:
|
|
var p := AudioStreamPlayer.new()
|
|
add_child(p)
|
|
players.append(p)
|
|
music_player = AudioStreamPlayer.new()
|
|
add_child(music_player)
|
|
var box := music_box
|
|
music_task = WorkerThreadPool.add_task(func(): box["wav"] = _music())
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
|
if music_task >= 0 and WorkerThreadPool.is_task_completed(music_task):
|
|
WorkerThreadPool.wait_for_task_completion(music_task)
|
|
music_task = -1
|
|
music_player.stream = music_box.wav
|
|
set_music_volume(music_volume)
|
|
|
|
|
|
func _exit_tree() -> void:
|
|
if music_task >= 0:
|
|
WorkerThreadPool.wait_for_task_completion(music_task)
|
|
music_task = -1
|
|
|
|
|
|
## Leise Hintergrundmusik: Arpeggio über vier Akkorde, als Schleife erzeugt.
|
|
func _music() -> AudioStreamWAV:
|
|
var rate := 22050
|
|
var chords := [[220.0, 261.63, 329.63], [174.61, 220.0, 261.63], [130.81, 164.81, 196.0], [196.0, 246.94, 293.66]]
|
|
var note_len := 0.25
|
|
var pattern := [0, 1, 2, 1, 0, 2, 1, 2]
|
|
var total := chords.size() * pattern.size() * note_len
|
|
var n := int(total * rate)
|
|
var data := PackedByteArray()
|
|
data.resize(n * 2)
|
|
for i in n:
|
|
var t := float(i) / rate
|
|
var step := int(t / note_len)
|
|
var chord: Array = chords[(step / pattern.size()) % chords.size()]
|
|
var f: float = chord[pattern[step % pattern.size()]]
|
|
var lt := t - step * note_len
|
|
var env := minf(1.0, lt * 30.0) * maxf(0.0, 1.0 - lt / note_len)
|
|
var v := sin(TAU * f * t) * 0.6 + sin(TAU * f * 2.0 * t) * 0.15 + sin(TAU * chord[0] * 0.5 * t) * 0.25
|
|
data.encode_s16(i * 2, int(clampf(v * env * 0.25, -1.0, 1.0) * 32767))
|
|
var wav := AudioStreamWAV.new()
|
|
wav.format = AudioStreamWAV.FORMAT_16_BITS
|
|
wav.mix_rate = rate
|
|
wav.stereo = false
|
|
wav.data = data
|
|
wav.loop_mode = AudioStreamWAV.LOOP_FORWARD
|
|
wav.loop_begin = 0
|
|
wav.loop_end = n
|
|
return wav
|
|
|
|
|
|
func set_music_volume(v: float) -> void:
|
|
music_volume = clampf(v, 0.0, 1.0)
|
|
if music_volume <= 0.0:
|
|
music_player.stop()
|
|
else:
|
|
music_player.volume_db = linear_to_db(music_volume * 0.6)
|
|
if not music_player.playing and music_player.stream != null:
|
|
music_player.play()
|
|
|
|
|
|
func set_volume(v: float) -> void:
|
|
volume = clampf(v, 0.0, 1.0)
|
|
|
|
|
|
func play(kind: String) -> void:
|
|
if volume <= 0.0 or not streams.has(kind):
|
|
return
|
|
for p in players:
|
|
if not p.playing:
|
|
p.stream = streams[kind]
|
|
p.volume_db = linear_to_db(volume)
|
|
p.play()
|
|
return
|
|
|
|
|
|
func _tone(freq: float, dur: float, shape: String, freq_end: float = -1.0) -> AudioStreamWAV:
|
|
var rate := 22050
|
|
var n := int(dur * rate)
|
|
var data := PackedByteArray()
|
|
data.resize(n * 2)
|
|
for i in n:
|
|
var t := float(i) / rate
|
|
var f := freq if freq_end < 0 else lerpf(freq, freq_end, t / dur)
|
|
var env := 1.0 - t / dur
|
|
var v := sin(TAU * f * t)
|
|
if shape == "square":
|
|
v = 1.0 if v >= 0 else -1.0
|
|
data.encode_s16(i * 2, int(clampf(v * env * 0.4, -1.0, 1.0) * 32767))
|
|
var wav := AudioStreamWAV.new()
|
|
wav.format = AudioStreamWAV.FORMAT_16_BITS
|
|
wav.mix_rate = rate
|
|
wav.stereo = false
|
|
wav.data = data
|
|
return wav
|