Skip to content

Filter Sweeps

Moving the SID's cutoff while a note plays

A filter sweep changes a filter's cutoff frequency while a note sounds, so the tone opens up or closes down. The C64's SID put a resonant analogue filter on the chip with an 11-bit cutoff a program could rewrite at any moment, and its data sheet recommended doing exactly that. The catch was the filter itself: it varied from chip to chip, and Martin Galway refused to use it.

A filter sweep moves a filter’s cutoff frequency while a note is playing. Sweep a low-pass filter downwards and a bright, buzzy note closes to a muffled thud; sweep it back up and the note opens out again. Add resonance and the cutoff point itself starts to sing, a whistling peak that slides through the sound.

On the Commodore 64 the effect came built into the sound chip. Bob Yannes’s SID carries a resonant analogue filter, and its cutoff is just a number in two registers that a program can rewrite whenever it likes. The data sheet tells programmers to do exactly that: the filter is “perhaps, the most important element in SID”, and “the best results are achieved by varying the Cutoff Frequency in real-time”. The same chip made the effect hard to trust. Yannes later admitted he had not had time to make the filter better, every batch of chips sounded a little different, and in 1986 Martin Galway told ZZAP!64 he would not use it at all.

Fast facts

  • What changes: the filter’s cutoff frequency, rewritten many times a second, usually once per frame.
  • On the SID: an 11-bit cutoff, 16 resonance settings, and low-pass, band-pass and high-pass outputs that can be mixed.
  • One filter per chip: all three voices share it, so only one sweep can run at a time.
  • The problem: the cutoff a given number produces varies from one 6581 to the next, and the later 8580 sounds different again.

How the SID’s filter works

Yannes described the design in 1996 as “a classic multi-mode (state variable) VCF”. A state-variable filter produces its low-pass, band-pass and high-pass outputs all at once, and in the SID, “analog switches selected which combination of outputs were sent to the final amplifier”. That is why the mode bits can be combined: low-pass and high-pass together give a notch, which cuts the frequencies at the cutoff and passes the rest. Low-pass and high-pass cut at 12 dB per octave, band-pass at 6 dB.

The filter only affects voices routed into it. A voice whose routing bit is clear goes straight to the output, untouched. A voice routed into the filter is heard only through whichever outputs are switched on: as the data sheet puts it, “at least one Filter output must be selected and at least one Voice must be routed through the Filter” for the filter to do anything.

Register Bits Purpose
$D415 (FC LO) 2–0 Cutoff, low 3 bits
$D416 (FC HI) 7–0 Cutoff, high 8 bits
$D417 (RES/FILT) 7–4 Resonance, 0–15
3 Route the external audio input through the filter
2 Route voice 3 through the filter
1 Route voice 2 through the filter
0 Route voice 1 through the filter
$D418 (MODE/VOL) 7 “3 OFF”: take voice 3 off the direct path to the output
6 High-pass output on
5 Band-pass output on
4 Low-pass output on
3–0 Master volume, 0–15

The cutoff is an 11-bit number, 0 to 2047, split awkwardly: its bottom three bits go in $D415 and the top eight in $D416. Yannes explained the odd split. The control voltage comes from “actually a 12-bit D/A, but the LSB had no audible affect so I disconnected it!” Many programs ignored the low register and wrote only $D416, which gives 256 steps across the range.

The “3 OFF” bit is meant for using voice 3 as a modulator: it removes voice 3 from the direct path to the output. It does not silence a voice 3 that is routed through the filter, so the data sheet pairs it with clearing voice 3’s routing bit.

A sweep in machine code

The SID does not sweep by itself; the program changes the cutoff, typically once per screen frame. This program, for the ACME assembler, plays a low sawtooth note on voice 1 through the low-pass filter at full resonance and sweeps the cutoff from the top of its range down to $0100, then starts again, about one and a half seconds a sweep on a PAL machine. Run it with SYS 49152; RUN/STOP and RESTORE together stop it.

Assembly
STEP  = $18             ; cutoff change per frame
TOP   = $07ff           ; the 11-bit maximum
FLOOR = $0100           ; start again when the sweep gets this low

        * = $c000

        lda #$00
        sta $d405       ; attack 0, decay 0
        lda #$f0
        sta $d406       ; sustain 15, release 0
        lda #$51
        sta $d400       ; frequency $0751: about 110 Hz on a PAL C64
        lda #$07
        sta $d401
        lda #$f1
        sta $d417       ; resonance 15, voice 1 through the filter
        lda #$1f
        sta $d418       ; low-pass output on, volume 15
        jsr top         ; set the cutoff to the top of its range
        lda #$21
        sta $d404       ; sawtooth, gate on

frame   bit $d011       ; wait for the raster to pass line 255
        bpl frame
        jsr update
wait    bit $d011       ; wait for the next frame to begin
        bmi wait
        jmp frame

update  sec             ; cutoff = cutoff - STEP
        lda cutoff
        sbc #<STEP
        sta cutoff
        lda cutoff+1
        sbc #>STEP
        sta cutoff+1
        cmp #>FLOOR     ; is it still at or above FLOOR?
        bne +
        lda cutoff
        cmp #<FLOOR
+       bcs write       ; yes: use it
top     lda #<TOP       ; no: start the sweep again from the top
        sta cutoff
        lda #>TOP
        sta cutoff+1
write   lda cutoff
        and #$07
        sta $d415       ; low 3 bits of the cutoff
        lda cutoff+1
        sta hi
        lda cutoff
        lsr hi          ; shift the 11-bit value right three places
        ror
        lsr hi
        ror
        lsr hi
        ror
        sta $d416       ; high 8 bits of the cutoff
        rts

