

SpcHandlerMain:
	php
	sep #$20
;	stz.w $4200			;disable irqs in case we are processing a lengthy spc transfer

;check if spc sends report data
	lda.w $2141
	and.b #$e0
	cmp.b #$e0
	bne SpcHandlerNoSpcReport

	rep #$31
	lda.w $2141			;get report type and select corresponding buffer accordingly
	and.w #7
	asl a
	tax
	lda.w $2142			;get report word and store in buffer
	sta.l SpcReportBuffer,x


SpcHandlerNoSpcReport:
	rep #$31
;	sep #$20
	lda.b SpcHandlerState
	and.w #$1f			;have 32 states maximum
	asl a
	tax
	jsr (SpcHandlerSubroutineJumpLUT,x)
	
	
	
	
	sep #$20
;	lda.b InterruptEnableFlags	;reenable irqs
;	sta.w $4200	
	
	plp
	rts

;stops currently playing stream, song, then waits for driver to return to idle state(wait for all scheduled sound effects to play)
SpcWaitAllCommandsProcessed:
	php
	sep #$20
	stz.w SpcStreamVolume
	jsr SpcStopSong
SpcWaitLoop:
	lda.b SpcCmdFifoStart
	cmp.b SpcCmdFifoEnd				;check if fifo is empty
	bne SpcWaitLoop
	
	lda.b SpcHandlerState
	cmp.b #1
	bne SpcWaitLoop
	
	plp
	rts
	
SpcHandlerSubroutineJumpLUT:
	.dw SpcUploadDriver		;0
	.dw SpcIdle
	.dw SpcUploadSong
	.dw SpcUploadSongWait
	.dw SpcUploadSampleset
	.dw SpcUploadSamplesetWait	;5
	.dw SpcStreamData
	.dw SpcStreamDataWait
	.dw SpcPlaySoundeffectUpload	
	.dw SpcPlaySoundeffectWait
	.dw SpcStopSongInit		;10
	.dw SpcStopSongWait 
	.dw SpcSetSpeedInit
        .dw SpcSetSpeedWait
	.dw SpcSetChMaskInit
        .dw SpcSetChMaskWait		;15
        .dw SpcSetReportTypeInit
	.dw SpcSetReportTypeWait



SpcSetReportTypeInit:
	rep #$31
	lda.b SpcHandlerArgument0		;store type and sub-arg
	sta.w $2141
	sep #$20

	lda.b #SpcCmdReportType		;exec command
	sta.w $2140
	
	
	inc.b SpcHandlerState					;goto "wait SE ack"-state
	rts

SpcSetReportTypeWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdReportType
	bne SpcSetReportTypeWaitNoIdle			;wait until spc has ack'd the speed change before returning

	lda.b #1
	sta.b SpcHandlerState					;return to idle once spc has answered

SpcSetReportTypeWaitNoIdle:
	rts

SpcSetChMaskInit:
	sep #$20
	lda.b SpcHandlerArgument0		;store mask
	sta.w $2141


	lda.b #SpcCmdSetSongChMask		;exec command
	sta.w $2140
	
	
	inc.b SpcHandlerState					;goto "wait SE ack"-state
	rts

SpcSetChMaskWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdSetSongChMask
	bne SpcSetChMaskWaitNoIdle			;wait until spc has ack'd the speed change before returing

	lda.b #1
	sta.b SpcHandlerState					;return to idle once spc has answered

SpcSetChMaskWaitNoIdle:
	rts

SpcSetSpeedInit:
	sep #$20
	lda.b SpcHandlerArgument0		;store speed
	sta.w $2141


	lda.b #SpcCmdSetSongSpeed		;exec command
	sta.w $2140
	
	
	inc.b SpcHandlerState					;goto "wait SE ack"-state
	rts

SpcSetSpeedWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdSetSongSpeed
	bne SpcSetSpeedWaitNoIdle			;wait until spc has ack'd the speed change before returing

	lda.b #1
	sta.b SpcHandlerState					;return to idle once spc has answered
	

SpcSetSpeedWaitNoIdle:
	rts	
	
	
SpcUploadSampleset:
	sep #$20
	lda.b #SpcCmdUploadSamplePack					;send "upload song" command
	sta.w $2140
	lda.b #5
	sta.b SpcHandlerState					;goto "wait for spc to ack song upload" state
	rts
	
SpcUploadSamplesetWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdUploadSamplePack					;wait until spc has ack'd upload song command
	bne SpcUploadSamplePackWaitExit				;else try again next frame
	
;	stz.w $4200						;disable irqs
;upload SamplePack here
	lda.b SpcHandlerArgument0				;get song number to upload
	sta.b PtPlayerCurrentSamplePack

	
	rep #$31				;multiply song number by 3 and use as index into song pointertable
	and.w #$00ff
	sta.b PtPlayerDataPointerLo
	asl a
	clc
	adc.b PtPlayerDataPointerLo
	tax

	lda.l (PtPlayerSamplePackPointertable+BaseAdress),x	;store pointer to song
	sta.b PtPlayerDataPointerLo
		
	lda.l (PtPlayerSamplePackPointertable+$c00001),x
	
	sta.b PtPlayerDataPointerHi	
;	sep #$20
;	sta.b PtPlayerDataPointerBa
	
;	rep #$31
	ldy.w #$0000
	lda.b [PtPlayerDataPointerLo],y		;get song length
	dec a					;substract length word
	dec a
	sta.w PtPlayerSmplBufferPosLo
	iny					;increment source pointer to actual song offset
	iny
	sep #$20

SpcUploadSamplePackTransfer1:		
		lda.b [PtPlayerDataPointerLo],y		;write 3 bytes to ports
		sta.w $2141
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2142
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2143
		iny
		
		lda.b #SpcCmdUploadSongT1		;write ack transfer 1 to port0
		sta.w $2140

SpcUploadSamplePackTransfer1WaitLoop:				;wait for spc to write transfer 1 ack back
		cmp.w $2140
		bne SpcUploadSamplePackTransfer1WaitLoop
	
SpcUploadSamplePackTransfer2:		
		lda.b [PtPlayerDataPointerLo],y		;write 3 bytes to ports
		sta.w $2141
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2142
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2143
		iny
		
		lda.b #SpcCmdUploadSongT2		;write ack transfer 1 to port0
		sta.w $2140

SpcUploadSamplePackTransfer2WaitLoop:				;wait for spc to write transfer 1 ack back
		cmp.w $2140
		bne SpcUploadSamplePackTransfer2WaitLoop
	
		cpy.w PtPlayerSmplBufferPosLo		;check if transfer length is exceeded
		bcc SpcUploadSamplePackTransfer1
		
		lda.b #SpcCmdUploadSamplePackDone		;send "upload song complete" commadn if transfer is done
		sta.w $2140
	
		lda.b #1
		sta.b SpcHandlerState					;return to idle

;		lda.b InterruptEnableFlags	;reenable irqs
;		sta.w $4200

SpcUploadSamplePackWaitExit:
	lda.b SpcUploadedFlag
	ora.b #$40						;set sample pack uploaded flag.
	sta.b SpcUploadedFlag

	rts	


SpcStopSongInit:
	rep #$31
	stz.w $2141
	stz.w $2142
	sep #$20
	lda.b #SpcCmdStopSong		;exec command
	sta.w $2140	
	inc.b SpcHandlerState		;goto "wait SE ack"-state
	rts

SpcStopSongWait:	
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdStopSong
	bne SpcStopSongWaitNoIdle			;wait until spc has ack'd the song/stream stop before returing

	lda.b #1
	sta.b SpcHandlerState					;return to idle once spc has answered
	

SpcStopSongWaitNoIdle:
	rts



SpcPlaySoundeffectUpload:
	rep #$31
	lda.b SpcHandlerArgument0		;store arguments
	sta.w $2141
	lda.b SpcHandlerArgument1
	and.w #$7fff				;mask off msb and use as wurst
	ora.w SpcSoundEffectFlipFlag
	sta.w $2142
	lda.w SpcSoundEffectFlipFlag
	eor.w #$8000
	sta.w SpcSoundEffectFlipFlag
	sep #$20
	lda.b #SpcCmdPlaySoundEffect		;exec command
	sta.w $2140
	
	
;	lda.b #1
;	sta.b SpcHandlerState					;don't wait
	inc.b SpcHandlerState					;goto "wait SE ack"-state
	rts

