quickdev16/snes/monitor/routines/spcinterface.asm
David Voswinkel a7270acdf1 o add monitor
2009-07-20 19:05:40 +02:00

1153 lines
25 KiB
NASM

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