;
; LOD Player V1.00
; Coded by Csabo of LOD 2000-2003
; Slightly modified: note constants start at A instead of C
F1LO	= $FF0E
F1HI	= $FF12
F2LO	= $FF0F
F2HI	= $FF10
VOL	= $FF11

; Address of freq table
; change it to whatever suits you
; the table will take up $80 bytes
freqs = $0380

; Constants
END_MARK	= $FF
SNARE		= $FE  
QUIET		= $FD
LOOP_START	= $FC
LOOPS		= $FC
LOOP_END	= $FB
LOOPE		= $FB
SET_VOL		= $F0
ns		= $80	; (N)o (S)peed

; Word Variables
PCH1		= $60	; channel data pattern pointers
PCH2		= $62

CH1		= $64	; channel data pointers
CH2		= $66

LOOP_CH1	= $68
LOOP_COUNT1	= $6A

LOOP_CH2	= $6C
LOOP_COUNT2	= $6E

; Byte Variables
CWAIT1		= $70	; wait counters
CWAIT2		= $71
PWAIT1		= $72	; (P)revious wait counters
PWAIT2		= $73

CHANNELS	= $74
VOLUME		= $75
DECFLAG		= $76

;-----
;Note contstants for music

C0 = 4
Ci = 5
D0 = 6
Di = 7
E0 = 8
F0 = 9
Fi = 10
G0 = 11
Gi = 12
A0 = 1
Ai = 2
B0 = 3

O0 = 0
O1 = 12
O2 = 24
O3 = 36
O4 = 48
O5 = 60

PLAYER_INIT
	JSR reset_ch1
	JSR reset_ch2
	;
PLAYER_INIT_POS			; use this entry point
				; if you manually reset
				; music position
	JSR advance_ch1
	JSR advance_ch2
	;
	LDX #$01
	STX CWAIT1
	STX CWAIT2
	;
	DEX
	LDY #$00
	STY freqs
	STY freqs+1
freq_init
	LDA freqs,x
	CLC
	ADC freqs_add,y
	STA freqs+2,x
	INX
	LDA freqs,x
	ADC #$00
	STA freqs+2,x
	INX
	INY
	CPY #63
	BNE freq_init
	;
	LDA #$30
	STA CHANNELS
	LDA #$07
	STA VOLUME
	;
	RTS

advance_ch1
	LDY #$01
	LDA (PCH1),y
	BEQ res_1		; 00 in channel means end of pattern list
	STA CH1 + 1
	DEY
	LDA (PCH1),y
	STA CH1
	INC PCH1
	INC PCH1
	RTS
res_1	JSR reset_ch1
	JMP advance_ch1	

reset_ch1
	LDX #channel1 & 255
	LDY #channel1 >> 8
reset_ch1_pos
	STX PCH1
	STY PCH1 + 1
	RTS

advance_ch2
	LDY #$01
	LDA (PCH2),y		
	BEQ res_2		; 00 - end of pattern list
	STA CH2 + 1
	DEY
	LDA (PCH2),y
	STA CH2
	INC PCH2
	INC PCH2
	RTS
res_2	JSR reset_ch2
	JMP advance_ch2

reset_ch2
	LDX #channel2 & 255
	LDY #channel2 >> 8
reset_ch2_pos
	STX PCH2
	STY PCH2 + 1
	RTS

adv_1	STY padd1 + 1
	;
	LDA CH1
	CLC
padd1	ADC #$00
	STA CH1
	BCC noi_1
	INC CH1 + 1
noi_1	RTS

adv_2	STY padd2 + 1
	;
	LDA CH2
	CLC
padd2	ADC #$00
	STA CH2
	BCC noi_2
	INC CH2 + 1
noi_2	RTS

PLAYER
	;------------------
	DEC CWAIT1		; new note yet?
	BEQ get_note1
	JMP get_note21		; nope, skip to channel 2
	;
get_note1
	LDY #$00
	LDA (CH1),y		; get note
	CMP #$F0		; special byte?
	BCC sound1		; no, jump to sound play
	;
	CMP #LOOP_START		; loop start?
	BEQ loop_start_1
	;
	CMP #LOOP_END
	BEQ loop_end_1
	;
	CMP #QUIET
	BEQ quiet_1
	;
	CMP #END_MARK
	BNE set_vol_1
	;
	JSR advance_ch1
	JMP get_note1
	;
set_vol_1
	AND #$0F
disable_set_vol			; PUT "$A9" here to disable
	STA VOLUME
	JMP end_of_loop_1
	;
quiet_1
	LDA CHANNELS
	AND #$20
	STA CHANNELS
	JMP get_speed_1
	;
