;Super Mario World demo using SKCTL 2-tone mode
;
; CHANNEL LAYOUT
;
;
; AUDCTL=$00 (no special settings)
; SKCTL=$8B (two tone mode)
;
; Channel 0:  $Ax distortion, square wave - modulated from channel 1
; Channel 1:  Silenced ($00) - frequency carrier to channel 0
; Channel 2:  $Ax distortion, no special settings
; Channel 3:  $Ax distortion, no special settings
;
; To play music:
;
; Channel 1 has frequency values taken from standard $Ax 8-bit note table
; Channel 0 plays the same melody as 1, taken from same $Ax note table
;           but transposed up 14 semitones to maintain the pulse width

	ORG	$2200									;TO $27FF

;	TUNE VARIABLES - $34 BYTES
TUNEAREA		EQU	$2200
TUNESOFF		EQU	TUNEAREA+$0000				;1 BYTE  - FLAG FOR ALL TUNES OFF
TUNNUM			EQU	TUNEAREA+$0001				;1 BYTE  - CURRENT TUNE NUMBER BEING PROCESSED
TUNCHANNEL		EQU	TUNEAREA+$0002				;1 BYTE  - CONVERTED FOR INDEX INTO POKEY CHANNEL REGISTERS
TUNFILLER		EQU	TUNEAREA+$0003				;1 BYTE  - NOT USED YET
TUNON			EQU	TUNEAREA+$0004				;4 BYTES - FLAG FOR TUNE PLAYING BY CHANNEL
NOTELO			EQU	TUNEAREA+$0008				;4 BYTES - INDEX INTO NOTE TABLE LOW
NOTEHI			EQU	TUNEAREA+$000C				;4 BYTES - INDEX INTO NOTE TABLE HI
CTLVOL			EQU	TUNEAREA+$0010				;4 BYTES - CONTROL / VOLUME VALUE BY CHANNEL
TUNINDEX		EQU	TUNEAREA+$0014				;4 BYTES - TUNE NUMBER BY CHANNEL
TUNFRM			EQU	TUNEAREA+$0018				;4 BYTES - NUMBER OF FRAMES (DURATION COUNT)
TUNPRIOR		EQU	TUNEAREA+$001C				;4 BYTES - TUNE PRIORITY BY CHANNEL
DURNLO			EQU	TUNEAREA+$0020				;4 BYTES - INDEX INTO DURATION TABLE LOW
DURNHI			EQU	TUNEAREA+$0024				;4 BYTES - INDEX INTO DURATION TABLE HI
DCYSTOR			EQU	TUNEAREA+$0028				;4 BYTES - FOR NOTE DECAY BY CHANNEL
FREQCNT			EQU	TUNEAREA+$002C				;4 BYTES - FOR NOTE DECAY BY CHANNEL
CTLSAV			EQU	TUNEAREA+$0030				;4 BYTES - TO SAVE THE CONTROL VALUE

	org $2240

;	SOUND -------------------------------------------------------------------------------------------------------------------->

;	TUNES - THESE ROUTINES HANDLE ALL OF THE SOUNDS

;	RESET POKEY CHIP
RSTPOKEY:
	LDX #$0F 
	LDA #$00
RSTLP:
	STA AUDF0,X									;CLEAR POKEY REGISTERS
	DEX 
	BPL RSTLP 
	LDA #$03
	STA SKCTL	;S									;TURN IT ON
	RTS

;	TURN OFF ALL SOUNDS
STOPTUN
	LDA #$00
	STA AUDC0
	STA AUDC1
	STA AUDC2
	STA AUDC3
	LDA #$01
	STA TUNESOFF
	RTS

;	TURN ON ALL SOUNDS
STARTTUN
	LDA #$00
	STA TUNESOFF
	RTS

;	THIS ROUTINE ERASES ALL TUNES
;	X AND Y ARE PRESERVED
CLEARTUN
	TXA											;STACK REGISTERS
	PHA
	TYA
	PHA
	LDX #$03
CTLOOP
	JSR ENDTUNE									;ERASE CURRENT TUNE
	DEX
	BPL CTLOOP
	PLA											;UNSTACK REGISTERS
	TAY
	PLA
	TAX
	RTS

;	ROUTINE TO KILL A PARTICULAR TUNE - IF IT IS RUNNING
;	INPUT: TUNE NUMBER IN A
;	X AND Y ARE PRESERVED
KILLTUNE
	STA TUNNUM									;SAVE IT
	TXA											;STACK REGISTERS
	PHA
	TYA
	PHA
	LDX #$03									;CHECK ALL CHANNELS
KTLOOP
	LDA TUNON,X									;SEE IF CHANNEL ON
	BEQ KTNEXT
	LDA TUNINDEX,X								;SEE IF HAS TUNE TO BE KILLED
	CMP TUNNUM
	BNE KTNEXT
	JSR ENDTUNE									;ERASE IT
