Homeentitysong

Dig Dug (C64, Datasoft 1984) — the music routine

The C64 cartridge conversion of Namco's arcade game ("copyright 1982 Namco, 1983 Atari, 1984 Datasoft"), whose music Stefano Tognon ripped into a PSID for hvsc in 2001–2002 and documented in sidin #1 with a commented source. The composer is not named: the game credits nobody and the rip's author field is <?> (source: s-sidin01-dig-dug-rip). What makes it worth a page is the routine — an interpreter of per-voice byte streams that writes SID registers directly, waits explicit durations and can be re-targeted voice by voice while the game runs, so "the music in the game are changed dinamically during the games".

Facts#

  • Eight pieces of music, selected by the value in the accumulator at initmusic (0–7, any other value = 7); the PSID has 8 songs and starts on song 7. The game's IRQ is a raster interrupt at line $20 (vector $9DE1); the track-setting routine sat at $BA0E and the track data around $BCxx–$BDxx in the cartridge image ($8000–$BFFF) (source: s-sidin01-dig-dug-rip).
  • Fourteen track slots (tracks) mapped to voices by a table (voices: $00,$01,$02,$02,$02,$02,$02,$02,$00,$01,$00,$00,$01,$02); track 12 is the silent track (control $00, frequency 0) (source: s-sidin01-dig-dug-rip).
  • Subtune contents (read from the data): song 0 = tracks 1–3, a three-voice one-shot — voice 1 triangle (ADSR $0F/$00, notes $430F $5983 $70C7 $430F $4B45, four frames each), voice 2 triangle ($2CC1 $12D1 $1FA5 $191E $25A2), voice 3 pulse $0900 (ADSR $0C/$00, six frames on, two off); songs 1–5 = one voice-3 track each: a 21-step rising frequency run at one frame per step under a held gate (pulse $0800, ADSR $00/$F0), a repeated two-note figure, six low pulse notes with ADSR $4F/$F4 ($0368 … $0393), three high triangle chirps played three times (ADSR $2C/$C2), six very high two-frame triangle notes ($861E … $B306); song 6 = tracks 9 + 10, the looping two-voice piece: voice 1 triangle (ADSR $07/$00) with the filter set to low-pass ($10), cutoff $00/$87 and resonance $20, voice 2 pulse $0800 (ADSR $37/$32) routed through the filter and playing every note as an octave pair$10C3 then $2187, $0FD2/$1FA5, $0EEF/$1DDF, $0E18/$1C31, $0D4E/$1A9C (four times), $0C8F/$191E — six frames on, two off (octave-bass, filter-programming); song 7 = track 11 alone, a looping triangle figure (ADSR $07/$60) (source: s-sidin01-dig-dug-rip).
  • PSID: version 2, load address 0 (the data starts with its own $01,$08), init initmusic, play play, 8 songs, start song 7, speed 0 (vertical blank), "Dig Dug" / "<?>" / "1984 Datasoft"; the same source assembles without sid defined to a .prg with a SYS 2061 stub, a raster IRQ at line $82 and the border colour toggled around jsr play as a rastertime meter (source: s-sidin01-dig-dug-rip; sid-format).

The music routine#

The model, from Tognon's listing (source: s-sidin01-dig-dug-rip):

  • A track is an instruction stream. playNext reads a byte, rejects anything with its low three bits set or above $B0, treats $B0 as the end (the voice goes inactive with a duration of $7F), and otherwise jumps through instTable — the byte is 8 × the routine's index. Instructions execute one after another in the same call until one sets a duration; the duration is the voice's wait in play calls.
  • The player sleeps. play decrements one global counter ($F5); at zero it lets every active voice with a zero counter fetch instructions, then adjustDuration takes the smallest of the three voice counters as the next wait and subtracts it from the others — a next-event scheduler rather than a per-frame tick. Voices are addressed by voiceIndex: $00, $07, $0E; a busy flag ($D0) guards re-entry.
  • Re-targeting a voice. setTrack (A = track slot) looks up the voice, stores the track address as the voice's pointer and as its restart address ($EC/$ED), adds the pending wait back to all counters, zeroes the new voice's and sets $F5 = 1, so the new track starts on the next call while the other voices keep time — the game's dynamic music. Because the SID cannot be read back, the frequency high byte is also kept per voice in $D8+voice.
  • Filter and volume are shared state. $FA = the voice-routing bits, $FC = the resonance nibble, $FB = the filter-mode nibble, $FD = the volume nibble; $D417 is always written as $FC + $FA and $D418 as $FB + $FD, so any voice can change one nibble without disturbing the rest (filter-programming).
  • Repeats. Two independent counters per voice (A in $D2+voice, B in $D5+voice): "set repeat n" stores n + 1, "goto" decrements and jumps back while the count is not zero, so a block bracketed by $78,$02 … $70,lo,hi plays three times; $48 restarts the whole track (the looping tunes end with $90, $48, $B0).

Instruction set#

Byte values decoded from instTable; "voice" is the voice the track is assigned to (source: s-sidin01-dig-dug-rip).

byteoperandseffect
$00control register = $11 (triangle, gate on)
$08lo, hifrequency (also saved in $D8+voice)
$10ncontrol register = n
$18lo, hipulse width
$20ad, srattack/decay, sustain/release
$28lo, hifilter cutoff $D415/$D416
$30nresonance nibble n & $F0$D417 with the routing bits
$38nvolume nibble n & $0F$D418 with the filter-mode nibble
$40nduration n calls — ends the step
$48restart the track from its first byte
$50route this voice through the filter (set its bit in $FA)
$58nfilter mode nibble n & $F0$D418
$60take this voice out of the filter
$68control register = $10 (triangle, gate off)
$70lo, higoto lo/hi while repeat counter A > 0
$78nrepeat counter A = n + 1
$80control register = $41 (pulse, gate on)
$88control register = $40 (pulse, gate off)
$90duration 2 — ends the step
$98duration 6 — ends the step
$A0nrepeat counter B = n + 1
$A8lo, higoto lo/hi while repeat counter B > 0
$B0end of track (voice inactive)

A typical note in the data: $80 / $08,$18,$0E / $98 / $88 / $90 — pulse on, frequency $0E18, six calls, gate off, two calls. The triangle tracks write gate-off and gate-on in the same call before the next frequency ($68 / $00 / $08,lo,hi / $40,$04), so the envelope restarts on every note; the sweep track never releases the gate and uses one-call durations instead (adsr-envelope, pitch-slide-and-portamento).

sid-player-routine · sid-format · hvsc · octave-bass · filter-programming · whittaker-player · vice · sidin

Sources#

s-sidin01-dig-dug-rip

To verify#

  • (unverified) Which song accompanies which game situation (digging, pumping, dying, the start jingle) is not stated; song 6 is presumably the walking music, being the default and the only looping two-voice piece.
  • (unverified) Code size and rastertime are not given; the .prg build's border-colour toggle is there to measure them.
source file wiki/entities/dig-dug.md · 2 unverified · graph