;dont use this cause it sometimes plays a sound effect twice
SpcPlaySoundeffectWait:	
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdPlaySoundEffect
	bne SpcPlaySoundeffectWaitNoIdle			;wait until spc has ack'd the soundeffect before returing

	lda.b #1
	sta.b SpcHandlerState					;return to idle once spc has answered
	

SpcPlaySoundeffectWaitNoIdle:
	rts
	
		
SpcUploadDriver:
		sep #$20
;		stz.w $4200
		lda.b #(:PtplayerSpcCode+BaseAdress>>16)
		ldx.w #PtplayerSpcCode
		sta.b PtPlayerDataPointerBa
		stx.b PtPlayerDataPointerLo
;		jsr PtPlayerInit
;		php
;		sep #$20
;		stz.w $4200
		REP #$31
		LDY.w #$0000				;clear data pointer
		LDA.w #$BBAA

PtPlayerInitSpcWaitLoop1:		
		CMP.w $2140				;wait for spc to respond
		BNE PtPlayerInitSpcWaitLoop1

		SEP #$20
		LDA.b #$CC				;send "start transfer"
		BRA PtPlayerInitDoTransfer

PtPlayerInitGetByte:
		LDA.b [PtPlayerDataPointerLo],y
		INY
		XBA
		LDA.b #$00
		BRA PtPlayerInitClearSpcPort0

PtPlayerInitGetNextByte:
		XBA
		LDA.b [PtPlayerDataPointerLo],y
		INY
		XBA

PtPlayerInitSpcWaitLoop2:
		CMP.w $2140
		BNE PtPlayerInitSpcWaitLoop2
		INC A
PtPlayerInitClearSpcPort0:
		REP #$20
		STA.w $2140
		SEP #$20
		DEX
		BNE PtPlayerInitGetNextByte

PtPlayerInitSpcWaitLoop3:
		CMP.w $2140
		BNE PtPlayerInitSpcWaitLoop3

PtPlayerInitAddLoop:
		ADC.b #$03
		BEQ PtPlayerInitAddLoop


PtPlayerInitDoTransfer:
		PHA
		REP #$20
		LDA.b [PtPlayerDataPointerLo],y
		INY
		INY
		TAX
		LDA.b [PtPlayerDataPointerLo],y
		INY
		INY
		STA.w $2142
		SEP #$20
		CPX.w #$0001				;whats this?
		LDA.b #$00
		ROL A
		STA.w $2141
		ADC.b #$7F
		PLA
		STA.w $2140
		cpx.w #$0001				;fix to be able to upload apucode during active nmi
		bcc PtPlayerInitDone

PtPlayerInitSpcWaitLoop4:
		CMP.w $2140
		BNE PtPlayerInitSpcWaitLoop4


		BVS PtPlayerInitGetByte

PtPlayerInitDone:
		SEP #$20
;		lda.b #%10000001
;		sta.w $4200

/*
		lda.b #$7f				;init some variables
		sta.b PtPlayerMainVolL
		sta.b PtPlayerMainVolR
		lda.b #%00001111
		sta.b PtPlayerChannelEnable
		lda.b #$00
		sta.b PtPlayerEchoVolL
		sta.b PtPlayerEchoVolR
		sta.b PtPlayerChannelEchoEnable
		lda.b #$01
		sta.b CGIntroPlaySongNumber
*/		
;		PLP
		lda.b InterruptEnableFlags	;reenable irqs
;		sta.w $4200
		inc.b SpcHandlerState			;go to idle state

;init some variables
	lda.b #$a0
	sta.w SpcSongSpeed			;set speed to default
	lda.b #$0f
	sta.w SpcSongChMask			;set song channel mask to default
		jsr ClearSpcReportBuffer
		
		RTS	
	
ClearSpcReportBuffer:
	php
	rep #$31
	lda.w #$0000			;clear with y-position at line 255
	ldx.w #16
ClearSpcReportBufferLoop:
	sta.l (SpcReportBuffer &$ffff + $7e0000-2),x
	dex
	dex
	bne ClearSpcReportBufferLoop
	plp
	rts	
		
;check if there's a new command in the fifo, else return
;fifo buffer organization is:
;each entry: 1 command byte, 3 argument bytes
;fifo has 16 entries/64bytes total
SpcIdle:
	sep #$20
	stz.w $2140					;clear port0
	
	lda.b SpcCmdFifoStart
	cmp.b SpcCmdFifoEnd				;check if fifo is empty
	beq SpcIdleFifoEmpty
	
