Give an accepted action a sound. The same caller changes its picture and triggers this effect; a second version performs the action with the trigger removed. Listen to both.
Working effect
Trigger omitted
Take the effect
The reusable effect
; POKEY channel1 at $E800; SKCTL enabled, AUDCTL conventional clocking.
trigger_sound:
lda #3
sta $e80f
lda #0
sta $e808
lda #100
sta $e800
lda #$af
sta $e801
lda #8
sta $1005
rts
service_sound:
lda $1005
beq sound_done
dec $1005
bne sound_done
lda #0
sta $e801
sound_done:
rtsPOKEY channel 1 at $E800/$E801, duration byte $1005. The trigger also sets global AUDCTL and SKCTL; it is not isolated from other POKEY users. A/flags change.
Include sound.inc once with the caller’s constants and duration byte. Initialise the duration byte to zero before the first service call. Call trigger_sound for an accepted action, then call service_sound exactly once per accepted display update. The eighth service call mutes the effect. Because the supplied caller services in the triggering iteration too, this is a count of service calls, not eight complete elapsed frame intervals. Triggering again restarts the duration; there is no queue.
The complete initialiser also mutes other channels. To reuse just this effect beside music, agree channel ownership and remove unrelated global setup only after providing a replacement. Device latches, power, routing and master volume may affect more than one voice.
Change it and recognise a mistake
Change the frequency/distortion values after deciding who owns global POKEY configuration. A cartridge must retain the BIOS entry contract.
The omitted-trigger control still accepts the action but fails the same audio guard as the working caller. Keyboard clicks or other machine output are not enough: the BASIC checks compare against a separate rejected-command recording.
Deliberately omitted sound trigger
; Capability caller: original input/frame service, explicit drawing and sound.
; atari-5200: untimed turns from a new fire press, with independent field work.
; Owns display/input and $1000-$1004; stack is page 1. IRQ disabled.
turns = $1000
previous = $1001
clock_ticks = $1002
current = $1004
* = $4000
start:
sei
cld
ldx #$ff
txs
lda #0
sta $d40e ; disable ANTIC NMI ownership from BIOS
sta $d400 ; display-list DMA off: background-only output
lda #0
sta turns
sta previous
sta clock_ticks
sta clock_ticks+1
jsr init_picture
main:
jsr wait_frame
inc clock_ticks
bne sample
inc clock_ticks+1
sample:
!source "../sample.inc"
lda previous
eor #$ff
and current
beq no_action
inc turns
nop
nop
nop
no_action:
lda current
sta previous
jsr draw_picture
jsr service_sound
jmp main
wait_frame:
lda $d40b ; VCOUNT bit 7 covers the tail of the NTSC field
bmi wait_frame
wait_new:
lda $d40b
bpl wait_new
rts
!source "../picture.inc"
!source "../sound.inc"
!fill $bffe-*, $ff
!word start ; genuine BIOS cartridge handover addressThe working implementation above repairs that omission. If an effect instead drones on, check the mute/service path and that its state is initialised. Servicing twice makes a counted effect shorter; servicing only after input can leave it running while the player waits. Those are lifecycle decisions to test when adapting it.
Run the caller
Build the complete caller with make -C atari-5200/patterns/assembly/input/read-action. Press fire once, keep it held, then release and press again. The piece moves on each new press and returns to its starting position after two; holding does not repeat the action. Load the cartridge produced by the Makefile in the named configuration; retain its reset/header setup.

Where setup, trigger and service belong
; Capability caller: original input/frame service, explicit drawing and sound.
; atari-5200: untimed turns from a new fire press, with independent field work.
; Owns display/input and $1000-$1004; stack is page 1. IRQ disabled.
turns = $1000
previous = $1001
clock_ticks = $1002
current = $1004
* = $4000
start:
sei
cld
ldx #$ff
txs
lda #0
sta $d40e ; disable ANTIC NMI ownership from BIOS
sta $d400 ; display-list DMA off: background-only output
lda #0
sta turns
sta previous
sta clock_ticks
sta clock_ticks+1
jsr init_picture
main:
jsr wait_frame
inc clock_ticks
bne sample
inc clock_ticks+1
sample:
!source "sample.inc"
lda previous
eor #$ff
and current
beq no_action
inc turns
jsr trigger_sound
no_action:
lda current
sta previous
jsr draw_picture
jsr service_sound
jmp main
wait_frame:
lda $d40b ; VCOUNT bit 7 covers the tail of the NTSC field
bmi wait_frame
wait_new:
lda $d40b
bpl wait_new
rts
!source "picture.inc"
!source "sound.inc"
!fill $bffe-*, $ff
!word start ; genuine BIOS cartridge handover addressCompare blocking, serviced and queued sound when choosing the next step.
Verification and sources
Target: NTSC 32 KiB cartridge, recorded BIOS handover. These callers were executed with released Emu198x 0.44.1; assembly uses Asm198x 0.0.71. The sample folder contains reproduction instructions and retained observations. The independent checker binds source, native captures and actual output; its rejection tests exercise wrong state, missing files and false audio claims.
This qualifies the named emulator/firmware path. Pitch accuracy, original hardware and other peripherals require their own observations.
Atari, 5200/GTIA hardware documentation: trigger inputs; POKEY data sheet: AUDF/AUDC/AUDCTL/SKCTL; ANTIC VCOUNT.