A bang for the crash, which is this game's first sound

Noise through a low pass that the modulation envelope shuts as the level
falls, so the bright part is only at the front of it: a boom rather than
a hiss. Noise because every other waveform here has a pitch, and a
pitched bang is a note.

The instrument is built at startup the way the tiles are, and a crash
only says "this channel, this note". That is what the selector and value
registers are for - a patch is twenty odd writes and a note is two - and
it is the shape every sound after this one should take.

CHANNEL THREE. There are four, and effects count down from the top so
that music, if it ever arrives, can take nought and count up and the two
never have to negotiate. This is also the first program to drive the
sound device while also doing something else; the only other customer is
the patch editor, whose whole job is the device.

---- A byte of envelope is not seconds ----

It is squared and scaled to four of them, so the decay first written here
was 200 - which is two and a half seconds. Over the eight tenths of a
second the pieces are in the air that is not a bang fading, it is the
FRONT THIRD of one, and it both sounded and measured as a flat wash of
noise. Ninety is about half a second and it fades to silence with time to
spare.

Two checks, each seen to fail on its own break. The first is against
SILENCE - a landing in the same conditions makes no sound at all, so it
is measuring the crash and not the machine humming - and the second is
that it is louder in its first half than its second, which is the
difference the decay was getting wrong.
This commit is contained in:
Anachronaut
2026-09-04 12:35:29 -04:00
parent 0264b19a3d
commit 9ae59bfccb
13 changed files with 180 additions and 11 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -32,7 +32,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -108,7 +108,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -27,7 +27,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -13,7 +13,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 8243
Lander.sbx 8388
Pad.sbx 264
Crash.sbx 632
vars.script 50
+53
View File
@@ -2661,6 +2661,59 @@ EOT
&& result ok "and are gone before the verdict" "nothing left over the words" \
|| result no "and are gone before the verdict" "$AFTERBITS pixels still there"
# ---- And a bang to go with it ----
#
# The first sound this game makes, and the first time anything has driven the sound device
# while also doing something else - the only other customer is the patch editor, whose whole
# job is the device.
#
# A patch is twenty odd writes and a note is two, which is what the selector and value
# registers are for: the instrument is built at startup like the tiles are, and a crash only
# says "this channel, this note". Channel THREE, effects counting down from the top, so music
# can one day take nought and count up without the two having to negotiate.
#
# Checked against silence, which is the useful half: a landing in the same conditions makes no
# sound at all, so this is measuring the crash and not the machine humming.
timeout 60 "$EMU" --fast --cycles 3000000 --keyboard "$BUILD/fly.keys" \
--pad "$BUILD/none.pad" --sound "$BUILD/bang.raw" \
--disk "$BUILD/crash.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/bang.out" 2>&1 || true
timeout 60 "$EMU" --fast --cycles 3000000 --keyboard "$BUILD/fly.keys" \
--pad "$BUILD/none.pad" --sound "$BUILD/hush.raw" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/hush.out" 2>&1 || true
read -r BANGPEAK BANGLOUD BANGFADE HUSHPEAK <<EOT
$(python3 -c "
import struct
def look(path):
raw = open(path, 'rb').read()
s = struct.unpack('<%dh' % (len(raw) // 2), raw)
if not s:
return 0, 0, 0
peak = max(abs(v) for v in s)
loud = sum(1 for v in s if abs(v) > 500)
# Louder at the front than at the back, which is what a bang is and a hiss is not.
half = len(s) // 2
front = max((abs(v) for v in s[:half]), default=0)
back = max((abs(v) for v in s[half:]), default=0)
return peak, loud, (1 if front > back else 0)
b = look('$BUILD/bang.raw')
print(b[0], b[1], b[2], look('$BUILD/hush.raw')[0])
" 2>/dev/null || echo "0 0 0 -1")
EOT
[ "$BANGPEAK" -gt 2000 ] && [ "$BANGLOUD" -gt 5000 ] && [ "$HUSHPEAK" = "0" ] \
&& result ok "a crash makes a noise, and a landing does not" "peak $BANGPEAK against silence" \
|| result no "a crash makes a noise, and a landing does not" "crash peak $BANGPEAK, landing peak $HUSHPEAK"
# ---- And it fades ----
#
# A byte of envelope is not seconds: it is squared and scaled to four of them, so the first
# decay written here was 200, which is two and a half - and over the eight tenths of a second
# the pieces are in the air that is not a bang fading, it is the FRONT THIRD of one. It read
# as a flat wash of noise and measured as one.
[ "$BANGFADE" = "1" ] \
&& result ok "and it is loudest at the front" "which is what makes it a bang" \
|| result no "and it is loudest at the front" "louder in the second half than the first"
# ---- Dust on landing, and gas on letting go ----
#
# The same six pieces as the explosion, thrown differently: dust goes sideways and UP off the