;theres a spc command present:

	rep #$31
	and.w #$3f					;limit fifo pointer to 64 bytes
	tax						
	lda.w SpcCmdFifo,x				;get command
	
	sta.b SpcHandlerState					;store command/state and argument 1
	
	lda.w SpcCmdFifo+2,x				;get command
	
	sta.b SpcHandlerArgument1				;store arguments 1 and 2

	lda.b SpcHandlerState				;directly execute fetched command
	and.w #$1f					;except when its an idle command
	cmp.w #1					;because this would allow for unlimited nesting and possibly stack overflow
	beq SpcIdleFifoEmpty
	
	asl a
	tax
	jsr (SpcHandlerSubroutineJumpLUT,x)
	
	sep #$20
	lda.b SpcCmdFifoStart				;goto next fifo entry next frame
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoStart	
	
SpcIdleFifoEmpty:
	rts
	
SpcUploadSong:
	sep #$20

	lda.b #SpcCmdUploadSong					;send "upload song" command
	sta.w $2140
	lda.b #3
	sta.b SpcHandlerState					;goto "wait for spc to ack song upload" state
	rts
	
SpcUploadSongWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdUploadSong					;wait until spc has ack'd upload song command
	bne SpcUploadSongWaitExit				;else try again next frame
	
	
;upload song here
;	stz.w $4200
	lda.b SpcHandlerArgument0				;get song number to upload
	sta.b PtPlayerCurrentSong

	
	rep #$31				;multiply song number by 3 and use as index into song pointertable
	and.w #$00ff
	sta.b PtPlayerDataPointerLo
	asl a
	clc
	adc.b PtPlayerDataPointerLo
	tax

	lda.l (PtPlayerSongPointertable+BaseAdress),x	;store pointer to song
	sta.b PtPlayerDataPointerLo
		
	lda.l (PtPlayerSongPointertable+$c00001),x
	
	sta.b PtPlayerDataPointerHi	
;	sep #$20
;	sta.b PtPlayerDataPointerBa
	
;	rep #$31
	ldy.w #$0000
	lda.b [PtPlayerDataPointerLo],y		;get song length
	dec a					;substract length word
	dec a
	sta.w PtPlayerSmplBufferPosLo
	iny					;increment source pointer to actual song offset
	iny
	sep #$20

SpcUploadSongTransfer1:		
		lda.b [PtPlayerDataPointerLo],y		;write 3 bytes to ports
		sta.w $2141
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2142
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2143
		iny
		
		lda.b #SpcCmdUploadSongT1		;write ack transfer 1 to port0
		sta.w $2140

SpcUploadSongTransfer1WaitLoop:				;wait for spc to write transfer 1 ack back
		cmp.w $2140
		bne SpcUploadSongTransfer1WaitLoop
	
SpcUploadSongTransfer2:		
		lda.b [PtPlayerDataPointerLo],y		;write 3 bytes to ports
		sta.w $2141
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2142
		iny
		lda.b [PtPlayerDataPointerLo],y
		sta.w $2143
		iny
		
		lda.b #SpcCmdUploadSongT2		;write ack transfer 1 to port0
		sta.w $2140

SpcUploadSongTransfer2WaitLoop:				;wait for spc to write transfer 1 ack back
		cmp.w $2140
		bne SpcUploadSongTransfer2WaitLoop
	
		cpy.w PtPlayerSmplBufferPosLo		;check if transfer length is exceeded
		bcc SpcUploadSongTransfer1
		
		lda.b #SpcCmdUploadSongDone		;send "upload song complete" commadn if transfer is done
		sta.w $2140
	
		lda.b #1
		sta.b SpcHandlerState					;return to idle

		lda.b InterruptEnableFlags	;reenable irqs
;		sta.w $4200

SpcUploadSongWaitExit:
	lda.b SpcUploadedFlag
	ora.b #$80						;set song uploaded flag.
	sta.b SpcUploadedFlag

	rts	

;stops currently playing song/stream
SpcStopSong:
	php
	rep #$31
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax	
	sep #$20
;	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdStopSong
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	plp
	rts

