SIDin #11 — Tiny Sid 2, part 2: BLOCK ACID DUB and Resolution (Stefano Tognon, 2007)
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 arpeggioSID_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$41at pitch$08with pulse high$08, triangle$11,$10at$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
@hardrestartrow (SID_SR | SID_CTRL | STAY / $00, $10) — sustain/release$00and 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 #%11100000ofSONGPOS, low-pass$10forced when the result is 0, OR volume$0Finto$D418), the cutoff is the drum channel's tick counter<< 3into$D416, resonance/routing$FBinto$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$0314and 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 infreqLow/freqHightables; a note's default duration is$0Aframes,$15when 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$FAdecides 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 $0420in 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,
STAYholds,JUMPloops — "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
$00two 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$DC04as 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
$0Aunless the high bit is set (then$15); the listing'sprocessValueassigns$0Aon the bit-7 branch and$15on the bit-6 branch — the two readings disagree, and the listing is a reconstruction.