Sound Effects
Every action has audio feedback. Menu select, claim, error, victory, draw.
We already have two sounds: a rising tone when claiming cells, and a harsh buzz for invalid moves. But the game is missing audio feedback for other events — selecting menu options, game outcomes. This unit completes the audio experience.
The ZX Spectrum’s beeper is simple: one bit controls the speaker. But by toggling it at different rates, we can create distinct sounds for every game event.
Run It
pasmonext --sna inkwar.asm inkwar.sna

Select a menu option and hear the confirmation beep. Claim cells and hear the rising tone. Win and hear the victory fanfare.
Sound Design Philosophy
Each sound should be:
- Distinctive — Immediately identifiable
- Appropriate — Matches the emotional context
- Brief — Doesn’t interrupt gameplay
| Event | Sound Character | Purpose |
|---|---|---|
| Menu select | Quick high beep | Confirms input |
| Cell claim | Rising tone | Positive feedback |
| Invalid move | Low buzz | Negative feedback |
| Victory | Ascending fanfare | Celebration |
| Draw | Neutral two-tone | Neither win nor loss |
Menu Selection Sound
A quick, high-pitched beep confirms menu choices:
This code sample could not be loaded. The file may be missing or the path may be incorrect.
Short duration (15 cycles) and high pitch (delay of 20) creates a crisp “click” feeling. We add call sound_select at the start of each menu handler.
Victory Fanfare
When someone wins, we play three ascending notes — a triumphant scale:
This code sample could not be loaded. The file may be missing or the path may be incorrect.
The pitch decreases with each note (delay decreases = higher frequency). A brief pause between notes creates distinct tones rather than a continuous sweep.
Draw Sound
A draw gets a neutral sound — two identical tones:
This code sample could not be loaded. The file may be missing or the path may be incorrect.
Same pitch for both tones signals neither triumph nor defeat — just equilibrium.
Result Sound Dispatch
We need to play the right sound based on the game outcome:
play_result_sound:
; Compare scores
ld a, (p1_count)
ld b, a
ld a, (p2_count)
cp b
jr z, .prs_draw ; Equal = draw
; Someone won - play victory
call sound_victory
ret
.prs_draw:
call sound_draw
ret
We check if scores are equal (draw) or different (someone won). The victory sound plays regardless of which player won — both humans and AI get the same celebration.
Beeper Fundamentals
The Spectrum beeper works by toggling bit 4 of port $FE:
ld a, $10 ; Bit 4 = speaker
out (KEY_PORT), a ; Speaker on
; ... delay ...
xor a
out (KEY_PORT), a ; Speaker off
; ... delay ...
The delay duration determines the pitch:
- Short delay (20) = High pitch
- Long delay (80) = Low pitch
The number of cycles determines the duration:
- Few cycles (15) = Brief sound
- Many cycles (30) = Longer sound
Sound Placement
We added sound calls at key points:
- state_title:
call sound_selectbefore starting game - try_claim/.tc_valid: Already had
call sound_claim - try_claim/.tc_invalid: Already had
call sound_error - Game over:
call play_result_soundbefore showing results
The Complete Code
This code sample could not be loaded. The file may be missing or the path may be incorrect.
Try This: Turn Change Sound
Add a brief sound when the turn switches:
sound_turn:
ld b, 8
.st_loop:
; Quick descending chirp
; ... tone generation ...
djnz .st_loop
ret
Call it after switching players in try_claim.
Try This: AI Thinking Sound
Add a subtle sound while the AI “thinks”:
; Before AI makes move
ld b, 3
.think:
; Short quiet tick
push bc
; ... minimal beep ...
pop bc
djnz .think
This creates anticipation before the AI moves.
What You’ve Learnt
- Beeper programming — Toggling speaker bit for sound
- Pitch control — Delay duration determines frequency
- Sound design — Matching sounds to events
- Audio feedback — Every action acknowledged
What’s Next
In Unit 15, we’ll create a proper results screen with winner display and final scores.