--- 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) ```basic 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) ``` ```asm ; 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 ```basic 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 ```basic 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) ```basic 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 ```basic 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 ```basic 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 ```