KTNEXT
	DEX
	BPL KTLOOP
	PLA											;UNSTACK REGISTERS
	TAY
	PLA
	TAX
	RTS

;	THIS ROUTINE CLEARS OUT A TUNE CHANNEL
;	INPUT: X IS CHANNEL
ENDTUNE
	LDA #$00
	STA TUNON,X									;INDICATE CHANNEL CLEAR
	STA TUNINDEX,X								;CLEAR TUNE INDEX
	STA DCYSTOR,X
	STA FREQCNT,X
	RTS

;	THIS ROUTINE ENTERS A TUNE INTO ONE OF THE SOUND CHANNELS IF IT CAN
;	INPUT:  TUNE NUMBER IN A
;	X AND Y ARE PRESERVED
DOTUNE
	STA TUNNUM									;SAVE IT
	;LDA AUTOPLAY								;IF IN AUTOPLAY - NO SOUND
	;BEQ DTCONT
	;RTS
DTCONT
	TXA											;STACK REGISTERS
	PHA
	TYA
	PHA
	LDY TUNNUM									;SEE IF WE CAN PUT IT IN
	LDX CHANNLTBL,Y								;GET WHAT CHANNEL TO TRY TO PUT IT IN
	LDA TUNON,X									;SEE IF CHANNEL OPEN
	BEQ DTDOIT
	LDA PRIRTYTBL,Y								;SEE IF WE CAN BUMP CHANNEL
	CMP TUNPRIOR,X
	BMI DTOUT
DTDOIT
	LDA TUNNUM
	TAY											;PUT TUNE IN Y
	STA TUNINDEX,X								;SET THE TUNE INDEX
	LDA #$00									;TURN TUNE OFF WHILE CHANGING IT
	STA TUNON,X
	LDA CNTVOLTBL,Y								;GET TUNE CONTROL / VOLUME
	STA CTLVOL,X
	STA CTLSAV,X								;USED TO RESTORE AFTER DECAY
	LDA NOTETBLLO,Y								;GET TUNE FREQUENCY LOW ADDRESS
	STA NOTELO,X
	LDA NOTETBLHI,Y								;GET TUNE FREQUENCY HIGH ADDRESS
	STA NOTEHI,X
	LDA DURNTBLLO,Y								;GET TUNE DURATION LOW ADDRESS
	STA DURNLO,X
	LDA DURNTBLHI,Y								;GET TUNE DURATION HIGH ADDRESS
	STA DURNHI,X
	LDA PRIRTYTBL,Y								;SET PRIORITY
	STA TUNPRIOR,X
	LDA #$01									;SET FREQ, CTL, AND VOL TO BE SET
	STA TUNFRM,X
	STA TUNON,X									;AND TURN THE TUNE ON!
DTOUT
	PLA											;UNSTACK REGISTERS
	TAY
	PLA
	TAX
	RTS

;  THIS ROUTINE IS CALLED EVERY VBLANK TO TAKE CARE OF TUNES
;  REGISTERS ARE NOT SAVED
TUNER
	LDX #$03									;FOUR TUNES CHANNELS, START WITH LAST
	LDA TUNESOFF
	BEQ TUNLOOP
	RTS
TUNLOOP
	TXA
	ASL
	STA TUNCHANNEL								;CHANNELS ARE OFFSET 0, 2, 4, 6 IN THE POKEY
	TAY
	LDA TUNON,X
	BNE TUNBODY
	STA AUDC0,Y									;CHANNEL OFF - MAKE SURE VOLUME OFF
	JMP TUNNEXT
TUNBODY
	DEC TUNFRM,X								;SEE IF WE'RE DONE WITH THIS SOUND
	BEQ TUNFRMFRQ								;YES - GET NEXT NOTE / DURATION
	DEC FREQCNT,X                               ;REDUCE THE NUMBER OF FRAMES UNTIL NEXT DECAY
	BEQ DEC_VOLUME
	JMP TUNNEXT                                 ;IF WE AREN'T AT ZERO YET, DON'T DECAY

DEC_VOLUME
	LDA DCYSTOR,X                               ;RESET THE DECAY FOR THE NEXT COUNT
	STA FREQCNT,X

	LDA CTLVOL,X                                ;IF VOLUME ALREADY 0 DO NOT DECREMENT
	AND #$0F
	BEQ TUNNEXT
	
	DEC CTLVOL,X                                ;DECREMENT THE VOLUME
	LDA CTLVOL,X
	LDY TUNCHANNEL
	;AND MUTEMASK,Y
	STA AUDC0,Y
	JMP TUNNEXT                                 ;GO TO NEXT CHANNEL
