Files
zombie-fps/docs/MUSIC.md
T
enne2 956a15a525 Add industrial metal soundtrack with seamless loop
- assets/audio/music/zombie_industrial_loop.ogg: 57.60 s Ogg Vorbis loop
  generated locally with YuE2-3B on the Tesla V100 (score written for this
  track; vocals removed with HTDemucs). The loop is spliced at the track's
  structural repeat with a 0.6 s crossfade: measured seam dip <= 1.6 dB.
- scripts/main.gd: "Music" AudioStreamPlayer at -11 dB, started at boot on
  desktop and on the start click on Web (browser autoplay policy). It forces
  stream.loop at runtime because the Web staging step re-imports the OGG with
  loop=false.
- tools/test_music.gd: soundtrack test (loop, length, volume, playback,
  still playing after player death).
- docs/MUSIC.md: source, loop construction, verification, licence.
- docs/WEB-DEPLOY.md: release ab6054111f5919a8 notes.

Initial commit of the project.
2026-10-10 23:11:13 +02:00

3.2 KiB

Soundtrack — industrial metal loop

Endless survival loop played from the first frame, at -11 dB, independent of gameplay state.

Source

Generated locally (2026-10-10) with YuE2-3B Q8_0 through the audio.cpp CUDA build for the Tesla V100 (~/dev/audio.cpp, cmake -DCMAKE_CUDA_ARCHITECTURES=70), seed 31337, 16 steps, cot=melody + an external ABC score written for this track (K:Em Phrygian, Q:1/4=168, 96 bars; the model rendered it at a perceived 112.5 BPM). Style prompt: instrumental industrial metal, Nine Inch Nails meets the Quake 2 soundtrack, machine drums, palm-muted downtuned guitars, atonal synth stabs, no vocals.

--lyrics "[instrumental]" does not suppress singing (verified: male shouts 0:52-1:17 and 1:37-2:35). The instrumental was therefore obtained by HTDemucs vocal removal (--task sep --family htdemucs, input resampled to 44.1 kHz, RTF 0.049) and remixed as drums + bass + other.

Working files: ~/yue2-out/zombie-industrial/.

Loop construction

The track has a structural repeat (bars 24-30 ≈ 46-52, spectral similarity 0.95), so the loop splices at matching material instead of cutting arbitrarily:

  • region 51.37 s → 108.97 s of the instrumental master = 27 bars (bar = 2.1333 s, 112.5 BPM);
  • rotation by one tail segment plus a 0.60 s equal-power crossfade;
  • result: 57.60 s, seam dip ≤ 1.6 dB in 20 ms windows, sample step 0.04 (inaudible);
  • perceptual check on a 3 s + 3 s excerpt around the seam: no click, no level hole, natural continuation.

A longer variant (132 s) was rejected: its crossfade cancels (a -48 dB hole) because the two overlapped sections are out of phase.

Asset and import

assets/audio/music/zombie_industrial_loop.ogg — Ogg Vorbis q6, 48 kHz stereo, 1.0 MB, -14 LUFS / -1.0 dBTP. Import: loop=true, bpm=112.5, beat_count=108, bar_beats=4.

The Web staging step (tools/prepare_web.py) copies the asset but ignores *.import, and the staging import regenerates it with loop=false. main.gd therefore sets stream.loop = true at runtime: keep that line, it is what makes the browser build loop.

Runtime wiring

scripts/main.gd: _setup_music() creates the AudioStreamPlayer named Music (group music), _start_music() starts it once, _restart_music() restarts it if the loop flag is ever absent. On Web the start is deferred to the click that captures the mouse, because browsers only allow audio after a user gesture. Music keeps playing while the player is dead; R reloads the scene and the track restarts with it.

Verification

godot --headless --path . --script res://tools/test_music.gd
godot --display-driver headless --audio-driver PulseAudio --path . --script res://tools/test_music.gd
godot --headless --path . -- --smoke

Both runs PASS: node present, loop=true, length 57.60 s, volume -11 dB, playback advancing (confirmed on the real PulseAudio device, not only the Dummy driver), music still playing after player death. Grenade, wave, death and damage-feedback tests also pass unchanged.

License

YuE2-3B weights are CC BY-NC 4.0 (non-commercial): this track is for personal/experimental use. It is an AI-generated render, not a recording of a third-party work.