cutoff  !word TOP
hi      !byte 0

Two details matter. The 11-bit value has to be split, not just stored as two bytes: the low three bits go to $D415, and the value shifted right three places goes to $D416. Writing the high byte of a 16-bit number to $D416 instead would put a cutoff of $07FF almost at the bottom of the range. And the sweep stops at a limit instead of running past zero, because the registers would wrap round and the cutoff would leap to the top. Sidplayer’s manual warned its users about the same thing: “If the cutoff is swept too far, it will wrap around.” The program keeps its own copy of the cutoff because the SID’s filter registers can be written but not read.

In music players and editors

Sidplayer, the music system that COMPUTE! published for the 64, gave each voice a filter sweep command, F-S, taking a rate from −127 to 127: positive values swept upwards, negative ones downwards, “the larger the number, the faster the sweep”. It also had an “autofilter” mode in which “the filter cutoff is automatically set according to the pitch of each note”, so high and low notes got the same filtering.

In a table-driven player the sweep is an instrument effect like pulse width modulation. Lasse Öörni (Cadaver) suggests commands of the form “add m to cutoff frequence for n frames”. The difficulty is that the chip has one filter for three voices, so “either only one voice must control the filter at a time”, chosen by a command in the pattern data, or the filter is driven entirely from the pattern data, separately from the instruments.

A filter you could not rely on

Yannes was frank about the filter. In 1996 he called it “the worst part of SID because I could not create high-gain op-amps in NMOS”. He set the cutoff with FETs used as voltage-controlled resistors, and “the resistance of the FETs varied considerably with processing, so different lots of SID chips had different cutoff frequency characteristics. I knew it wouldn’t work very well, but it was better than nothing and I didn’t have time to make it better.” The data sheet says the register “linearly controls” the cutoff; real chips do not follow that line, and each follows a different curve.

Composers knew. Asked by ZZAP!64 in February 1986 whether he had reservations about using the filters, Martin Galway said: “No, the filters are too unreliable. A brilliant result on one machine is no guarantee of satisfactory sound on another.” He expected to use them only once the C128, whose filters he believed were “greatly improved”, was more common. In the same interview he rejected the magazine’s claim that Rob Hubbard had “stretched the SID chip to its limits”: “There are plenty of things you can do with it yet!”

6581 and 8580

Commodore’s later HMOS version of the chip, documented in its 6582 data sheet and fitted to later C64s as the 8580, has the same registers but a redesigned filter. The data sheets give different formulas for the maximum cutoff (2.6×10⁻⁵/C for the 6581, 8.2×10⁻⁵/C for the HMOS chip, where C is the value of the two filter capacitors) and recommend different capacitors, 2200 pF against 6800 pF. The 6582 sheet also describes the resonance differently, from “about 0.707 (Critical Damping)” at 0 up to a maximum at 15.

Public descriptions agree on how they sound: the 6581’s filter “varies wildly between chips, and often distorts”, while the 8580’s has a linear cutoff range, is more consistent between chips, is nearly free of distortion and “can achieve higher resonances”. A filter setting chosen by ear on one chip can sound thin, muffled or harsh on the other, so a sweep written on a 6581 rarely sounds the same on an 8580. Emulators leave the choice to the listener: VICE’s reSIDfp engine has a “6581 filter curve” setting, and its reSID engine a filter bias, for matching the sound of a particular chip.

Sources

  • MOS Technology, 6581 Sound Interface Device (SID) data sheet, as reprinted in the Commodore 64 Programmer’s Reference Guide (Commodore, 1983), Appendix O: the filter registers and routing, the filter modes and slopes, notch from low-pass plus high-pass, “3 OFF”, the maximum-cutoff formula, and the advice to vary the cutoff in real time.
  • Commodore Semiconductor Group, 6582 Sound Interface Device (SID) data sheet (HMOS): cutoff range and capacitor values, resonance, maximum-cutoff formula.
  • Commodore 64 Programmer’s Reference Guide, “Filtering”, pp. 199–201: the cutoff in registers 21 and 22 and the mode bits in register 24.
  • Andreas Varga, “Interview with Bob Yannes” (e-mail, August 1996; web, secondary, read in the copy on the Codebase64 wiki): the state-variable design, the FETs, the 12-bit converter with its lowest bit disconnected, the analogue output switches, the variation between batches of chips, and “I didn’t have time to make it better”.
  • ZZAP!64, issue 10, February 1986, p. 51: interview with Martin Galway.
  • COMPUTE!’s The Complete 64 (COMPUTE! Publications, 1986), chapter 5, “Sidplayer”, pp. 144–145: the cutoff command, autofilter mode and filter sweep.
  • Lasse Öörni (Cadaver), “Building a musicroutine”, Codebase64 wiki (web, secondary). https://codebase64.org/doku.php?id=base:building_a_music_routine
  • VICE 3.10 source code, SID command-line options: -resid6581filtercurve, “reSIDfp 6581 filter curve setting”, and -residfilterbias.
  • Wikipedia, “MOS Technology SID” (web, secondary): the 8580’s filter compared with the 6581’s. https://en.wikipedia.org/wiki/MOS_Technology_SID
  • The sweep program was assembled with ACME and run on the Commodore 64 ROMs in an emulated PAL C64. A copy that also logged each pair of values written to $D415 and $D416 showed one write a frame, the cutoff falling by $18 from $07FF, never below $0100, and starting again at the top every 75 frames.

See also

Checked. Verified against primary sources and signed off by a person.