Difference between revisions of "Snippet:Playsong"
Line 1: | Line 1: | ||
− | This code is taken from [[ | + | This code is taken from [[Disassembly:Videocart_24|cart #24]]. It plays a song from memory using the address stored in [[Data counter|DC0]]. It starts a loop through the data, taking two bytes at a time; the first is the duration of the note, and the second is the frequency. It outputs it through the [[port]]s, delays, and takes another two bytes. If it finds the duration byte is equal to 0, it exits, so a 0 byte marks the end of a song. If it finds the frequency byte is 255, it instead generates a pause for the specified duration. (note: using a frequency of 254 ''or'' 255 otherwise outputs the same note) The pausing functionality isn't in the original disassembly, but was added afterwards. |
Second version has some edits and additions B00daW from his Sleizsa-package v.0.3. | Second version has some edits and additions B00daW from his Sleizsa-package v.0.3. |
Latest revision as of 13:48, 5 February 2020
This code is taken from cart #24. It plays a song from memory using the address stored in DC0. It starts a loop through the data, taking two bytes at a time; the first is the duration of the note, and the second is the frequency. It outputs it through the ports, delays, and takes another two bytes. If it finds the duration byte is equal to 0, it exits, so a 0 byte marks the end of a song. If it finds the frequency byte is 255, it instead generates a pause for the specified duration. (note: using a frequency of 254 or 255 otherwise outputs the same note) The pausing functionality isn't in the original disassembly, but was added afterwards.
Second version has some edits and additions B00daW from his Sleizsa-package v.0.3.
;-----------; ; Play Song ; ;-----------; ; plays a song from memory ; song address stored in DC0 ; uses r3, r4, r5, r7 playSong: ; taken from Pro Football lis 3 ; A = 3 lr 4, A ; A -> r4, r4 = 3 .playSongDelay1: inc ; increase A bnz .playSongDelay1 ; [Branch if not zero] back to .psdly1 am ; Memory adressed by DC0 is added to A, flags set - get duration data lr 7, A ; A -> r7 bz .playSongEnd ; Go to end if zero lm ; Load memory into A (adressed by DC0) - get frequency data lr 5, A ; A -> r5 ; check to see if we should pause inc bnc .playSongLoop ; it didn't roll over, play a note instead .playSongPause: li $ff lr 6, A .playSongPauseLoop: ds 6 ; pause counter bnz .playSongPauseLoop ds 7 ; duration of the pause bnz .playSongPause ; play the next note br playSong .playSongLoop: li $80 ; A= $80 outs 5 ; Send A -> port 5 lr A, 5 ; r5 -> A .playSongDelay2: inc ; increase A bnz .playSongDelay2 ; [Branch if not zero] back to .psdly2 outs 5 ; A -> port 5 lr A, 5 ; r5 -> A .playSongDelay3: inc ; increase A bnz .playSongDelay3 ; [Branch if not zero] back to .psdly3 ds 4 ; decrease r4 bnz .playSongLoop ; [Branch if not zero] back to .psloop lis 3 ; A = 3 lr 4, A ; A -> r4 ds 7 ; decrease r7 bnz .playSongLoop ; [Branch if not zero] back to .psloop br playSong ; start over - branch to beginning .playSongEnd: pop ; return from the subroutine
Sleizsa-version: ;--------------------------------------------------------------------------- ; Play Song Routine / Visuals ;--------------------------------------------------------------------------- ; plays a song from a memory location stored in DC0 ; (taken from Pro Football) ; ; r0 = unused ; r1 = noise value ; r2 = octave set value ; r3 = octave set value copy ; r4 = delay/tempo ; r5 = delay/tempo copy ; r6 = frequency/pitch ; r7 = pulse value ; r8 = note/rest length ; ; **Leave this Alone!** playSong: .playSongDelay1: inc ; increase A bnz .playSongDelay1 ; [Branch if not zero] back to .psdly1 am ; memory addressed by DC0 is added to A, flags set - get duration lr 8, A ; store note/rest length bz .playSongEnd ; go to end if zero lm ; load memory into A (addressed by DC0) - get frequency lr 6, A ; store frequency ; check to see if we should delay inc ; increment A to see if 255 (rest) supplied bnc .playSongLoop ; if it didn't wrap, play notes .playSongPause: clr ; A = $00 .playSongPauseLoop: inc ; increment A as "rest counter" bnc .playSongPauseLoop ; loop until counter wraps ds 8 ; decrement duration of the pause bnz .playSongPause ; rest until note/rest length counter depleted ; play the next note br playSong ; loop back and fetch more data .playNoise lr A, (IS) xs 6 sl 1 xs 1 lr 6, A br .playSound .playSongLoop lr A, 7 ; A = instrument value ci $F0 ; instrument = $F0 (noise)? bz .playNoise ; if so, play noise. if not, pulse. .playSound outs 5 ; send A -> port 5 (to make sound) lr A, 6 ; load frequency .playSongDelay2: inc ; increment A as "frequency speed" bnz .playSongDelay2 ; loop until frequency rate met outs 5 ; send A -> port 5 (to make sound) lr A, 6 ; exchange pitch values to A ds 2 ; decrement delay for lower octaves bnz .playSongLoop ; if so, loop. lr A, 3 lr 2, A ; restore original "octave" value lr A, 6 ; exchange pitch values to A .playSongDelay3: inc ; increase A bnz .playSongDelay3 ds 4 ; decrement delay for "tempo" bnz .playSongLoop ; if so, loop. lr A, 5 lr 4, A ; restore original "tempo" value ds 8 ; decrement note/rest delay bnz .playSongLoop br playSong ; start over - branch to beginning .playSongEnd: pop ; return from the subroutine
How does it sound?
Second generation PAL and NTSC machines differ a little in clock frequency, the values doesn't match for both machines. Here's a table for PAL with the frequency contents of each value in this playSong routine, the step size increases the further up you go:
F8-Value frequency note (Hz) 1 197.63 G3+14 2 194.17 -16 3 194.88 -9 4 195.62 -6 5 196.36 +3 6 197.31 +11 7 198.06 +18 8 198.82 +24 9 199.58 +31 10 200.34 +37 11 201.32 +46 12 202.09 G#3-47 13 202.87 -40 14 203.66 -33 15 204.44 -27 16 205.43 -18 17 206.23 -11 18 207.03 -5 19 208.05 +3 20 208.85 +9 21 209.68 +16 22 210.50 +23 23 211.53 +32 24 212.36 +38 25 213.20 +45 26 214.25 A3-45 27 215.10 -38 28 216.16 -30 29 217.02 -23 30 217.89 -16 31 218.97 -8 32 219.85 -1 33 221.12 +8 34 221.83 +14 35 222.93 +22 36 223.83 +29 37 224.94 +38 38 225.86 +45 39 226.61 A#3-48 40 227.76 -39 41 228.94 -31 42 229.91 -23 43 231.03 -15 44 232.06 -7 45 233.09 +0 46 234.41 +9 47 235.39 +17 48 236.46 +24 49 237.69 +33 50 238.60 +40 51 239.72 +48 52 241.06 B3-41 53 242.09 -34 54 243.17 -26 55 244.55 -16 56 245.88 -7 57 247.09 +1 58 248.06 +7 59 249.40 +17 60 250.74 +26 61 252.01 +35 62 253.41 +44 63 254.58 C4-47 64 255.97 -37 65 257.28 -28 66 258.61 -20 67 260.11 -10 68 260.80 -5 69 262.62 +6 70 263.99 +15 71 265.51 +25 72 266.85 +34 73 268.34 +43 74 269.98 C#4-45 75 271.49 -35 76 272.91 -26 77 274.39 -17 78 276.04 -7 79 277.44 +1 80 278.97 +11 81 280.49 +20 82 282.25 +31 83 283.75 +40 84 285.51 D4-48 85 287.00 -39 86 288.89 -28 87 290.33 -19 88 292.27 -8 89 293.77 +0 90 295.71 +12 91 297.24 +20 92 299.21 +32 93 301.09 +43 94 302.64 D#4-47 95 304.67 -36 96 306.47 -26 97 308.54 -14 98 310.46 -3 99 312.04 +5 100 314.46 +18 101 316.09 +27 102 317.90 +37 103 320.07 +49 104 322.15 E4-39 105 324.20 -28 106 326.63 -15 107 328.88 -3 108 331.21 +8 109 332.87 +16 110 335.47 +30 111 337.60 +41 112 339.61 F4-48 113 342.17 -35 114 344.80 -22 115 346.89 -11 116 349.52 +1 117 352.10 +14 118 354.48 +25 119 357.00 +38 120 359.81 F#4-48 121 362.28 -36 122 364.54 -25 123 367.24 -12 124 370.34 +1 125 373.13 +14 126 375.88 +27 127 378.97 +41 128 382.00 G4-44 129 385.09 -30 130 387.80 -18 131 390.64 -5 132 393.93 +8 133 397.12 +22 134 400.21 +35 135 402.77 +46 136 406.64 G#4-36 137 410.17 -21 138 412.97 -9 139 416.96 +6 140 420.36 +20 141 424.09 +36 142 427.67 A4-49 143 431.23 -34 144 435.11 -19 145 438.92 -4 146 443.29 +12 147 447.12 +27 148 449.97 +38 149 455.10 A#4-41 150 459.31 -25 151 463.47 -10 152 468.12 +7 153 472.46 +23 154 477.27 +40 155 481.98 B4-42 156 486.27 -26 157 491.54 -8 158 496.25 +8 159 500.77 +23 160 506.17 +42 161 511.54 C5-39 162 517.05 -20 163 522.58 -2 164 528.02 +15 165 533.80 +34 166 539.37 C#5-47 167 544.95 -29 168 550.92 -10 169 556.89 +7 170 564.15 +30 171 570.45 +49 172 577.08 D5-30 173 583.86 -10 174 591.05 +10 175 597.40 +29 176 604.65 D#5-49 177 612.17 -28 178 620.08 -6 179 628.17 +16 180 636.08 +38 181 644.40 E5-39 182 652.50 -17 183 661.27 +5 184 670.35 +28 185 679.88 F5-46 186 689.31 -22 187 689.90 +1 188 708.89 +25 189 719.03 F#5-49 190 729.74 -24 191 740.57 +1 192 751.86 +27 193 763.37 G5-46 194 774.81 -20 195 787.47 +7 196 799.71 +34 197 813.22 G#5-36 198 846.49 -8 199 840.01 +19 200 854.95 A5-49 201 869.59 -20 202 885.80 +11 203 901.40 +41 204 917.70 A#5-27 205 935.11 +5 206 953.14 +38 207 972.19 B5-27 208 990.96 +5 209 1011.8 +41 210 1033.1 C6-22 211 1054.8 +13 212 1077.7 C#6-49 213 1101.8 -10 214 1126.7 +27 215 1152.5 D6-33 216 1180.0 +7 217 1208.8 +49 218 1239.1 D#6-7 219 1270.7 +36 220 1303.8 E6-19 221 1338.8 +26 222 1375.8 F6-26 223 1414.1 +21 224 1455.2 F#6-29 225 1500.3 +23 226 1547.4 G6-22 227 1597.1 +31 228 1650.3 G#6-11 229 1705.5 +45 230 1767.4 A6+7 231 1830.0 A#6-32 232 1900.6 +33 233 1976.0 B6+0 234 2028.5 +45 235 2146.9 C7+44 236 2245.9 C#7+22 237 2350.1 D7+0 238 2467.3 D#7-15 239 2597.1 E7-26 240 2739.8 F7-33 241 2899.9 F#7-35 242 3080.9 G7-30 243 3281.5 G#7-21 244 3515.6 A7-2 245 3781.4 A#7+24 246 4096.3 C8-38 247 4462.4 C#8+10 248 4907.9 D#8-24 249 5445.5 F8-44 250 6107.0 G8-46 251 6969.4 A8-17 252 8100.4 B8+42 253 9677.9 D#9-49 254 12022.0 F#9+26
See Also
- Music_60.h - Contains the correct frequency and duration for notes ranging from G3-G5 in the form of DASM macros, to make song writing easier.