Overview
Each of the SID's three voices needs configuration before playing. Set the frequency (pitch), waveform (tone character), and ADSR envelope (volume shape over time). This pattern shows how to initialise a voice for typical game audio.
Code
; =============================================================================
; SID VOICE SETUP - COMMODORE 64
; Configure SID voice with frequency, waveform, and ADSR
; Taught: Game 6 (SID Symphony), Unit 3
; CPU: ~60 cycles per voice | Memory: ~40 bytes
; =============================================================================
; SID register base
SID = $D400
; Voice 1 registers
SID_V1_FREQ_LO = $D400
SID_V1_FREQ_HI = $D401
SID_V1_PWLO = $D402 ; Pulse width low
SID_V1_PWHI = $D403 ; Pulse width high
SID_V1_CTRL = $D404 ; Control (waveform + gate)
SID_V1_AD = $D405 ; Attack/Decay
SID_V1_SR = $D406 ; Sustain/Release
; Voice 2 registers (add 7 to voice 1 addresses)
SID_V2_FREQ_LO = $D407
SID_V2_CTRL = $D40B
SID_V2_AD = $D40C
SID_V2_SR = $D40D
; Voice 3 registers (add 14 to voice 1 addresses)
SID_V3_FREQ_LO = $D40E
SID_V3_CTRL = $D412
SID_V3_AD = $D413
SID_V3_SR = $D414
SID_VOLUME = $D418 ; Master volume
; Waveform values (for control register)
WAVE_TRIANGLE = $11 ; Soft, mellow tone
WAVE_SAWTOOTH = $21 ; Bright, buzzy tone
WAVE_PULSE = $41 ; Hollow, reedy tone (needs pulse width)
WAVE_NOISE = $81 ; White noise (drums, explosions)
; Initialize SID for audio
init_sid:
; Clear all SID registers
ldx #$18
lda #0
- sta SID,x
dex
bpl -
; Set master volume (0-15)
lda #$0F ; Maximum volume
sta SID_VOLUME
; === Configure Voice 1 ===
; C5 on PAL: 523.25 Hz × 16777216 / 985248 = 8910 = $22CE
lda #$CE
sta SID_V1_FREQ_LO
lda #$22 ; Frequency high byte (C5 PAL)
sta SID_V1_FREQ_HI
lda #$08 ; Pulse width (50% duty cycle)
sta SID_V1_PWHI
; ADSR: Attack=0 (instant), Decay=9 (medium)
; Sustain=0, Release=0 (instant)
lda #$09
sta SID_V1_AD
lda #$00
sta SID_V1_SR
rts
; Play voice 1 (call init_sid first)
; The waveform constants above already include the gate bit, so writing one
; of them directly starts the note.
play_voice1:
lda #WAVE_SAWTOOTH ; Waveform + gate (gate bit already set)
sta SID_V1_CTRL
rts
; Stop voice 1
stop_voice1:
lda #WAVE_SAWTOOTH ; Keep waveform
and #$FE ; Clear gate bit (release note)
sta SID_V1_CTRL
rts
Trade-offs
| Aspect | Cost |
|---|---|
| CPU | ~60 cycles per voice setup |
| Memory | ~40 bytes |
| Limitation | Must clear SID before init on some hardware |
When to use: Any game with SID audio. Always initialise before playing.
When to avoid: Never - uninitialised SID gives unpredictable results.
ADSR Envelope
The ADSR envelope shapes how volume changes over time:
Volume
│ ╱╲
│ ╱ ╲___________
│ ╱ ╲
│ ╱ ╲
└──┴─────────────────────▶ Time
A D S R
A = Attack - Time to reach peak volume
D = Decay - Time to fall to sustain level
S = Sustain - Volume level while held
R = Release - Time to silence after release
AD register format: $AD where A=attack (0-15), D=decay (0-15)
SR register format: $SR where S=sustain (0-15), R=release (0-15)
Common ADSR Values
| Sound Type | AD | SR | Description |
|---|---|---|---|
| Pluck | $09 | $00 | Instant attack, medium decay, no sustain |
| Organ | $00 | $F0 | Instant attack, full sustain |
| Pad | $88 | $84 | Slow attack/release, medium sustain |
| Drum | $09 | $00 | Quick hit, no sustain |
Frequency Reference (PAL)
The 16-bit SID frequency value is FREQ = Hz × 16777216 / clock, with PAL clock = 985,248 Hz and NTSC clock = 1,022,727 Hz. Values double per octave:
| Note | Hz | PAL ($Hi $Lo) | NTSC ($Hi $Lo) |
|---|---|---|---|
| C3 | 130.81 | $08 $B3 | $08 $50 |
| C4 (middle C) | 261.63 | $11 $67 | $10 $A1 |
| C5 | 523.25 | $22 $CE | $20 $5C |
| C6 | 1046.5 | $45 $9C | $42 $1B |
For a complete chromatic scale, see the SID frequency tables in the VIC-II and SID vault entries.
Multi-voice setup
The SID has three independent voices. Setup is identical for each — the same code with different base addresses. The simplest way to handle all three is to parameterise on the voice's base register:
; Configure all three voices with the same envelope and waveform
init_all_voices:
ldx #0 ; Voice 0
jsr setup_voice
ldx #7 ; Voice 1 base offset
jsr setup_voice
ldx #14 ; Voice 2 base offset
jsr setup_voice
rts
; X = voice base offset (0, 7, or 14)
setup_voice:
lda #$09
sta SID_V1_AD,x ; AD register at base+5 (V1=$D405, V2=$D40C, V3=$D413)
lda #$00
sta SID_V1_SR,x ; SR register at base+6
rts
Voice 1 ($D400-$D406), Voice 2 ($D407-$D40D), and Voice 3 ($D40E-$D414) are evenly spaced at 7-byte intervals.
Related
Patterns: SID Note Trigger
Vault: Commodore 64