Skip to content
Game 0 Unit 17 of 18 1 hr learning time

The Machine Speaks Back

Unit 10 taught the machine to hear you. This one teaches it to answer. The NES has a sound chip — the APU — built into the same 2A03 as the CPU. Set up a pulse channel, switch it on, and it holds the note on its own while your code does nothing.

94% of Meet The Machine

Back in Unit 10 the machine learned to hear you, reading the joypad through a register. This unit is the answer: the machine speaking back. On the NES, the sound comes from the APU.

The APU (Audio Processing Unit) lives inside the same chip as the CPU — the 2A03 is a 6502 with a sound generator bolted on. It has five voices: two pulse channels, a triangle, a noise channel, and a sample player. You don't generate the waveform yourself; you set a channel's registers — volume, pitch, length — switch it on, and the APU produces the sound while the CPU is free.

This unit plays one steady tone on pulse channel 1. Its registers live from $4000, with the master switch for all channels at $4015.

What you'll hear by the end

NES · 2A03 APU · pulse channel 1
A pulse-wave tone — APU pulse channel 1 holding one note

A steady square-ish tone, held for as long as the machine runs. It's a pulse wave at 50% duty — the bright, hollow voice behind countless NES melodies. The waveform strip above is the real captured output.

A flat blue NES screen with nothing drawn on it.
There's nothing to see — the work is in the speakers. The blue is just a sign the program is running.

Set the registers, switch it on

; ============================================================================
; Meet the Machine (NES) - Unit 17: The Machine Speaks Back
;
; Unit 10 taught the machine to hear you. This one teaches it to answer. The NES
; has a sound chip - the APU - built into the same 2A03 as the CPU. You set a
; pulse channel's volume, pitch and length, switch it on, and it holds the note
; on its own while the CPU does nothing.
; ============================================================================

.segment "HEADER"
    .byte "NES", $1a
    .byte 2
    .byte 1
    .byte $00, $00

.segment "CODE"

reset:
    sei
    cld
    ldx #$40
    stx $4017               ; silence the frame-counter IRQ
    ldx #$ff
    txs
    inx
    stx $2000               ; rendering + NMI off while we set up
    stx $2001
    stx $4010
warm1:
    bit $2002
    bpl warm1
warm2:
    bit $2002
    bpl warm2

    ; --- backdrop colour: blue, so the screen shows it's running ---
    bit $2002
    lda #$3f
    sta $2006
    lda #$00
    sta $2006
    lda #$11                ; blue
    sta $2007

    ; --- clear the nametable to the blank tile (a flat screen) ---
    bit $2002
    lda #$20
    sta $2006
    lda #$00
    sta $2006
    ldx #0
    ldy #4                  ; 4 pages = 1024 bytes (960 tiles + attributes)
clear:
    lda #$00
    sta $2007
    inx
    bne clear
    dey
    bne clear

    ; ----------------------------------------------- YOUR CODE START
    ; --- play a tone on pulse channel 1 ---
    lda #$01
    sta $4015               ; switch pulse 1 on
    lda #$bf
    sta $4000               ; 50% duty, hold the note, constant volume 15
    lda #$00
    sta $4001               ; sweep off (leave the pitch alone)
    lda #$fd
    sta $4002               ; timer low byte  -> the pitch
    lda #$08
    sta $4003               ; timer high + length  -> the note starts
    ; ------------------------------------------------- YOUR CODE END

    ; --- turn the picture on so the blue backdrop shows ---
    bit $2002
    lda #$00
    sta $2006
    sta $2006
    sta $2005
    sta $2005
    lda #$0a
    sta $2001

forever:
    jmp forever

nmi:
    rti
irq:
    rti

.segment "VECTORS"
    .word nmi
    .word reset
    .word irq

.segment "CHARS"
    .res 8192, $00

The sound is one block of stores, after the usual reset and a blue backdrop:

lda #$01
sta $4015               ; switch pulse 1 on
lda #$bf
sta $4000               ; 50% duty, hold the note, constant volume 15
lda #$00
sta $4001               ; sweep off (leave the pitch alone)
lda #$fd
sta $4002               ; timer low byte  -> the pitch
lda #$08
sta $4003               ; timer high + length  -> the note starts

$4015 is the master enable — bit 0 switches pulse 1 on. $4000 packs several controls into one byte: the top bits choose the duty (the shape of the square), and the rest set a constant volume of 15 and tell the channel to hold its note instead of counting itself down. $4001 is the sweep unit, which can slide the pitch — we switch it off so the note stays put.

$4002 and $4003 set the pitch as an 11-bit timer, low byte then high. Writing $4003 is the trigger: it loads the note's length and restarts the channel, so the tone begins the instant that store lands. Because the channel is set to hold, it rings on while the CPU sits in forever. You set the registers and walked away; the APU does the rest.

Assemble and run

ca65 apu.asm -o apu.o && ld65 -C nes.cfg apu.o -o apu.nes

A steady pulse tone; a blank blue screen.

Try this: change the pitch

$4002/$4003 are the timer — a smaller number is a higher note (the timer counts down, so fewer counts means a faster wave). Lower the timer low byte toward $80 and the note rises; raise it and the note falls. The number is the pitch.

Try this: a different duty

The top two bits of $4000 set the duty cycle. Try $3f (duty 0 — a thin, nasal 12.5%), $7f (25%), or back to $bf (50%). Same channel, same pitch; a different duty gives the note a different colour. That choice is most of what makes one NES instrument sound unlike another.

If it doesn't work

  • Silence. Pulse 1 isn't enabled — $4015 needs bit 0 set ($01). And a sweep with the negate bit set can mute the channel even when it looks off; keep $4001 at $00.
  • A click, then nothing. The channel counted its length down to zero. Bit 5 of $4000 tells it to hold — set it (the $bf here does) so the note sustains.
  • A tone that drifts in pitch. The sweep unit is running. $4001 at $00 leaves the pitch alone.

What you've learnt

The APU is the NES's sound chip, inside the 2A03 itself. You set a pulse channel's duty and volume ($4000), its pitch ($4002/$4003), switch it on at $4015, and the write to $4003 starts the note. Told to hold, the channel rings on its own while the CPU is free. You set the registers; the chip plays.

What's next

That's the last of what the machine can do — its screen, its colour, its shapes, its input, and now its sound. One unit remains, and it isn't about a new instruction. Next — The Machine Trusts You — what it means to program a machine that does exactly what you wrote, even when you're wrong.