name: sound-sid
description: >
Use this skill for all SID 6581 sound programming on the Commodore 64.
Covers all 29 SID registers, ADSR envelopes, waveforms, filters, frequency
calculation, sound effects, and music programming techniques.
Sources: COMPUTE!‘s Mapping the C64, The Anatomy of the C64.
SID 6581 Sound Programming
SID Chip Overview
The MOS 6581 Sound Interface Device (SID) is located at $D400–$D7FF (54272–55295).
Only addresses $D400–$D41C (29 registers) are actually used.
Features:
- 3 independent voices (oscillators), each fully programmable
- 4 waveforms per voice: triangle, sawtooth, pulse, noise
- ADSR (Attack/Decay/Sustain/Release) amplitude envelope per voice
- Oscillator synchronization and ring modulation between voices
- Programmable filter (high-pass, low-pass, band-pass) affecting any voices
- 16-step master volume
Important: Most SID registers are write-only. Only $D419–$D41C can be read.
SID Register Map
Voice 1 ($D400–$D406)
| Address |
Dec |
Name |
Description |
| $D400 |
54272 |
FRELO1 |
Voice 1 frequency low byte |
| $D401 |
54273 |
FREHI1 |
Voice 1 frequency high byte |
| $D402 |
54274 |
PWLO1 |
Voice 1 pulse width low byte |
| $D403 |
54275 |
PWHI1 |
Voice 1 pulse width high nybble (bits 3-0) |
| $D404 |
54276 |
VCREG1 |
Voice 1 control register |
| $D405 |
54277 |
ATDCY1 |
Voice 1 attack (bits 7-4) / decay (bits 3-0) |
| $D406 |
54278 |
SUREL1 |
Voice 1 sustain (bits 7-4) / release (bits 3-0) |
Voice 2 ($D407–$D40D)
| Address |
Dec |
Name |
Description |
| $D407 |
54279 |
FRELO2 |
Voice 2 frequency low byte |
| $D408 |
54280 |
FREHI2 |
Voice 2 frequency high byte |
| $D409 |
54281 |
PWLO2 |
Voice 2 pulse width low byte |
| $D40A |
54282 |
PWHI2 |
Voice 2 pulse width high nybble |
| $D40B |
54283 |
VCREG2 |
Voice 2 control register |
| $D40C |
54284 |
ATDCY2 |
Voice 2 attack / decay |
| $D40D |
54285 |
SUREL2 |
Voice 2 sustain / release |
Voice 3 ($D40E–$D414)
| Address |
Dec |
Name |
Description |
| $D40E |
54286 |
FRELO3 |
Voice 3 frequency low byte |
| $D40F |
54287 |
FREHI3 |
Voice 3 frequency high byte |
| $D410 |
54288 |
PWLO3 |
Voice 3 pulse width low byte |
| $D411 |
54289 |
PWHI3 |
Voice 3 pulse width high nybble |
| $D412 |
54290 |
VCREG3 |
Voice 3 control register |
| $D413 |
54291 |
ATDCY3 |
Voice 3 attack / decay |
| $D414 |
54292 |
SUREL3 |
Voice 3 sustain / release |
Filter and Master ($D415–$D41C)
| Address |
Dec |
Name |
Description |
| $D415 |
54293 |
SIGVOL |
Filter cutoff frequency low (bits 2-0) |
| $D416 |
54294 |
FRESHI |
Filter cutoff frequency high byte |
| $D417 |
54295 |
RESON |
Filter resonance (bits 7-4) / voice enable (bits 2-0) |
| $D418 |
54296 |
SIGVOL |
Volume (bits 3-0) / filter mode (bits 7-4) |
| $D419 |
54297 |
POTX |
Paddle X (read-only) |
| $D41A |
54298 |
POTY |
Paddle Y (read-only) |
| $D41B |
54299 |
RANDOM |
Voice 3 oscillator output (read-only, use for random numbers) |
| $D41C |
54300 |
ENV3 |
Voice 3 envelope output (read-only) |
Control Register ($D404 / $D40B / $D412)
Bit 7 NOISE — Noise waveform
Bit 6 PULSE — Pulse waveform
Bit 5 SAW — Sawtooth waveform
Bit 4 TRI — Triangle waveform
Bit 3 TEST — Test bit (disables oscillator, clears noise LFSR)
Bit 2 RING — Ring modulation (TRI waveform modulated by prev voice)
Bit 1 SYNC — Oscillator synchronization with prev voice
Bit 0 GATE — Gate: 1=start ADSR, 0=start Release
Only one waveform should be active at a time (combining may produce unusual results).
Ring modulation works with voice 1→2, 2→3, 3→1 pairing.
Sync: voice 1 syncs to voice 3, voice 2 to voice 1, voice 3 to voice 2.
Frequency Calculation
Register Value = (Frequency × 16777216) / Clock
NTSC Clock = 1,022,730 Hz
PAL Clock = 985,248 Hz
For NTSC: Register = Frequency / 0.0609594
For PAL: Register = Frequency / 0.0587721
Common Note Frequencies (NTSC)
| Note |
Freq (Hz) |
Register (hex) |
Register (dec) |
| C3 |
130.81 |
$086C |
2156 |
| D3 |
146.83 |
$0975 |
2421 |
| E3 |
164.81 |
$0A9B |
2715 |
| F3 |
174.61 |
$0B40 |
2880 |
| G3 |
196.00 |
$0C91 |
3217 |
| A3 |
220.00 |
$0E16 |
3606 |
| B3 |
246.94 |
$0F9C |
3996 |
| C4 |
261.63 |
$10D9 |
4313 |
| D4 |
293.66 |
$12EA |
4842 |
| E4 |
329.63 |
$1537 |
5431 |
| F4 |
349.23 |
$1680 |
5760 |
| G4 |
392.00 |
$1921 |
6433 |
| A4 (440Hz) |
440.00 |
$1CCC |
7372 |
| B4 |
493.88 |
$1F38 |
7992 |
| C5 |
523.25 |
$21B3 |
8627 |
ADSR Envelope
Attack/Decay Register Bits
Bits 7-4: Attack rate (0-15)
Bits 3-0: Decay rate (0-15)
Sustain/Release Register Bits
Bits 7-4: Sustain level (0=silent, 15=full volume)
Bits 3-0: Release rate (0-15)
ADSR Rate Table
| Value |
Attack Time |
Decay/Release Time |
| 0 |
2 ms |
6 ms |
| 1 |
8 ms |
24 ms |
| 2 |
16 ms |
48 ms |
| 3 |
24 ms |
72 ms |
| 4 |
38 ms |
114 ms |
| 5 |
56 ms |
168 ms |
| 6 |
68 ms |
204 ms |
| 7 |
80 ms |
240 ms |
| 8 |
100 ms |
300 ms |
| 9 |
250 ms |
750 ms |
| 10 |
500 ms |
1.5 s |
| 11 |
800 ms |
2.4 s |
| 12 |
1 s |
3 s |
| 13 |
3 s |
9 s |
| 14 |
5 s |
15 s |
| 15 |
8 s |
24 s |
Playing a Note (Complete Example)
10 REM SID SOUND EXAMPLE - A4 (440 Hz) on Voice 1, NTSC
20 POKE 54296, 15 : REM Volume = 15 (maximum)
30 POKE 54277, 9 : REM Attack=0, Decay=9 (250ms)
40 POKE 54278, 240 : REM Sustain=15 (full), Release=0
50 POKE 54272, 204 : REM Frequency low byte ($CC)
60 POKE 54273, 28 : REM Frequency high byte ($1C) → $1CCC
70 POKE 54276, 33 : REM Sawtooth wave + GATE=1 (%00100001)
80 FOR W=1 TO 500 : NEXT : REM Hold note
90 POKE 54276, 32 : REM Gate=0, start release (%00100000)
; Assembly version of the above
LDA #15
STA $D418 ; volume = 15
LDA #9
STA $D405 ; attack=0, decay=9
LDA #$F0
STA $D406 ; sustain=15, release=0
LDA #$CC
STA $D400 ; freq low
LDA #$1C
STA $D401 ; freq high
LDA #%00100001 ; sawtooth + gate
STA $D404
; ... wait ...
LDA #%00100000 ; sawtooth, gate off (release)
STA $D404
RTS
Waveform Selection Guide
| Waveform |
Bit |
Character |
Good for |
| Triangle |
bit 4 ($10) |
Mellow, flute-like |
Lead melody, smooth tones |
| Sawtooth |
bit 5 ($20) |
Bright, rich harmonics |
Strings, brass, lead |
| Pulse |
bit 6 ($40) |
Variable timbre |
Woodwinds, organ; varies with pulse width |
| Noise |
bit 7 ($80) |
Random noise |
Drums, explosions, wind effects |
Pulse Width
- Controlled by $D402/$D403 (voice 1), etc.
- 12-bit value (0–4095), duty cycle = value/40.95 percent
- 0 = very thin pulse (faint sound)
- 2048 ($800) = 50% square wave (full, rich sound)
- 4095 = very thin pulse again (same as 0)
Filters ($D415–$D418)
Filter Cutoff Frequency ($D415–$D416)
- 11-bit value (low 3 bits in $D415 bits 0-2, high 8 bits in $D416)
- Frequency range: ~30 Hz to ~12 kHz
$D417 — Filter Resonance and Voice Routing
Bits 7-4: RESON — Resonance (0=low, 15=high peak at cutoff)
Bit 3: FILTEX — Filter voice from external input
Bit 2: FILT3 — Route voice 3 through filter
Bit 1: FILT2 — Route voice 2 through filter
Bit 0: FILT1 — Route voice 1 through filter
$D418 — Volume and Filter Mode
Bit 7: 3OFF — Voice 3 direct output OFF (disconnect voice 3 from output)
Bit 6: HP — High-pass filter on
Bit 5: BP — Band-pass filter on
Bit 4: LP — Low-pass filter on
Bits 3-0: VOL — Master volume (0-15)
Filter Example — Low-Pass Filter on Voice 1
POKE 54293, 0 : REM Filter cutoff low = 0
POKE 54294, 64 : REM Filter cutoff high = 64 (mid-range)
POKE 54295, 241 : REM Resonance=15, filter voice 1 (%11110001)
POKE 54296, 31 : REM Low-pass on, volume=15 (%00011111)
Practical Sound Effects
Explosion
POKE 54296,15 : REM Vol=15
POKE 54277,0 : REM Fast attack+decay
POKE 54278,0 : REM No sustain, fast release
POKE 54272,0 : REM Freq low=0
POKE 54273,0 : REM Freq high=0
POKE 54276,143 : REM Noise + gate (%10001111)
FOR T=1 TO 50:NEXT
POKE 54276,128 : REM Gate off (%10000000)
Laser Zap (descending frequency)
POKE 54296,15
POKE 54277,0 : POKE 54278,0
F=3000
FOR I=1 TO 50
POKE 54272, F AND 255
POKE 54273, INT(F/256)
POKE 54276, 33 : REM Sawtooth + gate
F=F-50
FOR W=1 TO 5:NEXT
NEXT I
POKE 54276,32
Using Voice 3 as a Random Number Source
R = PEEK(54299) ' RANDOM - read voice 3 oscillator for pseudo-random value
' First set voice 3 to noise with high frequency:
' POKE 54290,128+1 : POKE 54286,255 : POKE 54287,255 : POKE 54296,0
' (Note: $D418 bit7=1 disconnects voice 3 from audio output)
Silencing the SID
POKE 54296, 0 : REM Volume = 0 (immediate silence)
' Or for each voice:
POKE 54276, 0 : REM Voice 1: gate off, no waveform
POKE 54283, 0 : REM Voice 2: gate off, no waveform
POKE 54290, 0 : REM Voice 3: gate off, no waveform