TUNFRMFRQ
	LDA DURNLO,X								;GET THE CURRENT DURATION
	STA SOUNDZP
	LDA DURNHI,X
	STA SOUNDZP+1
	LDY #$00
	LDA (SOUNDZP),Y
	BEQ TUNEND									;$00 IN DURATION MEANS TUNE IS OVER
	STA TUNFRM,X
	TAY
	LDA DECAYTBL,Y								;GET THE CURRENT DECAY VALUE INDEXED BY NOTE
	STA DCYSTOR,X								;STORE IT HERE TO REFRESH THE COUNTER FOR THE NEXT DECAY
	STA FREQCNT,X								;ALSO STORE IT HERE FOR TUNER
	LDY TUNCHANNEL
	LDA CTLSAV,X
	STA CTLVOL,X								;RESTORE THE ORIGINAL CONTROL AND VOLUME FOR NEXT NOTE
	STA AUDC0,Y
	LDA NOTELO,X								;GET THE CURRENT FREQUENCY
	STA SOUNDZP
	LDA NOTEHI,X
	STA SOUNDZP+1
	LDY #$00
	LDA (SOUNDZP),Y
	LDY TUNCHANNEL
	STA AUDF0,Y
	INC NOTELO,X
	BNE TUNNEXTNOTE
	INC NOTEHI,X
TUNNEXTNOTE
	INC DURNLO,X
	BNE TUNNEXT
	INC DURNHI,X
TUNNEXT
	DEX
	CPX #$00
	BMI TUNEXIT
	JMP TUNLOOP
TUNEXIT
	RTS

TUNEND
	LDA NOTELO,X								;SEE IF WE SHOULD REPEAT
	STA SOUNDZP
	LDA NOTEHI,X
	STA SOUNDZP+1
	LDY #$00
	LDA (SOUNDZP),Y
	BMI TUNRESTART
	JSR ENDTUNE
	JMP TUNNEXT
TUNRESTART
	LDA TUNINDEX,X								;GET TUNE NUMBER
	TAY
	LDA CNTVOLTBL,Y								;GET TUNE CONTROL / VOLUME
	STA CTLVOL,X
	STA CTLSAV,X								;USED TO RESTORE AFTER DECAY
	LDA NOTETBLLO,Y								;GET TUNE FREQUENCY LOW ADDRESS
	STA NOTELO,X
	LDA NOTETBLHI,Y								;GET TUNE FREQUENCY HIGH ADDRESS
	STA NOTEHI,X
	LDA DURNTBLLO,Y								;GET TUNE DURATION LOW ADDRESS
	STA DURNLO,X
	LDA DURNTBLHI,Y								;GET TUNE DURATION HIGH ADDRESS
	STA DURNHI,X
	LDY TUNCHANNEL
	LDA CTLVOL,X
	STA AUDC0,Y									;STORE THE CONTROL / VOLUME IN THE CHANNEL
	LDA #$01									;SET FREQ, CTL, AND VOL TO BE SET
	STA TUNFRM,X
	JMP TUNNEXT

;	DATA FOR TUNES

;	CNTVOLTBL - HIGH NYBBLE FOR VOICE CONTROL (7654XXXX), AND LOW NYBBLE FOR VOLUME (XXXX3210)
CNTVOLTBL:
	
	.byte $a4,$a4,$c5,$a5
	

;	PRIORITY TABLE
PRIRTYTBL:
	
	.byte $02,$02,$02,$00	
	
	
	
;	CHANNEL TABLE ($00 - $03 ARE VALID)
CHANNLTBL:
	
	.byte $00,$01,$02,$03
	

;	DECAY TABLE - DEFINES DECAY COUNT INDEXED BY NOTE DURATION
DECAYTBL:
	.byte $01,$01,$01,$01,$02,$02,$02,$02
	.byte $02,$03,$03,$03,$03,$03,$03,$03
	.byte $04,$04,$04,$04,$04,$04,$04,$04
	.byte $05,$05,$05,$05,$05,$05,$05,$05
	.byte $05,$05,$06,$06,$06,$06,$06,$06
	.byte $06,$06,$06,$06,$07,$07,$07,$07
	.byte $07,$07,$07,$07,$07,$07,$07,$07
	.byte $07,$08,$08,$08,$08,$08,$08,$08

;	FREQUENCY TABLE
NOTETBLHI:
	.byte >(TUNE00),>(TUNE01),>(TUNE02),>(TUNE03)
	
NOTETBLLO:
	.byte <(TUNE00),<(TUNE01),<(TUNE02),<(TUNE03)
	

;	DURATION TABLE
DURNTBLHI:
	.byte >(DURN00),>(DURN01),>(DURN02),>(DURN03)
	

DURNTBLLO:
	.byte <(DURN00),<(DURN01),<(DURN02),<(DURN03)
	

