APU basics
This article covers basic usage of the APU's four waveform channels. It does not cover the DMC, or more advanced usage. Any registers unrelated to basic operation are not even mentioned here.
Channels
The APU has five channels: two square waves, triangle wave, noise, and DMC (sample playback). Only the first four are covered here.
The channel registers begin at $4000, and each channel has four registers devoted to it. All but the triangle wave have 4-bit volume control (the triangle just has an un-mute flag).
$4000-$4003 | First square |
$4004-$4007 | Second square |
$4008-$400B | Triangle |
$400C-$400F | Noise |
In register descriptions below, bits listed as - can have any value written to them, while bits listed as 1 must have a 1 written, otherwise other APU features will be enabled, causing the registers to behave differently than described here.
Register initialization
Before using the APU, first initialize all the registers to known values that silence all channels.
init_apu: lda #$0F sta $4015 ldy #0 @loop: lda @regs,y sta $4000,y iny cpy #$18 bne @loop rts @regs: .byte $30,$08,$00,$00 ; constant volume = 0, sweep = off .byte $30,$08,$00,$00 ; constant volume = 0, sweep = off .byte $80,$00,$00,$00 ; linear counter = 0 .byte $30,$00,$00,$00 ; constant volume = 0 .byte $00,$00,$00,$00 .byte $00,$0F,$00,$40
This writes values that are most useful for basic use of the channels. It's not important exactly what they do, just that they establish a known state.
Square wave channels
- Main article: APU Pulse
There are two square wave channels, each with pitch, volume, and timbre controls.
$4000 | $4004 | %DD11VVVV | Duty cycle and volume DD: 00=12.5% 01=25% 10=50% 11=75% |
$4002 | $4006 | %LLLLLLLL | Low 8 bits of raw period |
$4003 | $4007 | %-----HHH | High 3 bits of raw period |
To determine the raw period for a given frequency in Hz, use this formula:
- raw period = 111861/frequency - 1
The following code plays a 400 Hz square wave (50% duty) at maximum volume:
jsr init_apu lda #<279 sta $4002 lda #>279 sta $4003 lda #%10111111 sta $4000
All parameters can be changed while the tone is playing. Note that writing to $4003 and $4007 resets the phase, which causes a slight pop. This is an issue when doing vibrato, for example, and beyond the scope of this article.
Noise channel
- Main article: APU Noise
The noise channel allows control over frequency, volume, and timbre.
$400C | %--11VVVV | Volume VVVV: 0000=silence 1111=maximum |
$400E | %T---PPPP | Tone mode enable, Period |
The following code plays a tone-like noise at maximum volume:
jsr init_apu lda #%10000101 sta $400E lda #%00111111 sta $400C
All parameters can be changed while the noise is playing.
Triangle channel
- Main article: APU Triangle
The triangle channel allows control over frequency and muting.
$4008 | %1U------ | Un-mute |
$400A | %LLLLLLLL | Low 8 bits of raw period |
$400B | %-----HHH | High 3 bits of raw period |
To determine the raw period for a given frequency in Hz, use this formula:
- raw period = 55930/frequency - 1
The following code plays a 400 Hz triangle wave:
jsr init_apu lda #%11000000 sta $4008 lda #<139 sta $400A lda #>139 sta $400B
To silence the wave, write %10000000 to $4008. Note that writes to $4008 can take up to 1/240 second before affecting the triangle channel. Writing a raw period of 0 also silences the wave, but produces a pop, so it's not the preferred method.
The raw period can be changed while the channel is playing.