SIDin #15 — Inside Matt Gray's Serpent Demo player (the 4-bit sample voice, reverse-engineered, 2015)
Answering Gray's remark in the same issue that the Serpent Demo drums were "too loud" (s-sidin15-matt-gray-interview), Tognon reverse-engineers the tune's player: the Driller-generation matt-gray-player plus a fourth, sample track that streams 4-bit values into the SID volume register from a CIA-timer NMI — the wiki's first complete listing of a 1980s chip-samples ("digi") voice inside a music driver.
Key claims#
- Which engine: the Serpent Demo — "spread as a demo with a cobra serpent images" — uses an engine "younger of the one in Dominator, and it is about the same of Driller one": tracks, patterns, commands and instruments are the Driller set (
$FD kk= duration, arpeggio from instrument byte 5, hard-coded pulse limits$08/$0E, theEOR #$23noise effect), "what is new is the sample management". Tognon's reading order of the three engines: Driller → Serpent Demo → Dominator; the Vendetta build "that use filter" is left for "maybe another issue". - A fourth voice: every song has
VOICE4LO/HIpointers next toVOICE1–3; the sample track is a list of pattern numbers with$FFrestart /$FEend like the others, and its patterns sit in the sameBARLO/BARHItable — but with their own command set:
| byte | meaning |
|---|---|
NN | sample speed: written to CIA 2 Timer A low byte $DD04 (high byte fixed at 1) — "more little is this value and more often the NMI is triggered", i.e. the note/transpose of the sample |
$FD VV | sample length (duration in tempo ticks) |
$FA BI | bank B (0 or 1, high nibble) and sample index I (low nibble) |
$FF | end of pattern |
- How it plays: the raster IRQ still runs the three SID voices once a frame (
MUSICROUTINE→MAIN×3, thenMAINEXTRAfor the sample track);SETNMIpoints$0318/$0319atNMI, starts Timer A ($DD0E = $11) and enables its NMI ($DD0D = $81). Each NMI callsSAMPLEROUTINE, which reads one byte from a self-modified address (MEMPOINT), outputs the high nibble first and the low nibble on the next NMI to$D418, then advances the pointer; when the high byte of the pointer reachesBANKENDthe sample stops (SAMPLEVOL = 0) or restarts from a second start page.MAINwrites volume$09to$D418whenever no sample is playing ("volume to middle"),$0Eat init. - Sample data: 4-bit, "two samples to play in sequences" per byte; seven samples in labels
SM10 … SM1FfromSTARTADD = $1000(4 KB before the code), described byBANKLO(start low byte,$00or$FF),BANKHI0(start page),BANKEND(end page) andBANKHI1(bank-1 start page): e.g. index 3 =SM18–SM1A, bank 1 fromSM19. "16x2 max samples area … even if using bank 0 or bank 1 gives different behavior". Put a sample at a page boundary ($1100–$12FF→ start$11, end$13). - Pattern examples:
T29 .BYTE $FD,$00, $FA,$03, $01,$02,$03 … $40, $FF— the first pattern ofTUNE4: fastest duration, sample 3, and a run of speed values$01–$40"with a fasting increasing frequency … that you can easy heart in the drums";T6/T7alternate sample 1 at speed$0Aand sample 2 at$40;T14ends with$35,$30,$25,$20,$15,$10,$05,$01(a falling-pitch tail).TUNE4 .BYTE $1D,$09,$0A,$0A,$0A,$0B,$0A … $FF. A second song,EMPTY, plays no SID voices and only sample patternT16— "maybe a way to test only the sample engine". - Leftovers: undeclared patterns
T2912,T28A9and three unused tracksT27DB,T2836,T285F"are from Hunter's Moon tune (Serpent Demo was spread across the Hunter's Moon game)" (hunters-moon); many declared patterns are unused. - The SID side, as listed: 19 instruments (
VDATA/VDATA2), speed 4 (TDATA .BYTE $00,$04,$04), and eight four-note PLEX tables —P0 $13,$0C,$07,$00,P1 $00,$07,$0A,$0C,P2 $00,$03,$07,$0C,P3 $00,$04,$07,$0C,P4 $00,$05,$09,$0C,P5 $00,$05,$07,$0C,P6 $00,$04,$09,$0C,P7 $00,$03,$08,$0C— selected from instrument byte 5 ($40,$41,$43–$47: four notes, table 0–7) (chord-arpeggio). The header Tognon reconstructs reads "PLAYER <V4.2 (C)1987 MATT GRAY"; the copyright string(C)1987 MATT GRAYappears twice in the data. - Rights: "The source code presented here is Copyright by Matt Gray", obtained by reverse-engineering "and applying all the notations of Dominator engine when possible" — the labels and comments of Tognon's Dominator edition (s-sidin14-dominator-player).
Practical takeaways#
- The classic C64 digi recipe in one place: samples as packed nibbles, an NMI from a CIA timer whose low byte is the "note", one nibble to
$D418per interrupt, the music IRQ untouched (chip-samples, sid); compare Galway's synthesised$D418percussion in s-realdmx-galway-arkanoid-player and Hülsbeck's NMI streaming noted on chip-samples. - Treat the sample track as a fourth pattern channel with three commands — pitch, length, sample — and write drum fills as pattern data (
T29's rising$01 … $40sweep is a pitch envelope written by hand). - Level matching: the sample nibble replaces the whole volume register, while the music runs at
$09— the loudness Gray regrets is structural, not a sample-normalisation slip.
Notable quotes#
"The only secret is that you have to use a NMI routine over the logic governed by the IRQ to performs the sample generation. The other trick is to store the 4 bit value of each sample in one byte (8 bits)."
"At this point we have seen 3 Matt Gray engines, that has to be read in this sequences (as features maturated from one to another): Driller, Serpent Demo, Dominator."
Relevance to the wiki#
Adds the sample voice (fourth track, three commands, NMI nibble streaming, bank tables) to matt-gray-player and a complete 1980s digi routine to chip-samples; dates the engine between Driller and Dominator (driller); links the demo to hunters-moon; four-note chord tables for chord-arpeggio.
To verify#
- Bank semantics (my reading of
SETSAMPLESPEED/SETSAMPLEVOL): with bank 0 the end of the area stops playback and the volume returns to$09; with bank 1 the pointer restarts at theBANKHI1page, soBANKHI1looks like a loop start inside the sample (the table values lie between eachBANKHI0andBANKEND). Tognon only says bank 0 "set[s] the volume to middle before the sample playback" (unverified). - Nibble rate: Timer A =
$01NNcycles, so roughly 985 kHz ÷ (256 + NN) NMIs per second on PAL — about 3.7 kHz at$0A, 3.1 kHz at$40(computed, unverified). - "Younger" in Tognon's English means earlier here (his own ordering is Driller → Serpent → Dominator).
- Tognon calls
T29's$FA,$03"index 3 of bank 1"; the high nibble is 0, so by his own table it is bank 0; the address range he gives ($1800–$19FF) matches index 3. - The demo's year, group and the "Robin Levy" credit for the serpent picture (from the interview) are not otherwise documented here; no song page was created.
Pages touched#
matt-gray-player · chip-samples · matt-gray · driller · dominator · hunters-moon · chord-arpeggio · sid · sid-player-routine · sidin