;TEMPOS
T1	=	$03
T2      =       (T1*2)
T3      =       (T1*3)
T4      =       (T1*4)
T5      =       (T1*5)
T6      =       (T1*6)
T7      =       (T1*7)
T8      =       (T1*8)
T9      =       (T1*9)
TA      =       (T1*10)
TB      =       (T1*11)
TC      =       (T1*12)
TD      =       (T1*13)
TE      =       (T1*14)
TF      =       (T1*15)
T0      =       (T1*16)


; CHANNEL 0 - $Ax setting, plays melody transposed up 14 semitones 

TUNE00:
	.byte 60,53,50,60,53,50,53,60,53
	.byte 60,53,50,60,53,50,53,60,53
	.byte 50,45,40,50,45,40,45,50,45
	.byte 50,45,40,50,45,40,45,50,45
	.byte 37,33,30,37,33,30,33,37,33
	.byte 37,33,30,37,33,30,33,37,33
	.byte 40,35,31,40,35,31,35,40,35
	.byte 40,35,31,30,26,25,22,19
	.byte 14,16,18,19,22,19
	.byte 16,18,19,22,19
	.byte 18,19,22,25
	.byte 26,25,26,25,26,25,26,25,26,25,26,25,26,25,26,25,26
	.byte -1
	
	


DURN00:
    .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,12,12,12,12,12
	 .byte 48,48,6,12,6,72
	 .byte 48,48,48,24,24
	 .byte 48,48,48,48
	 .byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,96
	
	.byte 0
	
; CHANNEL 1 - Silenced ($00) but plays the main melody.  Frequency carrier for channel 0


TUNE01:   
	.byte 162,144,136,162,144,136,144,162,144
	.byte 162,144,136,162,144,136,144,162,144
	.byte 136,121,108,136,121,108,121,136,121
	.byte 136,121,108,136,121,108,121,136,121
	.byte 102,91,81,102,91,81,91,102,91
	.byte 102,91,81,102,91,81,91,102,91
	.byte 108,96,85,108,96,85,96,108,96
	.byte 108,96,85,81,72,68,60,53
	.byte 40,45,50,53,60,53
	.byte 45,50,53,60,53
	.byte 50,53,60,68
	.byte 72,68,72,68,72,68,72,68,72,68,72,68,72,68,72,68,72
	
	
	.byte -1
			
	
	
DURN01:
	.byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,6,12,6,12,12,12
	 .byte 12,12,12,12,12,12,12,12
	 .byte 48,48,6,12,6,72
	 .byte 48,48,48,24,24
	 .byte 48,48,48,48
	 .byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,96
	
	.byte 0
	
	

	
	
	
	



	

	
	
; Channel 2 - Normal 8-bit channel ($Ax)



TUNE02:
   .byte 131,131,110,110,80,80,86,86
   .byte 131,131,110,110,80,80,86,86
	.byte -1
	
		
	
	
	
	

DURN02: 
	
	

    
    .byte 96,96,96,96,96,96,96,96
	.byte 96,96,96,96,96,96,96,96
	
	.byte 0
	
; CHANNEL 3 - Normal 8-bit channel ($Ax)
	
TUNE03:
	.byte 0,0,162,81,40,81,162,0,0,0,162,81,40,81,162,0
	.byte 0,0,162,81,40,81,162,0,0,0,162,81,40,81,162,0
	.byte 0,0,136,68,33,68,136,0,0,0,136,68,33,68,136,0
	.byte 0,0,136,68,33,68,136,0,0,0,136,68,33,68,136,0
	.byte 0,204,102,50,25,50,102,204,0,204,102,50,25,50,102,204
	.byte 0,204,102,50,25,50,102,204,0,204,102,50,25,50,102,204
	.byte 0,217,108,53,26,53,108,217,0,217,108,53,26,53,108,217
	.byte 0,217,108,53,26,53,108,217,0,217,108,53,26,53,108,217
	
	
	.byte 0,0,162,81,40,81,162,0,0,0,162,81,40,81,162,0
	.byte 0,0,162,81,40,81,162,0,0,0,162,81,40,81,162,0
	.byte 0,0,136,68,33,68,136,0,0,0,136,68,33,68,136,0
	.byte 0,0,136,68,33,68,136,0,0,0,136,68,33,68,136,0
	.byte 0,204,102,50,25,50,102,204,0,204,102,50,25,50,102,204
	.byte 0,204,102,50,25,50,102,204,0,204,102,50,25,50,102,204
	.byte 0,217,108,53,26,53,108,217,0,217,108,53,26,53,108,217
	.byte 0,217,108,53,26,53,108,217,0,217,108,53,26,53,108,217
	
	.byte -1
	
	
DURN03:
    .byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	.byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	
	
	.byte 0


