Homeentitytool

David Whittaker's player (the Panther driver)

The 1986 driver of david-whittaker as reverse-engineered by dmx87 from Panther (Mastertronic): a three-voice player without an instrument table — the timbre of a voice is whatever the last command prefixes in its pattern set (waveform, ADSR, pulse bounce, vibrato, slide, drum), kept in a 36-byte voice struct (source: s-realdmx-fredgray-kimmel-whittaker). It is not the Lazy Jones routine that sidin #2 analysed — that one is raw two-voice frequency lists with equal note lengths and no effects (sources: s-realdmx-fredgray-kimmel-whittaker, s-sidin02-matt-gray-driller).

Facts#

  • $9000–$9cff, 3328 bytes: engine and structs ≈ 1.7 KB, note table and arpeggios 267 bytes, tracks 354, patterns 1022. Unlabelled bytes after init are a sub-tune selector (6 bytes per tune), so the original driver served several tunes per game (source: s-realdmx-fredgray-kimmel-whittaker).
  • Once per frame: the sequencer every SongTempo frames (7 by default, changeable in the pattern), the effects every frame; every frame writes frequency, pulse, AD, SR and control, gate off then on at note starts — silence is made with SR = 0, not with the gate (hard-restart). SIDId's David_Whittaker signature is that gate write (sources: s-realdmx-fredgray-kimmel-whittaker, s-sidid-player-list).

Cheat sheet#

All from the Panther disassembly (source: s-realdmx-fredgray-kimmel-whittaker).

Track = list of pattern addresses, !wo 0 loops it; the three tracks have different lengths (53 / 65 / 53 entries). Pattern = byte stream; FLAGS is cleared at every note, so arpeggio, slide and drum must be re-issued per note.

bytemeaning
$00–$7fnote (index into a 95-entry table, $0116 = C-0); ends the step
$80–$93command (below)
$b8–$bftempo = value − $b7 (1–8 frames per tick)
$c0–$ccarpeggio list 0–12
$d0 aa ssADSR follows (two bytes)
$e0–$ffduration = value − $df (1–32 ticks)
commandeffect
$80hold the current note for another duration (no retrigger)
$81 / $82vibrato off / on
$83 vvolume / mode byte
$84 lo,hi,delay / $85slide down / up: after delay frames the step accumulates every frame (a quadratic sweep)
$86 / $87bend down / up one semitone per tick
$88end of pattern
$89 speed,depthvibrato parameters
$8a / $8b / $8c / $8dwaveform noise / pulse / sawtooth / triangle
$8edrum: on odd frames control $80 (noise) with the frequency high byte + $31
$8f npulse width high byte
$90 min,max,speedpulse bounce between two high bytes
$91stop music
$92 / $93triangle + ring modulation / pulse + sync

Arpeggio lists (one step per frame; any byte ≥ $54 restarts): $00,$03,$07,$88 · $00,$04,$07,$88 · $00,$03,$07,$0c,$88 · $00,$04,$07,$0c,$88 · $07,$0c,$0f,$88 · $07,$0c,$10,$88 · $03,$07,$0c,$88 · $04,$07,$0c,$88 · $00,$0c,$88 · $00,$04,$88 · $00,$03,$88 · $00,$05,$88 · $00,$07,$88 (chord-arpeggio).

"Instruments" as they appear in the data: PC_PULSE,$90,$02,$08,$28,$d0,$0a,$40 (pulse bouncing between $02xx and $08xx at speed $28, AD $0a, SR $40); $92,$90,$02,$08,$14,$89,$7f,$fe,$82,$d0,$df,$00,$ff,$84,$80,$00,$01 (ring-triangle, pulse bounce, deep vibrato, slide down — a siren); $8d,$89,$28,$50,$82,$d0,$0d,$70 / $f7,$c0,$3c,$e7,$c1,$3a (triangle, vibrato, then 24 ticks of a minor arpeggio on $3c and 8 of a major one on $3a); $be,$d0,$00,$00,$ff,$80,$88 (tempo 7, ADSR $00/$00, 32 ticks, hold — a silent pattern).

The Lazy Jones routine (1984)#

sidin #2's reverse-engineering of the hvsc rip of Lazy Jones (Terminal Software, 1984) — a different and far smaller routine than the Panther driver above, "the most simple I had seen until now" in Tognon's words (source: s-sidin02-whittaker-lazy-jones):

  • Data: 20 pieces of $80 bytes; a step is 4 bytes — frequency low/high for voice 1, then for voice 2 (voice 3 is never used) — so a piece is 32 steps, looped when the byte index reaches $80. A zero low byte skips that voice for the step (its registers are left alone); the rests in Tune17 are $00,$00,$00,$00 rows. Tune 1 is the exception: for song 0 init patches the loop compare to $00, so the index wraps after 256 bytes and tunes 10 and 11, consecutive in memory, play back to back.
  • Timing: one step every $0C calls (DELAY); every note has the same length, there is no duration byte.
  • One sound, no effects: setAD writes $D418 = $1F and attack/decay $66 to $D405 and $D40C; initEngine writes $D416 = $FF and $D417 = $03; sustain/release is never written (0). A new note is frequency low, frequency high, then control $20 and immediately $21 — sawtooth with the gate dropped and raised in the same call, restarting the attack/decay envelope (adsr-envelope).
  • Per call: on eleven of twelve frames only dec DELAY; on the twelfth the writes above for two voices and the pointer/index update, then jmp $EA31. Rastertime: at most 4 raster lines when picking a new note, 1 otherwise (sid-player-routine).
  • The PSID: 21 songs (tune 1 = 10 + 11, plus the 20 pieces), a header typed as .byte "PSID", .word $0200 (v2), data offset $7C, load and init at the listing's init, play at IRQ, "lazy Jones / David Whittaker / 1984 Terminal Software"; variables MUSIC, INDEX, DELAY, PATTL/H at $03E0–$03E5, the running pointer in $B4/$B5. The rip lacks the sound effects and came from a cracked version: a faulty, unused track (label wrong) follows tune 21 (sid-format).
  • In the notes: Tognon's annotation of tune 10 has voice 1 alternating H1/H2 (B in two octaves, German naming) on every 12-frame step under the melody of voice 2 — an octave-bass in 1984. His verdict on where the magic comes from: "I think from the music notes themselves!"

david-whittaker · hubbard-player · galway-player · sid-player-routine · sidin · sidid · pulse-width-modulation · pitch-slide-and-portamento · chord-arpeggio

Sources#

s-realdmx-fredgray-kimmel-whittaker · s-sidin02-matt-gray-driller · s-sidid-player-list · s-sidin02-whittaker-lazy-jones

source file wiki/entities/whittaker-player.md · graph