;in:	a,8bit: SE number to play
;	x,16bit: volume & pitch low byte: pitch(use default if zero, multiplied by 16). high byte: volume(use default if zero) bit7:sign, bits6-4:panning, bits 3-0:volume(multiplied with $10)	
SpcPlaySoundEffect:
	php
	rep #$31
	pha					;push SE number
	phx					;push arguments
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	pla					;get arguments
	sta.w (SpcCmdFifo+2),x			;store in fifo arguments 2,3
	
	pla					;fetch song number again
	sep #$20
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdPlaySE
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	plp
	rts

;same as above, but doesn't use x as input
SpcPlaySoundEffectSimple:
	php
	rep #$31
	phx					;push arguments
	pha					;push SE number

	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	lda.w #0
	sta.w (SpcCmdFifo+2),x			;store in fifo arguments 2,3
	
	pla					;fetch song number again
	sep #$20
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdPlaySE
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	plx
	plp
	rts


;in: a,8bit: song number to play
SpcPlaySong:
	php
	rep #$31
	pha					;push song number
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
	pla					;fetch song number again
	sep #$20
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdUploadSong
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	
	stz.w SpcStreamVolume			;mute eventually playing stream, stop stream
	
	lda.b SpcUploadedFlag
	and.b #$7f						;clear song uploaded flag. will be set once song upload has been completed later on
	sta.b SpcUploadedFlag
;	lda.b SpcCurrentStreamSet		;useful, but messes up if sampleset + song dont fit into spc ram
;	jsr SpcIssueSamplePackUpload
	plp
	rts

;in: a,8bit: streamset number to play
SpcPlayStream:
	php
	sep #$20
	pha
	rep #$31
	stz.w SpcStreamFrame
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
	sep #$20
	pla					;store frameset number
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdStreamBrr
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd

	sep #$20
	stz.w SpcStreamVolume			;mute eventually playing stream, stop stream
	plp
	rts
	
	
;in: a,8bit: sample pack number to upload
SpcIssueSamplePackUpload:
	php
	rep #$31
	pha					;push song number
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
	pla					;fetch song number again
	sep #$20
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdUploadSamplePack
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd

	lda.b SpcUploadedFlag
	and.b #$bf						;clear sample pack uploaded flag. will be set once song upload has been completed later on
	sta.b SpcUploadedFlag
	
	plp
	rts

SpcStreamData:
	sep #$20
	lda.b #$7f				;turn on streaming volume
	sta.w SpcStreamVolume
	
	lda.b SpcHandlerArgument0		;get frameset number to stream
	sta.b SpcCurrentStreamSet		;multiply by 5 to get pointer into frameset table			
	rep #$31
	and.w #$ff
	sta.b SpcTempBuffer
	asl a
	asl a
	clc
	adc.b SpcTempBuffer
	
	tax
	lda.l (StreamSetLut+BaseAdress+3),x	;get number of frames for this set
	sta.w $2141				;write number of frames to stream to spc
	
				
	sep #$20	
	lda.b #SpcCmdReceiveStream				;send "upload song" command
	sta.w $2140

	lda.l $2140
	cmp.b #SpcCmdReceiveStreamComplete			;don't switch to streamer yet if spc is still finishing the last transfer.(only applicable if last command was streaming)
	beq SpcStreamDataWaitSpcLastStream
	
	lda.b #7
	sta.b SpcHandlerState					;goto "wait for spc to ack song upload" state
	
SpcStreamDataWaitSpcLastStream:	
	rts


SpcStreamDataReturnIdle:
	sep #$20
	lda.b HdmaFlags
	and.b #$7f					;disable spc stream on hdma channel 7
	sta.b HdmaFlags	
	lda.b #1						;return to idle if spc signalizes that transfer is complete
	sta.b SpcHandlerState
SpcStreamDataExit:
	rts

	
