1153 lines
25 KiB
NASM
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
|
|
|
|
|