; ; Disassembly of CD System Card - bank 2 ; PSG_ON ; ; ; ZP & BSS usage: ; ; $e7 - bitmap: ; bit 7 = inhibit flag ; bit 0 = trigger; TIMER = 0, VSYNC = 1 ; ; $e8-9 - used as pointer within per-voice track data ; $ea-b - used as pointer for per-voice stack and evelope data ; ; $22d0-1 = Track header pointer ; $22d2-3 = Wave Data header pointer ; $22d4 = Tempo data (delay from index @ $d7c4) ; $22d5-6 = Envelope header pointer ; $22d7-8 = FM header pointer ; $22d9-a = Pitch Envelope header pointer ; $22db-c = Percussion data header pointer ; $22dd = main track delay counter (# interrupts to get a 60Hz timebase, minus 1) ; $22de = main track/subtrack control ; bit 7 = main track pause ; bit 6 = subtrack pause ; bit 2-0 = up-counter to count to $22dd value (IRQ counter for main track) ; $22df = PSG_INIT parameter (ie. 0 = main track only; 1 = subtrack only) ; $22e0 = current voice # (index, 0 through 5) ; $22e1 = song number to play (from PSG_PLAY) (bit $80 set if already started) ; $22e2 = debug mode (from PSG_PLAY) ; $22eb-c = PSG bank numbers in use ; ; "MAIN TRACK" per-voice variables: ; --------------------------------- ; $22ee (6 bytes) = Track pointer (LOW) ; $22f4 (6 bytes) = Track pointer (HIGH) ; $22fa (6 bytes) = Octave number ; $2300 (6 bytes) = frequency data (LOW) ; $2306 (6 bytes) = frequency data (HIGH) ; $230c (6 bytes) = Current note duration (countdown) ; $2312 (6 bytes) = Per-channel volume (reverse; (value-#$1F) ) ; $2318 (6 bytes) = Key on/off ratio (reverse; (8-value) ) ; $231e (6 bytes) = Key on duration (countdown) (reverse; (8-value) ) ; $2324 (6 bytes) = 'Save point' (LOW) ; $232a (6 bytes) = 'Save point' (HIGH) ; $2330 (6 bytes) = Transpose (value * 2) ; $2336 (6 bytes) = Duration multiplier ; $233c (6 bytes) = Envelope pointer (LOW) ; $2342 (6 bytes) = Envelope pointer (HIGH) ; $2348 (6 bytes) = Envelope pointer offset index ; $234e (6 bytes) = Envelope 'level data' ($FC) (LOW) ; $2354 (6 bytes) = Envelope 'level data' ($FC) (HIGH) ; $235a (6 bytes) = Envelope 'duration data' ($00-$FA) (LOW) ; $2360 (6 bytes) = Envelope 'duration data' ($00-$FA) (HIGH) ; $2366 (6 bytes) = Attack/release rate (LOW) (reset by set envelope & set mode) ; $236c (6 bytes) = Attack/release rate (HIGH) (reset by set envelope & set mode) ; $2372 (6 bytes) = Envelope 'duration command' ($00-$FA) ; $2378 (6 bytes) = FM effect pointer (LOW) ; $237e (6 bytes) = FM effect pointer (HIGH) ; $2384 (6 bytes) = FM effect pointer offset index ; $238a (6 bytes) = FM Delay ; $2390 (6 bytes) = FM Delay countdown ; $2396 (6 bytes) = FM Correction ; $239c (6 bytes) = Pitch Envelope pointer (LOW) ; $23a2 (6 bytes) = Pitch Envelope pointer (HIGH) ; $23a8 (6 bytes) = Pitch Envelope pointer offset index ; $23ae (6 bytes) = Pitch Envelope Delay ; $23b4 (6 bytes) = Pitch Envelope Delay countdown ; $23ba (6 bytes) = Detune ; $23c0 (6 bytes) = Volume change amount (reset at volume set) ; $23c6 (6 bytes) = Minor volume change accum. (top bit triggers 1 bit vol. chg) ; $23cc (6 bytes) = Pan pot right change (reset during pan pot set) ; $23d2 (6 bytes) = Minor pan pot right change accum. (top bit triggers 1 bit chg) ; $23d8 (6 bytes) = Pan pot left change (reset during pan pot set) ; $23de (6 bytes) = Minor pan pot left change accum. (top bit triggers 1 bit chg) ; $23e4 (6 bytes) = Sweep ; $23ea (6 bytes) = Sweep amount (LSB) ; $23f0 (6 bytes) = Sweep amount (MSB) ; $23f6 (6 bytes) = Sweep time ; $23fc (6 bytes) = Sweep time countdown ; $2402 (6 bytes) = Percussion 'sub-track' pointer (LOW) ; $2408 (6 bytes) = Percussion 'sub-track' pointer (HIGH) ; $240e (12 bytes) = stack frame, voice 0 ; $241a (12 bytes) = stack frame, voice 1 ; $2426 (12 bytes) = stack frame, voice 2 ; $2432 (12 bytes) = stack frame, voice 3 ; $243e (12 bytes) = stack frame, voice 4 ; $244a (12 bytes) = stack frame, voice 5 ; $2456 (6 bytes) = stack/misc per voice (top 4 bits = mode; bottom 4 bits = frame offset) ; $245c (6 bytes) = direct tone (LSB) ; $2462 (6 bytes) = direct tone (MSB - only 4 bits) ; $2468 (6 bytes) = final volume (post-envelope) ; $246e (6 bytes) = Pan pot value per voice ; $2474 (6 bytes) = Waveform per voice (if bit $80 reset, then download waveform) ; $247a/b = noise frequency ($80 if disabled). Only for the two noise voices ; $247c (6 bytes) = Per-voice control. Values: ; 0 = voice off ; 1 = voice on ; 2 = data-end condition ; ff = suspend ; $2482 (6 bytes) = envelope transition phase: ; 0=complete ; 1=regular ; 2=initial strike ; 3=initial strike, 'tie' (ie. reset key on/off ratio to full on) ; bit $80 set indicates 'key released' condition ; $2488 = PSG_FADEOUT value (abs val) ; $2489 = fadeout volume change register ; $248a = fadeout volume attenuation register ; ; ; "SUB TRACK" per-voice variables: ; -------------------------------- ; $248b (6 bytes) = Track pointer (LOW) ; $2491 (6 bytes) = Track pointer (HIGH) ; $2497 (6 bytes) = Octave number ; $249d (6 bytes) = frequency data (LOW) ; $24a3 (6 bytes) = frequency data (HIGH) ; $24a9 (6 bytes) = Current note duration (countdown) ; $24af (6 bytes) = Per-channel volume (reverse; (value-#$1F) ) ; $24b5 (6 bytes) = Key on/off ratio (reverse; (8-value) ) ; $24bb (6 bytes) = Key on duration (countdown) (reverse; (8-value) ) ; $24c1 (6 bytes) = 'Save point' (LOW) ; $24c7 (6 bytes) = 'Save point' (HIGH) ; $24cd (6 bytes) = Transpose (value * 2) ; $24d3 (6 bytes) = Duration multiplier ; $24d9 (6 bytes) = Envelope pointer (LOW) ; $24df (6 bytes) = Envelope pointer (HIGH) ; $24e5 (6 bytes) = Envelope pointer offset index ; $24eb (6 bytes) = Envelope 'level data' ($FC) (LOW) ; $24f1 (6 bytes) = Envelope 'level data' ($FC) (HIGH) ; $24f7 (6 bytes) = Envelope 'duration data' ($00-$FA) (LOW) ; $24fd (6 bytes) = Envelope 'duration data' ($00-$FA) (HIGH) ; $2503 (6 bytes) = Attack/release rate (LOW) (reset by set envelope & set mode) ; $2509 (6 bytes) = Attack/release rate (HIGH) (reset by set envelope & set mode) ; $250f (6 bytes) = Envelope 'duration command' ($00-$FA) ; $2515 (6 bytes) = FM effect pointer (LOW) ; $251b (6 bytes) = FM effect pointer (HIGH) ; $2521 (6 bytes) = FM effect pointer offset index ; $2527 (6 bytes) = FM Delay ; $252d (6 bytes) = FM Delay countdown ; $2533 (6 bytes) = FM Correction ; $2539 (6 bytes) = Pitch Envelope pointer (LOW) ; $253f (6 bytes) = Pitch Envelope pointer (HIGH) ; $2545 (6 bytes) = Pitch Envelope pointer offset index ; $254b (6 bytes) = Pitch Envelope Delay ; $2551 (6 bytes) = Pitch Envelope Delay countdown ; $2557 (6 bytes) = Detune ; $255d (6 bytes) = Volume change amount (reset at volume set) ; $2563 (6 bytes) = Minor volume change accum. (top bit triggers 1 bit vol. chg) ; $2569 (6 bytes) = Pan pot right change (reset during pan pot set) ; $256f (6 bytes) = Minor pan pot right change accum. (top bit triggers 1 bit chg) ; $2575 (6 bytes) = Pan pot left change (reset during pan pot set) ; $257b (6 bytes) = Minor pan pot left change accum. (top bit triggers 1 bit chg) ; $2581 (6 bytes) = Sweep ; $2587 (6 bytes) = Sweep Amount (LSB) ; $258d (6 bytes) = Sweep Amount (MSB) ; $2593 (6 bytes) = Sweep time ; $2599 (6 bytes) = Sweep time countdown ; $259f (6 bytes) = percussion 'sub-track' pointer (LOW) ; $25a5 (6 bytes) = percussion 'sub-track' pointer (HIGH) ; $25ab (9 bytes) = stack frame, voice 0 ; $25b4 (9 bytes) = stack frame, voice 1 ; $25bd (9 bytes) = stack frame, voice 2 ; $25c6 (9 bytes) = stack frame, voice 3 ; $25cf (9 bytes) = stack frame, voice 4 ; $25d8 (9 bytes) = stack frame, voice 5 ; $25e1 (6 bytes) = stack/misc per voice (top 4 bits = mode; bottom 4 bits = frame offset) ; $25e7 (6 bytes) = direct tone (LSB) ; $25ed (6 bytes) = direct tone (MSB - only 4 bits) ; $25f3 (6 bytes) = final volume (post-envelope) ; $25f9 (6 bytes) = Pan pot value per voice ; $25ff (6 bytes) = Waveform per voice (if bit $80 reset, then download waveform) ; $2605/6 = noise frequency ($80 if disabled). Only for the two noise voices ; $2607 (6 bytes) = Per-voice control. Values: ; 0 = voice off ; 1 = voice on ; 2 = data-end condition ; ff = suspend ; $260d (6 bytes) = envelope transition phase: ; 0=complete ; 1=regular ; 2=initial strike ; 3=initial strike, 'tie' (ie. reset key on/off ratio to full on) ; bit $80 set indicates 'key released' condition ; $2613 = PSG_FADEOUT value (abs val) ; $2614 = fadeout volume change register ; $2615 = fadeout volume attenuation register ; ; ; PSG_ON ; c000: a5 e7 LDA $e7 c002: 30 03 BMI $c007 ; if upper bit of $e7 is set, don't call PSG_OFF first c004: 20 19 c0 JSR $c019 ; PSG_OFF c007: a5 f8 LDA $f8 ; parameter: (0:TIMER interrupt; 1: VSYNC) c009: 29 01 AND #$01 c00b: 09 80 ORA #$80 c00d: 85 e7 STA $e7 ; ($e7) = 0x80 + ((_al) & 1 ) ; player is on, but inhibited c00f: 29 01 AND #$01 c011: d0 05 BNE $c018 c013: a9 01 LDA #$01 ; if (_al) & 1 == 0 then ($0c01) = 1 c015: 8d 01 0c STA $0c01 ; i.e. launch timer c018: 60 RTS ; ; PSG_OFF ; c019: a5 e7 LDA $e7 c01b: 30 03 BMI $c020 ; if ($e7) & 0x80, don't first Astop (? A for Audio ?) c01d: 20 21 c2 JSR $c221 ; PSG_ASTOP c020: a5 e7 LDA $e7 c022: 29 01 AND #$01 c024: d0 03 BNE $c029 c026: 9c 01 0c STZ $0c01 ; if ($e7) & 1 == 0, ($0c01) = 0 ; i.e. stop timer c029: 60 RTS c02a: 43 44 2d 52 4f 4d 20 c4 de d7 b2 ca de b0 ... c038: 20 42 59 20 4c 55 2e 20 ds "CD-ROM PSG (do ra i ba --) BY LU. " ; certainly "CD-ROM PSG DRIVER BY LU. " ; ; PSG_INIT ; ; input parameter values: ; 0: main track plays, subtrack off, 60Hz interrupt ; 1: subtrack plays, main track off, 60Hz interrupt ; 2: both tracks play, 60Hz interrupt ; 3: both tracks play, 120Hz interrupt ; 4: both tracks play, 240Hz interrupt ; 5: both tracks play, 300Hz interrupt ; c043: c9 06 CMP #$06 c045: 90 02 BCC $c049 c047: a9 02 LDA #$02 ; if A >= 6 then A = 2 c049: a8 TAY c04a: 43 40 TMA #$40 c04c: 48 PHA c04d: a9 02 LDA #$02 c04f: 53 40 TAM #$40 c051: a9 40 LDA #$40 c053: a2 05 LDX #$05 c055: 8e ed 22 STX $22ed ; ($22ed) = current voice c058: 8e 00 08 STX $0800 ; ($0800) = X ; i.e. chose channel from 5 downto 0 c05b: 8d 04 08 STA $0804 c05e: 9c 04 08 STZ $0804 ; this piece of code reset the read/write counter for wave c061: d3 a6 d9 06 08 20 00 TIN $d9a6, $0806, $0020 ; fill the wave pattern with a simple square pattern ; -----------+ ; | ; +----------- c068: ca DEX c069: 10 ea BPL $c055 ; repeat for each channel c06b: a9 ff LDA #$ff c06d: 8d 01 08 STA $0801 ; set volume to max on both side c070: a9 01 LDA #$01 c072: 8d 08 08 STA $0808 ; set LFO frequency to mini c075: 9c 09 08 STZ $0809 ; disable LFO usage c078: f3 c8 c0 d0 22 1e 00 TAI $c0c8, $22d0, $001e ; clear 14 bytes at $22d0 c07f: 73 c7 c0 e3 22 08 00 TII $c0c7, $22e3, $0008 ; init 8 bytes at $22e3 c086: 8c df 22 STY $22df ; ($22df) = initial value of A (when entering) c089: c0 01 CPY #$01 c08b: f0 09 BEQ $c096 c08d: f3 c8 c0 ee 22 9d 01 TAI $c0c8, $22ee, $019d ; if initial A != 1, clear 413 bytes ; from $22ee to $248a c094: 90 07 BCC $c09d c096: f3 c8 c0 8b 24 8b 01 TAI $c0c8, $248b, $018b ; if carry set (what does it mean ?) ; clear from $248b to $2615 c09d: 64 e8 STZ $e8 c09f: 64 e9 STZ $e9 c0a1: 64 ea STZ $ea ; init some variables c0a3: 64 eb STZ $eb c0a5: 64 e6 STZ $e6 c0a7: a5 e7 LDA $e7 c0a9: 09 80 ORA #$80 ; ($e7) |= 0x80 c0ab: 85 e7 STA $e7 c0ad: a9 80 LDA #$80 c0af: 8d e1 22 STA $22e1 ; ($22e1) = 0x80 (song # in track) c0b2: a9 c0 LDA #$c0 c0b4: 8d de 22 STA $22de ; ($22de) = 0xc0 c0b7: b9 cf c0 LDA $c0cf, Y c0ba: 8d dd 22 STA $22dd ; ($22dd) = ($c0cf + Y) c0bd: b9 d5 c0 LDA $c0d5, Y ; A = ($c0d5 + Y) c0c0: 20 28 c1 JSR $c128 ; PSG_TEMPO c0c3: 68 PLA c0c4: 53 40 TAM #$40 ; restore mapping c0c6: 60 RTS ; ; data for PSG_INIT ? ; c0c7: d3 .db $d3 c0c8: 00 .db $00 c0c9: 00 .db $00 c0ca: 06 .db $06 c0cb: 08 .db $08 c0cc: 20 .db $20 c0cd: 00 .db $00 c0ce: 60 .db $60 c0cf: 00 .db $00 ; TIMER counter c0d0: 00 .db $00 c0d1: 00 .db $00 c0d2: 01 .db $01 c0d3: 03 .db $03 c0d4: 04 .db $04 c0d5: 26 .db $26 ; default tempo control c0d6: 26 .db $26 c0d7: 26 .db $26 c0d8: 4d .db $4d c0d9: 9b .db $9b c0da: c3 .db $c3 ; ; PSG_BANK ; c0db: a5 f8 LDA $f8 c0dd: 8d eb 22 STA $22eb ; put (_AX) to ($22eb-$22ec) c0e0: a5 f9 LDA $f9 c0e2: 8d ec 22 STA $22ec c0e5: 60 RTS ; ; PSG_TRACK ; c0e6: a5 f8 LDA $f8 c0e8: 8d d0 22 STA $22d0 ; put (_AX) to ($22d0-$22d1) c0eb: a5 f9 LDA $f9 c0ed: 8d d1 22 STA $22d1 c0f0: 60 RTS ; ; PSG_WAVE ; c0f1: a5 f8 LDA $f8 c0f3: 8d d2 22 STA $22d2 ; put (_AX) to ($22d2-$22d3) c0f6: a5 f9 LDA $f9 c0f8: 8d d3 22 STA $22d3 c0fb: 60 RTS ; ; PSG_ENV ; c0fc: a5 f8 LDA $f8 c0fe: 8d d5 22 STA $22d5 ; put (_AX) to ($22d5-$22d6) c101: a5 f9 LDA $f9 c103: 8d d6 22 STA $22d6 c106: 60 RTS ; ; PSG_FM ; c107: a5 f8 LDA $f8 c109: 8d d7 22 STA $22d7 ; put (_AX) to ($22d7-$22d8) c10c: a5 f9 LDA $f9 c10e: 8d d8 22 STA $22d8 c111: 60 RTS ; ; PSG_PE ; c112: a5 f8 LDA $f8 c114: 8d d9 22 STA $22d9 ; put (_AX) to ($22d9-$22da) c117: a5 f9 LDA $f9 c119: 8d da 22 STA $22da c11c: 60 RTS ; ; PSG_PC ; c11d: a5 f8 LDA $f8 c11f: 8d db 22 STA $22db ; put (_AX) to ($22db-$22dc) c122: a5 f9 LDA $f9 c124: 8d dc 22 STA $22dc c127: 60 RTS ; ; PSG_TEMPO ; c128: aa TAX ; keep the arg in X c129: 43 40 TMA #$40 c12b: 48 PHA c12c: a9 02 LDA #$02 c12e: 53 40 TAM #$40 ; map the second bank to #$C000 c130: 8a TXA ; grab anew the argument in A c131: c9 23 CMP #$23 c133: b0 02 BCS $c137 ; here, A = min(A, #$23) c135: a9 23 LDA #$23 ; range = 35-255 c137: aa TAX c138: bd a1 d7 LDA $d7a1, X c13b: 8d d4 22 STA $22d4 ; ($22d4) = ($d7a1 + X) c13e: 68 PLA c13f: 53 40 TAM #$40 ; restore bank setting c141: 60 RTS ; ; PSG_PLAY ; c142: 8d e1 22 STA $22e1 ; store arg to ($22e1) c145: a5 f9 LDA $f9 c147: 8d e2 22 STA $22e2 ; store (_ah) to ($22e2) (debug mode) c14a: a5 e7 LDA $e7 c14c: 29 7f AND #$7f ; reset the upper bit of ($e7) c14e: 85 e7 STA $e7 c150: 60 RTS ; ; PSG_MSTAT ; "Main track check" ; c151: a9 80 LDA #$80 c153: ae df 22 LDX $22df c156: e0 01 CPX #$01 c158: f0 11 BEQ $c16b ; if ($22df) == 1, return 0x80 (ie. if subtrack only) c15a: a2 05 LDX #$05 c15c: 62 CLA c15d: bc 7c 24 LDY $247c, X c160: d0 04 BNE $c166 c162: 18 CLC c163: 2a ROL a ; show each voice's usage in bitmap (on/off) c164: 80 02 BRA $c168 ; return in bits 5-0 for voices 5-0 c166: 38 SEC c167: 2a ROL a c168: ca DEX c169: 10 f2 BPL $c15d c16b: 60 RTS ; ; PSG_SSTAT ; "Sub track check" ; c16c: a9 80 LDA #$80 c16e: ae df 22 LDX $22df c171: f0 11 BEQ $c184 ; if ($22df) == 0, return 0x80 (ie. if main track only) c173: a2 05 LDX #$05 c175: 62 CLA c176: bc 07 26 LDY $2607, X c179: d0 04 BNE $c17f c17b: 18 CLC c17c: 2a ROL a c17d: 80 02 BRA $c181 ; show each voice's usage in bitmap (on/off) c17f: 38 SEC ; return in bits 5-0 for voices 5-0 c180: 2a ROL a c181: ca DEX c182: 10 f2 BPL $c176 c184: 60 RTS ; ; PSG_MSTOP ; "Main track stop" ; c185: ae df 22 LDX $22df c188: e0 01 CPX #$01 c18a: f0 3d BEQ $c1c9 ; if ($22df) == 1, return now (ie. if subtrack only) c18c: a8 TAY ; store arg to Y c18d: 10 08 BPL $c197 c18f: ad de 22 LDA $22de c192: 09 80 ORA #$80 ; if upper bit of the arg is set, ($22de) |= 0x80 c194: 8d de 22 STA $22de ; "pause switch" c197: 82 CLX c198: bd 7c 24 LDA $247c, X ; if main track voice control is off, don't kill it c19b: f0 1e BEQ $c1bb c19d: 98 TYA ; branch if pause switch on c19e: 30 06 BMI $c1a6 c1a0: 4a LSR a ; stop bit not set; don't turn off voice c1a1: 90 18 BCC $c1bb c1a3: 9e 7c 24 STZ $247c, X ; stop voice sequencing c1a6: ad df 22 LDA $22df ; if ($22df) == 0 (ie. main track only), c1a9: f0 07 BEQ $c1b2 ; toggle the current chan off c1ab: bd 07 26 LDA $2607, X c1ae: c9 01 CMP #$01 ; if ($2607 + X) != 1, toggle Xth chan off c1b0: f0 09 BEQ $c1bb ; (ie. if subtrack not playing, turn off sound) c1b2: 8e ed 22 STX $22ed c1b5: 8e 00 08 STX $0800 ; toggle Xth chan off c1b8: 9c 04 08 STZ $0804 c1bb: 98 TYA c1bc: 4a LSR a c1bd: 89 40 BIT #$40 ; shift bitmask, but keep pause switch in bit $80) c1bf: f0 02 BEQ $c1c3 c1c1: 09 80 ORA #$80 c1c3: a8 TAY c1c4: e8 INX ; next voice c1c5: e0 06 CPX #$06 c1c7: 90 cf BCC $c198 c1c9: 60 RTS ; ; PSG_SSTOP ; "Sub track stop" ; c1ca: ae df 22 LDX $22df c1cd: f0 51 BEQ $c220 ; if ($22df) == 0, exit (ie. if main track only) c1cf: a8 TAY c1d0: 10 08 BPL $c1da c1d2: ad de 22 LDA $22de c1d5: 09 40 ORA #$40 ; set "pause switch" for subtrack c1d7: 8d de 22 STA $22de c1da: 82 CLX ; X is the current chan number c1db: bd 07 26 LDA $2607, X ; if subtrack voice control is off, don't kill it) c1de: f0 32 BEQ $c212 c1e0: 98 TYA ; branch if pause switch off c1e1: 10 07 BPL $c1ea c1e3: a9 ff LDA #$ff ; put $ff in voice control for pause c1e5: 9d 07 26 STA $2607, X c1e8: 80 06 BRA $c1f0 c1ea: 4a LSR a ; if no pause, check bits c1eb: 90 25 BCC $c212 c1ed: 9e 07 26 STZ $2607, X ; if bit on, stop sequencing voice c1f0: ad df 22 LDA $22df ; if subtrack only, kill sound c1f3: c9 01 CMP #$01 c1f5: f0 12 BEQ $c209 c1f7: bd 7c 24 LDA $247c, X ; if main track off, kill sound c1fa: f0 0d BEQ $c209 c1fc: bd 74 24 LDA $2474, X ; reset waveform on main track c1ff: 29 7f AND #$7f c201: 9d 74 24 STA $2474, X c204: ad de 22 LDA $22de ; if main channel paused, don't kill sound c207: 10 09 BPL $c212 c209: 8e ed 22 STX $22ed c20c: 8e 00 08 STX $0800 c20f: 9c 04 08 STZ $0804 ; kill chan number X c212: 98 TYA ; shift & retain pause switch c213: 4a LSR a c214: 89 40 BIT #$40 c216: f0 02 BEQ $c21a c218: 09 80 ORA #$80 c21a: a8 TAY ; next voice c21b: e8 INX c21c: e0 06 CPX #$06 c21e: 90 bb BCC $c1db c220: 60 RTS ; ; PSG_ASTOP ; "All track stop" ; ; kill some chans (certainly the ones that are still active) c221: a5 e7 LDA $e7 c223: 09 80 ORA #$80 ; inhibit sound c225: 85 e7 STA $e7 c227: a9 c0 LDA #$c0 ; ($22de) = 0xc0 c229: 8d de 22 STA $22de ; pause main and sub tracks c22c: ac df 22 LDY $22df ; get PSG_INIT parameter c22f: a2 05 LDX #$05 ; X is the current chan number c231: c0 01 CPY #$01 c233: f0 05 BEQ $c23a ; if subtrack only, don't kill main track and goes to ; subtrack killing c235: 9e 7c 24 STZ $247c, X ; turn off main track c238: 90 03 BCC $c23d c23a: 9e 07 26 STZ $2607, X ; turn off subtrack c23d: 8e ed 22 STX $22ed c240: 8e 00 08 STX $0800 c243: 9c 04 08 STZ $0804 ; disable chan number X c246: ca DEX ; next voice c247: 10 e8 BPL $c231 c249: 60 RTS ; ; PSG_MVOFF ; "Main Track Volume cut" ; ; seems to kill some chans ; c24a: ae df 22 LDX $22df c24d: e0 01 CPX #$01 c24f: f0 2a BEQ $c27b ; if subtrack only, exit c251: 82 CLX ; X seems to be the current chan number c252: 4a LSR a ; if bit off, next voice c253: 90 21 BCC $c276 c255: bc 7c 24 LDY $247c, X c258: f0 1c BEQ $c276 ; if main voice off, skip work c25a: a0 ff LDY #$ff c25c: 42 SAY c25d: 9d 7c 24 STA $247c, X ; store 0xff (sound off) to control register c260: 42 SAY c261: ac df 22 LDY $22df ; if main track only, kill channel c264: f0 07 BEQ $c26d c266: bc 07 26 LDY $2607, X ; if subtrack playing, don't kill sound c269: c0 01 CPY #$01 c26b: f0 09 BEQ $c276 c26d: 8e ed 22 STX $22ed c270: 8e 00 08 STX $0800 c273: 9c 04 08 STZ $0804 ; disable channel number X c276: e8 INX ; next voice c277: e0 06 CPX #$06 c279: 90 d7 BCC $c252 c27b: 60 RTS ; ; PSG_CONT ; "continue" ; ; parameter: ; 0 = main track ; 1 = sub track ; 2 = both ; c27c: a8 TAY c27d: ad df 22 LDA $22df c280: c9 01 CMP #$01 c282: f0 1b BEQ $c29f ; if only subtrack sequencing, skip effort for main track c284: c0 01 CPY #$01 c286: f0 17 BEQ $c29f ; if only subtrack continue, also skip this part c288: a2 05 LDX #$05 ; loop voices c28a: bd 7c 24 LDA $247c, X ; if track is off, loop c28d: f0 05 BEQ $c294 c28f: a9 01 LDA #$01 ; put 1 here (ie. 'running') c291: 9d 7c 24 STA $247c, X c294: ca DEX ; next voice c295: 10 f3 BPL $c28a c297: ad de 22 LDA $22de ; turn off pause bit for main tracks c29a: 29 7f AND #$7f c29c: 8d de 22 STA $22de ; whatever values in ($22df) or the arg, we arrive there ... c29f: ad df 22 LDA $22df c2a2: f0 22 BEQ $c2c6 ; if only main track sequencing, skip subtrack effort c2a4: 98 TYA c2a5: f0 1f BEQ $c2c6 ; if only main track continue, also skip c2a7: a2 05 LDX #$05 ; loop through voices c2a9: bd 07 26 LDA $2607, X ; if track is off, loop c2ac: f0 0d BEQ $c2bb c2ae: a9 01 LDA #$01 ; restart voice c2b0: 9d 07 26 STA $2607, X c2b3: bd ff 25 LDA $25ff, X ; force waveform download again c2b6: 29 7f AND #$7f c2b8: 9d ff 25 STA $25ff, X c2bb: ca DEX ; next voice c2bc: 10 eb BPL $c2a9 c2be: ad de 22 LDA $22de ; turn off pause bit for subtracks c2c1: 29 bf AND #$bf c2c3: 8d de 22 STA $22de c2c6: a5 e7 LDA $e7 ; uninhibit sound c2c8: 29 7f AND #$7f c2ca: 85 e7 STA $e7 c2cc: 60 RTS ; ; PSG_FDOUT ; "fadeout" ; c2cd: ae df 22 LDX $22df c2d0: e0 01 CPX #$01 c2d2: f0 14 BEQ $c2e8 ; if subtrack only, return c2d4: 89 7f BIT #$7f c2d6: f0 10 BEQ $c2e8 ; if parm = 0, return c2d8: 9c 89 24 STZ $2489 c2db: 9c 8a 24 STZ $248a ; zeroes fadeout variables c2de: c9 00 CMP #$00 c2e0: 10 03 BPL $c2e5 ; if A < 0, then make an absolute value c2e2: 49 ff EOR #$ff c2e4: 1a INC a c2e5: 8d 88 24 STA $2488 ; ($2488) = absolute value of A ; ie. fadeout speed c2e8: 60 RTS ; ; PSG_DCNT ; "Main Track Delay counter set" ; c2e9: 29 07 AND #$07 c2eb: 8d dd 22 STA $22dd ; ($22dd) = arg & 7 c2ee: 60 RTS ; ; MAIN TRACK MUSIC DRIVER ; called from $e701 (00) ; c2ef: 20 30 c3 JSR $c330 ; check if song needs to be initialized c2f2: ad de 22 LDA $22de ; if main track is off, skip this section c2f5: 30 36 BMI $c32d c2f7: ee de 22 INC $22de ; count up & compare with $22dd value c2fa: 29 0f AND #$0f c2fc: cd dd 22 CMP $22dd c2ff: 90 2c BCC $c32d c301: a9 0f LDA #$0f ; OK, reset counter & do sequencing work now c303: 1c de 22 TRB $22de c306: a9 05 LDA #$05 ; loop through all 6 voices c308: 8d e0 22 STA $22e0 c30b: ae e0 22 LDX $22e0 ; voice # c30e: bd 7c 24 LDA $247c, X ; if main track voice is off, skip it c311: f0 0f BEQ $c322 c313: 20 e7 c3 JSR $c3e7 ; process byte codes c316: 20 5a c8 JSR $c85a ; adjust relative volume & pan left/right amounts c319: 20 53 c9 JSR $c953 ; process percussion c31c: 20 25 ca JSR $ca25 ; process envelope c31f: 20 13 cb JSR $cb13 ; process frequency effects c322: ce e0 22 DEC $22e0 ; next voice c325: 10 e4 BPL $c30b c327: 20 26 cc JSR $cc26 ; process fadeout volume adjustment c32a: 20 50 cc JSR $cc50 ; send data to hardware c32d: 4c 51 c1 JMP $c151 ; PSG_MSTAT ; ; check if song needs to be initialized ; c330: ad e1 22 LDA $22e1 ; song number c333: 10 01 BPL $c336 ; initial set song (ie. bit $80 not set) c335: 60 RTS ; ; initial setup for "set song" ; including voice mask and main track/subtrack ; c336: 0a ASL a ; make an offset c337: a8 TAY c338: ad d0 22 LDA $22d0 ; get track header pointer c33b: 85 ea STA $ea c33d: ad d1 22 LDA $22d1 c340: 85 eb STA $eb c342: b1 ea LDA ($ea), Y ; get song pointer within list of pointer c344: 85 e8 STA $e8 c346: c8 INY c347: b1 ea LDA ($ea), Y c349: 85 e9 STA $e9 c34b: b2 e8 LDA ($e8) ; get mask of voices from song header ; bit 7: 0= main track; 1= subtrack ; bit 6: 0= normal; 1= debug mode ; bit 5-0: voice in use c34d: 30 e6 BMI $c335 ; if most-significant bit set, return c34f: 85 ea STA $ea ; store voice mask c351: 85 eb STA $eb c353: c2 CLY c354: 82 CLX c355: 46 ea LSR $ea ; rotate through voices c357: 90 72 BCC $c3cb ; skip voice if bit off c359: a9 01 LDA #$01 c35b: 9d 7c 24 STA $247c, X ; per-voice control register c35e: 9d 0c 23 STA $230c, X ; current note duration (countdown) c361: 9e 82 24 STZ $2482, X ; ? (tie-related flag) c364: 9e 18 23 STZ $2318, X ; key on duration (same as 8/8 on ratio) c367: 9e 12 23 STZ $2312, X ; per-channel volume (same as 100%) c36a: 9e 8a 23 STZ $238a, X ; FM Delay c36d: 9e ae 23 STZ $23ae, X ; PE Delay c370: 9e 96 23 STZ $2396, X ; FM Correction c373: 9e ba 23 STZ $23ba, X ; Detune c376: 9e e4 23 STZ $23e4, X ; ? (sweep-related) c379: 9e f6 23 STZ $23f6, X ; Sweep time c37c: 9e 56 24 STZ $2456, X ; stack/misc c37f: 9e 30 23 STZ $2330, X ; Transpose c382: 9e c0 23 STZ $23c0, X ; Volume change amount c385: 9e cc 23 STZ $23cc, X ; Pan pot right change amount c388: 9e d8 23 STZ $23d8, X ; Pan pot left change amount c38b: 9e 36 23 STZ $2336, X ; Duration multiplier c38e: ad a1 d8 LDA $d8a1 ; envelope #0 c391: 9d 3c 23 STA $233c, X ; set as default envelope c394: ad a2 d8 LDA $d8a2 c397: 9d 42 23 STA $2342, X c39a: a9 84 LDA #$84 ; set default attack rate = $8400 c39c: 9d 6c 23 STA $236c, X c39f: a9 04 LDA #$04 ; default octave = 4 c3a1: 9d fa 22 STA $22fa, X c3a4: c8 INY c3a5: b1 e8 LDA ($e8), Y ; get address of voice track within song c3a7: 9d ee 22 STA $22ee, X ; set track pointer (LOW) c3aa: 9d 24 23 STA $2324, X ; and 'set point' (LOW) c3ad: c8 INY c3ae: b1 e8 LDA ($e8), Y c3b0: 9d f4 22 STA $22f4, X ; set track pointer (HIGH) c3b3: 9d 2a 23 STA $232a, X ; and 'set point' (HIGH) c3b6: a9 80 LDA #$80 c3b8: e0 04 CPX #$04 c3ba: 90 03 BCC $c3bf c3bc: 9d 76 24 STA $2476, X ; disable noise (if voice is noise-capable) c3bf: 9d 74 24 STA $2474, X ; disable waveform download c3c2: 6f eb 06 BBR6 $eb, $c3cb ; if bit 6 of voice mask reset ; ; if 'debug mode' (bit 6) is set, it forces a waveform # ; (from debug byte) into voice data ; c3c5: ad e2 22 LDA $22e2 ; debug waveform c3c8: 9d 74 24 STA $2474, X ; waveform per voice c3cb: e8 INX ; sequence to next voice c3cc: e0 06 CPX #$06 c3ce: 90 85 BCC $c355 c3d0: 9c 88 24 STZ $2488 ; PSG_FADEOUT value c3d3: 9c 8a 24 STZ $248a ; fade volume attenuation c3d6: a9 80 LDA #$80 c3d8: 0c e1 22 TSB $22e1 ; set top bit in 'song number' (ie. set and running) c3db: ad de 22 LDA $22de ; turn off main track pause flag & reset up-counter c3de: 29 70 AND #$70 c3e0: 0d dd 22 ORA $22dd c3e3: 8d de 22 STA $22de c3e6: 60 RTS ; ; Process byte codes ; c3e7: de 0c 23 DEC $230c, X ; decrement the countdown counter c3ea: f0 01 BEQ $c3ed ; process next byte if counted to zero c3ec: 60 RTS c3ed: 02 SXY c3ee: b9 ee 22 LDA $22ee, Y ; track pointer (LOW) per voice c3f1: 85 e8 STA $e8 c3f3: b9 f4 22 LDA $22f4, Y ; track pointer (HIGH) per voice c3f6: 85 e9 STA $e9 c3f8: b2 e8 LDA ($e8) ; read next bytecode c3fa: e6 e8 INC $e8 ; increment pointer c3fc: d0 02 BNE $c400 c3fe: e6 e9 INC $e9 c400: 48 PHA c401: c9 d0 CMP #$d0 ; is it tone, or metadata ? c403: 90 69 BCC $c46e ; tone c405: 38 SEC c406: e9 d0 SBC #$d0 ; metadata c408: 0a ASL a ; form offset into jump table c409: aa TAX c40a: 68 PLA c40b: 7c 0e JMP ($c40e, X) c40e: 59 c5 ; d0 - set duration c410: 63 c5 ; d1 - set octave 1 c412: 63 c5 ; d2 - set octave 2 c414: 63 c5 ; d3 - set octave 3 c416: 63 c5 ; d4 - set octave 4 c418: 63 c5 ; d5 - set octave 5 c41a: 63 c5 ; d6 - set octave 6 c41c: 63 c5 ; d7 - set octave 7 c41e: 6b c5 ; d8 - octave up c420: 74 c5 ; d9 - octave down c422: 7d c5 ; da - tie c424: 85 c5 ; db - set tempo c426: 97 c5 ; dc - set volume c428: a8 c5 ; dd - set pan pot c42a: b7 c5 ; de - set key on/off ratio c42c: c7 c5 ; df - relative volume c42e: f8 c3 ; e0 - unused (no operation) c430: de c5 ; e1 - "da se nio" c432: eb c5 ; e2 - "se nio" c434: f8 c5 ; e3 - repeat begin c436: 27 c6 ; e4 - repeat end c438: 53 c6 ; e5 - set timbre/wave c43a: 5b c6 ; e6 - set envelope c43c: ce c6 ; e7 - frequency modulated (?) c43e: ef c6 ; e8 - FM Delay c440: f7 c6 ; e9 - FM correction c442: 01 c7 ; ea - Pitch Envelope c444: 22 c7 ; eb - PE Delay c446: 2a c7 ; ec - Detune c448: 32 c7 ; ed - Sweep c44a: 3a c7 ; ee - sweep time c44c: 42 c7 ; ef - Jump c44e: 54 c7 ; f0 - Call c450: 81 c7 ; f1 - Return c452: a5 c7 ; f2 - Transpose c454: ae c7 ; f3 - Relative Transpose c456: be c7 ; f4 - Entire Transpose c458: d4 c7 ; f5 - volume change c45a: df c7 ; f6 - pan right change c45c: ea c7 ; f7 - pan left change c45e: f5 c7 ; f8 - set mode c460: f8 c3 ; f9 - unused (no operation) c462: f8 c3 ; fa - unused (no operation) c464: f8 c3 ; fb - unused (no operation) c466: f8 c3 ; fc - unused (no operation) c468: f8 c3 ; fd - unused (no operation) c46a: 16 c8 ; fe - fade out (no operation ????) c46c: 2e c8 ; ff - data end ; ; Tone Data Process ; c46e: be 36 LDX $2336, Y ; duration multiplier per voice c471: f0 13 BEQ $c486 ; if not set, get next byte as direct length c473: 29 0f AND $0f c474: 1a INC c475: d9 36 23 CMP $2336, Y c479: b0 01 BCS $c47c c47b: 22 SAX c47c: 85 ea STA $ea ; MAX(note dur'n, dur'n multiplier) c47e: 18 CLC c47f: ca DEX c480: f0 0c BEQ $c48e c482: 65 ea ADC $ea c484: 80 f9 BRA $c47f ; multiply by successive adding c486: b2 e8 LDA ($e8) ; get next byte as direct length c488: e6 e8 INC $e8 ; inc pointer c48a: d0 02 BNE $c48e c48c: e6 e9 INC $e9 c48e: 99 0c 23 STA $230c, Y ; store current note total duration c491: aa TAX c492: b2 e8 LDA ($e8) ; fetch next byte c494: 22 SAX c495: e0 da CPX #$da c497: f0 13 BEQ $c4ac ; tie - override key on/off ratio c499: 4a LSR a c49a: 4a LSR a c49b: 4a LSR a c49c: 85 ea STA $ea ; total duration/8 c49e: 38 SEC c49f: b9 0c 23 LDA $230c, Y ; total duration c4a2: be 18 23 LDX $2318, Y ; key on/off ratio c4a5: f0 05 BEQ $c4ac ; skip calculation if not set c4a7: e5 ea SBC $ea c4a9: ca DEX c4aa: 80 f9 BRA $c4a5 ; subtract 1/8's until ready c4ac: 99 1e 23 STA $231e, Y ; store 'key on' duration c4af: 68 PLA ; restore original tone c4b0: 29 f0 AND #$f0 ; get tone value c4b2: d0 04 BNE $c4b8 ; not a 'rest' c4b4: 62 CLA c4b5: 4c 4b c5 JMP $c54b ; 'rest' c4b8: 38 SEC c4b9: e9 10 SBC #$10 ; 0-relative note, still in $x0 format c4bb: 4a LSR a c4bc: 4a LSR a c4bd: 4a LSR a c4be: aa TAX ; form an offset (ie. for 2-byte ptr) c4bf: b9 56 24 LDA $2456, Y c4c2: 29 f0 AND #$f0 ; get voice's "mode" (0=music, 1=percussion; 2=noise) c4c4: 22 SAX c4c5: f0 38 BEQ $c4ff ; music c4c7: e0 10 CPX #$10 ; is it percussion ? c4c9: d0 1e BNE $c4e9 c4cb: 18 CLC ; percussion data c4cc: 6d db 22 ADC $22db ; index into percussion effect table c4cf: 85 ea STA $ea c4d1: 62 CLA c4d2: 6d dc 22 ADC $22dc c4d5: 85 eb STA $eb c4d7: b2 ea LDA ($ea) c4d9: 99 02 24 STA $2402, Y ; store percussion 'sub-track' pointer c4dc: e6 ea INC $ea c4de: d0 02 BNE $c4e2 c4e0: e6 eb INC $eb c4e2: b2 ea LDA ($ea) c4e4: 99 08 24 STA $2408, Y c4e7: 80 36 BRA $c51f c4e9: c0 04 CPY #$04 ; noise data c4eb: 90 12 BCC $c4ff ; no use if not noise-capable c4ed: 18 CLC c4ee: 79 30 23 ADC $2330, Y ; add transpose c4f1: 4a LSR a ; divide by 2 c4f2: 99 76 24 STA $2476, Y ; noise data in 247a/b c4f5: 80 28 BRA $c51f ; ; data - octave index offset (ie. note basis) ; c4f7: 00 c4f8: 18 c4f9: 30 c4fa: 48 c4fb: 60 c4fc: 78 c4fd: 90 c4fe: a8 c4ff: be fa 22 LDX $22fa, Y ; get octave number (must be > 0) c502: 18 CLC c503: 7d f6 c4 ADC $c4f6, X ; add octave basis (to note as index) c506: 79 30 23 ADC $2330, Y ; add transpose c509: aa TAX ; use as index c50a: bd 1a d7 LDA $d71a, X ; get frequency data c50d: 99 00 23 STA $2300, Y ; freq (LOW) c510: bd 1b d7 LDA $d71b, X c513: 99 06 23 STA $2306, Y ; freq (HIGH) c516: c0 04 CPY #$04 c518: 90 05 BCC $c51f ; go to c51f if not a noise-capable voice c51a: a9 80 LDA #$80 ; some sort of noise flag (no noise value) c51c: 99 76 24 STA $2476, Y ; actually 247a & 247b c51f: b9 82 24 LDA $2482, Y ; is it a 'tie' note ? c522: c9 03 CMP #$03 c524: d0 04 BNE $c52a ; no c526: a9 01 LDA #$01 ; yes... change bits c528: 80 21 BRA $c54b c52a: 62 CLA c52b: 99 84 23 STA $2384, Y ; FM-related ? c52e: 99 a8 23 STA $23a8, Y ; PE-related ? c531: 99 ea 23 STA $23ea, Y ; Sweep-related ? c534: 99 f0 23 STA $23f0, Y ; Sweep-related ? c537: b9 8a 23 LDA $238a, Y ; FM Delay c53a: 99 90 23 STA $2390, Y ; use as countdown c53d: b9 ae 23 LDA $23ae, Y ; PE Delay c540: 99 b4 23 STA $23b4, Y ; use as countdown c543: b9 f6 23 LDA $23f6, Y ; Sweep time c546: 99 fc 23 STA $23fc, Y ; use as countdown c549: a9 02 LDA #$02 c54b: 99 82 24 STA $2482, Y ; 'tie' flags c54e: a5 e8 LDA $e8 c550: 99 ee 22 STA $22ee, Y ; store pointers back c553: a5 e9 LDA $e9 c555: 99 f4 22 STA $22f4, Y c558: 60 RTS ; ; TRACK DATA BYTE CODE OPERATIONS ; ; $d0 - set duration, 0-15 ; c559: b2 e8 LDA ($e8) c55b: 29 0f AND #$0f c55d: 99 36 23 STA $2336, Y c560: 4c 34 c8 JMP $c834 ; ; $d1-$d7 - set octave 0-7 ; c563: 29 07 AND #$07 c565: 99 fa 22 STA $22fa, Y c568: 4c f8 c3 JMP $c3f8 ; ; $d8 - octave up ; c56b: ae e0 22 LDX $22e0 c56e: fe fa 22 INC $22fa, X c571: 4c f8 c3 JMP $c3f8 ; ; $d9 - octave down ; c574: ae e0 22 LDX $22e0 c577: de fa 22 DEC $22fa, X c57a: 4c f8 c3 JMP $c3f8 ; ; $da - tie ; c57d: a9 03 LDA #$03 c57f: 99 82 24 STA $2482, Y c582: 4c f8 c3 JMP $c3f8 ; ; $db - set tempo (35-255) ; c585: b2 e8 LDA ($e8) c587: c9 23 CMP #$23 c589: b0 02 BCS $c58d c58b: a9 23 LDA #$23 c58d: aa TAX c58e: bd a1 d7 LDA $d7a1, X c591: 8d d4 22 STA $22d4 c594: 4c 34 c8 JMP $c834 ; ; $dc - set volume ; ; weird; it sets volume to (value - $1f) ; c597: b2 e8 LDA ($e8) c599: 29 1f AND #$1f c59b: 38 SEC c59c: e9 1f SBC #$1f c59e: 99 12 23 STA $2312, Y c5a1: 62 CLA c5a2: 99 c0 23 STA $23c0, Y c5a5: 4c 34 c8 JMP $c834 ; ; $dd - set pan pot ; c5a8: b2 e8 LDA ($e8) c5aa: 99 6e 24 STA $246e, Y c5ad: 62 CLA c5ae: 99 cc 23 STA $23cc, Y c5b1: 99 d8 23 STA $23d8, Y c5b4: 4c 34 c8 JMP $c834 ; ; $de - set key on/key off ratio ; ; sets ratio to (8-value) ; c5b7: b2 e8 LDA ($e8) c5b9: 3a DEC a c5ba: 29 07 AND #$07 c5bc: 38 SEC c5bd: e9 08 SBC #$08 c5bf: 49 ff EOR #$ff c5c1: 99 18 23 STA $2318, Y c5c4: 4c 34 c8 JMP $c834 ; ; $df - relative volume ; c5c7: b9 12 23 LDA $2312, Y c5ca: 18 CLC c5cb: 72 e8 ADC ($e8) c5cd: 30 03 BMI $c5d2 c5cf: 62 CLA c5d0: 80 06 BRA $c5d8 c5d2: c9 e1 CMP #$e1 c5d4: b0 02 BCS $c5d8 c5d6: a9 e1 LDA #$e1 c5d8: 99 12 23 STA $2312, Y c5db: 4c 34 c8 JMP $c834 ; ; $e1 - Da Se Nyo ; ; continue from save point ; c5de: b9 24 23 LDA $2324, Y c5e1: 85 e8 STA $e8 c5e3: b9 2a 23 LDA $232a, Y c5e6: 85 e9 STA $e9 c5e8: 4c f8 c3 JMP $c3f8 ; ; $e2 - Se Nyo ; ; Save current spot as save point ; c5eb: a5 e8 LDA $e8 c5ed: 99 24 23 STA $2324, Y c5f0: a5 e9 LDA $e9 c5f2: 99 2a 23 STA $232a, Y c5f5: 4c f8 c3 JMP $c3f8 ; ; $e3 - repeat begin ; c5f8: 02 SXY c5f9: b2 e8 LDA ($e8) ; get # iterations c5fb: d0 02 BNE $c5ff c5fd: a9 02 LDA #$02 ; if 0, use 2 c5ff: 48 PHA c600: e6 e8 INC $e8 c602: d0 02 BNE $c606 c604: e6 e9 INC $e9 c606: 20 3d c8 JSR $c83d ; get stack frame fo voice c609: a5 e8 LDA $e8 c60b: 91 ea STA ($ea), Y ; store LOW(track_data_ptr) c60d: c8 INY c60e: a5 e9 LDA $e9 c610: 91 ea STA ($ea), Y ; store HIGH(track_data_ptr) c612: c8 INY c613: 68 PLA c614: 91 ea STA ($ea), Y ; store # iterations c616: c8 INY c617: 84 ea STY $ea ; store stack index c619: bd 56 24 LDA $2456, X c61c: 29 f0 AND #$f0 c61e: 05 ea ORA $ea c620: 9d 56 24 STA $2456, X ; put stack index here c623: 02 SXY c624: 4c f8 c3 JMP $c3f8 ; ; $e4 - repeat end ; c627: 02 SXY c628: 20 3d c8 JSR $c83d ; get stack frame c62b: 88 DEY c62c: b1 ea LDA ($ea), Y ; get #iter's c62e: 3a DEC a c62f: f0 10 BEQ $c641 ; done c631: 91 ea STA ($ea), Y ; dec # iter's c633: 88 DEY c634: b1 ea LDA ($ea), Y ; restore beginning of repeat location c636: 85 e9 STA $e9 c638: 88 DEY c639: b1 ea LDA ($ea), Y c63b: 85 e8 STA $e8 c63d: 02 SXY c63e: 4c f8 c3 JMP $c3f8 ; continue parsing c641: 88 DEY ; remove item from stack c642: 88 DEY c643: 84 ea STY $ea c645: bd 56 24 LDA $2456, X c648: 29 f0 AND #$f0 c64a: 05 ea ORA $ea c64c: 9d 56 24 STA $2456, X ; store new stack index c64f: 02 SXY c650: 4c f8 c3 JMP $c3f8 ; ; $e5 - set timbre/wave ; c653: b2 e8 LDA ($e8) c655: 99 74 24 STA $2474, Y c658: 4c 34 c8 JMP $c834 ; ; $e6 - set envelope ; c65b: 02 SXY c65c: b2 e8 LDA ($e8) ; get envelope number c65e: c9 10 CMP #$10 c660: b0 0e BCS $c670 ; >$10 is user envelope data c662: 0a ASL a ; make 2-byte offset c663: a8 TAY c664: b9 a1 d8 LDA $d8a1, Y ; get pointer for internal envelope data c667: 85 ea STA $ea c669: b9 a2 d8 LDA $d8a2, Y c66c: 85 eb STA $eb c66e: 80 1f BRA $c68f c670: 38 SEC c671: e9 10 SBC #$10 ; make it 0-relative c673: 0a ASL a ; make 2-byte offset c674: 18 CLC c675: 6d d5 22 ADC $22d5 ; add to user envelope pointer c678: 85 ea STA $ea c67a: 62 CLA c67b: 6d d6 22 ADC $22d6 c67e: 85 eb STA $eb c680: b2 ea LDA ($ea) ; get pointer to envelope data c682: a8 TAY c683: e6 ea INC $ea c685: d0 02 BNE $c689 c687: e6 eb INC $eb c689: b2 ea LDA ($ea) c68b: 85 eb STA $eb ; ($ea) points to envelope data now c68d: 84 ea STY $ea c68f: 9e 66 23 STZ $2366, X ; clear initial level (LOW) c692: 9e 6c 23 STZ $236c, X ; clear initial level (HIGH) c695: b2 ea LDA ($ea) c697: c9 fb CMP #$fb ; is first byte an attack level ? c699: d0 19 BNE $c6b4 c69b: a0 01 LDY #$01 ; yes - move value to $2366 and $236c c69d: b1 ea LDA ($ea), Y c69f: 9d 66 23 STA $2366, X c6a2: c8 INY c6a3: b1 ea LDA ($ea), Y c6a5: 9d 6c 23 STA $236c, X c6a8: a9 03 LDA #$03 c6aa: 18 CLC c6ab: 65 ea ADC $ea ; increase pointer c6ad: 85 ea STA $ea c6af: 62 CLA c6b0: 65 eb ADC $eb c6b2: 85 eb STA $eb c6b4: a5 ea LDA $ea c6b6: 9d 3c 23 STA $233c, X ; reset envelope pointer c6b9: a5 eb LDA $eb c6bb: 9d 42 23 STA $2342, X c6be: 9e 72 23 STZ $2372, X ; ? c6c1: 9e 54 23 STZ $2354, X ; ? c6c4: 9e 5a 23 STZ $235a, X ; ? c6c7: 9e 60 23 STZ $2360, X ; ? c6ca: 02 SXY c6cb: 4c 34 c8 JMP $c834 ; ; $e7 - frequency modulated ; c6ce: 02 SXY c6cf: b2 e8 LDA ($e8) c6d1: 0a ASL a ; turn value into offset (for 2-byte values) c6d2: a8 TAY c6d3: ad d7 22 LDA $22d7 ; base FM pointer location c6d6: 85 ea STA $ea c6d8: ad d8 22 LDA $22d8 c6db: 85 eb STA $eb c6dd: b1 ea LDA ($ea), Y ; get pointer to effect and save it at $2378 & $237e c6df: 9d 78 23 STA $2378, X c6e2: c8 INY c6e3: b1 ea LDA ($ea), Y c6e5: 9d 7e 23 STA $237e, X c6e8: 9e 84 23 STZ $2384, X ; ? c6eb: 02 SXY c6ec: 4c 34 c8 JMP $c834 ; ; $e8 - FM delay ; c6ef: b2 e8 LDA ($e8) c6f1: 99 8a 23 STA $238a, Y c6f4: 4c 34 c8 JMP $c834 ; ; $e9 - FM Correction ; c6f7: b2 e8 LDA ($e8) c6f9: 29 07 AND #$07 c6fb: 99 96 23 STA $2396, Y c6fe: 4c 34 c8 JMP $c834 ; ; $ea - Pitch Envelope ; c701: 02 SXY c702: b2 e8 LDA ($e8) c704: 0a ASL a ; turn value into offset (for 2-byte values) c705: a8 TAY c706: ad d9 22 LDA $22d9 ; base PE pointer location c709: 85 ea STA $ea c70b: ad da 22 LDA $22da c70e: 85 eb STA $eb c710: b1 ea LDA ($ea), Y ; get pointer and save it at $239c & $23a2 c712: 9d 9c 23 STA $239c, X c715: c8 INY c716: b1 ea LDA ($ea), Y c718: 9d a2 23 STA $23a2, X c71b: 9e a8 23 STZ $23a8, X ; ? c71e: 02 SXY c71f: 4c 34 c8 JMP $c834 ; ; $eb - PE Delay ; c722: b2 e8 LDA ($e8) c724: 99 ae 23 STA $23ae, Y c727: 4c 34 c8 JMP $c834 ; ; $ec - Detune ; c72a: b2 e8 LDA ($e8) c72c: 99 ba 23 STA $23ba, Y c72f: 4c 34 c8 JMP $c834 ; ; $ed - Sweep ; c732: b2 e8 LDA ($e8) c734: 99 e4 23 STA $23e4, Y c737: 4c 34 c8 JMP $c834 ; ; $ee - Sweep time ; c73a: b2 e8 LDA ($e8) c73c: 99 f6 23 STA $23f6, Y c73f: 4c 34 c8 JMP $c834 ; ; $ef - Jump ; c742: b2 e8 LDA ($e8) ; get next 2 bytes and move to track pointer c744: aa TAX c745: e6 e8 INC $e8 c747: d0 02 BNE $c74b c749: e6 e9 INC $e9 c74b: b2 e8 LDA ($e8) c74d: 85 e9 STA $e9 c74f: 86 e8 STX $e8 c751: 4c f8 c3 JMP $c3f8 ; ; $f0 - Call ; c754: 02 SXY c755: 20 3d c8 JSR $c83d ; get stack frame c758: a5 e8 LDA $e8 ; save return address c75a: 91 ea STA ($ea), Y c75c: c8 INY c75d: a5 e9 LDA $e9 c75f: 91 ea STA ($ea), Y c761: c8 INY c762: 84 ea STY $ea ; offset pointer c764: bd 56 24 LDA $2456, X ; store it back into offset pointer/mode register c767: 29 f0 AND #$f0 c769: 05 ea ORA $ea c76b: 9d 56 24 STA $2456, X c76e: b2 e8 LDA ($e8) ; get new address c770: a8 TAY c771: e6 e8 INC $e8 c773: d0 02 BNE $c777 c775: e6 e9 INC $e9 c777: b2 e8 LDA ($e8) c779: 85 e9 STA $e9 ; jump there c77b: 84 e8 STY $e8 c77d: 02 SXY c77e: 4c f8 c3 JMP $c3f8 ; ; $f1 - Return ; c781: 02 SXY c782: 20 3d c8 JSR $c83d ; get stack frame c785: 88 DEY c786: b1 ea LDA ($ea), Y ; restore return address c788: 85 e9 STA $e9 c78a: 88 DEY c78b: b1 ea LDA ($ea), Y c78d: 85 e8 STA $e8 c78f: 84 ea STY $ea c791: bd 56 24 LDA $2456, X ; store offset pointer again c794: 29 f0 AND #$f0 c796: 05 ea ORA $ea c798: 9d 56 24 STA $2456, X c79b: e6 e8 INC $e8 ; don't forget to add 2 to pointer - 1 here c79d: d0 02 BNE $c7a1 c79f: e6 e9 INC $e9 c7a1: 02 SXY c7a2: 4c 34 c8 JMP $c834 ; and this is an increment & jmp $c3f8 ; ; $f2 - Tranpose ; c7a5: b2 e8 LDA ($e8) c7a7: 0a ASL a c7a8: 99 30 23 STA $2330, Y ; store absolute transpose amount (as offset) c7ab: 4c 34 c8 JMP $c834 ; ; $f3 - Relative Transpose ; c7ae: b2 e8 LDA ($e8) c7b0: 0a ASL a c7b1: 85 ea STA $ea c7b3: b9 30 23 LDA $2330, Y ; add transpose amount to existing value (as offset) c7b6: 18 CLC c7b7: 65 ea ADC $ea c7b9: 99 30 23 STA $2330, Y c7bc: 80 76 BRA $c834 ; ; $f4 - Entire Transpose ; c7be: 5a PHY c7bf: b2 e8 LDA ($e8) c7c1: 0a ASL a c7c2: a8 TAY c7c3: a2 05 LDX #$05 ; for all of the voices, c7c5: bd 7c 24 LDA $247c, X ; check if voice is active c7c8: f0 04 BEQ $c7ce c7ca: 98 TYA c7cb: 9d 30 23 STA $2330, X ; if yes, set transpose amount c7ce: ca DEX c7cf: 10 f4 BPL $c7c5 ; and loop c7d1: 7a PLY c7d2: 80 60 BRA $c834 ; ; $f5 - Volume Change ; c7d4: b2 e8 LDA ($e8) c7d6: 99 c0 23 STA $23c0, Y ; set volume change amount c7d9: 62 CLA c7da: 99 c6 23 STA $23c6, Y ; ? c7dd: 80 55 BRA $c834 ; ; $f6 - Pan Right Change ; c7df: b2 e8 LDA ($e8) c7e1: 99 cc 23 STA $23cc, Y ; set Pan pot right change amount c7e4: 62 CLA c7e5: 99 d2 23 STA $23d2, Y ; ? c7e8: 80 4a BRA $c834 ; ; $f7 - Pan Left Change ; c7ea: b2 e8 LDA ($e8) c7ec: 99 d8 23 STA $23d8, Y ; set Pan pot left change amount c7ef: 62 CLA c7f0: 99 de 23 STA $23de, Y ; ? c7f3: 80 3f BRA $c834 ; ; $f8 - Change mode ; c7f5: b2 e8 LDA ($e8) c7f7: 0a ASL a ; shift mode left 4 bits c7f8: 0a ASL a c7f9: 0a ASL a c7fa: 0a ASL a c7fb: 85 ea STA $ea c7fd: b9 56 24 LDA $2456, Y ; and install in top 4 bits of stack offset/misc variable c800: 29 0f AND #$0f c802: 05 ea ORA $ea c804: 99 56 24 STA $2456, Y c807: b2 e8 LDA ($e8) c809: c9 01 CMP #$01 ; is it percussion ? c80b: d0 27 BNE $c834 ; no c80d: 62 CLA ; yes c80e: 99 66 23 STA $2366, Y ; reset envelope attack value c811: 99 6c 23 STA $236c, Y ; reset envelope attack value c814: 80 1e BRA $c834 ; ; $fe - Fade Out ; c816: b2 e8 LDA ($e8) c818: 89 7f BIT #$7f ; if zero, ignore c81a: f0 18 BEQ $c834 c81c: c9 00 CMP #$00 c81e: 10 03 BPL $c823 c820: 49 ff EOR #$ff ; if negative, negate (for absolute value) c822: 1a INC a c823: 8d 88 24 STA $2488 ; fadeout value c826: 9c 89 24 STZ $2489 ; fadeout volume change register c829: 9c 8a 24 STZ $248a ; fadeout volume attenuation register c82c: 80 06 BRA $c834 ; ; $ff - Data End ; c82e: a9 02 LDA #$02 c830: 99 7c 24 STA $247c, Y c833: 60 RTS ; ; Inc pointer & recycle ; (used for bytecdes with parameter values to read) ; c834: e6 e8 INC $e8 c836: d0 02 BNE $c83a c838: e6 e9 INC $e9 c83a: 4c f8 c3 JMP $c3f8 ; ; get stack frame & offset ; c83d: bd 4e c8 LDA $c84e, X c840: 85 ea STA $ea c842: bd 54 c8 LDA $c854, X c845: 85 eb STA $eb c847: bd 56 24 LDA $2456, X c84a: 29 0f AND #$0f c84c: a8 TAY c84d: 60 RTS ; ; data - stack frame address (LOW) per voice ; c84e: 0e c84f: 1a c850: 26 c851: 32 c852: 3e c853: 4a ; ; data - stack frame address (HIGH) per voice ; c854: 24 c855: 24 c856: 24 c857: 24 c858: 24 c859: 24 ; ; relative volume/pan pot change ; called from main track PSG driver ; c85a: ae e0 22 LDX $22e0 ; current voice c85d: bd c0 23 LDA $23c0, X ; volume change amount per voice c860: f0 44 BEQ $c8a6 ; no change c862: 30 18 BMI $c87c ; negative c864: 18 CLC c865: 7d c6 23 ADC $23c6, X ; minor volume change accum c868: 85 ea STA $ea c86a: 2a ROL a c86b: 2a ROL a c86c: 29 01 AND #$01 ; was bit $80 before rotate (ie. value >$80) c86e: 18 CLC c86f: 7d 12 23 ADC $2312, X ; per-channel volume c872: f0 28 BEQ $c89c ; max c874: 30 26 BMI $c89c ; regular range c876: 62 CLA ; too high; clip it to max ; recall that max = 0; min = -$1f) c877: 9e c0 23 STZ $23c0, X ; volume change amount per-voice c87a: 80 20 BRA $c89c c87c: 49 ff EOR #$ff ; negate value c87e: 1a INC a c87f: 18 CLC c880: 7d c6 23 ADC $23c6, X ; minor volume change accum c883: 85 ea STA $ea c885: 2a ROL a c886: 2a ROL a c887: 29 01 AND #$01 ; was bit $80 before rotate c889: 85 eb STA $eb c88b: bd 12 23 LDA $2312, X ; per-channel volume c88e: 38 SEC c88f: e5 eb SBC $eb c891: f0 09 BEQ $c89c c893: c9 e1 CMP #$e1 c895: b0 05 BCS $c89c c897: a9 e1 LDA #$e1 c899: 9e c0 23 STZ $23c0, X c89c: 9d 12 23 STA $2312, X ; per-channel volume c89f: a5 ea LDA $ea c8a1: 29 7f AND #$7f c8a3: 9d c6 23 STA $23c6, X ; minor volume change accum ; now do pan pot right adjust: c8a6: bd cc 23 LDA $23cc, X ; pan pot right change per voice c8a9: f0 51 BEQ $c8fc ; no change c8ab: 30 1f BMI $c8cc ; negative c8ad: 18 CLC c8ae: 7d d2 23 ADC $23d2, X ; minor pan pot right accum c8b1: 85 ea STA $ea c8b3: 2a ROL a c8b4: 2a ROL a c8b5: 29 01 AND #$01 ; if big enough, trigger volume change c8b7: 85 eb STA $eb c8b9: bd 6e 24 LDA $246e, X ; pan pot register c8bc: 29 0f AND #$0f ; right side c8be: 18 CLC c8bf: 65 eb ADC $eb c8c1: c9 10 CMP #$10 ; if range OK, go to $c8e9 c8c3: 90 24 BCC $c8e9 c8c5: a9 0f LDA #$0f ; fix level to max c8c7: 9e cc 23 STZ $23cc, X c8ca: 80 1d BRA $c8e9 c8cc: 49 ff EOR #$ff ; negate value (ie. make negative into positive) c8ce: 1a INC a c8cf: 18 CLC c8d0: 7d d2 23 ADC $23d2, X ; minor pan pot right accum c8d3: 85 ea STA $ea c8d5: 2a ROL a c8d6: 2a ROL a c8d7: 29 01 AND #$01 ; if big enough, trigger volume change c8d9: 85 eb STA $eb c8db: bd 6e 24 LDA $246e, X ; pan pot register c8de: 29 0f AND #$0f c8e0: 38 SEC c8e1: e5 eb SBC $eb ; subtract c8e3: d0 04 BNE $c8e9 c8e5: 62 CLA c8e6: 9e cc 23 STZ $23cc, X ; clear it c8e9: 85 eb STA $eb c8eb: bd 6e 24 LDA $246e, X ; put pan pot right value into combined register c8ee: 29 f0 AND #$f0 c8f0: 05 eb ORA $eb c8f2: 9d 6e 24 STA $246e, X c8f5: a5 ea LDA $ea c8f7: 29 7f AND #$7f c8f9: 9d d2 23 STA $23d2, X ; reset trigger bit on minor accumulator bit ; now do pan pot left adjust: c8fc: bd d8 23 LDA $23d8, X ; pan pot left change per voice c8ff: f0 51 BEQ $c952 ; no change c901: 30 1e BMI $c921 ; negative c903: 18 CLC c904: 7d de 23 ADC $23de, X ; minor pan pot left accum c907: 85 ea STA $ea c909: 29 80 AND #$80 ; if big enough c90b: 4a LSR a c90c: 4a LSR a c90d: 4a LSR a c90e: 85 eb STA $eb c910: bd 6e 24 LDA $246e, X ; pan pot register c913: 29 f0 AND #$f0 ; left side c915: 18 CLC c916: 65 eb ADC $eb c918: 90 25 BCC $c93f c91a: a9 f0 LDA #$f0 ; if overflow, reset to max c91c: 9e d8 23 STZ $23d8, X c91f: 80 1e BRA $c93f c921: 49 ff EOR #$ff ; negative value; get absolute val c923: 1a INC a c924: 18 CLC c925: 7d de 23 ADC $23de, X c928: 85 ea STA $ea c92a: 29 80 AND #$80 ; if big enough c92c: 4a LSR a c92d: 4a LSR a c92e: 4a LSR a c92f: 85 eb STA $eb c931: bd 6e 24 LDA $246e, X ; pan pot register c934: 29 f0 AND #$f0 ; left side c936: 38 SEC c937: e5 eb SBC $eb ; subtract c939: d0 04 BNE $c93f c93b: 62 CLA c93c: 9e d8 23 STZ $23d8, X ; clear it c93f: 85 eb STA $eb c941: bd 6e 24 LDA $246e, X ; put pan pot left value into combined register c944: 29 0f AND #$0f c946: 05 eb ORA $eb c948: 9d 6e 24 STA $246e, X c94b: a5 ea LDA $ea c94d: 29 7f AND #$7f c94f: 9d de 23 STA $23de, X ; reset trigger bit on minor accumulator bit c952: 60 RTS ; ; Percussion Sequencer ; called from main track PSG driver ; c953: ac e0 22 LDY $22e0 c956: b9 56 24 LDA $2456, Y c959: 29 f0 AND #$f0 c95b: c9 10 CMP #$10 ; is voice in percussion mode ? c95d: f0 01 BEQ $c960 ; if not, return c95f: 60 RTS c960: b9 82 24 LDA $2482, Y ; if tone = 'rest' c963: f0 fa BEQ $c95f c965: b9 02 24 LDA $2402, Y ; get percussion pointer c968: 85 e8 STA $e8 c96a: b9 08 24 LDA $2408, Y c96d: 85 e9 STA $e9 c96f: b2 e8 LDA ($e8) ; get bytecode c971: e6 e8 INC $e8 ; increment pointer c973: d0 02 BNE $c977 c975: e6 e9 INC $e9 c977: aa TAX c978: c9 b0 CMP #$b0 ; < $b0 c97a: 90 15 BCC $c991 c97c: 29 f0 AND #$f0 c97e: c9 b0 CMP #$b0 ; = $bx c980: f0 1a BEQ $c99c c982: c9 c0 CMP #$c0 ; = $cx c984: f0 3c BEQ $c9c2 c986: c9 d0 CMP #$d0 ; = $dx c988: f0 70 BEQ $c9fa c98a: c9 e0 CMP #$e0 ; = $ex c98c: f0 73 BEQ $ca01 c98e: 4c 08 ca JMP $ca08 ; = $fx c991: c0 04 CPY #$04 ; bytecode < $b0 (noise value, $00-$1f) c993: 90 22 BCC $c9b7 ; not a noise voice; return c995: 29 1f AND #$1f c997: 99 76 24 STA $2476, Y ; noise value c99a: 80 1b BRA $c9b7 c99c: 8a TXA ; = $bx (direct frequency, '$bx $yy'-> freq = $xyy) c99d: 38 SEC c99e: e9 b0 SBC #$b0 c9a0: 99 62 24 STA $2462, Y ; put in direct frequency register (top 4 bits) c9a3: b2 e8 LDA ($e8) ; get next byte c9a5: e6 e8 INC $e8 ; increment pointer c9a7: d0 02 BNE $c9ab c9a9: e6 e9 INC $e9 c9ab: 99 5c 24 STA $245c, Y ; put in direct frequency register (bottom 8 bits) c9ae: c0 04 CPY #$04 c9b0: 90 05 BCC $c9b7 ; not a noise register; return c9b2: a9 80 LDA #$80 ; disable noise value c9b4: 99 76 24 STA $2476, Y c9b7: a5 e8 LDA $e8 ; put back the percussion pointer c9b9: 99 02 24 STA $2402, Y c9bc: a5 e9 LDA $e9 c9be: 99 08 24 STA $2408, Y c9c1: 60 RTS c9c2: b2 e8 LDA ($e8) ; = $cx (envelope sequence, value $00-$7f) c9c4: c9 10 CMP #$10 ; get next byte c9c6: b0 10 BCS $c9d8 c9c8: 0a ASL a ; internal envelope definition c9c9: aa TAX c9ca: bd a1 d8 LDA $d8a1, X c9cd: 99 3c 23 STA $233c, Y ; put in envelope pointer c9d0: bd a2 d8 LDA $d8a2, X c9d3: 99 42 23 STA $2342, Y c9d6: 80 44 BRA $ca1c c9d8: 38 SEC ; external envelope definition c9d9: e9 10 SBC #$10 c9db: 0a ASL a c9dc: 18 CLC c9dd: 6d d5 22 ADC $22d5 ; add to user envelope pointer c9e0: 85 ea STA $ea c9e2: 62 CLA c9e3: 6d d6 22 ADC $22d6 c9e6: 85 eb STA $eb c9e8: b2 ea LDA ($ea) ; get pointer & put it in envelope location c9ea: 99 3c 23 STA $233c, Y c9ed: e6 ea INC $ea c9ef: d0 02 BNE $c9f3 c9f1: e6 eb INC $eb c9f3: b2 ea LDA ($ea) c9f5: 99 42 23 STA $2342, Y c9f8: 80 22 BRA $ca1c c9fa: b2 e8 LDA ($e8) ; = $dx c9fc: 99 6e 24 STA $246e, Y ; set pan pot value c9ff: 80 1b BRA $ca1c ca01: b2 e8 LDA ($e8) ; = $ex ca03: 99 74 24 STA $2474, Y ; set waveform ca06: 80 14 BRA $ca1c ca08: 62 CLA ; = $fx ca09: 99 82 24 STA $2482, Y ; 'tie' type = rest ca0c: a5 e8 LDA $e8 ca0e: 38 SEC ca0f: e9 01 SBC #$01 ca11: 99 02 24 STA $2402, Y ; decrement pointer (continue to point @ end) ca14: a5 e9 LDA $e9 ca16: e9 00 SBC #$00 ca18: 99 08 24 STA $2408, Y ca1b: 60 RTS ca1c: e6 e8 INC $e8 ; increment pointer & return for more ca1e: d0 02 BNE $ca22 ca20: e6 e9 INC $e9 ca22: 4c 6f c9 JMP $c96f ; ; Envelope processing ; called from main track PSG driver ; ca25: ae e0 22 LDX $22e0 ; current voice ca28: bd 82 24 LDA $2482, X ; envelope phase ca2b: d0 03 BNE $ca30 ca2d: 4c 9d ca JMP $ca9d ; finished ca30: 30 41 BMI $ca73 ; is key off ? ca32: c9 02 CMP #$02 ; initial strike ca34: f0 5f BEQ $ca95 ca36: de 1e 23 DEC $231e, X ; key on/off ratio ca39: d0 05 BNE $ca40 ; key on still ca3b: 09 80 ORA #$80 ; key off ca3d: 9d 82 24 STA $2482, X ca40: bd 72 23 LDA $2372, X ; envelope 'duration' command ca43: d0 02 BNE $ca47 ; execute it ca45: 80 6f BRA $cab6 ; no duration ; execute 'envelope duration command' ; ca47: bd 4e 23 LDA $234e, X ; take 'level data' ca4a: 18 CLC ca4b: 7d 5a 23 ADC $235a, X ; add 'duration data' ca4e: 9d 4e 23 STA $234e, X ca51: bd 54 23 LDA $2354, X ca54: 7d 60 23 ADC $2360, X ca57: 10 0b BPL $ca64 ; still in range (0-$7fff) ca59: 62 CLA ca5a: 9d 4e 23 STA $234e, X ; set LSB of level to 0 ca5d: bc 60 23 LDY $2360, X ; MSB of duration data ca60: 30 02 BMI $ca64 ca62: a9 7c LDA #$7c ca64: 9d 54 23 STA $2354, X ; set MSB of level to either 0 or $7c (min/max) ca67: bd 72 23 LDA $2372, X ; get duration command ca6a: c9 ff CMP #$ff ca6c: f0 38 BEQ $caa6 ; go away if it's finished ca6e: de 72 23 DEC $2372, X ; else decrement duration ca71: 80 33 BRA $caa6 ; now, key is 'released' ; ca73: bd 4e 23 LDA $234e, X ; level data LSB ca76: 18 CLC ca77: 7d 66 23 ADC $2366, X ; add 'release' rate ca7a: 9d 4e 23 STA $234e, X ca7d: bd 54 23 LDA $2354, X ; level data MSB ca80: 7d 6c 23 ADC $236c, X ca83: 10 0b BPL $ca90 ca85: 62 CLA ; out of range ca86: 9d 4e 23 STA $234e, X ; set LSB of level to 0 ca89: bc 6c 23 LDY $236c, X ; check increase/decrease ca8c: 30 02 BMI $ca90 ca8e: a9 7c LDA #$7c ca90: 9d 54 23 STA $2354, X ; set LSB of level to 0 or $7c (min/max) ca93: 80 11 BRA $caa6 ; 'tie flag' was 2 ('initial strike') ; ca95: de 82 24 DEC $2482, X ; strike becomes normal note ca98: 9e 48 23 STZ $2348, X ; envelope pointer offset ca9b: 80 19 BRA $cab6 ; 'tie flag' was rest ; ca9d: 9e 68 24 STZ $2468, X ; post-envelope volume caa0: 80 13 BRA $cab5 ; ready to exit envelope loop ; caa2: 98 TYA caa3: 9d 48 23 STA $2348, X ; store envelope offset caa6: bd 54 23 LDA $2354, X ; divide level data by $400 caa9: 4a LSR a caaa: 4a LSR a caab: 18 CLC caac: 7d 12 23 ADC $2312, X ; per-channel volume (max = $00; min = -$1f) caaf: 10 01 BPL $cab2 ; in range cab1: 62 CLA ; out of range; force to zero cab2: 9d 68 24 STA $2468, X ; real hardware volume cab5: 60 RTS cab6: bc 48 23 LDY $2348, X ; envelope index cab9: bd 3c 23 LDA $233c, X ; copy envelope pointer to ZP cabc: 85 e8 STA $e8 cabe: bd 42 23 LDA $2342, X cac1: 85 e9 STA $e9 cac3: b1 e8 LDA ($e8), Y ; get next byte of envelope data cac5: c9 fb CMP #$fb cac7: 90 08 BCC $cad1 ; < $fb cac9: f0 1d BEQ $cae8 ; = $fb cacb: c9 fc CMP #$fc cacd: f0 1e BEQ $caed ; = $fc cacf: 80 34 BRA $cb05 ; all others ; < $fb in envelope data ; cad1: c9 00 CMP #$00 cad3: d0 01 BNE $cad6 cad5: 3a DEC a cad6: 9d 72 23 STA $2372, X ; envelope duration command cad9: c8 INY cada: b1 e8 LDA ($e8), Y cadc: 9d 5a 23 STA $235a, X ; envelope duration data (LSB) cadf: c8 INY cae0: b1 e8 LDA ($e8), Y cae2: 9d 60 23 STA $2360, X ; envelope duration data (MSB) cae5: c8 INY cae6: 80 ba BRA $caa2 ; $fb in envelope data ; cae8: c8 INY ; disregard 3 bytes ($fb should only be first in data) cae9: c8 INY caea: c8 INY caeb: 80 d6 BRA $cac3 ; $fc in envelope data ; caed: c8 INY caee: b1 e8 LDA ($e8), Y ; get next byte caf0: 9d 4e 23 STA $234e, X ; envelope 'level data' (LSB) caf3: c8 INY caf4: b1 e8 LDA ($e8), Y caf6: 9d 54 23 STA $2354, X ; envelope 'level data' (MSB) caf9: c8 INY cafa: b1 e8 LDA ($e8), Y ; get next byte cafc: c9 fb CMP #$fb cafe: 90 d1 BCC $cad1 ; < $fb cb00: 9e 72 23 STZ $2372, X ; clear 'envelope duration' command cb03: 80 9d BRA $caa2 ; all other envelope data ; cb05: a9 ff LDA #$ff cb07: 9d 72 23 STA $2372, X ; end of envelope duration cb0a: 9e 5a 23 STZ $235a, X ; clear envelope duration data cb0d: 9e 60 23 STZ $2360, X ; clear envelope duration data cb10: 4c a6 ca JMP $caa6 ; ; process frequency effects ; called from main track PSG driver ; cb13: ae e0 22 LDX $22e0 ; current voice cb16: bd 56 24 LDA $2456, X ; get mode cb19: 29 f0 AND #$f0 cb1b: f0 01 BEQ $cb1e ; if tone, continue cb1d: 60 RTS ; else return cb1e: bd 00 23 LDA $2300, X ; copy tone frequency data to cb21: 9d 5c 24 STA $245c, X ; output frequency area cb24: bd 06 23 LDA $2306, X cb27: 9d 62 24 STA $2462, X cb2a: bd e4 23 LDA $23e4, X ; sweep value cb2d: a8 TAY cb2e: f0 39 BEQ $cb69 ; no sweep cb30: bd f6 23 LDA $23f6, X ; sweep time cb33: f0 17 BEQ $cb4c cb35: de fc 23 DEC $23fc, X ; sweep time countdown cb38: d0 12 BNE $cb4c ; still counting down cb3a: fe fc 23 INC $23fc, X ; sweep time count up cb3d: bd ea 23 LDA $23ea, X ; sweep value LSB cb40: 85 ea STA $ea cb42: bd f0 23 LDA $23f0, X ; sweep value MSB cb45: 85 eb STA $eb cb47: 20 14 cc JSR $cc14 ; add to tone frequency cb4a: 80 1d BRA $cb69 ; sweep time 0, or still counting down ; cb4c: 84 ea STY $ea ; use sweep value as basis to change 'freq change amount' cb4e: 20 e5 cb JSR $cbe5 ; (but use FM correction and octave to modify this amount) cb51: bd ea 23 LDA $23ea, X ; add $ea/$eb to sweep amount cb54: 18 CLC ; and store result in $ea/$eb AND sweep amount cb55: 65 ea ADC $ea cb57: 9d ea 23 STA $23ea, X cb5a: 85 ea STA $ea cb5c: bd f0 23 LDA $23f0, X cb5f: 65 eb ADC $eb cb61: 9d f0 23 STA $23f0, X cb64: 85 eb STA $eb cb66: 20 14 cc JSR $cc14 ; add $ea/$eb to tone frequency ; sweep done... ; ; now apply detune frequency change ; cb69: bd ba 23 LDA $23ba, X ; Detune amount cb6c: f0 08 BEQ $cb76 ; if none... cb6e: 85 ea STA $ea cb70: 20 e5 cb JSR $cbe5 ; use this as basis for changing freq. change amount cb73: 20 14 cc JSR $cc14 ; add $ea/$eb to tone frequency ; now apply pitch envelope ; cb76: bd ae 23 LDA $23ae, X ; Pitch envelope delay cb79: f0 34 BEQ $cbaf ; none cb7b: de b4 23 DEC $23b4, X ; pitch envelope delay countdown cb7e: d0 2f BNE $cbaf ; still counting down cb80: fe b4 23 INC $23b4, X ; count up cb83: bd 9c 23 LDA $239c, X ; pitch envelope pointer cb86: 85 e8 STA $e8 cb88: bd a2 23 LDA $23a2, X cb8b: 85 e9 STA $e9 cb8d: bc a8 23 LDY $23a8, X ; pitch envelope offset cb90: b1 e8 LDA ($e8), Y ; fetch pitch envelope data cb92: c9 80 CMP #$80 ; data end cb94: d0 07 BNE $cb9d ; process data cb96: c0 00 CPY #$00 cb98: f0 15 BEQ $cbaf ; if data end is first byte cb9a: 88 DEY ; use previous byte instead cb9b: b1 e8 LDA ($e8), Y cb9d: 85 ea STA $ea ; use as basis for freq amount adjust cb9f: 5a PHY cba0: 20 e5 cb JSR $cbe5 ; change freq. change amount cba3: 20 14 cc JSR $cc14 ; add $ea/$eb to tone frequency cba6: 7a PLY cba7: c8 INY ; next pitch envelope offset in data cba8: d0 01 BNE $cbab cbaa: 88 DEY cbab: 98 TYA cbac: 9d a8 23 STA $23a8, X ; put back pitch envelope offset ; Pitch envelope delay, countdown, or done ; cbaf: bd 8a 23 LDA $238a, X ; FM Delay cbb2: f0 30 BEQ $cbe4 ; none cbb4: de 90 23 DEC $2390, X ; FM delay countdown cbb7: d0 2b BNE $cbe4 ; not done yet cbb9: fe 90 23 INC $2390, X ; count up cbbc: bd 78 23 LDA $2378, X ; FM Effect pointer cbbf: 85 e8 STA $e8 cbc1: bd 7e 23 LDA $237e, X cbc4: 85 e9 STA $e9 cbc6: bc 84 23 LDY $2384, X ; FM effect offset cbc9: b1 e8 LDA ($e8), Y ; FM effect data cbcb: c9 80 CMP #$80 ; end of list cbcd: d0 0a BNE $cbd9 ; no, so process cbcf: c0 00 CPY #$00 ; if first byte exit cbd1: f0 11 BEQ $cbe4 cbd3: 9e 84 23 STZ $2384, X ; recycle if true cbd6: c2 CLY cbd7: 80 f0 BRA $cbc9 cbd9: 85 ea STA $ea ; use byte as amount to change frequency by cbdb: 20 e5 cb JSR $cbe5 ; change freq change amount cbde: 20 14 cc JSR $cc14 ; add $ea/$eb to tone frequency cbe1: fe 84 23 INC $2384, X ; replace FM effect offset cbe4: 60 RTS ; figure out how much to change ; the 'frequency change amount' by ; cbe5: 64 eb STZ $eb cbe7: a5 ea LDA $ea cbe9: 10 02 BPL $cbed ; positive amount cbeb: c6 eb DEC $eb ; sign-extend cbed: bd 96 23 LDA $2396, X ; FM correction cbf0: f0 21 BEQ $cc13 ; exit if zero cbf2: 38 SEC cbf3: fd fa 22 SBC $22fa, X ; octave number cbf6: a8 TAY cbf7: 30 09 BMI $cc02 ; octave # > FM correction cbf9: f0 18 BEQ $cc13 ; equal, so exit cbfb: 06 ea ASL $ea ; shift left (go up an octave) cbfd: 26 eb ROL $eb cbff: 88 DEY ; loop for number of octaves cc00: 80 f7 BRA $cbf9 cc02: f0 07 BEQ $cc0b ; exit if done cc04: 46 eb LSR $eb ; shift right (go down an octave) cc06: 66 ea ROR $ea cc08: c8 INY cc09: 80 f7 BRA $cc02 ; loop cc0b: a5 eb LDA $eb ; if zero do nothing cc0d: f0 04 BEQ $cc13 cc0f: a9 ff LDA #$ff ; else put $ff there (started as minus cc11: 85 eb STA $eb ; until right-shifts... so restore sign) cc13: 60 RTS ; add value in $ea/$eb to tone frequency ; and put it back in tone frequency ; cc14: bd 5c 24 LDA $245c, X cc17: 18 CLC cc18: 65 ea ADC $ea cc1a: 9d 5c 24 STA $245c, X cc1d: bd 62 24 LDA $2462, X cc20: 65 eb ADC $eb cc22: 9d 62 24 STA $2462, X cc25: 60 RTS ; ; execute Fadeout volume adjustment ; cc26: ad 88 24 LDA $2488 ; PSG_FADEOUT value cc29: f0 24 BEQ $cc4f ; return if zero cc2b: 18 CLC cc2c: 6d 89 24 ADC $2489 ; adjust fadeout volume change counter cc2f: 10 05 BPL $cc36 ; if >$7f, increment attenuation register cc31: ee 8a 24 INC $248a cc34: 29 7f AND #$7f cc36: 8d 89 24 STA $2489 cc39: ad 8a 24 LDA $248a ; attenuation register cc3c: c9 1e CMP #$1e ; if not maximum, return cc3e: 90 0f BCC $cc4f cc40: a2 05 LDX #$05 ; for all voices cc42: bd 7c 24 LDA $247c, X ; if voice off, continue cc45: f0 05 BEQ $cc4c cc47: a9 02 LDA #$02 ; put 2 in control value cc49: 9d 7c 24 STA $247c, X cc4c: ca DEX ; loop cc4d: 10 f3 BPL $cc42 cc4f: 60 RTS ; ; Set PSG data ; cc50: a2 05 LDX #$05 ; for each of 6 voices cc52: bd 7c 24 LDA $247c, X ; per voice control cc55: c9 01 CMP #$01 cc57: 10 03 BPL $cc5c cc59: 4c fd cc JMP $ccfd ; if inactive, end voice cc5c: 8e 00 08 STX $0800 ; set voice # in hardware cc5f: f0 09 BEQ $cc6a ; go, if ($247c + x) == 1 cc61: 9c 04 08 STZ $0804 ; reset voice pointer cc64: 9e 7c 24 STZ $247c, X ; zero voice control (inactive) cc67: 4c fd cc JMP $ccfd ; end voice cc6a: ad df 22 LDA $22df ; PSG_INIT parm cc6d: f0 0a BEQ $cc79 ; if main track only cc6f: bd 07 26 LDA $2607, X ; or if subtrack off cc72: c9 01 CMP #$01 cc74: d0 03 BNE $cc79 ; proceed cc76: 4c fd cc JMP $ccfd ; else end voice ; ; set wave # ; cc79: bd 74 24 LDA $2474, X ; get wave # of voice cc7c: 30 45 BMI $ccc3 ; if $80 bit set, keep old wave in PSG hardware cc7e: 09 80 ORA #$80 ; else set voice & set bit cc80: 9d 74 24 STA $2474, X cc83: 29 7f AND #$7f cc85: c9 2d CMP #$2d ; $2d internal voices cc87: b0 12 BCS $cc9b ; set internal wave number ; cc89: 20 04 cd JSR $cd04 ; $e8 = voice * $20 byte offset cc8c: a9 a6 LDA #$a6 ; add base address $d9a6 cc8e: 18 CLC cc8f: 65 e8 ADC $e8 cc91: 85 e8 STA $e8 cc93: a9 d9 LDA #$d9 cc95: 65 e9 ADC $e9 cc97: 85 e9 STA $e9 cc99: 80 15 BRA $ccb0 ; set user wave number ; cc9b: 38 SEC cc9c: e9 2d SBC #$2d ; subtract # internal voices cc9e: 20 04 cd JSR $cd04 ; $e8 = voice * $20 byte offset cca1: ad d2 22 LDA $22d2 ; add user data base address cca4: 18 CLC cca5: 65 e8 ADC $e8 cca7: 85 e8 STA $e8 cca9: ad d3 22 LDA $22d3 ccac: 65 e9 ADC $e9 ccae: 85 e9 STA $e9 ccb0: a9 40 LDA #$40 ; reset wave index to 0 ccb2: 8d 04 08 STA $0804 ccb5: 9c 04 08 STZ $0804 ccb8: c2 CLY ; loop to load wave data into wave buffer ccb9: b1 e8 LDA ($e8), Y ; $20 bytes of wave data ccbb: 8d 06 08 STA $0806 ccbe: c8 INY ccbf: c0 20 CPY #$20 ccc1: 90 f6 BCC $ccb9 ccc3: e0 04 CPX #$04 ; if not a noise-capable voice, go to ccd3 ccc5: 90 0c BCC $ccd3 ccc7: bd 76 24 LDA $2476, X ; check special noise register ccca: 30 07 BMI $ccd3 ; if done, skip it cccc: 09 80 ORA #$80 ; else mark it for next time ccce: 8d 07 08 STA $0807 ; place noise frequency in register ccd1: 80 0f BRA $cce2 ccd3: 9c 07 08 STZ $0807 ; no noise ccd6: bd 5c 24 LDA $245c, X ; store tone frequency (low) ccd9: 8d 02 08 STA $0802 ccdc: bd 62 24 LDA $2462, X ; store tone frequency (high) ccdf: 8d 03 08 STA $0803 cce2: bd 6e 24 LDA $246e, X ; pan pot value cce5: 8d 05 08 STA $0805 cce8: bd 68 24 LDA $2468, X ; final volume cceb: 38 SEC ccec: ed 8a 24 SBC $248a ; minus fadeout volume attenuation ccef: f0 02 BEQ $ccf3 ccf1: 10 05 BPL $ccf8 ccf3: 9c 04 08 STZ $0804 ; if zero or less, turn off voice ccf6: 80 05 BRA $ccfd ccf8: 09 80 ORA #$80 ; enable voice, with proper volume ccfa: 8d 04 08 STA $0804 ccfd: ca DEX ; loop back to next voice ccfe: 30 03 BMI $cd03 cd00: 4c 52 cc JMP $cc52 cd03: 60 RTS ; finished ; ; multiply accumulator by $20 and put in ; $e8/$e9 (wave data offset calculation) ; cd04: 64 e8 STZ $e8 cd06: 4a LSR a cd07: 66 e8 ROR $e8 cd09: 4a LSR a cd0a: 66 e8 ROR $e8 cd0c: 4a LSR a cd0d: 66 e8 ROR $e8 cd0f: 85 e9 STA $e9 cd11: 60 RTS ; ; SUBTRACK Music Driver ; cd12: 20 45 cd JSR $cd45 ; check if song needs to be initialized cd15: 93 40 de 22 TST #$40,$22de; if subtrack paused, exits cd19: d0 27 BNE $cd42 cd1b: a9 05 LDA #$05 cd1d: 8d e0 22 STA $22e0 ; ($22e0) is a local arg with the channel number cd20: ae e0 22 LDX $22e0 ; voice # cd23: bd 07 26 LDA $2607, X ; if subtrack voice is off, skip it cd26: f0 0f BEQ $cd37 cd28: 20 f6 cd JSR $cdf6 ; process byte codes cd2b: 20 57 d2 JSR $d257 ; adjust relative volume & pan left/right amounts cd2e: 20 50 d3 JSR $d350 ; process percussion cd31: 20 22 d4 JSR $d42 ; process envelope cd34: 20 10 d5 JSR $d510 ; process frequency effects cd37: ce e0 22 DEC $22e ; next voice cd3a: 10 e4 BPL $cd20 cd3c: 20 23 d6 JSR $d623 ; process fadeout volume adjustment cd3f: 20 4d d6 JSR $d64d ; send data to hardware cd42: 4c 6c c1 JMP $c16c ; PSG_SSTAT ; ; check if song needs to be initialized ; cd45: ad e1 22 LDA $22e1 cd48: 10 01 BPL $cd4b ; if ($22e1) & 0x80 == 0, dwell further cd4a: 60 RTS ; else return ; ; Initial setup for "set song" ; including voice mask and main track/subtrack flag ; cd4b: 0a ASL a ; make an offset cd4c: a8 TAY cd4d: ad d0 22 LDA $22d0 ; get track header pointer cd50: 85 ea STA $ea cd52: ad d1 22 LDA $22d1 cd55: 85 eb STA $eb cd57: b1 ea LDA ($ea), Y ; get song pointer within list of pointers cd59: 85 e8 STA $e8 cd5b: c8 INY cd5c: b1 ea LDA ($ea), Y cd5e: 85 e9 STA $e9 cd60: b2 e8 LDA ($e8) ; get mask of voices from song header ; bit 7: 0=main track; 1=subtrack ; bit 6: 0=normal; 1=debug mode ; bit 5-0: voice in use cd62: 10 e6 BPL $cd4a ; if not subtrack song, return cd64: 85 ea STA $ea ; store voice mask cd66: 85 eb STA $eb cd68: c2 CLY cd69: 82 CLX cd6a: 46 ea LSR $ea ; rotate through voices cd6c: 90 72 BCC $cde0 ; skip voice if bit off cd6e: a9 01 LDA #$01 cd70: 9d 07 26 STA $2607, X ; per-voice control register cd73: 9d a9 24 STA $24a9, X ; current note duration (countdown) cd76: 9e 0d 26 STZ $260d, X ; note-struck flag cd79: 9e b5 24 STZ $24b5, X ; key-on duration (same as 100% "on" duty cycle) cd7c: 9e af 24 STZ $24af, X ; per-channel volume cd7f: 9e 27 25 STZ $2527, X ; FM Delay cd82: 9e 4b 25 STZ $254b, X ; PE Delay cd85: 9e 33 25 STZ $2533, X ; FM Correction cd88: 9e 57 25 STZ $2557, X ; Detune cd8b: 9e 81 25 STZ $2581, X ; Sweep cd8e: 9e 93 25 STZ $2593, X ; Sweep time cd91: 9e e1 25 STZ $25e1, X ; Stack/misc cd94: 9e cd 24 STZ $24cd, X ; Transpose cd97: 9e 5d 25 STZ $255d, X ; Volume change amount cd9a: 9e 69 25 STZ $2569, X ; Pan Pot right change amount cd9d: 9e 75 25 STZ $2575, X ; Pan Pot left change amount cda0: 9e d3 24 STZ $24d3, X ; Duration multipier cda3: ad a1 d8 LDA $d8a1 ; envelope #0 cda6: 9d d9 24 STA $24d9, X ; as default envelope cda9: ad a2 d8 LDA $d8a2 cdac: 9d df 24 STA $24df, X cdaf: a9 84 LDA #$84 ; set default attack rate = $8400 cdb1: 9d 09 25 STA $2509, X cdb4: a9 04 LDA #$04 ; octave number cdb6: 9d 97 24 STA $2497, X cdb9: c8 INY cdba: b1 e8 LDA ($e8), Y ; get address of voice track within song cdbc: 9d 8b 24 STA $248b, X ; set track pointer (LOW) cdbf: 9d c1 24 STA $24c1, X ; and 'set point' (LOW) cdc2: c8 INY cdc3: b1 e8 LDA ($e8), Y ; and 'high' bytes also cdc5: 9d 91 24 STA $2491, X cdc8: 9d c7 24 STA $24c7, X cdcb: a9 80 LDA #$80 cdcd: e0 04 CPX #$04 cdcf: 90 03 BCC $cdd4 cdd1: 9d 01 26 STA $2601, X ; disable noise (if voice is noise-capable) cdd4: 9d ff 25 STA $25ff, X ; disable waveform download cdd7: 6f eb 06 BBR6 $eb, $cde0 ; if bit 6 of voice mask reset ; ; if 'debug mode' (bit 6) is set, it forces a waveform # ; (from debug byte) into voice data ; cdda: ad e2 22 LDA $22e2 ; debug waveform cddd: 9d ff 25 STA $25ff, X ; waveform per voice cde0: e8 INX ; sequence to next voice cde1: e0 06 CPX #$06 cde3: 90 85 BCC $cd6a cde5: 9c 13 26 STZ $2613 ; PSG_FADEOUT value cde8: 9c 15 26 STZ $2615 ; fade volume attenuation cdeb: a9 80 LDA #$80 cded: 0c e1 22 TSB $22e1 ; set top bit in 'song number' (ie. set and running) cdf0: a9 40 LDA #$40 cdf2: 1c de 22 TRB $22de ; turn of subtrack pause flag cdf5: 60 RTS ; ; Process byte codes ; cdf6: de a9 24 DEC $24a9, X ; decrement the countdown counter cdf9: f0 01 BEQ $cdfc ; process next byte if counted to zero cdfb: 60 RTS cdfc: 02 SXY cdfd: b9 8b 24 LDA $248b, Y ; track pointer (LOW) per voice ce00: 85 e8 STA $e8 ce02: b9 91 24 LDA $2491, Y ; track pointer (HIGH) per voice ce05: 85 e9 STA $e9 ce07: b2 e8 LDA ($e8) ; read next bytecode ce09: e6 e8 INC $e8 ; increment pointer ce0b: d0 02 BNE $ce0f ce0d: e6 e9 INC $e9 ce0f: 48 PHA ce10: c9 d0 CMP #$d0 ; is it tone, or metadata ? ce12: 90 69 BCC $ce7d ; tone ce14: 38 SEC ce15: e9 d0 SBC #$d0 ; metadata ce17: 0a ASL a ; form offset into jump table ce18: aa TAX ce19: 68 PLA ce1a: 7c 1d ce JMP ($ce1d, X) ce1d: 68 cf ; d0 - set duration ce1f: 72 cf ; d1 - set octave 1 ce21: 72 cf ; d2 - set octave 2 ce23: 72 cf ; d3 - set octave 3 ce25: 72 cf ; d4 - set octave 4 ce27: 72 cf ; d5 - set octave 5 ce29: 72 cf ; d6 - set octave 6 ce2b: 72 cf ; d7 - set octave 7 ce2d: 7a cf ; d8 - octave up ce2f: 83 cf ; d9 - octave down ce31: 8c cf ; da - tie ce33: 07 ce ; db - set tempo (ineffective on subtrack) ce35: 94 cf ; dc - set volume ce37: a5 cf ; dd - set pan pot ce39: b4 cf ; de - set key on/key off ratio ce3b: c4 cf ; df - relative volume ce3d: 07 ce ; e0 - unused (no operation) ce3f: db cf ; e1 - "da se nio" ce41: e8 cf ; e2 - "se nio" ce43: f5 cf ; e3 - repeat begin ce45: 24 d0 ; e4 - repeat end ce47: 50 d0 ; e5 - set timbre/wave ce49: 58 d0 ; e6 - set envelope ce4b: cb d0 ; e7 - frequency modulate ce4d: ec d0 ; e8 - FM Delay ce4f: f4 d0 ; e9 - FM Correction ce51: fe d0 ; ea - Pitch Envelope ce53: 1f d1 ; eb - PE Delay ce55: 27 d1 ; ec - Detune ce57: 2f d1 ; ed - Sweep ce59: 37 d1 ; ee - sweep time ce5b: 3f d1 ; ef - Jump ce5d: 51 d1 ; f0 - Call ce5f: 7e d1 ; f1 - Return ce61: a2 d1 ; f2 - Transpose ce63: ab d1 ; f3 - Relative Transpose ce65: bb d1 ; f4 - Entire Transpose ce67: d1 d1 ; f5 - volume change ce69: dc d1 ; f6 - pan rigth change ce6b: e7 d1 ; f7 - pan left change ce6d: f2 d1 ; f8 - set mode ce6f: 07 ce ; f9 - unused (no operation) ce71: 07 ce ; fa - unused (no operation) ce73: 07 ce ; fb - unused (no operation) ce75: 07 ce ; fc - unused (no operation) ce77: 07 ce ; fd - unused (no operation) ce79: 13 d2 ; fe - fade out ce7b: 2b d2 ; ff - data end ; ; Tone Data Process ; ce7c: be d3 LDX $24D3 ; duration multiplier per voice ce7f: f0 13 BEQ $CE84 ; if not set, get next byte as direct length ce81: 29 0f AND #$0f ce83: 1a INC ce85: d9 d3 24 CMP $24d3, Y ce88: b0 01 BCS $ce8b ce8a: 22 SAX ce8b: 85 ea STA $ea ; MAX(note duration, duration multiplier) ce8d: 18 CLC ce8e: ca DEX ce8f: f0 0c BEQ $ce9d ce91: 65 ea ADC $ea ce93: 80 f9 BRA $ce8e ; multiply by succesive adding ce95: b2 e8 LDA ($e8) ; get next byte as direct length ce97: e6 e8 INC $e8 ; inc pointer ce99: d0 02 BNE $ce9d ce9b: e6 e9 INC $e9 ce9d: 99 a9 24 STA $24a9, Y ; store current note total duration cea0: aa TAX cea1: b2 e8 LDA ($e8) ; fetch next byte cea3: 22 SAX cea4: e0 da CPX #$da cea6: f0 13 BEQ $cebb ; tie - override key on/off ratio cea8: 4a LSR a cea9: 4a LSR a ceaa: 4a LSR a ceab: 85 ea STA $ea ; total duration/8 cead: 38 SEC ceae: b9 a9 24 LDA $24a9, Y ; total duration ceb1: be b5 24 LDX $24b5, Y ; key on/off ratio ceb4: f0 05 BEQ $cebb ; skip calculation if not set ceb6: e5 ea SBC $ea ceb8: ca DEX ceb9: 80 f9 BRA $ceb4 ; subtract 1/8's until ready cebb: 99 bb 24 STA $24bb, Y ; store 'key on' duration cebe: 68 PLA ; restore original tone cebf: 29 f0 AND #$f0 ; get tone value cec1: d0 04 BNE $cec7 ; not a 'rest' cec3: 62 CLA cec4: 4c 5a cf JMP $cf5a ; 'rest' cec7: 38 SEC cec8: e9 10 SBC #$10 ; 0-relative note, still in $x0 format ceca: 4a LSR a cecb: 4a LSR a cecc: 4a LSR a cecd: aa TAX ; form an offset (ie. for 2-byte ptr) cece: b9 e1 25 LDA $25e1, Y ced1: 29 f0 AND #$f0 ; get voice's "mode" (0-music; 2=percussion; 2=noise) ced3: 22 SAX ced4: f0 38 BEQ $cf0e ; music ced6: e0 10 CPX #$10 ; is it percussion ? ced8: d0 1e BNE $cef8 ceda: 18 CLC ; percussion data cedb: 6d db 22 ADC $22db ; index into percussion effect table cede: 85 ea STA $ea cee0: 62 CLA cee1: 6d dc 22 ADC $22dc cee4: 85 eb STA $eb cee6: b2 ea LDA ($ea) cee8: 99 9f 25 STA $259f, Y ; store percussion 'sub-track' pointer ceeb: e6 ea INC $ea ceed: d0 02 BNE $cef1 ceef: e6 eb INC $eb cef1: b2 ea LDA ($ea) cef3: 99 a5 25 STA $25a5, Y cef6: 80 36 BRA $cf2e cef8: c0 04 CPY #$04 ; noise data cefa: 90 12 BCC $cf0e ; no use ifnot noise-capable cefc: 18 CLC cefd: 79 cd 24 ADC $24cd, Y ; add transpose cf00: 4a LSR a ; divide by 2 cf01: 99 01 26 STA $2601, Y ; noide data in 247a/b cf04: 80 28 BRA $cf2e ; ; data - octave index offset (ie. note basis) ; cf06: 00 cf07: 18 cf08: 30 cf09: 48 cf0a: 60 cf0b: 78 cf0c: 90 cf0d: a8 cf0e: be 97 24 LDX $2497, Y ; get octave number (must be > 0) cf11: 18 CLC cf12: 7d 05 cf ADC $cf05, X ; add octave basis cf15: 79 cd 24 ADC $24cd, Y ; add transpose cf18: aa TAX ; use as index cf19: bd 1a d7 LDA $d71a, X ; get frequency data cf1c: 99 9d 24 STA $249d, Y ; freq (LOW) cf1f: bd 1b d7 LDA $d71b, X cf22: 99 a3 24 STA $24a3, Y ; freq (HIGH) cf25: c0 04 CPY #$04 cf27: 90 05 BCC $cf2e ; go to cf2e if not a noise-capable voice cf29: a9 80 LDA #$80 ; noise flag (no noise value) cf2b: 99 01 26 STA $2601, Y ; actually 2605/6 cf2e: b9 0d 26 LDA $260d, Y ; is it a 'tie' note ? cf31: c9 03 CMP #$03 cf33: d0 04 BNE $cf39 ; no cf35: a9 01 LDA #$01 ; yes... change bits cf37: 80 21 BRA $cf5a cf39: 62 CLA cf3a: 99 21 25 STA $2521, Y ; FM-related ? cf3d: 99 45 25 STA $2545, Y ; PE-related ? cf40: 99 87 25 STA $2587, Y ; Sweep-related ? cf43: 99 8d 25 STA $258d, Y ; Sweep-related ? cf46: b9 27 25 LDA $2527, Y ; FM Delay cf49: 99 2d 25 STA $252d, Y ; use as countdown cf4c: b9 4b 25 LDA $254b, Y ; PE Delay cf4f: 99 51 25 STA $2551, Y ; use as countdown cf52: b9 93 25 LDA $2593, Y ; Sweep time cf55: 99 99 25 STA $2599, Y ; use as countdown cf58: a9 02 LDA #$02 cf5a: 99 0d 26 STA $260d, Y ; 'tie' flags cf5d: a5 e8 LDA $e8 cf5f: 99 8b 24 STA $248b, Y ; store pointers back cf62: a5 e9 LDA $e9 cf64: 99 91 24 STA $2491, Y cf67: 60 RTS ; ; TRACK DATA BYTE CODE OPERATIONS ; ; $d0 - set duration, 0-15 ; cf68: b2 e8 LDA ($e8) cf6a: 29 0f AND #$0f cf6c: 99 d3 24 STA $24d3, Y cf6f: 4c 31 d2 JMP $d231 ; ; $d1-$d7 - set octave 0-7 ; cf72: 29 07 AND #$07 cf74: 99 97 24 STA $2497, Y cf77: 4c 07 ce JMP $ce07 ; ; $d8 - octave up ; cf7a: ae e0 22 LDX $22e0 cf7d: fe 97 24 INC $2497, X cf80: 4c 07 ce JMP $ce07 ; ; $d9 - octave down ; cf83: ae e0 22 LDX $22e0 cf86: de 97 24 DEC $2497, X cf89: 4c 07 ce JMP $ce07 ; ; $da - tie ; cf8c: a9 03 LDA #$03 cf8e: 99 0d 26 STA $260d, Y cf91: 4c 07 ce JMP $ce07 ; ; $dc - set volume ; ; sets volume to (value - $1f) ; cf94: b2 e8 LDA ($e8) cf96: 29 1f AND #$1f cf98: 38 SEC cf99: e9 1f SBC #$1f cf9b: 99 af 24 STA $24af, Y cf9e: 62 CLA cf9f: 99 5d 25 STA $255d, Y cfa2: 4c 31 d2 JMP $d231 ; ; $dd - set pan pot ; cfa5: b2 e8 LDA ($e8) cfa7: 99 f9 25 STA $25f9, Y cfaa: 62 CLA cfab: 99 69 25 STA $2569, Y cfae: 99 75 25 STA $2575, Y cfb1: 4c 31 d2 JMP $d231 ; ; $de - set key on/key off ratio ; ; sets ratio to (8-value) ; cfb4: b2 e8 LDA ($e8) cfb6: 3a DEC a cfb7: 29 07 AND #$07 cfb9: 38 SEC cfba: e9 08 SBC #$08 cfbc: 49 ff EOR #$ff cfbe: 99 b5 24 STA $24b5, Y cfc1: 4c 31 d2 JMP $d231 ; ; $df - relative volume ; cfc4: b9 af 24 LDA $24af, Y cfc7: 18 CLC cfc8: 72 e8 ADC ($e8) cfca: 30 03 BMI $cfcf cfcc: 62 CLA cfcd: 80 06 BRA $cfd5 cfcf: c9 e1 CMP #$e1 cfd1: b0 02 BCS $cfd5 cfd3: a9 e1 LDA #$e1 cfd5: 99 af 24 STA $24af, Y cfd8: 4c 31 d2 JMP $d231 ; ; $e1 - Da Se Nyo ; ; continue from save point ; cfdb: b9 c1 24 LDA $24c1, Y cfde: 85 e8 STA $e8 cfe0: b9 c7 24 LDA $24c7, Y cfe3: 85 e9 STA $e9 cfe5: 4c 07 ce JMP $ce07 ; ; $e2 - Se Nyo ; ; Save current spot as save point ; cfe8: a5 e8 LDA $e8 cfea: 99 c1 24 STA $24c1, Y cfed: a5 e9 LDA $e9 cfef: 99 c7 24 STA $24c7, Y cff2: 4c 07 ce JMP $ce07 ; ; $e3 - repeat begin ; cff5: 02 SXY cff6: b2 e8 LDA ($e8) ; get # iterations cff8: d0 02 BNE $cffc cffa: a9 02 LDA #$02 ; if 0, use 2 cffc: 48 PHA cffd: e6 e8 INC $e8 cfff: d0 02 BNE $d003 d001: e6 e9 INC $e9 d003: 20 3a d2 JSR $d23a ; get stack frame of voice d006: a5 e8 LDA $e8 d008: 91 ea STA ($ea), Y ; store LOW(track_data_ptr) d00a: c8 INY d00b: a5 e9 LDA $e9 d00d: 91 ea STA ($ea), Y ; store HIGH(track_data_ptr) d00f: c8 INY d010: 68 PLA d011: 91 ea STA ($ea), Y ; store # iterations d013: c8 INY d014: 84 ea STY $ea ; store stack index d016: bd e1 25 LDA $25e1, X d019: 29 f0 AND #$f0 d01b: 05 ea ORA $ea d01d: 9d e1 25 STA $25e1, X ; put stack index here d020: 02 SXY d021: 4c 07 ce JMP $ce07 ; ; $e4 - repeat end ; d024: 02 SXY d025: 20 3a d2 JSR $d23a ; get stack frame d028: 88 DEY d029: b1 ea LDA ($ea), Y ; get #iter's d02b: 3a DEC a d02c: f0 10 BEQ $d03e ; done d02e: 91 ea STA ($ea), Y ; dec # iter's d030: 88 DEY d031: b1 ea LDA ($ea), Y ; restore beginning of repeat location d033: 85 e9 STA $e9 d035: 88 DEY d036: b1 ea LDA ($ea), Y d038: 85 e8 STA $e8 d03a: 02 SXY d03b: 4c 07 ce JMP $ce07 ; continue parsing d03e: 88 DEY ; remove item from stack d03f: 88 DEY d040: 84 ea STY $ea d042: bd e1 25 LDA $25e1, X d045: 29 f0 AND #$f0 d047: 05 ea ORA $ea d049: 9d e1 25 STA $25e1, X ; store new stack index d04c: 02 SXY d04d: 4c 07 ce JMP $ce07 ; ; $e5 - set timbre/wave ; d050: b2 e8 LDA ($e8) d052: 99 ff 25 STA $25ff, Y d055: 4c 31 d2 JMP $d231 ; ; $e6 - set envelope ; d058: 02 SXY d059: b2 e8 LDA ($e8) ; get envelope number d05b: c9 10 CMP #$10 d05d: b0 0e BCS $d06d ; >$10 is user envelope data d05f: 0a ASL a ; make 2-byte offset d060: a8 TAY d061: b9 a1 d8 LDA $d8a1, Y ; get pointer for internal envelope data d064: 85 ea STA $ea d066: b9 a2 d8 LDA $d8a2, Y d069: 85 eb STA $eb d06b: 80 1f BRA $d08c d06d: 38 SEC d06e: e9 10 SBC #$10 ; make it 0-relative d070: 0a ASL a ; make 2-byte offset d071: 18 CLC d072: 6d d5 22 ADC $22d5 ; add to user envelope pointer d075: 85 ea STA $ea d077: 62 CLA d078: 6d d6 22 ADC $22d6 d07b: 85 eb STA $eb d07d: b2 ea LDA ($ea) ; get pointer to envelope data d07f: a8 TAY d080: e6 ea INC $ea d082: d0 02 BNE $d086 d084: e6 eb INC $eb d086: b2 ea LDA ($ea) d088: 85 eb STA $eb ; ($ea) points to envelope data now d08a: 84 ea STY $ea d08c: 9e 03 25 STZ $2503, X ; clear initial level (LOW) d08f: 9e 09 25 STZ $2509, X ; clear initial level (HIGH) d092: b2 ea LDA ($ea) d094: c9 fb CMP #$fb ; is first byte a release level ? d096: d0 19 BNE $d0b1 d098: a0 01 LDY #$01 ; yes - move value to $2503 and 2509 d09a: b1 ea LDA ($ea), Y d09c: 9d 03 25 STA $2503, X d09f: c8 INY d0a0: b1 ea LDA ($ea), Y d0a2: 9d 09 25 STA $2509, X d0a5: a9 03 LDA #$03 d0a7: 18 CLC d0a8: 65 ea ADC $ea ; increase pointer d0aa: 85 ea STA $ea d0ac: 62 CLA d0ad: 65 eb ADC $eb d0af: 85 eb STA $eb d0b1: a5 ea LDA $ea d0b3: 9d d9 24 STA $24d9, X ; reset envelope pointer d0b6: a5 eb LDA $eb d0b8: 9d df 24 STA $24df, X d0bb: 9e 0f 25 STZ $250f, X ; envelope 'duration' command d0be: 9e f1 24 STZ $24f1, X ; envelope 'level data' MSB d0c1: 9e f7 24 STZ $24f7, X ; envelope 'duration data' LSB d0c4: 9e fd 24 STZ $24fd, X ; envelope 'duration data' MSB d0c7: 02 SXY d0c8: 4c 31 d2 JMP $d231 ; ; $e7 - frequency modulation ; d0cb: 02 SXY d0cc: b2 e8 LDA ($e8) d0ce: 0a ASL a ; turn value into offset (for 2-byte values) d0cf: a8 TAY d0d0: ad d7 22 LDA $22d7 ; base FM pointer location d0d3: 85 ea STA $ea d0d5: ad d8 22 LDA $22d8 d0d8: 85 eb STA $eb d0da: b1 ea LDA ($ea), Y ; get pointer to effect and save it at $2515 & $251b d0dc: 9d 15 25 STA $2515, X d0df: c8 INY d0e0: b1 ea LDA ($ea), Y d0e2: 9d 1b 25 STA $251b, X d0e5: 9e 21 25 STZ $2521, X d0e8: 02 SXY d0e9: 4c 31 d2 JMP $d231 ; ; $e8 - FM Delay ; d0ec: b2 e8 LDA ($e8) d0ee: 99 27 25 STA $2527, Y d0f1: 4c 31 d2 JMP $d231 ; ; $e9 - FM Correction ; d0f4: b2 e8 LDA ($e8) d0f6: 29 07 AND #$07 d0f8: 99 33 25 STA $2533, Y d0fb: 4c 31 d2 JMP $d231 ; ; $ea - Pitch Envelope ; d0fe: 02 SXY d0ff: b2 e8 LDA ($e8) d101: 0a ASL a ; turnvalue into offset (for 2-byte values) d102: a8 TAY d103: ad d9 22 LDA $22d9 ; base PE pointer location d106: 85 ea STA $ea d108: ad da 22 LDA $22da d10b: 85 eb STA $eb d10d: b1 ea LDA ($ea), Y ; get pointer and save it at $2539 & $253f d10f: 9d 39 25 STA $2539, X d112: c8 INY d113: b1 ea LDA ($ea), Y d115: 9d 3f 25 STA $253f, X d118: 9e 45 25 STZ $2545, X ; ? d11b: 02 SXY d11c: 4c 31 d2 JMP $d231 ; ; $eb - PE Delay ; d11f: b2 e8 LDA ($e8) d121: 99 4b 25 STA $254b, Y d124: 4c 31 d2 JMP $d231 ; ; $ec - Detune ; d127: b2 e8 LDA ($e8) d129: 99 57 25 STA $2557, Y d12c: 4c 31 d2 JMP $d231 ; ; $ed - Sweep ; d12f: b2 e8 LDA ($e8) d131: 99 81 25 STA $2581, Y d134: 4c 31 d2 JMP $d231 ; ; $ee - Sweep Time ; d137: b2 e8 LDA ($e8) d139: 99 93 25 STA $2593, Y d13c: 4c 31 d2 JMP $d231 ; ; $ef - Jump ; d13f: b2 e8 LDA ($e8) ; get next 2 bytes and move to track pointer d141: aa TAX d142: e6 e8 INC $e8 d144: d0 02 BNE $d148 d146: e6 e9 INC $e9 d148: b2 e8 LDA ($e8) d14a: 85 e9 STA $e9 d14c: 86 e8 STX $e8 d14e: 4c 07 ce JMP $ce07 ; ; $f0 - Call ; d151: 02 SXY d152: 20 3a d2 JSR $d23a ; get stack frame d155: a5 e8 LDA $e8 ; save return address d157: 91 ea STA ($ea), Y d159: c8 INY d15a: a5 e9 LDA $e9 d15c: 91 ea STA ($ea), Y d15e: c8 INY d15f: 84 ea STY $ea ; offset pointer d161: bd e1 25 LDA $25e1, X ; store it back into offset pointer/mode regsiter d164: 29 f0 AND #$f0 d166: 05 ea ORA $ea d168: 9d e1 25 STA $25e1, X d16b: b2 e8 LDA ($e8) ; get new address d16d: a8 TAY d16e: e6 e8 INC $e8 d170: d0 02 BNE $d174 d172: e6 e9 INC $e9 d174: b2 e8 LDA ($e8) d176: 85 e9 STA $e9 ; jump there d178: 84 e8 STY $e8 d17a: 02 SXY d17b: 4c 07 ce JMP $ce07 ; ; $f1 - Return ; d17e: 02 SXY d17f: 20 3a d2 JSR $d23a ; get stack frame d182: 88 DEY d183: b1 ea LDA ($ea), Y ; restore return address d185: 85 e9 STA $e9 d187: 88 DEY d188: b1 ea LDA ($ea), Y d18a: 85 e8 STA $e8 d18c: 84 ea STY $ea d18e: bd e1 25 LDA $25e1, X ; store offset pointer again d191: 29 f0 AND #$f0 d193: 05 ea ORA $ea d195: 9d e1 25 STA $25e1, X d198: e6 e8 INC $e8 ; don't forget to add 2 to pointer - 1 here d19a: d0 02 BNE $d19e d19c: e6 e9 INC $e9 d19e: 02 SXY d19f: 4c 31 d2 JMP $d231 ; and this is an increment & jmp to $ce07 ; ; $f2 - Transpose ; d1a2: b2 e8 LDA ($e8) d1a4: 0a ASL a d1a5: 99 cd 24 STA $24cd, Y ; store absolute transpose amount (as offset) d1a8: 4c 31 d2 JMP $d231 ; ; $f3 - Relative Transpose ; d1ab: b2 e8 LDA ($e8) d1ad: 0a ASL a d1ae: 85 ea STA $ea d1b0: b9 cd 24 LDA $24cd, Y ; add transpose amount (as offset) d1b3: 18 CLC d1b4: 65 ea ADC $ea d1b6: 99 cd 24 STA $24cd, Y d1b9: 80 76 BRA $d231 ; ; $f4 - Entire Transpose ; d1bb: 5a PHY d1bc: b2 e8 LDA ($e8) d1be: 0a ASL a d1bf: a8 TAY d1c0: a2 05 LDX #$05 ; for all of the voices, d1c2: bd 07 26 LDA $2607, X ; check if voice is active d1c5: f0 04 BEQ $d1cb d1c7: 98 TYA d1c8: 9d cd 24 STA $24cd, X ; if yes, set transpose amount d1cb: ca DEX d1cc: 10 f4 BPL $d1c2 ; and loop d1ce: 7a PLY d1cf: 80 60 BRA $d231 ; ; $f5 - Volume Change ; d1d1: b2 e8 LDA ($e8) d1d3: 99 5d 25 STA $255d, Y ; set volume change amount d1d6: 62 CLA d1d7: 99 63 25 STA $2563, Y ; ? d1da: 80 55 BRA $d231 ; ; $f6 - Pan Right Change ; d1dc: b2 e8 LDA ($e8) d1de: 99 69 25 STA $2569, Y ; set Pan Pot right change amount d1e1: 62 CLA d1e2: 99 6f 25 STA $256f, Y ; ? d1e5: 80 4a BRA $d231 ; ; $f7 - Pan Left Change ; d1e7: b2 e8 LDA ($e8) d1e9: 99 75 25 STA $2575, Y ; set Pan Pot left change amount d1ec: 62 CLA d1ed: 99 7b 25 STA $257b, Y ; ? d1f0: 80 3f BRA $d231 ; ; $f8 - Change mode ; d1f2: b2 e8 LDA ($e8) d1f4: 0a ASL a ; shift mode left 4 bits d1f5: 0a ASL a d1f6: 0a ASL a d1f7: 0a ASL a d1f8: 85 ea STA $ea d1fa: b9 e1 25 LDA $25e1, Y ; and install in top 4 bits of stack offset/misc variable d1fd: 29 0f AND #$0f d1ff: 05 ea ORA $ea d201: 99 e1 25 STA $25e1, Y d204: b2 e8 LDA ($e8) d206: c9 01 CMP #$01 ; is it percussion ? d208: d0 27 BNE $d231 ; no d20a: 62 CLA ; yes d20b: 99 03 25 STA $2503, Y ; reset envelop release value d20e: 99 09 25 STA $2509, Y ; reset envelope release value d211: 80 1e BRA $d231 ; ; $fe - Fade Out ; d213: b2 e8 LDA ($e8) d215: 89 7f BIT #$7f ; if zero, ignore d217: f0 18 BEQ $d231 d219: c9 00 CMP #$00 d21b: 10 03 BPL $d220 d21d: 49 ff EOR #$ff ; if negative, negate (for absolute value) d21f: 1a INC a d220: 8d 13 26 STA $2613 ; fadeout value d223: 9c 14 26 STZ $2614 ; fadeout volume change register d226: 9c 15 26 STZ $2615 ; fadeout volume attentuation register d229: 80 06 BRA $d231 ; ; $ff - Data End ; d22b: a9 02 LDA #$02 d22d: 99 07 26 STA $2607, Y d230: 60 RTS ; ; Inc pointer & recycle ; (used for bytecodes with paramters values to read) ; d231: e6 e8 INC $e8 d233: d0 02 BNE $d237 d235: e6 e9 INC $e9 d237: 4c 07 ce JMP $ce07 ; ; get stack frame & offset ; d23a: bd 4b d2 LDA $d24b, X d23d: 85 ea STA $ea d23f: bd 51 d2 LDA $d251, X d242: 85 eb STA $eb d244: bd e1 25 LDA $25e1, X d247: 29 0f AND #$0f d249: a8 TAY d24a: 60 RTS ; ; data - stack frame address (LOW) per voice ; d24b: ab d24c: b4 d24d: bd d24e: c6 d24f: cf d250: d8 ; ; data - stack frame address (HIGH) per voice ; d251: 25 d252: 25 d253: 25 d254: 25 d255: 25 d256: 25 ; ; relative volume/pan pot change ; called from main track PSG driver ; d257: ae e0 22 LDX $22e0 ; current voice d25a: bd 5d 25 LDA $255d, X ; volume change amount per voice d25d: f0 44 BEQ $d2a3 ; no change d25f: 30 18 BMI $d279 ; negative d261: 18 CLC d262: 7d 63 25 ADC $2563, X ; minor volume change accum d265: 85 ea STA $ea d267: 2a ROL a d268: 2a ROL a d269: 29 01 AND #$01 ; was bit $80 before rotate (ie. value > $80) d26b: 18 CLC d26c: 7d af 24 ADC $24af, X ; per-channel volume d26f: f0 28 BEQ $d299 ; max d271: 30 26 BMI $d299 ; regular range d273: 62 CLA ; too high; clip it to max ; (recall that max = 0; min = -$1f) d274: 9e 5d 25 STZ $255d, X ; volume change amount per-voice d277: 80 20 BRA $d299 d279: 49 ff EOR #$ff ; negate value d27b: 1a INC a d27c: 18 CLC d27d: 7d 63 25 ADC $2563, X ; minor volume change accum d280: 85 ea STA $ea d282: 2a ROL a d283: 2a ROL a d284: 29 01 AND #$01 ; was bit $80 before rotate d286: 85 eb STA $eb d288: bd af 24 LDA $24af, X ; per-channel volume d28b: 38 SEC d28c: e5 eb SBC $eb d28e: f0 09 BEQ $d299 d290: c9 e1 CMP #$e1 d292: b0 05 BCS $d299 d294: a9 e1 LDA #$e1 d296: 9e 5d 25 STZ $255d, X d299: 9d af 24 STA $24af, X ; per-channel volume d29c: a5 ea LDA $ea d29e: 29 7f AND #$7f d2a0: 9d 63 25 STA $2563, X ; minor volume change accum ; now do pan pot right adjust: d2a3: bd 69 25 LDA $2569, X ; pan pot right change per voice d2a6: f0 51 BEQ $d2f9 ; no change d2a8: 30 1f BMI $d2c9 ; negative d2aa: 18 CLC d2ab: 7d 6f 25 ADC $256f, X ; minor pan pot right accum d2ae: 85 ea STA $ea d2b0: 2a ROL a d2b1: 2a ROL a d2b2: 29 01 AND #$01 ; if big enough, trigger volume change d2b4: 85 eb STA $eb d2b6: bd f9 25 LDA $25f9, X ; pan pot register d2b9: 29 0f AND #$0f ; right side d2bb: 18 CLC d2bc: 65 eb ADC $eb d2be: c9 10 CMP #$10 ; if range OK, go to $d2e6 d2c0: 90 24 BCC $d2e6 d2c2: a9 0f LDA #$0f ; fix level to max d2c4: 9e 69 25 STZ $2569, X d2c7: 80 1d BRA $d2e6 d2c9: 49 ff EOR #$ff ; negate value (ie. make negative into positive) d2cb: 1a INC a d2cc: 18 CLC d2cd: 7d 6f 25 ADC $256f, X ; minor pan pot right accum d2d0: 85 ea STA $ea d2d2: 2a ROL a d2d3: 2a ROL a d2d4: 29 01 AND #$01 ; if big enough, trigger volume change d2d6: 85 eb STA $eb d2d8: bd f9 25 LDA $25f9, X ; pan pot register d2db: 29 0f AND #$0f d2dd: 38 SEC d2de: e5 eb SBC $eb ; subtract d2e0: d0 04 BNE $d2e6 d2e2: 62 CLA d2e3: 9e 69 25 STZ $2569, X ; clear it d2e6: 85 eb STA $eb d2e8: bd f9 25 LDA $25f9, X ; put pan pot right value into combined register d2eb: 29 f0 AND #$f0 d2ed: 05 eb ORA $eb d2ef: 9d f9 25 STA $25f9, X d2f2: a5 ea LDA $ea d2f4: 29 7f AND #$7f d2f6: 9d 6f 25 STA $256f, X ; reset trigger bit on minor accumulator bit ; now do pan pot left adjust: d2f9: bd 75 25 LDA $2575, X ; pan pot left change per voice d2fc: f0 51 BEQ $d34f ; no change d2fe: 30 1e BMI $d31e ; negative d300: 18 CLC d301: 7d 7b 25 ADC $257b, X ; minor pan pot left accum d304: 85 ea STA $ea d306: 29 80 AND #$80 ; if big enough d308: 4a LSR a d309: 4a LSR a d30a: 4a LSR a d30b: 85 eb STA $eb d30d: bd f9 25 LDA $25f9, X ; pan pot register d310: 29 f0 AND #$f0 ; left side d312: 18 CLC d313: 65 eb ADC $eb d315: 90 25 BCC $d33c d317: a9 f0 LDA #$f0 ; if overflow, reset to max d319: 9e 75 25 STZ $2575, X d31c: 80 1e BRA $d33c d31e: 49 ff EOR #$ff ; negative value; get absolute val d320: 1a INC a d321: 18 CLC d322: 7d 7b 25 ADC $257b, X d325: 85 ea STA $ea d327: 29 80 AND #$80 ; if big enough d329: 4a LSR a d32a: 4a LSR a d32b: 4a LSR a d32c: 85 eb STA $eb d32e: bd f9 25 LDA $25f9, X ; pan pot register d331: 29 f0 AND #$f0 ; left side d333: 38 SEC d334: e5 eb SBC $eb ; subtract d336: d0 04 BNE $d33c d338: 62 CLA d339: 9e 75 25 STZ $2575, X ; clear it d33c: 85 eb STA $eb d33e: bd f9 25 LDA $25f9, X ; put pan pot left value into combined register d341: 29 0f AND #$0f d343: 05 eb ORA $eb d345: 9d f9 25 STA $25f9, X d348: a5 ea LDA $ea d34a: 29 7f AND #$7f d34c: 9d 7b 25 STA $257b, X ; reset trigger bit on minor accumulator bit d34f: 60 RTS ; ; Percussion Sequencer ; called from subtrack PSG driver ; d350: ac e0 22 LDY $22e0 d353: b9 e1 25 LDA $25e1, Y d356: 29 f0 AND #$f0 d358: c9 10 CMP #$10 ; is voice in percussion mode ? d35a: f0 01 BEQ $d35d ; if not, return d35c: 60 RTS d35d: b9 0d 26 LDA $260d, Y ; if tone = 'rest' d360: f0 fa BEQ $d35c d362: b9 9f 25 LDA $259f, Y ; get percussion pointer d365: 85 e8 STA $e8 d367: b9 a5 25 LDA $25a5, Y d36a: 85 e9 STA $e9 d36c: b2 e8 LDA ($e8) ; get bytecode d36e: e6 e8 INC $e8 ; increment pointer d370: d0 02 BNE $d374 d372: e6 e9 INC $e9 d374: aa TAX d375: c9 b0 CMP #$b0 ; < $b0 d377: 90 15 BCC $d38e d379: 29 f0 AND #$f0 d37b: c9 b0 CMP #$b0 ; = $bx d37d: f0 1a BEQ $d399 d37f: c9 c0 CMP #$c0 ; = $cx d381: f0 3c BEQ $d3bf d383: c9 d0 CMP #$d0 ; = $dx d385: f0 70 BEQ $d3f7 d387: c9 e0 CMP #$e0 ; = $ex d389: f0 73 BEQ $d3fe d38b: 4c 05 d4 JMP $d405 ; = $fx d38e: c0 04 CPY #$04 ; bytecode < $b0 (noise value, $00-$1f) d390: 90 22 BCC $d3b4 ; not a noise voice; return d392: 29 1f AND #$1f d394: 99 01 26 STA $2601, Y ; noise value d397: 80 1b BRA $d3b4 d399: 8a TXA ; = $bx (direct frequency, '$bx $yy'-> freq = $xyy) d39a: 38 SEC d39b: e9 b0 SBC #$b0 d39d: 99 ed 25 STA $25ed, Y ; put in direct frequency register (top 4 bits) d3a0: b2 e8 LDA ($e8) ; get next byte d3a2: e6 e8 INC $e8 ; increment pointer d3a4: d0 02 BNE $d3a8 d3a6: e6 e9 INC $e9 d3a8: 99 e7 25 STA $25e7, Y ; put in direct frequency register (bottom 8 bits) d3ab: c0 04 CPY #$04 d3ad: 90 05 BCC $d3b4 ; not a noise register; return d3af: a9 80 LDA #$80 ; disable noise value d3b1: 99 01 26 STA $2601, Y d3b4: a5 e8 LDA $e8 ; put back the percussion pointer d3b6: 99 9f 25 STA $259f, Y d3b9: a5 e9 LDA $e9 d3bb: 99 a5 25 STA $25a5, Y d3be: 60 RTS d3bf: b2 e8 LDA ($e8) ; = $cx (envelope sequence, value $00-$7f) d3c1: c9 10 CMP #$10 ; get next byte d3c3: b0 10 BCS $d3d5 d3c5: 0a ASL a ; internal envelope pointer d3c6: aa TAX d3c7: bd a1 d8 LDA $d8a1, X d3ca: 99 d9 24 STA $24d9, Y ; put in envelope pointer d3cd: bd a2 d8 LDA $d8a2, X d3d0: 99 df 24 STA $24df, Y d3d3: 80 44 BRA $d419 d3d5: 38 SEC ; external envelope definition d3d6: e9 10 SBC #$10 d3d8: 0a ASL a d3d9: 18 CLC d3da: 6d d5 22 ADC $22d5 ; add to user envelope pointer d3dd: 85 ea STA $ea d3df: 62 CLA d3e0: 6d d6 22 ADC $22d6 d3e3: 85 eb STA $eb d3e5: b2 ea LDA ($ea) ; get pointer & put it in evelope location d3e7: 99 d9 24 STA $24d9, Y d3ea: e6 ea INC $ea d3ec: d0 02 BNE $d3f0 d3ee: e6 eb INC $eb d3f0: b2 ea LDA ($ea) d3f2: 99 df 24 STA $24df, Y d3f5: 80 22 BRA $d419 d3f7: b2 e8 LDA ($e8) ; = $dx d3f9: 99 f9 25 STA $25f9, Y ; set pan pot value d3fc: 80 1b BRA $d419 d3fe: b2 e8 LDA ($e8) ; = $ex d400: 99 ff 25 STA $25ff, Y ; set waveform d403: 80 14 BRA $d419 d405: 62 CLA ; = $fx d406: 99 0d 26 STA $260d, Y ; 'tie type' = rest (end note I guess) d409: a5 e8 LDA $e8 d40b: 38 SEC d40c: e9 01 SBC #$01 d40e: 99 9f 25 STA $259f, Y ; decrement pointer (continue to point @ end) d411: a5 e9 LDA $e9 d413: e9 00 SBC #$00 d415: 99 a5 25 STA $25a5, Y d418: 60 RTS d419: e6 e8 INC $e8 ; increment pointer & return for more d41b: d0 02 BNE $d41f d41d: e6 e9 INC $e9 d41f: 4c 6c d3 JMP $d36c ; ; Envelope processing ; called from subtrack PSG driver ; d422: ae e0 22 LDX $22e0 ; current voice d425: bd 0d 26 LDA $260d, X ; envelope phase d428: d0 03 BNE $d42d d42a: 4c 9a d4 JMP $d49a ; finished d42d: 30 41 BMI $d470 ; is 'key off' ? (ie. released) d42f: c9 02 CMP #$02 ; initial strike d431: f0 5f BEQ $d492 d433: de bb 24 DEC $24bb, X ; key on/off ratio d436: d0 05 BNE $d43d ; key on still d438: 09 80 ORA #$80 ; key off d43a: 9d 0d 26 STA $260d, X d43d: bd 0f 25 LDA $250f, X ; envelope 'duration' command d440: d0 02 BNE $d444 ; execute it d442: 80 6f BRA $d4b3 ; no duration ; execute 'envelope duration command' ; d444: bd eb 24 LDA $24eb, X ; take 'level data' d447: 18 CLC d448: 7d f7 24 ADC $24f7, X ; add 'duration data' d44b: 9d eb 24 STA $24eb, X d44e: bd f1 24 LDA $24f1, X d451: 7d fd 24 ADC $24fd, X d454: 10 0b BPL $d461 ; still in range (0-$7fff) d456: 62 CLA d457: 9d eb 24 STA $24eb, X ; set LSB of level to 0 d45a: bc fd 24 LDY $24fd, X ; MSB of diration data d45d: 30 02 BMI $d461 d45f: a9 7c LDA #$7c d461: 9d f1 24 STA $24f1, X ; set MSB of level to either 0 or $7c (min/max) d464: bd 0f 25 LDA $250f, X ; get duration command d467: c9 ff CMP #$ff d469: f0 38 BEQ $d4a3 ; go away if it's finished d46b: de 0f 25 DEC $250f, X ; else decrement duration d46e: 80 33 BRA $d4a3 ; now, key is 'released' ; d470: bd eb 24 LDA $24eb, X ; level data LSB d473: 18 CLC d474: 7d 03 25 ADC $2503, X ; add 'release' rate d477: 9d eb 24 STA $24eb, X d47a: bd f1 24 LDA $24f1, X ; level data MSB d47d: 7d 09 25 ADC $2509, X d480: 10 0b BPL $d48d d482: 62 CLA ; out of range d483: 9d eb 24 STA $24eb, X ; set LSB of level to 0 d486: bc 09 25 LDY $2509, X ; check increase/decrease d489: 30 02 BMI $d48d d48b: a9 7c LDA #$7c d48d: 9d f1 24 STA $24f1, X ; set MSB of level to either 0 or $7c (min/max) d490: 80 11 BRA $d4a3 ; 'initial strike' (envelope phase = 2) ; d492: de 0d 26 DEC $260d, X ; strike becomes normal note d495: 9e e5 24 STZ $24e5, X ; envelope pointer offset d498: 80 19 BRA $d4b3 ; envelope phase = 0 (rest/end) ; d49a: 9e f3 25 STZ $25f3, X ; post-envelope volume d49d: 80 13 BRA $d4b2 ; ready to exit envelope loop ; d49f: 98 TYA d4a0: 9d e5 24 STA $24e5, X ; store envelope offset d4a3: bd f1 24 LDA $24f1, X ; divide level data by $400 d4a6: 4a LSR a d4a7: 4a LSR a d4a8: 18 CLC d4a9: 7d af 24 ADC $24af, X ; per-channel volume (max = $00; min = -$1f) d4ac: 10 01 BPL $d4af ; in range d4ae: 62 CLA ; out of range; force to 0 d4af: 9d f3 25 STA $25f3, X ; real hardware volume d4b2: 60 RTS d4b3: bc e5 24 LDY $24e5, X ; envelope index d4b6: bd d9 24 LDA $24d9, X ; copy envelope pointer to ZP d4b9: 85 e8 STA $e8 d4bb: bd df 24 LDA $24df, X d4be: 85 e9 STA $e9 d4c0: b1 e8 LDA ($e8), Y ; get next byte of envelope data d4c2: c9 fb CMP #$fb d4c4: 90 08 BCC $d4ce ; < $fb d4c6: f0 1d BEQ $d4e5 ; = $fb d4c8: c9 fc CMP #$fc d4ca: f0 1e BEQ $d4ea ; = $fc d4cc: 80 34 BRA $d502 ; all others ; < $fb in envelope data ; d4ce: c9 00 CMP #$00 d4d0: d0 01 BNE $d4d3 d4d2: 3a DEC a d4d3: 9d 0f 25 STA $250f, X ; envelope duration command d4d6: c8 INY d4d7: b1 e8 LDA ($e8), Y d4d9: 9d f7 24 STA $24f7, X ; envelope duration data (LSB) d4dc: c8 INY d4dd: b1 e8 LDA ($e8), Y d4df: 9d fd 24 STA $24fd, X ; envelope duration data (MSB) d4e2: c8 INY d4e3: 80 ba BRA $d49f ; $fb in envelope data ; d4e5: c8 INY ; disregard 3 bytes ($fb should only be first in data) d4e6: c8 INY d4e7: c8 INY d4e8: 80 d6 BRA $d4c0 ; $fc in envelope data ; d4ea: c8 INY d4eb: b1 e8 LDA ($e8), Y ; get next byte d4ed: 9d eb 24 STA $24eb, X ; envelope 'level data' (LSB) d4f0: c8 INY d4f1: b1 e8 LDA ($e8), Y d4f3: 9d f1 24 STA $24f1, X ; envelope 'level data' (MSB) d4f6: c8 INY d4f7: b1 e8 LDA ($e8), Y ; get next byte d4f9: c9 fb CMP #$fb d4fb: 90 d1 BCC $d4ce ; < $fb d4fd: 9e 0f 25 STZ $250f, X ; clear 'envelope duration' command d500: 80 9d BRA $d49f ; all other envelope data ; d502: a9 ff LDA #$ff d504: 9d 0f 25 STA $250f, X ; end of envelope duration d507: 9e f7 24 STZ $24f7, X ; clear envelope duration data d50a: 9e fd 24 STZ $24fd, X ; clear envelope duration data d50d: 4c a3 d4 JMP $d4a3 ; ; process frequency effects ; called from main track PSG driver ; d510: ae e0 22 LDX $22e0 ; current voice d513: bd e1 25 LDA $25e1, X ; get mode d516: 29 f0 AND #$f0 d518: f0 01 BEQ $d51b ; if tone, continue d51a: 60 RTS ; else return d51b: bd 9d 24 LDA $249d, X ; copy tone frequency data to d51e: 9d e7 25 STA $25e7, X ; output frequency area d521: bd a3 24 LDA $24a3, X d524: 9d ed 25 STA $25ed, X d527: bd 81 25 LDA $2581, X ; sweep value d52a: a8 TAY d52b: f0 39 BEQ $d566 ; no sweep d52d: bd 93 25 LDA $2593, X ; sweep time d530: f0 17 BEQ $d549 d532: de 99 25 DEC $2599, X ; sweep time countdown d535: d0 12 BNE $d549 ; still counting down d537: fe 99 25 INC $2599, X ; sweep time count up d53a: bd 87 25 LDA $2587, X ; sweep value LSB d53d: 85 ea STA $ea d53f: bd 8d 25 LDA $258d, X ; sweep value MSB d542: 85 eb STA $eb d544: 20 11 d6 JSR $d611 ; add to tone frequency d547: 80 1d BRA $d566 ; sweep time 0, or still counting down ; d549: 84 ea STY $ea ; use sweep value as basis to change 'freq change amount' d54b: 20 e2 d5 JSR $d5e2 ; (but use FM correction and octave to modify this amount) d54e: bd 87 25 LDA $2587, X ; add $ea/$eb to sweep amount d551: 18 CLC ; and store result in $ea/$eb AND sweep amount d552: 65 ea ADC $ea d554: 9d 87 25 STA $2587, X d557: 85 ea STA $ea d559: bd 8d 25 LDA $258d, X d55c: 65 eb ADC $eb d55e: 9d 8d 25 STA $258d, X d561: 85 eb STA $eb d563: 20 11 d6 JSR $d611 ; add $ea/$eb to tone frequency ; sweep done... ; ; now apply detune frequency change ; d566: bd 57 25 LDA $2557, X ; detune amount d569: f0 08 BEQ $d573 ; if none... d56b: 85 ea STA $ea d56d: 20 e2 d5 JSR $d5e2 ; use this as basis for changing freq. change amount d570: 20 11 d6 JSR $d611 ; add $ea/$eb to tone frequency ; now apply pitch envelope ; d573: bd 4b 25 LDA $254b, X ; Pitch Envelope delay d576: f0 34 BEQ $d5ac ; none d578: de 51 25 DEC $2551, X ; pitch envelope delay countdown d57b: d0 2f BNE $d5ac ; still counting down d57d: fe 51 25 INC $2551, X ; count up d580: bd 39 25 LDA $2539, X ; pitch envelope pointer d583: 85 e8 STA $e8 d585: bd 3f 25 LDA $253f, X d588: 85 e9 STA $e9 d58a: bc 45 25 LDY $2545, X ; pitch envelope offset d58d: b1 e8 LDA ($e8), Y ; fetch pitch envelope data d58f: c9 80 CMP #$80 ; data end d591: d0 07 BNE $d59a ; process data d593: c0 00 CPY #$00 d595: f0 15 BEQ $d5ac ; if data end is first byte d597: 88 DEY ; use previous byte instead d598: b1 e8 LDA ($e8), Y d59a: 85 ea STA $ea ; use as basis for freq change amount adjust d59c: 5a PHY d59d: 20 e2 d5 JSR $d5e2 ; change freq. change amount d5a0: 20 11 d6 JSR $d611 ; $ea/$eb to tone frequency d5a3: 7a PLY d5a4: c8 INY ; next ptitch envelope offset in data d5a5: d0 01 BNE $d5a8 d5a7: 88 DEY d5a8: 98 TYA d5a9: 9d 45 25 STA $2545, X ; put back pitch envelope offset ; Pitch envelope delay, countdown, or done ; d5ac: bd 27 25 LDA $2527, X ; FM Delay d5af: f0 30 BEQ $d5e1 ; none d5b1: de 2d 25 DEC $252d, X ; FM Delay countdown d5b4: d0 2b BNE $d5e1 ; not done yet d5b6: fe 2d 25 INC $252d, X ; count up d5b9: bd 15 25 LDA $2515, X ; FM Effect pointer d5bc: 85 e8 STA $e8 d5be: bd 1b 25 LDA $251b, X d5c1: 85 e9 STA $e9 d5c3: bc 21 25 LDY $2521, X ; FM effect offset d5c6: b1 e8 LDA ($e8), Y ; FM effect data d5c8: c9 80 CMP #$80 ; end of list d5ca: d0 0a BNE $d5d6 ; no, so process d5cc: c0 00 CPY #$00 ; if first byte exit d5ce: f0 11 BEQ $d5e1 d5d0: 9e 21 25 STZ $2521, X ; recycle if true d5d3: c2 CLY d5d4: 80 f0 BRA $d5c6 d5d6: 85 ea STA $ea ; use byte as amount to change frequency by d5d8: 20 e2 d5 JSR $d5e2 ; change freq change amount d5db: 20 11 d6 JSR $d611 ; add $ea/$eb to tone frequency d5de: fe 21 25 INC $2521, X ; replace FM effect offset d5e1: 60 RTS ; figure out how much to change ; the 'frequenecy change amount' by ; d5e2: 64 eb STZ $eb d5e4: a5 ea LDA $ea d5e6: 10 02 BPL $d5ea ; positive amount d5e8: c6 eb DEC $eb ; sign-extend d5ea: bd 33 25 LDA $2533, X ; FM correction d5ed: f0 21 BEQ $d610 ; exit if zero d5ef: 38 SEC d5f0: fd 97 24 SBC $2497, X ; octave number d5f3: a8 TAY d5f4: 30 09 BMI $d5ff ; octave # > FM orrection d5f6: f0 18 BEQ $d610 ; equal, so exit d5f8: 06 ea ASL $ea ; shift left (go up an octave) d5fa: 26 eb ROL $eb d5fc: 88 DEY ; loop for number of octaves d5fd: 80 f7 BRA $d5f6 d5ff: f0 07 BEQ $d608 ; exit if done d601: 46 eb LSR $eb ; shift right (go down an octave) d603: 66 ea ROR $ea d605: c8 INY d606: 80 f7 BRA $d5ff ; loop d608: a5 eb LDA $eb ; if zero do nothing d60a: f0 04 BEQ $d610 d60c: a9 ff LDA #$ff ; else put $ff there (started as minus d60e: 85 eb STA $eb ; until right-shifts... so restore sign) d610: 60 RTS ; add value in $ea/$eb to tone frequency ; and put it back in tone frequency ; d611: bd e7 25 LDA $25e7, X d614: 18 CLC d615: 65 ea ADC $ea d617: 9d e7 25 STA $25e7, X d61a: bd ed 25 LDA $25ed, X d61d: 65 eb ADC $eb d61f: 9d ed 25 STA $25ed, X d622: 60 RTS ; ; execute Fadeout volume adjustment ; d623: ad 13 26 LDA $2613 ; PSG_FADEOUT value d626: f0 24 BEQ $d64c ; return if zero d628: 18 CLC d629: 6d 14 26 ADC $2614 ; adjust fadeout change counter d62c: 10 05 BPL $d633 ; if >$7f, increment attenuation register d62e: ee 15 26 INC $2615 d631: 29 7f AND #$7f d633: 8d 14 26 STA $2614 d636: ad 15 26 LDA $2615 ; attenuation register d639: c9 1e CMP #$1e ; if no maximum, return d63b: 90 0f BCC $d64c d63d: a2 05 LDX #$05 ; for all voices d63f: bd 07 26 LDA $2607, X ; if voice off, continue d642: f0 05 BEQ $d649a d644: a9 02 LDA #$02 ; put 2 in control value d646: 9d 07 26 STA $2607, X d649: ca DEX ; loop d64a: 10 f3 BPL $d63f d64c: 60 RTS ; ; Set PSG data ; ; Note: it seems that when both 'main track' and 'subtrack' are ; playing music, the 'main track' will continue to follow ; the track, but will not play sound; the subtrack will ; play its sound until complete (then main track will play ; play sound again when subtrack is off) ; d64d: a2 05 LDX #$05 ; fpr each of 6 voices d64f: bd 07 26 LDA $2607, X ; per voice control d652: c9 01 CMP #$01 d654: 10 03 BPL $d659 d656: 4c ff d6 JMP $d6ff ; if inactive, end voice d659: 8e 00 08 STX $0800 ; set voice # in hardware d65c: f0 1d BEQ $d67b ; go, if ($2607 + x) == 1 d65e: 9c 04 08 STZ $0804 ; reset voice pointer d661: 9e 07 26 STZ $2607, X ; zero voice control (inactive) d664: ad df 22 LDA $22df ; end voice d667: c9 01 CMP #$01 ; PSG_INIT parm d669: f0 0d BEQ $d678 ; if subtrack only d66b: bd 7c 24 LDA $247c, X ; or if main track off d66e: f0 08 BEQ $d678 d670: bd 74 24 LDA $2474, X ; else force main track voice download d673: 29 7f AND #$7f d675: 9d 74 24 STA $2474, X d678: 4c ff d6 JMP $d6ff ; and end voice ; ; set wave # ; d67b: bd ff 25 LDA $25ff, X ; get wave # of voice d67e: 30 45 BMI $d6c5 ; if $80 bit set, keep old wave in PSG hardware d680: 09 80 ORA #$80 ; else set voice & set bit d682: 9d ff 25 STA $25ff, X d685: 29 7f AND #$7f d687: c9 2d CMP #$2d ; $2d internal voices d689: b0 12 BCS $d69d ; set internal wave number ; d68b: 20 06 d7 JSR $d706 ; $e8 = voice * $20 byte offset d68e: a9 a6 LDA #$a6 ; add base address $d9a6 d690: 18 CLC d691: 65 e8 ADC $e8 d693: 85 e8 STA $e8 d695: a9 d9 LDA #$d9 d697: 65 e9 ADC $e9 d699: 85 e9 STA $e9 d69b: 80 15 BRA $d6b2 ; set user wave number ; d69d: 38 SEC ; subtract # internal voices d69e: e9 2d SBC #$2d ; $e8 = voice * $20 byte offset d6a0: 20 06 d7 JSR $d706 ; add user data base address d6a3: ad d2 22 LDA $22d2 d6a6: 18 CLC d6a7: 65 e8 ADC $e8 d6a9: 85 e8 STA $e8 d6ab: ad d3 22 LDA $22d3 d6ae: 65 e9 ADC $e9 d6b0: 85 e9 STA $e9 d6b2: a9 40 LDA #$40 ; reset wave index to 0 d6b4: 8d 04 08 STA $0804 d6b7: 9c 04 08 STZ $0804 d6ba: c2 CLY ; loop to load wave data into wave buffer d6bb: b1 e8 LDA ($e8), Y ; $20 bytes of wave data d6bd: 8d 06 08 STA $0806 d6c0: c8 INY d6c1: c0 20 CPY #$20 d6c3: 90 f6 BCC $d6bb d6c5: e0 04 CPX #$04 ; if not a noise-capable voice, go to d6d5 d6c7: 90 0c BCC $d6d5 d6c9: bd 01 26 LDA $2601, X ; check special moise register d6cc: 30 07 BMI $d6d5 ; if done, skip it d6ce: 09 80 ORA #$80 ; else mark it for next time d6d0: 8d 07 08 STA $0807 ; place noise frequency in register d6d3: 80 0f BRA $d6e4 d6d5: 9c 07 08 STZ $0807 ; no noise d6d8: bd e7 25 LDA $25e7, X ; store tone frequency (low) d6db: 8d 02 08 STA $0802 d6de: bd ed 25 LDA $25ed, X ; store tone frequency (high) d6e1: 8d 03 08 STA $0803 d6e4: bd f9 25 LDA $25f9, X ; pan pot value d6e7: 8d 05 08 STA $0805 d6ea: bd f3 25 LDA $25f3, X ; final volume d6ed: 38 SEC d6ee: ed 15 26 SBC $2615 ; minus fadeout volume attenuation d6f1: f0 02 BEQ $d6f5 d6f3: 10 05 BPL $d6fa d6f5: 9c 04 08 STZ $0804 ; if zero or less, turn off volume d6f8: 80 05 BRA $d6ff d6fa: 09 80 ORA #$80 ; enable voice, with proper volume d6fc: 8d 04 08 STA $0804 d6ff: ca DEX ; loop back to next voice d700: 30 03 BMI $d705 d702: 4c 4f d6 JMP $d64f d705: 60 RTS ; finished ; ; multiply accumulator by $20 and put in ; $e8/$e9 (wave data offset calculation) ; d706: 64 e8 STZ $e8 d708: 4a LSR a d709: 66 e8 ROR $e8 d70b: 4a LSR a d70c: 66 e8 ROR $e8 d70e: 4a LSR a d70f: 66 e8 ROR $e8 d711: 85 e9 STA $e9 d713: 60 RTS ; ; frequency data ; d714: e4 0f .dw $0fe4 d716: 00 0f .dw $0f00 d718: 28 0e .dw $0e28 d71a: 5d 0d .dw $0d5d d71c: 9d 0c .dw $0c9d d71e: e7 0b .dw $0be7 d720: 3d 0b .dw $0b3d d722: 9b 0a .dw $0a9b d724: 03 0a .dw $0a03 d726: 73 09 .dw $0973 d728: eb 08 .dw $08eb d72a: 6a 08 .dw $086a d72c: f2 07 .dw $07f2 d72e: 80 07 .dw $0780 d730: 14 07 .dw $0714 d732: af 06 .dw $06af d734: 4f 06 .dw $064f d736: f4 05 .dw $05f4 d738: 9e 05 .dw $059e d73a: 4e 05 .dw $054e d73c: 02 05 .dw $0502 d73e: b9 04 .dw $04b9 d740: 76 04 .dw $0476 d742: 35 04 .dw $0435 d744: f9 03 .dw $03f9 d746: c0 03 .dw $03c0 d748: 8a 03 .dw $038a d74a: 57 03 .dw $0357 d74c: 27 03 .dw $0327 d74e: fa 02 .dw $02fa d750: cf 02 .dw $02cf d752: a7 02 .dw $02a7 d754: 81 02 .dw $0281 d756: 5d 02 .dw $025d d758: 3b 02 .dw $023b d75a: 1b 02 .dw $021b d75c: fc 01 .dw $01fc d75e: e0 01 .dw $01e0 d760: c5 01 .dw $01c5 d762: ac 01 .dw $01ac d764: 93 01 .dw $0193 d766: 7d 01 .dw $017d d768: 68 01 .dw $0168 d76a: 53 01 .dw $0153 d76c: 40 01 .dw $0140 d76e: 2e 01 .dw $012e d770: 1d 01 .dw $011d d772: 0d 01 .dw $010d d774: fe 00 .dw $00fe d776: f0 00 .dw $00f0 d778: e3 00 .dw $00e3 d77a: d6 00 .dw $00d6 d77c: ca 00 .dw $00ca d77e: be 00 .dw $00be d780: b4 00 .dw $00b4 d782: aa 00 .dw $00aa d784: a0 00 .dw $00a0 d786: 97 00 .dw $0097 d788: 8f 00 .dw $008f d78a: 87 00 .dw $0087 d78c: 7f 00 .dw $007f d78e: 78 00 .dw $0078 d790: 71 00 .dw $0071 d792: 6b 00 .dw $006b d794: 65 00 .dw $0065 d796: 5f 00 .dw $005f d798: 5a 00 .dw $005a d79a: 55 00 .dw $0055 d79c: 50 00 .dw $0050 d79e: 4b 00 .dw $004b d7a0: 47 00 .dw $0047 d7a2: 43 00 .dw $0043 d7a4: 40 00 .dw $0040 d7a6: 3c 00 .dw $003c d7a8: 39 00 .dw $0039 d7aa: 35 00 .dw $0035 d7ac: 32 00 .dw $0032 d7ae: 30 00 .dw $0030 d7b0: 2d 00 .dw $002d d7b2: 2a 00 .dw $002a d7b4: 28 00 .dw $0028 d7b6: 26 00 .dw $0026 d7b8: 24 00 .dw $0024 d7ba: 22 00 .dw $0022 d7bc: 20 00 .dw $0020 d7be: 1e 00 .dw $001e d7c0: 1c 00 .dw $001c d7c2: 1b 00 .dw $001b ; ; TEMPO DATA ; ; starting with value $23 (as sent to PSG_TEMPO), ; these numbers are the timer values to use for ; that tempo ; d7c4: 7d 79 76 73 .db $7d,$79,$76,$73 d7c8: 70 6d 6b 68 .db $70,$6d,$6b,$68 d7cc: 65 63 61 5f .db $65,$63,$61,$5f d7d0: 5d 5b 59 57 .db $5d,$5b,$59,$57 d7d4: 56 54 52 51 .db $56,$54,$52,$51 d7d8: 4f 4e 4d 4b .db $4f,$4e,$4d,$4b d7dc: 4a 49 48 46 .db $4a,$49,$48,$46 d7e0: 45 44 43 42 .db $45,$44,$43,$42 d7e4: 41 40 3f 3e .db $41,$40,$3f,$3e d7e8: 3e 3d 3c 3b .db $3e,$3d,$3c,$3b d7ec: 3a 3a 39 38 .db $3a,$3a,$39,$38 d7f0: 37 37 36 35 .db $37,$37,$36,$35 d7f4: 35 34 33 33 .db $35,$34,$33,$33 d7f8: 32 32 31 31 .db $32,$32,$31,$31 d7fc: 30 30 2f 2f .db $30,$30,$2f,$2f d800: 2e 2e 2d 2d .db $2e,$2e,$2d,$2d d804: 2c 2c 2b 2b .db $2c,$2c,$2b,$2b d808: 2a 2a 2a 29 .db $2a,$2a,$2a,$29 d80c: 29 28 28 28 .db $29,$28,$28,$28 d810: 27 27 27 26 .db $27,$27,$27,$26 d814: 26 26 25 25 .db $26,$26,$25,$25 d818: 25 24 24 24 .db $25,$24,$24,$24 d81c: 24 23 23 23 .db $24,$23,$23,$23 d820: 22 22 22 22 .db $22,$22,$22,$22 d824: 22 21 21 21 .db $22,$21,$21,$21 d828: 20 20 20 20 .db $20,$20,$20,$20 d82c: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f d830: 1f 1e 1e 1e .db $1f,$1e,$1e,$1e d834: 1e 1e 1d 1d .db $1e,$1e,$1d,$1d d838: 1d 1d 1d 1c .db $1d,$1d,$1d,$1c db3c: 1c 1c 1c 1c .db $1c,$1c,$1c,$1c d840: 1b 1b 1b 1b .db $1b,$1b,$1b,$1b d844: 1b 1b 1a 1a .db $1b,$1b,$1a,$1a d848: 1a 1a 1a 1a .db $1a,$1a,$1a,$1a d84c: 1a 19 19 19 .db $1a,$19,$19,$19 d850: 19 19 19 19 .db $19,$19,$19,$19 d854: 18 18 18 18 .db $18,$18,$18,$18 d858: 18 18 18 17 .db $18,$18,$18,$17 d85c: 17 17 17 17 .db $17,$17,$17,$17 d860: 17 17 17 17 .db $17,$17,$17,$17 d864: 16 16 16 16 .db $16,$16,$16,$16 d868: 16 16 16 16 .db $16,$16,$16,$16 d86c: 16 15 15 15 .db $16,$15,$15,$15 d870: 15 15 15 15 .db $15,$15,$15,$15 d874: 15 15 15 14 .db $15,$15,$15,$14 d878: 14 14 14 14 .db $14,$14,$14,$14 db7c: 14 14 14 14 .db $14,$14,$14,$14 d880: 14 14 13 13 .db $14,$14,$13,$13 d884: 13 13 13 13 .db $13,$13,$13,$13 d888: 13 13 13 13 .db $13,$13,$13,$13 d88c: 13 13 12 12 .db $13,$13,$12,$12 d890: 12 12 12 12 .db $12,$12,$12,$12 d894: 12 12 12 12 .db $12,$12,$12,$12 d898: 12 12 12 11 .db $12,$12,$12,$11 d89c: 11 11 11 11 .db $11,$11,$11,$11 d8a0: 11 .db $11 ; Envelope Data ; ; Envelope Header (pointers to data) ; d8a1: c1 d8 .dw $d8c1 d8a3: cb d8 .dw $d8cb d8a5: d5 d8 .dw $d8d5 d8a7: df d8 .dw $d8df d8a9: e9 d8 .dw $d8e9 d8ab: f3 d8 .dw $d8f3 d8ac: fd d8 .dw $d8fd d8ae: 07 d9 .dw $d907 d8b1: 14 d9 .dw $d914 d8b3: 21 d9 .dw $d921 d8b5: 34 d9 .dw $d934 d8b7: 41 d9 .dw $d941 d8b9: 51 d9 .dw $d951 d8bb: 61 d9 .dw $d961 d8bd: 6e d9 .dw $d96e d8bf: 7b d9 .dw $d97b ; ; envelope #0 ; dbc1: fb 00 84 .db $fb,$00,$84 d8c4: fc 00 7c .db $fc,$00,$7c d8c7: 00 00 00 .db $00,$00,$00 dbca: ff .db $ff ; ; envelope #1 ; d8cb: fb 00 fa .db $fb,$00,$fa d8ce: fc 00 7c .db $fc,$00,$7c d8d1: 0c 00 fe .db $0c,$00,$fe d8d4: ff .db $ff ; ; envelope #2 ; dbd5: fb 00 fd .db $fb,$00,$fd d8d8: fc 00 7c .db $fc,$00,$7c d8db: 0c 00 fe .db $0c,$00,$fe d8de: ff .db $ff ; ; envelope #3 ; dbdf: fb 00 ff .db $fb,$00,$ff d8e2: fc 00 7c .db $fc,$00,$7c d8e5: 0c 00 fe .db $0c,$00,$fe d8e8: ff .db $ff ; ; envelope #4 ; d8e9: fb 00 fa .db $fb,$00,$fa d8ec: fc 00 7c .db $fc,$00,$7c d8ef: 00 80 ff .db $00,$80,$ff d8f2: ff .db $ff ; ; envelope #5 ; dbf3: fb 00 fa .db $fb,$00,$fa d8f6: fc 00 7c .db $fc,$00,$7c d8f9: 00 00 ff .db $00,$00,$ff dbfc: ff .db $ff ; ; envelope #6 ; dbfd: fb 00 fa .db $fb,$00,$fa d900: fc 00 7c .db $fc,$00,$7c d903: 00 00 fe .db $00,$00,$fe d906: ff .db $ff ; ; envelope #7 ; d907: fb 00 fb .db $fb,$00,$fb d90a: fc 00 2c .db $fc,$00,$2c d90d: 02 00 28 .db $02,$00,$28 d910: 00 80 ff .db $00,$80,$ff d913: ff .db $ff ; ; envelope #8 ; d914: fb 00 fb .db $fb,$00,$fb d917: fc 00 34 .db $fc,$00,$34 d91a: 03 00 18 .db $03,$00,$18 d91d: 00 80 ff .db $00,$80,$ff d920: ff .db $ff ; ; envelope #9 ; d921: fb 00 fb .db $fb,$00,$fb d924: fc 00 1c .db $fc,$00,$1c d927: 01 00 60 .db $01,$00,$60 d92a: 02 00 fe .db $02,$00,$fe d92d: 08 00 fc .db $08,$00,$fc d930: 32 80 00 .db $32,$80,$00 d933: ff .db $ff ; ; envelope #$0a ; d934: fb 00 fd .db $fb,$00,$fd d937: fc 00 04 .db $fc,$00,$04 d93a: 03 00 28 .db $03,$00,$28 d93d: 04 00 fe .db $04,$00,$fe d940: ff .db $ff ; ; envelope #$0b ; d941: fb 00 fd .db $fb,$00,$fd d944: fc 00 00 .db $fc,$00,$00 d947: fc 00 00 .db $fc,$00,$00 d94a: fc 00 7c .db $fc,$00,$7c d94d: 00 c0 ff .db $00,$c0,$ff d950: ff .db $ff ; ; envelope #$0c ; d951: fb 00 fa .db $fb,$00,$fa d954: fc 00 00 .db $fc,$00,$00 d957: fc 00 00 .db $fc,$00,$00 d95a: fc 00 68 .db $fc,$00,$68 d95d: 00 60 00 .db $00,$60,$00 d960: ff .db $ff ; ; envelope #$0d ; d961: fb 00 fa .db $fb,$00,$fa d964: fc 00 7c .db $fc,$00,$7c d967: 04 00 f8 .db $04,$c0,$f8 d96a: 00 40 ff .db $00,$40,$ff d96d: ff .db $ff ; ; envelope #$0e ; d96e: fb 00 fa .db $fb,$00,$fa d971: fc 00 7c .db $fc,$00,$7c d974: 08 00 f8 .db $08,$00,$f8 d977: 00 40 ff .db $00,$40,$ff d97a: ff .db $ff ; ; envelope #$0f ; d97b: fb 00 ff .db $fb,$00,$ff d97e: fc 00 7c .db $fc,$00,$7c d981: 05 00 fc .db $05,$00,$fc d984: fc 00 70 .db $fc,$00,$70 d987: 05 00 fc .db $05,$00,$fc d98a: fc 00 64 .db $fc,$00,$64 d98d: 05 00 fc .db $05,$00,$fc d990: fc 00 58 .db $fc,$00,$58 d993: 05 00 fc .db $05,$00,$fc d996: fc 00 4c .db $fc,$00,$4c d999: 05 00 fc .db $05,$00,$fc d99c: fc 00 40 .db $fc,$00,$40 d99f: 05 00 fc .db $05,$00,$fc d9a2: 00 00 ff .db $00,$00,$ff d9a5: ff .db $ff ; data for PSG_INIT ; ; wave #0 ; d9a6: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f d9aa: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f d9ae: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f d9b2: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f d9b6: 01 01 01 01 .db $01,$01,$01,$01 d9ba: 01 01 01 01 .db $01,$01,$01,$01 d9be: 01 01 01 01 .db $01,$01,$01,$01 d9c2: 01 01 01 01 .db $01,$01,$01,$01 ; ; wave #1 ; d9c6: 0f 12 15 17 .db $0f,$12,$15,$17 d9ca: 19 1b 1d 1e .db $19,$1b,$1d,$1e d9ce: 1e 1e 1d 1b .db $1e,$1e,$1d,$1b d9d2: 19 17 15 13 .db $19,$17,$15,$13 d9d6: 10 0d 0a 07 .db $10,$0d,$0a,$07 d9da: 05 03 01 00 .db $05,$03,$01,$00 d9de: 00 00 01 03 .db $00,$00,$01,$03 d9e2: 05 07 09 0d .db $05,$07,$09,$0d ; ; wave #2 ; d9e6: 00 01 02 03 .db $00,$01,$02,$03 d9ea: 04 05 06 07 .db $04,$05,$06,$07 d9ee: 08 09 0a 0b .db $08,$09,$0a,$0b d9f2: 0c 0d 0e 0f .db $0c,$0d,$0e,$0f d9f5: 10 11 12 13 .db $10,$11,$12,$13 d9fa: 14 15 16 17 .db $14,$15,$16,$17 d9fe: 18 19 1a 1b .db $18,$19,$1a,$1b da02: 1c 1d 1e 1f .db $1c,$1d,$1e,$1f ; ; wave #3 ; da06: 19 19 09 09 .db $19,$19,$09,$09 da0a: 02 02 13 13 .db $02,$02,$13,$13 da0e: 07 07 1e 1e .db $07,$07,$1e,$1e da12: 0b 0b 15 15 .db $0b,$0b,$15,$15 da16: 05 05 09 09 .db $05,$05,$09,$09 da1a: 02 17 17 10 .db $02,$17,$17,$10 da1e: 10 1f 1f 0e .db $10,$1f,$1f,$0e da22: 0e 04 04 12 .db $0e,$04,$04,$12 ; ; wave #4 ; da26: 00 07 0f 17 .db $00,$07,$0f,$17 da2a: 1e 17 0f 07 .db $1e,$17,$0f,$07 da2e: 00 07 0f 17 .db $00,$07,$0f,$17 da32: 0f 07 0f 13 .db $0f,$07,$0f,$13 da36: 0f 0b 0f 11 .db $0f,$0b,$0f,$11 da3a: 0f 0d 0f 10 .db $0f,$0d,$0f,$10 da3e: 10 10 10 07 .db $10,$10,$10,$07 da42: 07 07 0f 07 .db $07,$07,$0f,$07 ; ; wave #5 ; da46: 1e 1c 1a 18 .db $1e,$1c,$1a,$18 da4a: 16 14 12 10 .db $16,$14,$12,$10 da4e: 0e 0c 0a 08 .db $0e,$0c,$0a,$08 da52: 06 04 02 01 .db $06,$04,$02,$01 da56: 01 01 01 01 .db $01,$01,$01,$01 da5a: 01 01 01 01 .db $01,$01,$01,$01 da5e: 01 01 01 01 .db $01,$01,$01,$01 da62: 01 01 01 1f .db $01,$01,$01,$1f ; ; wave #6 ; da66: 10 19 1c 1d .db $10,$19,$1c,$1d da6a: 1e 1f 1f 1f .db $1e,$1f,$1f,$1f da6e: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f da72: 1e 1d 1c 19 .db $1e,$1d,$1c,$19 da76: 10 06 03 02 .db $10,$06,$03,$02 da7a: 01 01 01 01 .db $01,$01,$01,$01 da7e: 01 01 01 01 .db $01,$01,$01,$01 da82: 01 02 03 06 .db $01,$02,$03,$06 ; ; wave #7 ; da86: 1d 0f 09 05 .db $1d,$0f,$09,$05 da8a: 03 01 03 05 .db $03,$01,$03,$05 da8e: 09 0f 15 19 .db $09,$0f,$15,$19 da92: 1b 1d 1b 19 .db $1b,$1d,$1b,$19 da96: 15 0f 07 03 .db $15,$0f,$07,$03 da9a: 01 03 07 0f .db $01,$03,$07,$0f da9e: 17 1b 1d 1b .db $17,$1b,$1d.$1b daa2: 17 0f 01 0f .db $17,$0f,$01,$0f ; ; wave #8 ; daa6: 10 13 16 18 .db $10,$13,$16,$18 daaa: 1b 1d 1e 1f .db $1b,$1d,$1e,$1f daae: 1f 1f 1e 1d .db $1f,$1f,$1e,$1d dab2: 1b 18 16 13 .db $1b,$18,$16,$13 dab6: 10 0c 09 07 .db $10,$0c,$09,$07 daba: 04 02 01 01 .db $04,$02,$01,$01 dabe: 01 01 01 02 .db $01,$01,$01,$02 dac2: 04 07 09 0c .db $04,$07,$09,$0c ; ; wave #9 ; dac6: 1b 1d 1b 17 .db $1b,$1d,$1b,$17 daca: 0f 0f 15 19 .db $0f,$0f,$15,$19 dace: 19 15 0f 0f .db $19,$15,$0f,$0f dad2: 09 05 05 09 .db $09,$05,$05,$09 dad6: 0f 0f 0d 07 .db $0f,$0f,$0d,$07 dada: 03 01 03 09 .db $03,$01,$03,$09 dade: 11 13 13 0f .db $11,$13,$13,$0f dae2: 0b 0b 0d 17 .db $0b,$0b,$0d,$17 ; ; wave #$0a ; dae6: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f daea: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f daee: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f daf2: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f daf6: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dafa: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dafe: 01 01 01 01 .db $01,$01,$01,$01 db02: 01 01 01 01 .db $01,$01,$01,$01 ; ; wave #$0b ; db06: 1f 00 04 06 .db $1f,$00,$04,$06 db0a: 08 0a 0c 0e .db $08,$0a,$0c,$0e db0e: 10 12 14 16 .db $10,$12,$14,$16 db12: 18 1a 1c 1e .db $18,$1a,$1c,$1e db16: 1f 1e 1c 1a .db $1f,$1e,$1c,$1a db1a: 18 16 14 12 .db $18,$16,$14,$12 db1e: 10 0e 0c 0a .db $10,$0e,$0c,$0a db22: 08 06 04 02 .db $08,$06,$04,$02 ; ; wave #$0c ; db26: 12 10 1a 1f .db $12,$10,$1a,$1f db2a: 18 0d 14 1c .db $18,$0d,$14,$1c db2e: 18 12 18 1c .db $18,$12,$18,$1c db32: 10 01 05 0b .db $10,$01,$05,$0b db36: 05 01 09 10 .db $05,$01,$09,$10 db3a: 05 00 03 0d .db $05,$00,$03,$0d db3e: 09 07 10 1a .db $09,$07,$10,$1a db42: 0d 03 10 14 .db $0d,$03,$10,$14 ; ; wave #$0d ; db46: 0f 15 17 18 .db $0f,$15,$17,$18 db4a: 1a 1d 1e 10 .db $1a,$1d,$1e,$10 db4e: 1f 1f 1d 1c .db $1f,$1f,$1d,$1c db52: 1a 18 14 10 .db $1a,$18,$14,$10 db56: 0f 0f 0b 07 .db $0f,$0f,$0b,$07 db5a: 05 03 02 10 .db $05,$03,$02,$10 db5e: 00 01 01 02 .db $00,$01,$01,$02 db62: 05 07 08 10 .db $05,$07,$08,$10 ; ; wave #$0e ; db66: 1f 1e 1b 17 .db $1f,$1e,$1b,$17 db6a: 13 0f 0b 07 .db $13,$0f,$0b,$07 db6e: 03 0f 0c 09 .db $03,$0f,$0c,$09 db72: 07 04 02 01 .db $07,$04,$02,$01 db76: 00 00 01 02 .db $00,$00,$01,$02 db7a: 04 07 09 0c .db $04,$07,$09,$0c db7e: 1f 1b 17 13 .db $1f,$1b,$17,$13 db82: 0f 0b 07 03 .db $0f,$0b,$07,$03 ; ; wave #$0f ; db86: 18 1f 1d 1d .db $18,$1f,$1d,$1d db8a: 1f 1c 14 0f .db $1f,$1c,$14,$0f db8e: 12 1c 1e 12 .db $12,$1c,$1e,$12 db92: 05 02 03 0a .db $05,$02,$03,$0a db96: 15 1c 1d 1a .db $15,$1c,$1d,$1a db9a: 0d 01 03 0d .db $0d,$01,$03,$0d db9e: 10 0b 03 00 .db $10,$0b,$03,$00 dba2: 02 02 00 07 .db $02,$02,$00,$07 ; ; wave #$10 ; dba6: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbaa: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbae: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbb2: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbb6: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbba: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbbe: 1f 00 1f 00 .db $1f,$00,$1f,$00 dbc2: 1f 00 1f 00 .db $1f,$00,$1f,$00 ; ; wave #$11 ; dbc6: 0d 0f 0b 00 .db $0d,$0f,$0b,$00 dbca: 10 1e 1d 1f .db $10,$1e,$1d,$1f dbcd: 13 10 0f 04 .db $13,$10,$0f,$04 dbd2: 0e 0d 10 01 .db $0e,$0d,$10,$01 dbd6: 00 02 02 0e .db $00,$02,$02,$0e dbda: 01 0d 0f 10 .db $01,$0d,$0f,$10 dbde: 0e 01 01 03 .db $0e,$01,$01,$03 dbe2: 0e 01 01 00 .db $0e,$01,$01,$00 ; ; wave #$12 ; dbe6: 10 1a 1f 1c .db $10,$1a,$1f,$1c dbea: 14 10 11 14 .db $14,$10,$11,$14 dbee: 16 14 11 10 .db $16,$14,$11,$10 dbf2: 14 1c 1f 1a .db $14,$1c,$1f,$1a dbf6: 10 05 01 03 .db $10,$05,$01,$03 dbfa: 0b 0f 0e 0b .db $0b,$0f,$0e,$0b dbfe: 09 0b 0e 0f .db $09,$0b,$0e,$0f dc02: 0b 03 01 05 .db $0b,$03,$01,$05 ; ; wave #$13 ; dc06: 16 1e 1e 17 .db $16,$1e,$1e,$17 dc0a: 0d 06 01 00 .db $0d,$06,$01,$00 dc0e: 00 00 00 00 .db $00,$00,$00,$00 dc12: 01 03 07 0c .db $01,$03,$07,$0c dc16: 13 18 1c 1e .db $13,$18,$1c,$1e dc1a: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dc1e: 1f 1e 19 12 .db $1f,$1e,$19,$12 dc22: 08 01 01 09 .db $08,$01,$01,$09 ; ; wave #$14 ; dc26: 14 1a 1e 1f .db $14,$1a,$1e,$1f dc2a: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dc2e: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dc32: 1f 1e 1a 14 .db $1f,$1e,$1a,$14 dc36: 0b 05 01 00 .db $0b,$05,$01,$00 dc3a: 00 00 00 00 .db $00,$00,$00,$00 dc3e: 00 00 00 00 .db $00,$00,$00,$00 dc42: 00 01 05 0b .db $00,$01,$05,$0b ; ; wave #$15 ; dc46: 17 1e 1d 17 .db $17,$1e,$1d,$17 dc4a: 10 16 1f 1c .db $10,$16,$1f,$1c dc4e: 1a 1e 1f 1f .db $1a,$1e,$1f,$1f dc52: 1c 0e 07 0a .db $1c,$0e,$07,$0a dc56: 14 18 11 03 .db $14,$18,$11,$03 dc5a: 00 00 01 05 .db $00,$00,$01,$05 dc5e: 03 00 09 0f .db $03,$00,$09,$0f dc62: 08 02 01 08 .db $08,$02,$01,$08 ; ; wave #$16 ; dc66: 18 1e 19 0f .db $18,$1e,$19,$0f dc6a: 12 1e 1d 1e .db $12,$1e,$1d,$1e dc6e: 1e 1d 1e 12 .db $1e,$1d,$1e,$12 dc72: 0f 19 1e 18 .db $0f,$19,$1e,$18 dc76: 07 01 06 10 .db $07,$01,$06,$10 dc7a: 0d 01 02 01 .db $0d,$01,$02,$01 dc7e: 01 02 01 0d .db $01,$02,$01,$0d dc82: 10 06 01 07 .db $10,$06,$01,$07 ; ; wave #$17 ; dc86: 10 16 1a 1c .db $10,$16,$1a,$1c dc8a: 1e 1c 1a 16 .db $1e,$1c,$1a,$16 dc8e: 10 0a 06 04 .db $10,$0a,$06,$04 dc92: 02 04 06 0a .db $02,$04,$06,$0a dc96: 10 18 1c 1e .db $10,$18,$1c,$1e dc9a: 1c 18 10 08 .db $1c,$18,$10,$08 dc9e: 02 08 10 1e .db $02,$08,$10,$1e dca2: 10 02 10 02 .db $10,$02,$10,$02 ; ; wave #$18 ; dca6: 10 13 16 18 .db $10,$13,$16,$18 dcaa: 1b 1d 1e 1f .db $1b,$1d,$1e,$1f dcae: 1f 1f 1e 1d .db $1f,$1f,$1e,$1d dcb2: 1b 18 16 13 .db $1b,$18,$16,$13 dcb6: 10 01 04 08 .db $10,$01,$04,$08 dcba: 0c 10 14 18 .db $0c,$10,$14,$18 dcbe: 1c 01 04 08 .db $1c,$01,$04,$08 dcc2: 0c 10 14 18 .db $0c,$10,$14,$18 ; ; wave #$19 ; dcc6: 1a 1c 1d 1e .db $1a,$1c,$1d,$1e dcca: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dcce: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f dcd2: 1e 1d 1b 19 .db $1e,$1d,$1b,$19 dcd6: 06 04 02 01 .db $06,$04,$02,$01 dcda: 00 00 00 00 .db $00,$00,$00,$00 dcde: 00 00 00 00 .db $00,$00,$00,$00 dce2: 01 02 04 06 .db $01,$02,$04,$06 ; ; wave #$1a ; dce6: 1b 14 10 0e .db $1b,$14,$10,$0e dcea: 0c 0b 16 09 .db $0c,$0b,$16,$09 dcee: 02 07 0a 05 .db $02,$07,$0a,$05 dcf2: 03 03 02 01 .db $03,$03,$02,$01 dcf6: 0b 15 1c 1e .db $0b,$15,$1c,$1e dcfa: 1a 0c 15 19 .db $1a,$0c,$15,$19 dcfe: 0c 18 07 12 .db $0c,$18,$07,$12 dd02: 0c 09 16 1a .db $0c,$09,$16,$1a ; ; wave #$1b ; dd06: 0f 15 1a 1c .db $0f,$15,$1a,$1c dd0a: 1f 1c 1a 15 .db $1f,$1c,$1a,$15 dd0e: 0f 08 04 02 .db $0f,$08,$04,$02 dd12: 00 02 04 08 .db $00,$02,$04,$08 dd16: 0f 17 1c 1f .db $0f,$17,$1c,$1f dd1a: 1c 17 0f 06 .db $1c,$17,$0f,$06 dd1e: 01 02 07 0f .db $01,$02,$07,$0f dd22: 0f 13 0f 00 .db $0f,$13,$0f,$00 ; ; wave #$1c ; dd26: 1f 1b 19 1c .db $1f,$1b,$19,$1c dd2a: 1f 1c 1a 17 .db $1f,$1c,$1a,$17 dd2e: 0c 04 03 02 .db $0c,$04,$03,$02 dd32: 08 0e 0d 04 .db $08,$0e,$0d,$04 dd36: 00 06 09 05 .db $00,$06,$09,$05 dd3a: 00 00 00 01 .db $00,$00,$00,$01 dd3e: 0a 10 11 12 .db $0a,$10,$11,$12 dd42: 0e 0c 0e 19 .db $0e,$0c,$0e,$19 ; ; wave #$1d ; dd46: 0f 02 11 1f .db $0f,$02,$11,$1f dd4a: 0f 1c 0d 00 .db $0f,$1c,$0d,$00 dd4e: 0f 02 11 1f .db $0f,$02,$11,$1f dd52: 0f 1c 0d 00 .db $0f,$1c,$0d,$00 dd56: 0f 02 11 1f .db $0f,$02,$11,$1f dd5a: 0f 1c 0d 00 .db $0f,$1c,$0d,$00 dd5e: 0f 02 11 1f .db $0f,$02,$11,$1f dd62: 0f 1c 0d 00 .db $0f,$1c,$0d,$00 ; ; wave #$1e ; dd66: 10 0a 14 1c .db $10,$0a,$14,$1c dd6a: 15 1d 16 10 .db $15,$1d,$16,$10 dd6e: 18 11 18 1f .db $18,$11,$18,$1f dd72: 15 1b 12 0a .db $15,$1b,$12,$0a dd76: 10 08 0e 14 .db $10,$08,$0e,$14 dd7a: 0a 10 07 00 .db $0a,$10,$07,$00 dd7e: 08 01 09 12 .db $08,$01,$09,$12 dd82: 0a 12 0b 06 .db $0a,$12,$0b,$06 ; ; wave #$1f ; dd86: 12 19 1d 1e .db $12,$19,$1d,$1e dd8a: 1f 1f 1f 1e .db $1f,$1f,$1f,$1e dd8e: 1c 17 12 0c .db $1c,$17,$12,$0c dd92: 0d 12 16 11 .db $0d,$12,$16,$11 dd96: 08 04 01 00 .db $08,$04,$01,$00 dd9a: 00 00 00 00 .db $00,$00,$00,$00 dd9e: 00 00 00 00 .db $00,$00,$00,$00 dda2: 00 01 04 0c .db $00,$01,$04,$0c ; ; wave #$20 ; dda6: 04 14 1e 17 .db $04,$14,$1e,$17 ddaa: 00 17 1e 16 .db $00,$17,$1e,$16 ddae: 10 1a 1f 1c .db $10,$1a,$1f,$1c ddb2: 12 16 18 10 .db $12,$16,$18,$10 ddb6: 06 12 1c 10 .db $06,$12,$1c,$10 ddba: 0c 0e 10 06 .db $0c,$0e,$10,$06 ddbe: 02 08 12 0c .db $02,$08,$12,$0c ddc2: 04 08 0e 08 .db $04,$08,$0e,$08 ; ; wave #$21 ; ddc6: 0a 0c 0e 0f .db $0a,$0c,$0e,$0f ddca: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f ddce: 14 14 13 12 .db $14,$14,$13,$12 ddd2: 1b 1b 1b 1b .db $1b,$1b,$1b,$1b ddd6: 0a 08 06 04 .db $0a,$08,$06,$04 ddda: 0e 0e 0e 0e .db $0e,$0e,$0e,$0e ddde: 00 00 00 02 .db $00,$00,$00,$02 dde2: 13 13 13 13 .db $13,$13,$13,$13 ; ; wave #$22 ; dde6: 1b 1b 05 05 .db $1b,$1b,$05,$05 ddea: 09 09 1f 1f .db $09,$09,$1f,$1f ddee: 1b 1b 16 16 .db $1b,$1b,$16,$16 ddf2: 1a 1a 07 07 .db $1a,$1a,$07,$07 ddf6: 17 17 15 15 .db $17,$17,$15,$15 ddfa: 19 19 0c 0c .db $19,$19,$0c,$0c ddfe: 1b 1b 0c 0c .db $1b,$1b,$0c,$0c de02: 00 00 03 03 .db $00,$00,$03,$03 ; ; wave #$23 ; de06: 1f 1d 1b 19 .db $1f,$1d,$1b,$19 de0a: 17 15 13 11 .db $17,$15,$13,$11 de0e: 0f 0d 0b 09 .db $0f,$0d,$0b,$09 de12: 07 05 03 01 .db $07,$05,$03,$01 de16: 00 0f 11 0d .db $00,$0f,$11,$0d de1a: 13 0b 15 09 .db $13,$0b,$15,$09 de1e: 17 07 19 05 .db $17,$07,$19,$05 de22: 1b 03 1d 01 .db $1b,$03,$1d,$01 ; ; wave #$24 ; de26: 0b 0e 11 13 .db $0b,$0e,$11,$13 de2a: 1f 1d 1a 17 .db $1f,$1d,$1a,$17 de2e: 09 05 02 00 .db $09,$05,$02,$00 de32: 0a 0b 0e 11 .db $0a,$0b,$0e,$11 de36: 0b 0e 1b 1e .db $0b,$0e,$1b,$1e de3a: 14 12 1a 17 .db $14,$12,$1a,$17 de3e: 09 05 0d 0a .db $09,$05,$0d,$0a de42: 00 01 0e 11 .db $00,$01,$0e,$11 ; ; wave #$25 ; de46: 0f 16 1b 1e .db $0f,$16,$1b,$1e da4a: 1f 1e 1b 16 .db $1f,$1e,$1b,$16 de4e: 0f 08 04 01 .db $0f,$08,$04,$01 de52: 00 01 04 08 .db $00,$01,$04,$08 de56: 0f 00 00 00 .db $0f,$00,$00,$00 de5a: 1f 1f 1f 1f .db $1f,$1f,$1f,$1f de5e: 1c 18 14 10 .db $1c,$18,$14,$10 de62: 0c 07 03 00 .db $0c,$07,$03,$00 ; ; wave #$26 ; de66: 02 01 05 0b .db $02,$01,$05,$0b de6a: 11 17 1b 1f .db $11,$17,$1b,$1f de6e: 1e 1b 17 13 .db $1e,$1b,$17,$13 de72: 0f 0b 09 0e .db $0f,$0b,$09,$0e de76: 18 1d 1c 17 .db $18,$1d,$1c,$17 de7a: 0f 0a 07 06 .db $0f,$0a,$07,$06 de7e: 11 19 1a 19 .db $11,$19,$1a,$19 de82: 10 0b 06 03 .db $10,$0b,$06,$03 ; ; wave #$27 ; de86: 1d 1d 1d 10 .db $1d,$1d,$1d,$10 de8a: 10 10 1d 1d .db $10,$10,$1d,$1d de8e: 1d 1d 1b 1b .db $1d,$1d,$1b,$1b de92: 1b 1b 1b 1b .db $1b,$1b,$1b,$1b de96: 00 00 00 00 .db $00,$00,$00,$00 de9a: 00 00 02 02 .db $00,$00,$02,$02 de9e: 02 02 10 10 .db $02,$02,$10,$10 dea2: 10 02 02 02 .db $10,$02,$02,$02 ; ; wave #$28 ; dea6: 19 16 10 12 .db $19,$16,$10,$12 deae: 12 09 16 1f .db $12,$09,$16,$1f deae: 0f 17 0f 10 .db $0f,$17,$0f,$10 deb2: 1d 13 11 10 .db $1d,$13,$11,$10 deb6: 0e 19 1b 00 .db $0e,$19,$1b,$00 deba: 0f 03 0c 12 .db $0f,$03,$0c,$12 debe: 17 0f 16 11 .db $17,$0f,$16,$11 dec2: 12 05 0d 06 .db $12,$05,$0d,$06 ; ; wave #$29 ; dec6: 00 07 0b 0b .db $00,$07,$0b,$0b deca: 09 03 00 01 .db $09,$03,$00,$01 dece: 17 17 15 10 .db $17,$17,$15,$10 ded2: 0c 0a 0d 13 .db $0c,$0a,$0d,$13 ded6: 07 0e 12 11 .db $07,$0e,$12,$11 deda: 0f 09 07 07 .db $0f,$09,$07,$07 dede: 1f 1e 1d 17 .db $1f,$1e,$1d,$17 dee2: 13 11 13 1a .db $13,$11,$13,$1a ; ; wave #$2a ; dee6: 19 04 03 03 .db $19,$04,$03,$03 deea: 02 02 01 01 .db $02,$02,$01,$01 deee: 03 03 01 01 .db $03,$03,$01,$01 def2: 01 01 00 01 .db $01,$01,$00,$01 def6: 00 01 19 19 .db $00,$01,$19,$19 defa: 1b 1b 1b 1b .db $1b,$1b,$1b,$1b defe: 19 1e 1e 1e .db $19,$1e,$1e,$1e df02: 0d 1b 19 04 .db $0d,$1e,$19,$04 ; ; wave #$2b ; df06: 0f 15 19 1b .db $0f,$15,$19,$1b df0a: 1d 1e 1f 1e .db $1d,$1e,$1f,$1e df0e: 1d 1b 19 15 .db $1d,$1b,$19,$15 df12: 0f 07 17 0a .db $0f,$07,$17,$0a df16: 14 0d 12 0f .db $14,$0d,$12,$0f df1a: 10 0a 06 04 .db $10,$0a,$06,$04 df1e: 02 01 00 01 .db $02,$01,$00,$01 df22: 02 04 06 0a .db $02,$04,$06,$0a ; ; wave #$2c ; df26: 09 18 1d 0b .db $09,$18,$1d,$0b df2a: 00 06 13 1c .db $00,$06,$13,$1c df2e: 18 10 06 02 .db $18,$10,$06,$02 df32: 00 00 00 00 .db $00,$00,$00,$00 df36: 02 08 16 1b .db $02,$08,$16,$1b df3a: 09 03 10 1e .db $09,$03,$10,$1e df3e: 1e 1b 16 0b .db $1e,$1b,$16,$0b df42: 05 01 00 00 .db $05,$01,$00,$00 df46: ff ff ff df49: ff ff ff df4c: ff ff ff df4f: ff ff ff df52: ff ff ff df55: ff ff ff df58: ff ff ff df5b: ff ff ff df5e: ff ff ff df61: ff ff ff df64: ff ff ff df67: ff ff ff df6a: ff ff ff df6d: ff ff ff df70: ff ff ff df73: ff ff ff df76: ff ff ff df79: ff ff ff df7c: ff ff ff df7f: ff ff ff df82: ff ff ff df85: ff ff ff df88: ff ff ff df8b: ff ff ff df8e: ff ff ff df91: ff ff ff df94: ff ff ff df97: ff ff ff df9a: ff ff ff df9d: ff ff ff dfa0: ff ff ff dfa3: ff ff ff dfa6: ff ff ff dfa9: ff ff ff dfac: ff ff ff dfaf: ff ff ff dfb2: ff ff ff dfb5: ff ff ff dfb8: ff ff ff dfbb: ff ff ff dfbe: ff ff ff dfc1: ff ff ff dfc4: ff ff ff dfc7: ff ff ff dfca: ff ff ff dfcd: ff ff ff dfd0: ff ff ff dfd3: ff ff ff dfd6: ff ff ff dfd9: ff ff ff dfdc: ff ff ff dfdf: ff ff ff dfe2: ff ff ff dfe5: ff ff ff dfe8: ff ff ff dfeb: ff ff ff dfee: ff ff ff dff1: ff ff ff dff4: ff ff ff dff7: ff ff ff dffa: ff ff ff dffd: ff ff ff