SIDin #11 — Tiny Sid 2, part 2: BLOCK ACID DUB and Resolution (Stefano Tognon, 2007)

author Stefano Tognon (ice00), SIDin magazine; BLOCK ACID DUB source and comments by Frantic/Hack'n'Trade; Resolution by Eric Odland, disassembled by Tognon
date 2007-02-14
article SIDin issue 11 (version 1.00, 14 February 2007), pp. 19–29: 'Tiny Sid 2 (part 2)' — sections BLOCK ACID DUB (256b, source with the author's comments), Resolution (512b, reverse-engineered source), Conclusion; two more of the eight entries, the last two deferred again
created 2026-08-30 · updated 2026-08-30

Two more Tiny Sid 2 entries (tiny-sid-compo), the sequel to s-sidin10-tiny-sid-2-part-1: Frantic's 256-byte BLOCK ACID DUB, a generative dub tune whose player treats notes and instruments as one stream of SID register writes, and Eric Odland's 512-byte Resolution, which plays one note on all three voices and lets voice 3's envelope drive the filter. "Next time we will see the last 2 entries."

Key claims#

BLOCK ACID DUB (256 bytes, Frantic/Hack'n'Trade, alias Glenn Again/Kommando Knorr)#

  • Header facts: "Code + data + load address = 254 bytes. Two bytes reserved for the file system, so the tune will fit in a single disk block"; for the 6581, PAL; assembled with DreamAss; greetings "to NINJA/THE DREAMS, THE 252 BYTE PUNK!". Intent: "Last Tiny SID compo I aimed to make a long composition with harmonies and a 'real' melody … This time I aimed for fatter sounds instead" — hard restart, arpeggio, wavetables: "any combination of SID register values each frame is possible (but only one value per frame, and excluding lobyte of frequency)".
  • Only the frequency high byte is used; the low byte stays $00, so only notes that a high byte alone approximates are played — base notes $0400, $0800, $1000, $2000; the source ends with the error table (C 0, E 10, G −2, C 0, D −6, G −4, C 0, D# 6, G −7, C2 0 — the used ones marked) computed with a JavaScript file shipped in the package. Attack/decay never changes on voices 1 and 2 ($00).
  • Notes and instruments are the same thing: an instrument row is a control byte whose bits say which registers follow — SID_SR = $80, SID_AD = $40, SID_CTRL = $20, SID_PULHI = $10, SID_PULLO = $08, SID_FRQHI = $04, JUMP = $02 (next byte is a new instrument pointer), STAY = $01 (stop advancing: the instrument holds) — an empty byte (TICK) is a one-frame delay. Examples from the article: a note .byte SID_FRQHI | STAY / $06; an arpeggio SID_FRQHI / $0c / SID_FRQHI | JUMP / $09, arpeggio (two high bytes alternating for ever); "Acid Bass 2" SID_SR | SID_CTRL / $b8, $81 / TICK / SID_CTRL | STAY / $20; the bass drum sets SR/AD/control $fb,$04,$49, then pulse $41 at pitch $08 with pulse high $08, triangle $11, $10 at $07, then holds pitch $04 — a five-frame falling drum (instrument-tables, wavetable-programming).
  • Hard restart for the drum channel only: when the drum voice's tick counter reaches 2 the instrument pointer is forced to the @hardrestart row (SID_SR | SID_CTRL | STAY / $00, $10) — sustain/release $00 and gate off two frames before the next hit (hard-restart).
  • Random recombination: one 32-byte composition grid, one byte per voice step, dddp.pppp = duration 1–8 (D1 = 0<<5 … D8 = 7<<5) and a pointer into a 32-byte table of 4-byte "probability nodes"; when a step is read, a CIA timer value ($DC04) masked to 0–3 (ANC, ASR) picks one of the node's four instrument pointers, and pointer 0 means "no instrument change". So "the tune will appear different each time", one data stream serves all three voices, and there is no sequence table; the filter type also changes with the song position (ASR #%11100000 of SONGPOS, low-pass $10 forced when the result is 0, OR volume $0F into $D418), the cutoff is the drum channel's tick counter << 3 into $D416, resonance/routing $FB into $D417. Frantic's gloss: "one part of the brain follows what is steady in the music, and another part follows that which is fleeting and passing, and therebetween a tension arises … that is what constitutes dub."
  • Code tricks: the six registers of a voice are written through one self-modified sta $d4ff,x; the stack pointer holds the voice index temporarily (TXS/TSX); SBX #7 (.byte $cb,7) steps the voice index; the zero page holds instrument pointers ($03/$0a/$11), tick counters ($41/$48/$4f) and the song position ($99), chosen to be 0 at start.

Resolution (512 bytes, Eric Odland) — Tognon's reverse-engineered source#

  • Starts with a BASIC SYS 2061; hooks the IRQ through $0314 and chains to $EA31; initialises all 25 SID registers from a table in one loop (sidTable: voice 1 frequency $0430, pulse $0800, control $20, AD $05, SR $9F; voice 2 $0A8F, $0400, $40, $08/$A8; voice 3 $0FFF, $0500, $40, $0A/$B9; filter cutoff $5000, $D417 = $67, $D418 = $1F); when the track ends the whole init runs again — "a way to save code by reuse all code even if not all is necessary".
  • 13 patterns addressed by one-byte relative offsets in patTable (pat01 ×2, pat13 ×2, pat25, pat2F, pat3A, pat44, pat4E ×2, pat58, pat69, pat75, 0); 24 notes in freqLow/freqHigh tables; a note's default duration is $0A frames, $15 when a flag bit is set; a pattern's first byte is a base note index reused by the effect (orderlist).
  • All three voices play the same note (voice 3's low byte +8, a slight detune), voice 1 control $21, voices 2 and 3 $41; voice 3 is released differently ($40) from 1 and 2 ($20); "an effect of adding 4 notes over the current is also used. This is what make the instrument timbre you listen" — a bit rotated out of $FA decides whether the effect step plays the note 4 entries up the table.
  • Filter cutoff follows voice 3's envelope: every frame lda $D41C / lsr / sta $D416 — the envelope output register (ENV3) halved into the cutoff high byte, a free envelope follower (filter-programming).
  • inc $0420 in the IRQ makes a screen character count the frames.

Conclusion#

  • "The 512 bytes take emphasis to the notes to play and use the 3 voices together for creating a timbre of one instrument. The 256 bytes instead uses random sequences to make the composition more longer, but all 3 voices play different notes/instruments."

Practical takeaways#

  • A register-write language instead of notes + instruments (Frantic): every row says which SID registers get a byte this frame, STAY holds, JUMP loops — "almost looks like real wavetables". It is the wavetable-programming idea reduced to its minimum, and it makes pitch, waveform and drum all one table.
  • Generative arrangement with a timer as dice: a 4-way choice per step, with a "no change" option, keeps the piece recognisable while varying it — usable far above 256 bytes (arrangement).
  • Hard restart in two bytes of data: gate off with SR $00 two frames early, on the channel that needs it (drums).
  • Two ways to use the SID's read-only registers: ENV3 ($D41C) as a filter-cutoff modulator (Resolution), and CIA timer $DC04 as a random number (Frantic).
  • Frequency-high-byte-only tuning: with the low byte fixed at 0 the usable notes are those with small rounding error in a base of $0400; C, E, G, D and D# are available — enough for a dub bass line.

Notable quotes#

"Not using different code structures for 'notes' and 'instruments'. It's all just SID data." — Frantic

"It is interesting that you look at the point where random sequence is taken using $DC04 values." — Tognon

Relevance to the wiki#

Adds the register-stream instrument format, timer-driven random sequencing, a two-byte hard-restart and an envelope-follower filter to sid-player-routine, tiny-sid-compo, hard-restart, filter-programming and instrument-tables; names Frantic (Hack'n'Trade; later the author of DefMon, per s-sidid-player-list) and Eric Odland as Tiny Sid 2 entrants.

Pages touched#

tiny-sid-compo · sid-player-routine · hard-restart · filter-programming · instrument-tables · orderlist · arrangement · sidin

To verify#

  • Placings are not given; whether BLOCK ACID DUB and Resolution are the "winners" that part 1 promised for this issue is not said.
  • Frantic's greeting to "NINJA/THE DREAMS, THE 252 BYTE PUNK!" suggests a 252-byte entry by Ninja among the two entries still unanalysed — inference.
  • Resolution's duration flags: Tognon's prose says $0A unless the high bit is set (then $15); the listing's processValue assigns $0A on the bit-7 branch and $15 on the bit-6 branch — the two readings disagree, and the listing is a reconstruction.
source file wiki/summaries/s-sidin11-tiny-sid-2-part-2.md · graph