SpcStreamDataWait:
	sep #$20
	lda.w $2140
	cmp.b #SpcCmdReceiveStreamComplete			;check if transfer complete
	beq SpcStreamDataReturnIdle
	cmp.b #SpcCmdReceiveStream				;wait until spc has ack'd upload song command
	bne SpcStreamDataExit					;else try again next frame	

	
	
	lda.b SpcCurrentStreamSet				;get current frameset number
	rep #$31
	and.w #$ff
	sta.b SpcTempBuffer					;multiply by 5
	asl a
	asl a
	clc
	adc.b SpcTempBuffer
	
	tax
	lda.l (StreamSetLut+BaseAdress),x				;store offset of first frame in set
	sta.b SpcTempBuffer+2
	lda.l (StreamSetLut+BaseAdress+1),x
	sta.b SpcTempBuffer+3
	
	lda.w $2141						;get frame request number
									;multiply with 144, get pointer to requested frame. warning: one bank holds $1c7 frames, or $fff0 bytes of data. must wrap to next bank if bigger.
	sta.b SpcTempBuffer+5					;store frame request number
	sta.w SpcStreamFrame
	pha
	lda.w SpcStreamVolume			;only write current frame if stream hasnt been stopped. otherwise external routines might be confused when transitioning between streams
	and.w #$ff
	bne DontClearSpcStreamFrame
	
	stz.w SpcStreamFrame

	
DontClearSpcStreamFrame:
	pla

SpcStreamCalcFrameOffsetLoop:
	cmp.w #SpcFramesPerBank					;check if number of frames exceeds bank limit
	bcc SpcStreamCalcFrameOffsetNoBankWrap

	sep #$20						;if it does, increase bank
	inc.b SpcTempBuffer+4
	rep #$31						;and substract one bank full of samples from total amount
	sec
	sbc.w #SpcFramesPerBank
	bra SpcStreamCalcFrameOffsetLoop			;do this until we're in the bank the frame actually is in

SpcStreamCalcFrameOffsetNoBankWrap:
	
	asl a							;multiply by 144
	asl a
	asl a
	asl a							;first multiply by 16
	sta.b SpcTempBuffer+2
	
	asl a							;then by 128
	asl a
	asl a
	
	clc
	adc.b SpcTempBuffer+2					;this is x*144
	sta.b SpcTempBuffer+2					;and save in pointer

;line 1, command
	lda.w #36/2
	sta.b SpcTempBuffer					;set scanline counter
	lda.w #SpcScanlineWaitCount						;store 1 in frame count
	ldx.w #0						;clear hdma table pointer
	txy							;clear brr source counter
	
	sta.l HdmaSpcBuffer,x

	lda.w #SpcCmdSubmitStreamNumber				;send "submit frame #"-cmd
	sta.l HdmaSpcBuffer+1,x
	
	lda.b SpcTempBuffer+5					;get frame submit number
	sta.l HdmaSpcBuffer+2,x

	lda.w SpcStreamVolume
	sta.l HdmaSpcBuffer+4,x					;store volume
	
	inx
	inx
	inx
	inx
	inx
;line 2, waitloop &  frame transmit
SpcStreamSetupHdmaTableLoop:
	lda.w #1
	sta.l HdmaSpcBuffer,x				;one line
	
	lda.b [SpcTempBuffer+2],y				;brr data to ports $2140-$2143
	sta.l HdmaSpcBuffer+1,x

	iny
	iny
	
	lda.b [SpcTempBuffer+2],y
	sta.l HdmaSpcBuffer+3,x

	inx
	inx
	inx
	inx
	inx
	
;	iny
;	iny
	iny
	iny

	lda.w #1
	sta.l HdmaSpcBuffer,x				;one line
	
	lda.b [SpcTempBuffer+2],y				;brr data to ports $2140-$2143
	sta.l HdmaSpcBuffer+1,x

	iny
	iny
	
	lda.b [SpcTempBuffer+2],y
	sta.l HdmaSpcBuffer+3,x

	inx
	inx
	inx
	inx
	inx
	
;	iny
;	iny
	iny
	iny	
	dec.b SpcTempBuffer
	bne SpcStreamSetupHdmaTableLoop

;this doesnt work right. reason is that the the stream data sometimes contains "false" commands.
;write spc command here: (only play soundeffect, stop song/stream is allowed here)

	stz.b SpcTempBuffer				;clear spc command field
	stz.b SpcTempBuffer+2
