Sound Effects
Short BEEPs for firing and explosions — keeping durations minimal to avoid freezing the game loop.
A silent game feels lifeless. Blockstorm needs sound: a sharp tone when firing, a descending burst when enemies explode. But BEEP is blocking — while a BEEP plays, the entire program stops. Long sounds freeze the game loop. This unit adds sound effects and introduces the discipline of keeping BEEPs as short as possible.
The Program
5 REM === SOUND EFFECTS ===
10 BORDER 0: PAPER 0: INK 7: CLS
15 GO SUB 800
20 LET sc = 0: LET hi = 0: LET li = 3
22 LET wv = 1: LET ne = 8: LET sp = 4
25 DIM e(8): DIM r(8): DIM h(8)
30 FOR i = 1 TO ne
32 LET e(i) = (i - 1) * 2: LET r(i) = 0: LET h(i) = 1
34 NEXT i
36 LET fx = 6: LET fy = 2: LET fd = 1: LET tk = 0
40 LET px = 15: LET py = 20
42 LET ba = 0: LET bx = 0: LET by = 0
50 GO SUB 600
55 PRINT AT py, px; INK 7; CHR$ 152
57 GO SUB 400
60 REM === game loop ===
70 LET k$ = INKEY$
80 IF k$ = "o" OR k$ = "O" THEN IF px > 1 THEN PRINT AT py, px; " ": LET px = px - 1: PRINT AT py, px; INK 7; CHR$ 152
90 IF k$ = "p" OR k$ = "P" THEN IF px < 30 THEN PRINT AT py, px; " ": LET px = px + 1: PRINT AT py, px; INK 7; CHR$ 152
100 IF k$ = " " THEN IF ba = 0 THEN LET bx = px: LET by = py - 1: LET ba = 1: PRINT AT by, bx; INK 7; CHR$ 148: BEEP 0.01, 20
110 REM move bullet
115 IF ba = 0 THEN GO TO 170
120 PRINT AT by, bx; " "
130 LET by = by - 1
140 IF by < 1 THEN LET ba = 0: GO TO 170
150 LET ht = 0
155 FOR i = 1 TO ne
156 IF h(i) <= 0 THEN GO TO 158
157 IF bx = fx + e(i) AND by = fy + r(i) THEN LET ht = i: LET i = ne
158 NEXT i
160 IF ht > 0 THEN LET ba = 0: LET h(ht) = 0: PRINT AT fy + r(ht), fx + e(ht); INK 2; CHR$ 149: BEEP 0.02, -5: BEEP 0.02, -10: PAUSE 5: PRINT AT fy + r(ht), fx + e(ht); " ": LET sc = sc + 10: GO SUB 600: GO TO 170
165 PRINT AT by, bx; INK 7; CHR$ 148
170 REM move formation on tick
175 LET tk = tk + 1
180 IF tk < sp THEN GO TO 60
185 LET tk = 0
190 GO SUB 400
195 IF fy > 19 THEN GO TO 700
200 GO TO 60
400 REM === move formation ===
402 FOR i = 1 TO ne
404 IF h(i) <= 0 THEN GO TO 410
406 LET sx = fx + e(i): LET sy = fy + r(i)
408 IF sx >= 1 AND sx <= 30 AND sy >= 1 AND sy <= 21 THEN PRINT AT sy, sx; " "
410 NEXT i
412 LET fx = fx + fd
414 IF fx + 14 > 30 OR fx < 1 THEN LET fd = -fd: LET fy = fy + 1
416 FOR i = 1 TO ne
418 IF h(i) <= 0 THEN GO TO 425
420 LET sx = fx + e(i): LET sy = fy + r(i)
422 IF sx >= 1 AND sx <= 30 AND sy >= 1 AND sy <= 21 THEN PRINT AT sy, sx; INK 4; CHR$ 144
425 NEXT i
427 RETURN
600 REM === draw HUD ===
605 PRINT AT 0, 0; INK 7; BRIGHT 1; "SC:"; sc; " HI:"; hi; " LV:"; li; " W"; wv; " "
610 RETURN
700 REM === game over ===
705 CLS
710 PRINT AT 8, 10; INK 2; BRIGHT 1; "GAME OVER"
715 PRINT AT 10, 8; INK 7; "INVADED!"
720 PRINT AT 12, 7; INK 7; "Score: "; sc
730 PRINT AT 18, 6; INK 7; "Press any key"
735 PAUSE 0
800 REM === define UDGs ===
805 FOR i = 0 TO 13
810 FOR j = 0 TO 7
815 READ a
820 POKE USR CHR$ (65 + i) + j, a
825 NEXT j
830 NEXT i
835 RETURN
840 REM UDG A: drone
842 DATA 36, 126, 219, 255, 255, 102, 66, 0
844 REM UDG B: scout
846 DATA 24, 60, 126, 255, 219, 24, 36, 0
848 REM UDG C: tank
850 DATA 126, 255, 255, 255, 255, 255, 126, 0
852 REM UDG D: bomber
854 DATA 66, 231, 255, 126, 60, 90, 36, 0
856 REM UDG E: bullet
858 DATA 16, 56, 16, 16, 0, 0, 0, 0
860 REM UDG F: explosion
862 DATA 36, 153, 66, 129, 66, 153, 36, 0
864 REM UDG G: double shot
866 DATA 84, 170, 84, 170, 84, 170, 84, 0
868 REM UDG H: shield
870 DATA 60, 126, 255, 255, 255, 126, 60, 0
872 REM UDG I: player ship
874 DATA 16, 56, 56, 124, 254, 254, 130, 0
876 REM UDG J: enemy bomb
878 DATA 16, 16, 56, 16, 0, 0, 0, 0
880 REM UDG K: explosion 2
882 DATA 129, 66, 36, 0, 36, 66, 129, 0
884 REM UDG L: shield icon
886 DATA 60, 126, 126, 126, 60, 24, 0, 0
888 REM UDG M: drone frame 2
890 DATA 66, 102, 255, 255, 219, 126, 36, 0
892 REM UDG N: scout frame 2
894 DATA 36, 24, 219, 255, 126, 60, 24, 0
How It Works
Line 328 adds a fire sound: BEEP 0.01, 20. Duration 0.01 seconds (ten milliseconds), pitch 20 semitones above middle C. A short, sharp click that sounds like a laser firing. Ten milliseconds is barely audible as a tone — it registers as a percussive hit.
Lines 516 add explosion sounds: BEEP 0.02, -5: BEEP 0.02, -10. Two short tones descending in pitch. The first is five semitones below middle C, the second ten below. Together they create a quick downward sweep — the sound of something breaking apart. Total duration: 40 milliseconds.
BEEP Duration and Performance
BEEP takes two arguments: duration in seconds and pitch in semitones relative to middle C. The critical rule for real-time games is: keep the duration as short as possible.
During a BEEP, the Spectrum does nothing else. No input reading, no movement, no drawing. A BEEP 1, 0 would freeze the game for a full second. In a shooter where the loop runs 5-10 times per second, even a 0.1-second BEEP would be noticeable as a stutter.
The sounds in Blockstorm use durations of 0.01 to 0.02 seconds. At these lengths, the freeze is imperceptible. The sound effect registers but the game does not appear to pause.
Two BEEPs for One Sound
A single BEEP produces a single tone at a fixed pitch. By chaining two or three short BEEPs at different pitches, you create the illusion of a more complex sound. The explosion uses two descending tones. A power-up collection might use two ascending tones. A death sound might alternate high and low.
The total duration of chained BEEPs is the sum of their individual durations. Two BEEPs at 0.02 seconds each = 0.04 seconds total freeze time. Keep the total under 0.1 seconds and the game will not stutter.
Choosing Pitches
| Pitch | Semitones | Character |
|---|---|---|
| High positive (15-30) | Sharp, bright | Firing, collecting |
| Near zero (0-5) | Neutral, flat | UI confirmation |
| Negative (-5 to -15) | Low, heavy | Explosions, damage |
The second argument to BEEP is semitones relative to middle C. Positive values go up, negative values go down. The Spectrum can produce pitches from -60 to about 70 semitones, but extremes sound thin or buzzy. The sweet spot is -20 to +30.
Try This
Remove the sounds. Comment out the BEEP lines and play the game. Does it feel different without audio feedback? Sound cues confirm actions and give the player confidence that their input was registered.
Design a wave-clear fanfare. Three ascending BEEPs: BEEP 0.1, 12: BEEP 0.1, 16: BEEP 0.2, 19. This is longer than combat sounds (0.4 seconds total) but it plays during a pause between waves, not during gameplay. Longer sounds are acceptable when the game is not running.