Guest User

Untitled

a guest
Jun 21st, 2026
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.31 KB | Source Code | 0 0
  1. Here's a brief summary of the SID demo:
  2.  
  3. What it plays: A continuously looping three-voice piece. Voice 1 carries a short melody that cycles through the SID's three main waveforms each repeat — triangle (soft), sawtooth (bright/buzzy), pulse (hollow) — so you hear the chip's tone colors. Voice 2 holds a sawtooth bassline, and Voice 3 plays a sustained harmony a fifth up, routed through the filter with a sweeping cutoff for that signature SID "wah."
  4.  
  5. How it works: I poke the SID's registers at $D400–$D418 directly from assembly. Each voice gets a frequency, a waveform, and an ADSR envelope (attack/decay/sustain/release — the swell-and-fade shape of a note). A note sounds when I set the frequency and flip the voice's gate bit on; clearing the gate triggers the release. Timing comes from a raster-synced tick (wait_frame) that fires once per video frame (~50Hz), the standard heartbeat for C64 music. The filter sweep is just nudging the cutoff register up and down a little each frame.
  6.  
  7. ; sid_demo.asm - three-voice SID sound demonstration for the C64
  8. ;
  9. ; Assemble: acme -f cbm -o sid_demo.prg sid_demo.asm
  10. ; Run: x64sc sid_demo.prg
  11. ;
  12. ; What it does:
  13. ; Voice 1 (melody) - plays a short phrase, switching WAVEFORM every pass so
  14. ; you hear triangle -> sawtooth -> pulse -> back again.
  15. ; Voice 2 (bass) - a steady low sawtooth bassline under the melody.
  16. ; Voice 3 (harmony) - sustained notes a fifth above, with the SID FILTER
  17. ; sweeping open and closed so you hear the filter effect.
  18. ;
  19. ; Timing is done with a simple frame-counted delay loop driven off the VIC-II
  20. ; raster (a crude ~50Hz tick). No CIA/IRQ player - kept readable on purpose.
  21. ;
  22. ; SID register map (base $D400):
  23. ; +0/+1 voice1 freq lo/hi +7/+8 voice2 freq lo/hi +14/+15 v3 freq
  24. ; +2/+3 voice1 pulse width ...
  25. ; +4 voice1 control (waveform + gate)
  26. ; +5/+6 voice1 attack/decay , sustain/release
  27. ; (voices 2 and 3 follow at +7 and +14 offsets)
  28. ; +21/+22 filter cutoff lo/hi +23 filter resonance/routing +24 vol+mode
  29.  
  30. SID = $D400
  31. V1FREQ = SID+0
  32. V1PW = SID+2
  33. V1CTRL = SID+4
  34. V1AD = SID+5
  35. V1SR = SID+6
  36. V2FREQ = SID+7
  37. V2PW = SID+9
  38. V2CTRL = SID+11
  39. V2AD = SID+12
  40. V2SR = SID+13
  41. V3FREQ = SID+14
  42. V3PW = SID+16
  43. V3CTRL = SID+18
  44. V3AD = SID+19
  45. V3SR = SID+20
  46. FCUTLO = SID+21
  47. FCUTHI = SID+22
  48. FRESON = SID+23
  49. FVOLMODE = SID+24
  50.  
  51. RASTER = $D012
  52.  
  53. ; zero page scratch
  54. note_idx = $02 ; index into melody table
  55. wave_sel = $03 ; which waveform voice1 currently uses (control byte hi bits)
  56. sweep_dir= $04 ; filter sweep direction (0 = up, 1 = down)
  57. sweep_val= $05 ; current filter cutoff (hi byte)
  58. tmp = $06
  59.  
  60. * = $0801
  61. !byte $0b,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00 ; 10 SYS 2061
  62.  
  63. start:
  64. sei
  65.  
  66. ; ---- clear all SID registers ----
  67. lda #0
  68. ldx #$18
  69. clr: sta SID,x
  70. dex
  71. bpl clr
  72.  
  73. ; ---- master volume = max, filter mode set later ----
  74. lda #$0f
  75. sta FVOLMODE
  76.  
  77. ; ---- envelopes ----
  78. ; voice1 melody: quick attack, medium decay, mid sustain, short release
  79. lda #$09 ; attack=0 (fast), decay=9
  80. sta V1AD
  81. lda #$80 ; sustain=8, release=0
  82. sta V1SR
  83. ; voice2 bass: punchy
  84. lda #$0a
  85. sta V2AD
  86. lda #$90
  87. sta V2SR
  88. ; voice3 harmony: slow swell so the filter sweep is audible
  89. lda #$48 ; attack=4 (slowish), decay=8
  90. sta V3AD
  91. lda #$a0 ; sustain=A, release=0
  92. sta V3SR
  93.  
  94. ; voice1 + voice3 pulse width (used when pulse waveform selected) ~50%
  95. lda #$00
  96. sta V1PW
  97. lda #$08
  98. sta V1PW+1
  99. lda #$00
  100. sta V3PW
  101. lda #$08
  102. sta V3PW+1
  103.  
  104. ; ---- filter: route voice3 through it, low-pass, some resonance ----
  105. lda #%00000100 ; bit2 = filter voice3
  106. sta FRESON ; (low nibble = routing; high nibble = resonance)
  107. lda #%11110100 ; resonance=$F (high), and re-assert voice3 routing
  108. sta FRESON
  109. ; FVOLMODE: low nibble volume=$F, bit4=low-pass enable ($10)
  110. lda #$1f
  111. sta FVOLMODE
  112.  
  113. ; ---- init state ----
  114. lda #0
  115. sta note_idx
  116. sta sweep_dir
  117. lda #$10 ; voice1 waveform start = triangle ($10)
  118. sta wave_sel
  119. lda #$40
  120. sta sweep_val
  121.  
  122. cli
  123.  
  124. ; ================= MAIN LOOP =================
  125. mainloop:
  126. ; --- play current melody note on voice 1 ---
  127. ldx note_idx
  128. lda mel_lo,x
  129. sta V1FREQ
  130. lda mel_hi,x
  131. sta V1FREQ+1
  132. ; gate ON with current waveform
  133. lda wave_sel
  134. ora #$01 ; set gate bit
  135. sta V1CTRL
  136.  
  137. ; --- bass note on voice 2 (sawtooth), one per two melody notes ---
  138. lda bass_lo,x
  139. sta V2FREQ
  140. lda bass_hi,x
  141. sta V2FREQ+1
  142. lda #$21 ; sawtooth ($20) + gate ($01)
  143. sta V2CTRL
  144.  
  145. ; --- harmony on voice 3 (triangle through filter) ---
  146. lda harm_lo,x
  147. sta V3FREQ
  148. lda harm_hi,x
  149. sta V3FREQ+1
  150. lda #$11 ; triangle ($10) + gate ($01)
  151. sta V3CTRL
  152.  
  153. ; --- hold the note for a while, sweeping the filter as we wait ---
  154. jsr note_delay
  155.  
  156. ; --- gate OFF (release) all voices ---
  157. lda wave_sel
  158. sta V1CTRL ; gate bit cleared -> release
  159. lda #$20
  160. sta V2CTRL
  161. lda #$10
  162. sta V3CTRL
  163.  
  164. ; short gap
  165. jsr short_delay
  166.  
  167. ; --- advance to next note ---
  168. inc note_idx
  169. ldx note_idx
  170. lda mel_lo,x
  171. cmp #$ff ; $ff in lo table marks end of phrase
  172. bne mainloop
  173.  
  174. ; phrase finished: reset index and switch voice1 waveform
  175. lda #0
  176. sta note_idx
  177. jsr next_waveform
  178. jmp mainloop
  179.  
  180. ; ---- cycle voice1 waveform: triangle -> saw -> pulse -> triangle ... ----
  181. next_waveform:
  182. lda wave_sel
  183. cmp #$10
  184. bne nw_try_saw
  185. lda #$20 ; triangle -> sawtooth
  186. jmp nw_set
  187. nw_try_saw:
  188. cmp #$20
  189. bne nw_pulse
  190. lda #$40 ; sawtooth -> pulse
  191. jmp nw_set
  192. nw_pulse:
  193. lda #$10 ; pulse -> back to triangle
  194. nw_set:
  195. sta wave_sel
  196. rts
  197.  
  198. ; ---- note_delay: hold ~24 frames, advancing the filter sweep each frame ----
  199. note_delay:
  200. ldy #24
  201. nd_loop:
  202. jsr wait_frame
  203. ; sweep filter cutoff up and down
  204. lda sweep_dir
  205. bne nd_down
  206. inc sweep_val
  207. lda sweep_val
  208. cmp #$f0
  209. bcc nd_apply
  210. lda #1
  211. sta sweep_dir
  212. jmp nd_apply
  213. nd_down:
  214. dec sweep_val
  215. lda sweep_val
  216. cmp #$20
  217. bcs nd_apply
  218. lda #0
  219. sta sweep_dir
  220. nd_apply:
  221. lda sweep_val
  222. sta FCUTHI
  223. dey
  224. bne nd_loop
  225. rts
  226.  
  227. short_delay:
  228. ldy #6
  229. sd_loop:
  230. jsr wait_frame
  231. dey
  232. bne sd_loop
  233. rts
  234.  
  235. ; ---- wait_frame: spin until the raster reaches line $FA (250), which happens
  236. ; exactly once per frame -> a clean ~50Hz (PAL) / 60Hz (NTSC) tick.
  237. ; We first wait for it to LEAVE 250 (in case we're already there), then
  238. ; wait for it to come back, guaranteeing one full frame elapses.
  239. wait_frame:
  240. wf_leave:
  241. lda RASTER
  242. cmp #$fa
  243. beq wf_leave ; wait until we are NOT on line 250
  244. wf_reach:
  245. lda RASTER
  246. cmp #$fa
  247. bne wf_reach ; wait until raster hits line 250
  248. rts
  249.  
  250. ; ================= NOTE DATA =================
  251. ; Frequencies are 16-bit SID values (PAL). $ff in mel_lo ends the phrase.
  252. ; Melody: a little rising/falling phrase.
  253. mel_lo:
  254. !byte $25,$1c,$d6,$48,$d6,$1c,$25,$00,$ff
  255. mel_hi:
  256. !byte $11,$15,$11,$1c,$11,$15,$11,$00,$00
  257. ; Bass: lower octave roots
  258. bass_lo:
  259. !byte $25,$25,$d6,$d6,$d6,$25,$25,$25,$00
  260. bass_hi:
  261. !byte $08,$08,$06,$06,$06,$08,$08,$08,$00
  262. ; Harmony: a fifth above the melody, sustained
  263. harm_lo:
  264. !byte $b8,$ad,$1c,$8e,$1c,$ad,$b8,$00,$00
  265. harm_hi:
  266. !byte $19,$1f,$15,$23,$15,$1f,$19,$00,$00
Advertisement
Add Comment
Please, Sign In to add comment