Commit graph spaceship/audio
Author SHA1 Message Date
Loïc Wisniewski
66b314f51a Expand and stage boss encounter 2026-09-03 22:00:26 +02:00
Loïc Wisniewski
eb1615ab6b Restore landing fade and missing event sounds 2026-08-31 18:15:37 +02:00
Loïc Wisniewski
46196a1adb tmp 2026-08-30 16:53:08 +02:00
Loïc Wisniewski
9cf032c203 #150, #151: the sounds were a toy and a puff, and both were fair
"Shot sounds sound like a toy" and "death sounds from ship are really
cheap", and there was no arguing with either. The shot was a bare
descending sine, which is the sound every toy ray gun has ever made. The
death was one band of filtered noise with a sine under it - thin, and over
before the eye had finished with the explosion.

The synthesis is rewritten rather than tuned, because the shape was the
problem:

  LAYERS, not a waveform. A bang is a crack, then a body, then a tail, and
  they have different lengths. One envelope over one source cannot be any
  of those things, so the explosions now run three clocks - the crack is
  done in a fifth of the length, the roar runs most of it, and sparse
  debris keeps falling afterwards so there is an aftermath rather than a
  stop.

  A SUB. Below about 80Hz is where "big" lives; without it an explosion is
  a hiss however loud you play it. Measured: 74% of a ship death's energy
  and 86% of a structure's now sits under 200Hz, against almost none
  before.

  SATURATION. Soft-clipping folds in harmonics, so a sound reads as loud
  rather than merely being loud - and stops peak normalisation flattening
  everything into the same quiet mush.

  DETUNED PARTIALS on the shot. Three of them at deliberately wrong ratios
  beat against each other and read as a mechanism; the single sine was the
  whole of the toy problem. A noise transient and a sub thump under it give
  it something to hit with.

Lengths went up with the weight: the ship death from 0.85s to 1.45s and the
structure from 1.6s to 2.3s, both audible to the end rather than gone in the
first third.
2026-08-29 14:39:33 +02:00
Loïc Wisniewski
b8038c1f94 #148: keep the theme's master in the repository
SPACE_4.wav is the source the shipped theme is made from, so it belongs
under version control - but not in the game.

It lives in audio/masters/ with an empty .gdignore beside it, which makes
Godot skip the folder outright: nothing in it is imported into res://, and
nothing in it is carried into an export. Left where it was, in the project
root, its 59MB would be imported and then packed into every Android and web
build for a file nothing opens - the game loads audio/space_4.mp3, the same
5m36s at 6.7MB.

Its .import file goes with it, since there is no longer anything to import,
and the test runner stops copying the folder for the same reason it already
skips android/ and builds/: 59MB copied on every single run, for a folder no
test can even see.

README.md next to it records which shipped file each master became and the
command that made it, so the pair cannot drift apart silently.
2026-08-29 13:54:37 +02:00
Loïc Wisniewski
940540d60c #146: shots, deaths and collapses are heard
Three events get a sound: a shot leaving a gun, a vessel dying, a structure
coming down.

The sounds are SYNTHESISED rather than downloaded - audio/make_sfx.py
generates all three from scratch, and is committed alongside them. The
ticket asked for free sources and the good ones are in its comments
(Kenney's CC0 packs, OpenGameArt's CC0 sets, Freesound filtered to CC0),
but a generated sound has no licence to track, no attribution to keep, and
no binary in the repository whose provenance nobody can check a year from
now. It also makes the sounds DATA: too sharp a shot is a number in that
file and a re-run, not a hunt through a library. Dropping in a pack file
later means replacing a .wav and nothing else.

A voice POOL, not a player, because these overlap constantly - a fleet
firing is several shots inside one shot's length. Twelve voices, and when
they are all busy the one furthest through its own sound is recycled, which
is the one with the least left to lose.

Parented to the tree root, for the reason that matters: every one of these
sounds is started by something that is being freed on the same frame. A
dying ship cannot own the sound of its own death.

Levels are per sound rather than shared - a shot fires constantly and a
death happens once, so equal volumes are not proportionate ones - and shots
get a little pitch spread so a stream of them does not flatten into one
machine-gun note. The deaths get none: a wobbling explosion sounds broken
rather than varied.

The test goes at the failures a play-through would hide for weeks: firing
three times the pool size must leave exactly the pool's worth sounding and
no leaked voices, and the ship-death case is checked from a node that really
has been freed on that frame.
2026-08-29 13:05:47 +02:00
Loïc Wisniewski
aabd5804cf #148: the main theme plays, and keeps playing
"All the time" is the whole of the requirement and it decides the shape.
The theme has to survive the main menu becoming the game, the game becoming
a planet surface, and the surface becoming the game again - so the player
cannot live in any of those scenes, because change_scene_to_file() frees
whichever one is current.

It is parented to the tree root instead, beside the GameState autoload,
which is the same trick for the same reason. Music.ensure() is idempotent by
node name, so each scene asks for the music on the way up and gets the one
already playing rather than a second copy over the top of it. Two call
sites cover everything: MainMenu, and GameController - which is the root
script of BOTH the space scene and the planet surface.

Done this way rather than as an autoload deliberately: project.godot carries
the developer's own uncommitted window settings, and adding music should not
drag those into a commit.

It is also PROCESS_MODE_ALWAYS. Since #128 a dialog stops the tree, and a
soundtrack that cuts out every time someone reads a line is worse than no
soundtrack.

The theme ships as MP3 rather than the 59MB WAV that was sitting in the
project root. Same 5m36s, 6.7MB, encoded with LAME at 160k - 89% smaller,
which is the difference between a repository that carries its music and one
that carries a WAV forever in its history. The original file is untouched
and still there, untracked, so nothing is lost.

The test checks CONTINUITY rather than "a sound started": the same player,
never a second one, through two scene changes and a dialog.
2026-08-29 13:05:21 +02:00