/*
	
	lda.b SpcCmdFifoStart
	cmp.b SpcCmdFifoEnd				;check if fifo is empty
	beq SpcStreamFifoEmpty
	
;theres a spc command present:
	rep #$31
	and.w #$3f					;limit fifo pointer to 64 bytes
	tax						
	lda.w SpcCmdFifo,x				;get command
	and.w #$ff
	cmp.w #SpcCmdPlaySoundEffect
	beq SpcStreamFifoExecCmd
	cmp.w #SpcCmdStopSong
	beq SpcStreamFifoExecCmdExit
	
	bra SpcStreamFifoEmpty

SpcStreamFifoExecCmdExit:
	sep #$20
	lda.b #1
	sta.b SpcHandlerState				;if stop command is present in fifo, immediately halt streamer and return to idle state. next frame, fifo command handler will process the stop command normally.
	rts

SpcStreamFifoExecCmd:	

;state
	lda.w SpcCmdFifo,x				;get command
	sta.b TempBuffer				;store command/state and argument 1
	
	lda.w SpcCmdFifo+2,x				;get command
	
	sta.b TempBuffer+2				;store arguments 1 and 2

	
	sep #$20
	lda.b SpcCmdFifoStart				;goto next fifo entry next frame
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoStart	
	
SpcStreamFifoEmpty:
	rep #$31
*/
	lda.w #1
	sta.l HdmaSpcBuffer,x				;one line
	

	lda.b SpcTempBuffer
	sta.l HdmaSpcBuffer+1,x				

	
	lda.b SpcTempBuffer+2
	sta.l HdmaSpcBuffer+3,x

	inx
	inx
	inx
	inx
	inx

;terminate hdma table:	
	lda.w #0
	sta.l HdmaSpcBuffer,x
	
	lda.w #HdmaSpcBuffer & $ffff
	sta.l $4372					;hdma source offset
	
	sep #$20
	lda.b HdmaFlags
	ora.b #$80					;enable spc stream on hdma channel 7
	sta.b HdmaFlags
	
	lda.b #$7e					;hdma source bank
	sta.l $4374
	
	lda.b #%00000100				;hdma config, direct, 4 regs write once
	sta.l $4370
	
	lda.b #$40					;bbus target, apu port $2140-$2143
	sta.l $4371
	
	rts
	
;in: SpcSongSpeed,8bit: song speed(timer duration. default is #$a0. lower=faster, higher=slower
SpcSetSongSpeed:
	php
	rep #$31
;	pha					;push speed
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
;	pla					;fetch speed again
	sep #$20
	lda.w SpcSongSpeed
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdSetSpeed
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	
;	stz.w SpcStreamVolume			;mute eventually playing stream, stop stream
	
;	lda.b SpcCurrentStreamSet		;useful, but messes up if sampleset + song dont fit into spc ram
;	jsr SpcIssueSamplePackUpload
	plp
	rts

;in: SpcSongSpeed,8bit: song speed(timer duration. default is #$a0. lower=faster, higher=slower
SpcSetSongChannelMask:
	php
	rep #$31
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
	sep #$20
	lda.w SpcSongChMask
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdSetChMask
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	
	plp
	rts

;input: SpcReportType,8bit: 0=none 1=timecode 2=channel-levels(vol out) 3=special mod command (mod command $e0. this is "set filter", unused in almost any player
SpcSetReportType:
	php
	rep #$31
	lda.b SpcCmdFifoEnd			;get current position in spc command fifo buffer		
	and.w #$ff
	tax
	
	sep #$20
	lda.w SpcReportType
	and.b #$07				;8 types max
	sta.w (SpcCmdFifo+1),x
	lda.b #SpcFifoCmdSetReportType
	sta.w SpcCmdFifo,x
	
	lda.b SpcCmdFifoEnd
	clc
	adc.b #4
	and.b #$3f				;16x4byte entries maximum 
	sta.b SpcCmdFifoEnd
	
	plp
	rts
	
;legacy code:
PtPlayerInit:
PtPlayerMainHandler:
PtPlayerUploadVolEcho:
	rts
	
;plays sound effect with panning set to current objects x-position
SpcPlaySoundEffectObjectXPos:
	php

	rep #$31
	pha
	ldx.b ObjectListPointerCurrent
	lda.w ObjEntryXPos,x				;get upper 4 nibbles of x-pos
	lsr a												;remove subpixel prec
	lsr a
	lsr a
	lsr a
	
	lsr a						;use bits 6-4 for panning
	and.w #$7f					;clear sign
	ora.w #$0F					;set max volume
	xba
	tax
	pla
	sep #$20

	jsr SpcPlaySoundEffect	
	
	
	
	plp
	rts
		

