Science-Based 100% Dragon MMO
README.md
dragon.audio
Procedural sound synthesis for the dragon. Every cue is generated in Luau and
baked as a .soundClip asset holding lossless PCM (codec = "pcm" in the
clip's ZAUD payload), so loops stay sample-exact.
Usage
local Audio = require("dragon.audio")
Audio.ensure() -- bake every missing cue; idempotent
local clip = Audio.clip("wingbeat")
entity(id).component.add("Audio", { clip = clip, pitch = flapForce })
Cues
| name | kind | rate | note |
|---|---|---|---|
wingbeat | one-shot | 22050 | leathery flap; pitch with flap force |
wind | loop | 22050 | rushing air; volume/pitch with airspeed |
buffet | loop | 22050 | 22 Hz stall rumble |
thermal | loop | 22050 | Shepard–Risset endless rise |
hiss | loop | 22050 | gas leak + wet gurgle |
click | one-shot | 44100 | igniter tick |
whoomph | one-shot | 22050 | gas ignition blast |
heartbeat | loop | 22050 | lub-dub; pitch with heart rate |
roar | one-shot | 22050 | formant-filtered harmonic bellow |
bellow | one-shot | 22050 | aurochs lowing call |
Loops (spec.loop on Audio.CLIPS) are seam-validated at bake: the wrap step
must not exceed any interior sample step. Set looping = true on the Audio
component when playing them.
API
Audio.ensure() -> { created, skipped, stats }— synthesize + bake every missing cue; safe to call repeatedly.Audio.clip(name) -> AssetRef?— resolve a cue's soundClip.Audio.exists(name) -> booleanAudio.names() -> { string }Audio.CLIPS : { ClipSpec }— name / loop / sampleRate per cue.