APU_PL1_VOL		= $4000
APU_PL1_SWEEP	= $4001
APU_PL1_LO		= $4002
APU_PL1_HI		= $4003
APU_PL2_VOL		= $4004
APU_PL2_SWEEP	= $4005
APU_PL2_LO		= $4006
APU_PL2_HI		= $4007
APU_TRI_LINEAR	= $4008
APU_TRI_LO		= $400a
APU_TRI_HI		= $400b
APU_NOISE_VOL	= $400c
APU_NOISE_LO	= $400e
APU_NOISE_HI	= $400f
APU_DMC_FREQ	= $4010
APU_DMC_RAW		= $4011
APU_DMC_START	= $4012
APU_DMC_LEN		= $4013
APU_SND_CHN		= $4015


.segment "ZEROPAGE"

BGM_PRG:				.res 1
BGM_PTR:				.res 2
BGM_WAIT:				.res 1
BGM_ACTIVE:				.res 1
BGM_TAG_L:				.res 1
BGM_TAG_H:				.res 1
BGM_TRI_HI:				.res 1

DMC_PTR:				.res 2
DMC_LEN:				.res 2
DMC_SHIFT:				.res 1
DMC_BYTE_CNT:			.res 1
DMC_ORIG_PRG:			.res 1



.segment "FIXED"

;void __fastcall__ playdump_start(unsigned char prg,const unsigned char* data);

.import _playdump_sync
.export _playdump_start

_playdump_start:

	ldy #0
	sty <BGM_ACTIVE
	sty <BGM_WAIT
	sty _playdump_sync
	
	sta <BGM_PTR+0
	stx <BGM_PTR+1
	
	jsr popa
	
	sta <BGM_PRG
	
	lda #1
	sta <BGM_ACTIVE
	lda #$0f				;enable channels, stop DMC
	sta APU_SND_CHN
	lda #$00				;load noise length
	sta APU_NOISE_HI
	rts

	
	
;void __fastcall__ playdump_stop(void);

.export _playdump_stop

_playdump_stop:

	lda #0
	sta <BGM_ACTIVE
	sta APU_SND_CHN			;mute all
	rts



playdump_init:

	lda #$0f				;enable channels, stop DMC
	sta APU_SND_CHN
	
	lda #$80				;disable triangle length counter
	sta APU_TRI_LINEAR
	lda #$00				;load noise length
	sta APU_NOISE_HI
	sta <BGM_TRI_HI

	lda #$30				;volumes to 0
	sta APU_PL1_VOL
	sta APU_PL2_VOL
	sta APU_NOISE_VOL
	lda #$08				;no sweep
	sta APU_PL1_SWEEP
	sta APU_PL2_SWEEP
	
	lda #0
	sta <BGM_PRG

	lda #$00
	sta <BGM_WAIT
	sta <BGM_PTR+0
	lda #$80
	sta <BGM_PTR+1
	
	rts
	
	

playdump_update:

	lda <BGM_ACTIVE
	bne :+
	rts
:
	lda <BGM_WAIT
	beq :+
	dec <BGM_WAIT
	rts
:

_pdu_update:

	lda <BGM_PRG
	jsr mmc3_set_prg_temp

	ldy #0
	lda (BGM_PTR),y

	bmi _pdu_write
	bne :+
	jmp _pdu_done		;end of track, loops indefinitely
:
	cmp #$7f
	beq _pdu_next_bank
	
_pdu_skip:

	sta <BGM_WAIT
	dec <BGM_WAIT
	iny
	jmp _pdu_done
	
_pdu_next_bank:

	inc <BGM_PRG
	lda #$00
	sta <BGM_PTR+0
	lda #$80
	sta <BGM_PTR+1
	jmp _pdu_update
	
_pdu_write:

	iny
	sta <BGM_TAG_H
	lda (BGM_PTR),y
	sta <BGM_TAG_L
	iny
	
	ror <BGM_TAG_L		;0001
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL1_VOL
:

	ror <BGM_TAG_L		;0002
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL1_LO
:

	ror <BGM_TAG_L		;0004
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL1_HI
:

	ror <BGM_TAG_L		;0008
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL2_VOL
:

	ror <BGM_TAG_L		;0010
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL2_LO
:

	ror <BGM_TAG_L		;0020
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_PL2_HI
:

	ror <BGM_TAG_L		;0040
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_TRI_LINEAR
	lda <BGM_TRI_HI		;set reload flag for triangle channel
	sta APU_TRI_HI
:

	ror <BGM_TAG_L		;0080
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_TRI_LO
:

	ror <BGM_TAG_H		;0100
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_TRI_HI
	sta <BGM_TRI_HI
:

	ror <BGM_TAG_H		;0200
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_NOISE_VOL
:

	ror <BGM_TAG_H		;0400
	bcc :+
	lda (BGM_PTR),y
	iny
	sta APU_NOISE_LO
:
	ror <BGM_TAG_H		;0800 sync markers
	bcc :+
	lda #1
	sta _playdump_sync
:
	

_pdu_done:

	tya
	clc
	adc <BGM_PTR+0
	sta <BGM_PTR+0
	bcc :+
	inc <BGM_PTR+1
:
	
	jmp mmc3_restore_prg		;jsr:rts

	
	
;void __fastcall__ playdump_soft_dmc(unsigned char prg,const unsigned char* src,unsigned int len);

.export _playdump_soft_dmc

_playdump_soft_dmc:

	sta <DMC_LEN+0
	stx <DMC_LEN+1
	
	jsr popax
	
	sta <DMC_PTR+0
	stx <DMC_PTR+1
	
	lda <MMC3_PRG_SLOT
	sta <DMC_ORIG_PRG
	
	jsr popa
	jsr mmc3_set_prg
	
	ldx #31				;initial DMC value
	ldy #0
	
@playdmc1:

	lda #8
	sta <DMC_BYTE_CNT
	lda (DMC_PTR),y
	sta <DMC_SHIFT
	
@playdmc2:

	ror	<DMC_SHIFT		;2
	bcc @playdmcdec		;2/3
	
@playdmcinc:

	inx					;2
	inx					;2
	cpx #127			;2
	bcc :+				;2/3
	ldx #127			;2
:
	jmp @playdmcout		;3
	
@playdmcdec:

	dex					;2
	dex					;2
	cpx #127			;2
	bcc :+				;2/3
	ldx #0				;2
:
	nop					;2
	
@playdmcout:

	.repeat 13
	nop					;26
	.endrepeat
	
	stx APU_DMC_RAW		;4

	dec <DMC_BYTE_CNT	;5
	bne @playdmc2		;2/3=53

	iny
	bne :+
	inc <DMC_PTR+1
:

	lda <DMC_LEN+0
	bne :+
	dec <DMC_LEN+1
:
	dec <DMC_LEN+0
	
	lda <DMC_LEN+0
	ora <DMC_LEN+1
	bne @playdmc1
	
	lda <DMC_ORIG_PRG
	jmp mmc3_set_prg		;jsr:rts