loop_end_1
	DEC LOOP_COUNT1
	BEQ end_of_loop_1
	;
	LDA LOOP_CH1		; jump back!
	STA CH1
	LDA LOOP_CH1 + 1
	STA CH1 + 1
	;
	JMP get_note1
	;
end_of_loop_1
	INY
	JSR adv_1
	JMP get_note1
	;
	;-----
loop_start_1
	INY
	LDA (CH1),y		; get next byte loop counter value
	STA LOOP_COUNT1		; store it
	INY
	JSR adv_1
	;
	LDA CH1			; store loop position!
	STA LOOP_CH1
	LDA CH1 + 1
	STA LOOP_CH1 + 1
	;
	JMP get_note1
	;
sound1
	AND #$7F		; clear highest bit
	ASL A			; * 2
	TAX
	LDA freqs,x		; get freq low byte
	STA F1LO
	INX			; and high byte
	LDA F1HI		; keep bits 2-7
	AND #$FC
	ORA freqs,x
	STA F1HI		; for char. map
	;
	;-------
	LDA CHANNELS
	ORA #$10
	STA CHANNELS
	;-------
	;
	LDA (CH1),y		; get note again
	CMP #ns
	BCC get_speed_1
	;
	LDA PWAIT1
	BNE store_speed_1
	;
get_speed_1
	INY
	LDA (CH1),y
store_speed_1
	INY
	STA CWAIT1
	STA PWAIT1
	;------------
	JSR adv_1
	;------------------------------------------------------------------
	;
get_note21
	DEC CWAIT2		; new note yet on channel2?
	BEQ get_note2
	JMP pend_1		; nope, go to player end
	;
get_note2
	LDY #$00
	LDA (CH2),y
	CMP #$F0
	BCC sound2
	;
	CMP #SNARE
	BEQ play_snare
	;
	CMP #QUIET
	BEQ quiet_2
	;
	CMP #LOOP_START
	BEQ loop_start_2
	;
	CMP #END_MARK
	BNE loop_end_2
	;
	; --- assume end mark
	;
	JSR advance_ch2
	JMP get_note2
	;          
quiet_2
	LDA CHANNELS
	AND #$10
	STA CHANNELS
	JMP get_speed_2
	;
loop_end_2
	DEC LOOP_COUNT2
	BEQ end_of_loop_2
	;
	LDA LOOP_CH2		; jump back!
	STA CH2
	LDA LOOP_CH2 + 1
	STA CH2 + 1
	;
	JMP get_note2
	;
end_of_loop_2
	INY
	JSR adv_2
	JMP get_note2
	;
	;-----
loop_start_2
	INY
	LDA (CH2),y
	STA LOOP_COUNT2
	INY
	JSR adv_2
	;
	LDA CH2			; store loop position!
	STA LOOP_CH2
	LDA CH2 + 1
	STA LOOP_CH2 + 1
	;
	JMP get_note2
	;
play_snare
	STA F2LO	; = $fe
	LDA #$03
	STA F2HI	; Snare Drum starting Freq ($03FE)
	;
	LDA #$10
	STA DECFLAG	; Dec freq by $20 every cycle
	;
	LDA CHANNELS
	AND #$DF
	ORA #$40
	STA CHANNELS	; turn VOICE2 to noise
	;
	JMP ch_2
	;
sound2
	AND #$7F
	ASL A
	TAX
	LDA freqs,x
	STA F2LO
	INX
	LDA freqs,x
	STA F2HI
	;
	LDA #$00
	STA DECFLAG
	;
	LDA CHANNELS
	AND #$BF
	ORA #$20
	STA CHANNELS	; turn VOICE2 to sound
	;
	;
	LDA (CH2),y
	CMP #ns
	BCC get_speed_2
	;
	LDA PWAIT2
	BNE store_speed_2
	;
get_speed_2
	;
ch_2	;
	INY
	LDA (CH2),y
store_speed_2
	INY
	STA CWAIT2
	STA PWAIT2
	;
	JSR adv_2
	;
pend_1
	LDA DECFLAG
	BEQ pend_2
	;
	LDA F2LO
	SEC
	SBC DECFLAG
	STA F2LO
	LDA F2HI
	SBC #$00
	STA F2HI
	;
pend_2
	LDA CHANNELS
	ORA VOLUME
	STA VOL
	;
	RTS

freqs_add
	DB	7,57,54
	DB	51,48,45,43,40,38,36,34,32,31,28,27
	DB	25,24,23,21,21,19,18,17,16,15,14,14
	DB	12,12,12,10,10,10,9,8,8,8,7,7
	DB	6,6,6,5,5,5,4,5,4,3,4,3
	DB	4,3,2,3,3,2,2,2,2,2,2,2
