Walleij — A SID player routine (MIDI-driven player design, note tables, hard restart)

author Linus Walleij (Triad)
date undated; the note table is marked "Public Domain — Linus Walleij 2001"
article Introduction and a note on hard restart · The Pseudo-Code (instrument_on, note_on, note_process, note_off) · Note tables
created 2026-08-30 · updated 2026-08-30

Design notes, in pseudo-code, for a MIDI-controlled sid player, written on request from Michael Kleps (the "M.K." of the extended Soundtracker module signature and author of the QuadraSID VST). linus-walleij learned how players work by writing the C64 MIDI program MIDIslave and from the editors he used — SoundMonitor (Chris Hülsbeck), Future Composer (Finnish Gold), Rockmonitor, Pro-Drum and Music Assembler (the Dutch USA-team), the JCH Editor, Soundtracker 64 (Mechanix) and the Soedesoft Editor (Jeroen Soede). Sample playback is left out. In the raw copy a few lines of the note_process loop header (the channel loop and the waveform-macro write) were lost to HTML tag-stripping; the intent is clear from the surrounding comments.

Key claims#

  • Hard restart, as he describes it: the JCH player is "a very good one" because it uses hard restart — "the SID provides quite bad accuracy on attack after releasing a note", so the fix is "to write 0x00 to all registers at $d400–$d406 2/50 second (2 frames) before next attack"; "the actual minimum time is 33 ms = 2^15 cycles according to Dag Lem, author of reSID"; "some say setting the test bit … is just as good"; the problem "only affects the 6581 version of the SID chip (or so I am told...) and not the later 8580", so "for some MIDI appliances the 8580 is a lot better choice"; hard restart "only fixes problems with attack, not the ever-present problem with release".
  • The MIDI catch-22: hard restart needs to know two frames ahead that a note is coming, which a live MIDI player cannot; the SIDstation either hard-restarts every voice on key press (delaying every note by 1/50 s) or on key release ("kills the voice effectively, and makes all release settings superfluous").
  • Player structure: instrument_on writes the filter registers ($d415, $d416, and the resonance byte masked & $F0 | $0F into $d417 so all voices are routed) and the filter type into $d418; note_on allocates one of the three channels (stealing the oldest on a FIFO basis if wanted), then writes frequency → pulse width (only if the waveform is pulse, $40) → waveform | $01 (gate) → attack/decay → sustain/release, and arms the macro speed and the vibrato / pulse-vibrato delays; note_process runs "at a reasonably high rate, say 400 Hz" — the C64 macro rate is usually 50 Hz, so the default step is 8, and "the highest rate I have seen in a C64 playroutine is 600 Hz"; note_off only clears the gate bit (& $FE).
  • Macros: waveform table per instrument; an arpeggio table of bytes "which represents the number of halftones to transpose the current note UPWARDS. For example macro 0x00 0x03 0x07 creates a minor chord"; a pulse-width table usually writing only the high byte ($d403) — "most c64 players don't" write the low byte; a filter table writing the cutoff high byte and a resonance byte (masking the low nybble is "my choice" because that nybble "has dangerous effects like switching filter off or on for current channel"); tables "can loop or end".
  • Vibrato: a delay before vibrato, then an amplitude and a period (from the instrument or a wheel) added as an LFO over $d400/$d401, taking the pitch wheel into account; pulse-width vibrato the same over $d402/$d403 "but larger amplitude can be used"; the filter can follow a wheel or an LFO ("sinus or sawtooth, or square wave") for "a TB303-like-effect".
  • Note table: 95 entries of high and low bytes for the 6581, index 0 = C-0, 36 = C-3, 57 = A-4, 95 = A-7 — "last B in octave 8 is not possible to replay with c64"; "the numbers in the C64 hardware reference manual are simply WRONG"; calculating the values "is preferable, especially to modulate the pulsewidth and such".

Practical takeaways#

  • A minimal SID player is: per-frame macro steps for waveform, arpeggio (semitone offsets), pulse width and filter, plus delayed LFO vibrato — the same architecture as sid-wizard's and goattracker's instrument-tables.
  • Hard restart is incompatible with real-time MIDI unless you accept a one-frame delay or lose the release phase — a design constraint for any live SID instrument.

Notable quotes#

"This problem only affects the 6581 version of the SID chip (or so I am told...) and not the later 8580 version."

"Hard restart only fixes problems with attack, not the ever-present problem with release."

Relevance#

An independent player-author's description of hard-restart (with Dag Lem's 33 ms figure) that contradicts the wiki's other sources on the 8580 — recorded on the page; a compact model of a sid-player-routine; confirmation of the 0 3 7 arpeggio idiom from the player side (chord-arpeggio); and a MIDI-on-C64 data point for sync.

Pages touched#

hard-restart · sid-player-routine · vibrato · pulse-width-modulation · filter-programming · chord-arpeggio · sync · linus-walleij · c64-programmers-reference-guide

source file wiki/summaries/s-walleij-sid-player-routine.md · graph