Skip to content

Trigger a sound on Atari 5200

Reuse a small real effect, understand who stops it, and compare its native output with an omitted-trigger control.

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

sound.inc
; 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:
    rts

POKEY 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

no-sound.asm
; 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 address

The 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.

Atari 5200 native caller after accepted input.
Captured from the running caller in the configuration below.

Where setup, trigger and service belong

demo.asm
; 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 address

Compare 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.