spcinterface.asm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. SpcHandlerMain:
  2. php
  3. sep #$20
  4. ; stz.w $4200 ;disable irqs in case we are processing a lengthy spc transfer
  5. ;check if spc sends report data
  6. lda.w $2141
  7. and.b #$e0
  8. cmp.b #$e0
  9. bne SpcHandlerNoSpcReport
  10. rep #$31
  11. lda.w $2141 ;get report type and select corresponding buffer accordingly
  12. and.w #7
  13. asl a
  14. tax
  15. lda.w $2142 ;get report word and store in buffer
  16. sta.l SpcReportBuffer,x
  17. SpcHandlerNoSpcReport:
  18. rep #$31
  19. ; sep #$20
  20. lda.b SpcHandlerState
  21. and.w #$1f ;have 32 states maximum
  22. asl a
  23. tax
  24. jsr (SpcHandlerSubroutineJumpLUT,x)
  25. sep #$20
  26. ; lda.b InterruptEnableFlags ;reenable irqs
  27. ; sta.w $4200
  28. plp
  29. rts
  30. ;stops currently playing stream, song, then waits for driver to return to idle state(wait for all scheduled sound effects to play)
  31. SpcWaitAllCommandsProcessed:
  32. php
  33. sep #$20
  34. stz.w SpcStreamVolume
  35. jsr SpcStopSong
  36. SpcWaitLoop:
  37. lda.b SpcCmdFifoStart
  38. cmp.b SpcCmdFifoEnd ;check if fifo is empty
  39. bne SpcWaitLoop
  40. lda.b SpcHandlerState
  41. cmp.b #1
  42. bne SpcWaitLoop
  43. plp
  44. rts
  45. SpcHandlerSubroutineJumpLUT:
  46. .dw SpcUploadDriver ;0
  47. .dw SpcIdle
  48. .dw SpcUploadSong
  49. .dw SpcUploadSongWait
  50. .dw SpcUploadSampleset
  51. .dw SpcUploadSamplesetWait ;5
  52. .dw SpcStreamData
  53. .dw SpcStreamDataWait
  54. .dw SpcPlaySoundeffectUpload
  55. .dw SpcPlaySoundeffectWait
  56. .dw SpcStopSongInit ;10
  57. .dw SpcStopSongWait
  58. .dw SpcSetSpeedInit
  59. .dw SpcSetSpeedWait
  60. .dw SpcSetChMaskInit
  61. .dw SpcSetChMaskWait ;15
  62. .dw SpcSetReportTypeInit
  63. .dw SpcSetReportTypeWait
  64. SpcSetReportTypeInit:
  65. rep #$31
  66. lda.b SpcHandlerArgument0 ;store type and sub-arg
  67. sta.w $2141
  68. sep #$20
  69. lda.b #SpcCmdReportType ;exec command
  70. sta.w $2140
  71. inc.b SpcHandlerState ;goto "wait SE ack"-state
  72. rts
  73. SpcSetReportTypeWait:
  74. sep #$20
  75. lda.w $2140
  76. cmp.b #SpcCmdReportType
  77. bne SpcSetReportTypeWaitNoIdle ;wait until spc has ack'd the speed change before returning
  78. lda.b #1
  79. sta.b SpcHandlerState ;return to idle once spc has answered
  80. SpcSetReportTypeWaitNoIdle:
  81. rts
  82. SpcSetChMaskInit:
  83. sep #$20
  84. lda.b SpcHandlerArgument0 ;store mask
  85. sta.w $2141
  86. lda.b #SpcCmdSetSongChMask ;exec command
  87. sta.w $2140
  88. inc.b SpcHandlerState ;goto "wait SE ack"-state
  89. rts
  90. SpcSetChMaskWait:
  91. sep #$20
  92. lda.w $2140
  93. cmp.b #SpcCmdSetSongChMask
  94. bne SpcSetChMaskWaitNoIdle ;wait until spc has ack'd the speed change before returing
  95. lda.b #1
  96. sta.b SpcHandlerState ;return to idle once spc has answered
  97. SpcSetChMaskWaitNoIdle:
  98. rts
  99. SpcSetSpeedInit:
  100. sep #$20
  101. lda.b SpcHandlerArgument0 ;store speed
  102. sta.w $2141
  103. lda.b #SpcCmdSetSongSpeed ;exec command
  104. sta.w $2140
  105. inc.b SpcHandlerState ;goto "wait SE ack"-state
  106. rts
  107. SpcSetSpeedWait:
  108. sep #$20
  109. lda.w $2140
  110. cmp.b #SpcCmdSetSongSpeed
  111. bne SpcSetSpeedWaitNoIdle ;wait until spc has ack'd the speed change before returing
  112. lda.b #1
  113. sta.b SpcHandlerState ;return to idle once spc has answered
  114. SpcSetSpeedWaitNoIdle:
  115. rts
  116. SpcUploadSampleset:
  117. sep #$20
  118. lda.b #SpcCmdUploadSamplePack ;send "upload song" command
  119. sta.w $2140
  120. lda.b #5
  121. sta.b SpcHandlerState ;goto "wait for spc to ack song upload" state
  122. rts
  123. SpcUploadSamplesetWait:
  124. sep #$20
  125. lda.w $2140
  126. cmp.b #SpcCmdUploadSamplePack ;wait until spc has ack'd upload song command
  127. bne SpcUploadSamplePackWaitExit ;else try again next frame
  128. ; stz.w $4200 ;disable irqs
  129. ;upload SamplePack here
  130. lda.b SpcHandlerArgument0 ;get song number to upload
  131. sta.b PtPlayerCurrentSamplePack
  132. rep #$31 ;multiply song number by 3 and use as index into song pointertable
  133. and.w #$00ff
  134. sta.b PtPlayerDataPointerLo
  135. asl a
  136. clc
  137. adc.b PtPlayerDataPointerLo
  138. tax
  139. lda.l (PtPlayerSamplePackPointertable+BaseAdress),x ;store pointer to song
  140. sta.b PtPlayerDataPointerLo
  141. lda.l (PtPlayerSamplePackPointertable+$c00001),x
  142. sta.b PtPlayerDataPointerHi
  143. ; sep #$20
  144. ; sta.b PtPlayerDataPointerBa
  145. ; rep #$31
  146. ldy.w #$0000
  147. lda.b [PtPlayerDataPointerLo],y ;get song length
  148. dec a ;substract length word
  149. dec a
  150. sta.w PtPlayerSmplBufferPosLo
  151. iny ;increment source pointer to actual song offset
  152. iny
  153. sep #$20
  154. SpcUploadSamplePackTransfer1:
  155. lda.b [PtPlayerDataPointerLo],y ;write 3 bytes to ports
  156. sta.w $2141
  157. iny
  158. lda.b [PtPlayerDataPointerLo],y
  159. sta.w $2142
  160. iny
  161. lda.b [PtPlayerDataPointerLo],y
  162. sta.w $2143
  163. iny
  164. lda.b #SpcCmdUploadSongT1 ;write ack transfer 1 to port0
  165. sta.w $2140
  166. SpcUploadSamplePackTransfer1WaitLoop: ;wait for spc to write transfer 1 ack back
  167. cmp.w $2140
  168. bne SpcUploadSamplePackTransfer1WaitLoop
  169. SpcUploadSamplePackTransfer2:
  170. lda.b [PtPlayerDataPointerLo],y ;write 3 bytes to ports
  171. sta.w $2141
  172. iny
  173. lda.b [PtPlayerDataPointerLo],y
  174. sta.w $2142
  175. iny
  176. lda.b [PtPlayerDataPointerLo],y
  177. sta.w $2143
  178. iny
  179. lda.b #SpcCmdUploadSongT2 ;write ack transfer 1 to port0
  180. sta.w $2140
  181. SpcUploadSamplePackTransfer2WaitLoop: ;wait for spc to write transfer 1 ack back
  182. cmp.w $2140
  183. bne SpcUploadSamplePackTransfer2WaitLoop
  184. cpy.w PtPlayerSmplBufferPosLo ;check if transfer length is exceeded
  185. bcc SpcUploadSamplePackTransfer1
  186. lda.b #SpcCmdUploadSamplePackDone ;send "upload song complete" commadn if transfer is done
  187. sta.w $2140
  188. lda.b #1
  189. sta.b SpcHandlerState ;return to idle
  190. ; lda.b InterruptEnableFlags ;reenable irqs
  191. ; sta.w $4200
  192. SpcUploadSamplePackWaitExit:
  193. lda.b SpcUploadedFlag
  194. ora.b #$40 ;set sample pack uploaded flag.
  195. sta.b SpcUploadedFlag
  196. rts
  197. SpcStopSongInit:
  198. rep #$31
  199. stz.w $2141
  200. stz.w $2142
  201. sep #$20
  202. lda.b #SpcCmdStopSong ;exec command
  203. sta.w $2140
  204. inc.b SpcHandlerState ;goto "wait SE ack"-state
  205. rts
  206. SpcStopSongWait:
  207. sep #$20
  208. lda.w $2140
  209. cmp.b #SpcCmdStopSong
  210. bne SpcStopSongWaitNoIdle ;wait until spc has ack'd the song/stream stop before returing
  211. lda.b #1
  212. sta.b SpcHandlerState ;return to idle once spc has answered
  213. SpcStopSongWaitNoIdle:
  214. rts
  215. SpcPlaySoundeffectUpload:
  216. rep #$31
  217. lda.b SpcHandlerArgument0 ;store arguments
  218. sta.w $2141
  219. lda.b SpcHandlerArgument1
  220. and.w #$7fff ;mask off msb and use as wurst
  221. ora.w SpcSoundEffectFlipFlag
  222. sta.w $2142
  223. lda.w SpcSoundEffectFlipFlag
  224. eor.w #$8000
  225. sta.w SpcSoundEffectFlipFlag
  226. sep #$20
  227. lda.b #SpcCmdPlaySoundEffect ;exec command
  228. sta.w $2140
  229. ; lda.b #1
  230. ; sta.b SpcHandlerState ;don't wait
  231. inc.b SpcHandlerState ;goto "wait SE ack"-state
  232. rts
  233. ;dont use this cause it sometimes plays a sound effect twice
  234. SpcPlaySoundeffectWait:
  235. sep #$20
  236. lda.w $2140
  237. cmp.b #SpcCmdPlaySoundEffect
  238. bne SpcPlaySoundeffectWaitNoIdle ;wait until spc has ack'd the soundeffect before returing
  239. lda.b #1
  240. sta.b SpcHandlerState ;return to idle once spc has answered
  241. SpcPlaySoundeffectWaitNoIdle:
  242. rts
  243. SpcUploadDriver:
  244. sep #$20
  245. ; stz.w $4200
  246. lda.b #(:PtplayerSpcCode+BaseAdress>>16)
  247. ldx.w #PtplayerSpcCode
  248. sta.b PtPlayerDataPointerBa
  249. stx.b PtPlayerDataPointerLo
  250. ; jsr PtPlayerInit
  251. ; php
  252. ; sep #$20
  253. ; stz.w $4200
  254. REP #$31
  255. LDY.w #$0000 ;clear data pointer
  256. LDA.w #$BBAA
  257. PtPlayerInitSpcWaitLoop1:
  258. CMP.w $2140 ;wait for spc to respond
  259. BNE PtPlayerInitSpcWaitLoop1
  260. SEP #$20
  261. LDA.b #$CC ;send "start transfer"
  262. BRA PtPlayerInitDoTransfer
  263. PtPlayerInitGetByte:
  264. LDA.b [PtPlayerDataPointerLo],y
  265. INY
  266. XBA
  267. LDA.b #$00
  268. BRA PtPlayerInitClearSpcPort0
  269. PtPlayerInitGetNextByte:
  270. XBA
  271. LDA.b [PtPlayerDataPointerLo],y
  272. INY
  273. XBA
  274. PtPlayerInitSpcWaitLoop2:
  275. CMP.w $2140
  276. BNE PtPlayerInitSpcWaitLoop2
  277. INC A
  278. PtPlayerInitClearSpcPort0:
  279. REP #$20
  280. STA.w $2140
  281. SEP #$20
  282. DEX
  283. BNE PtPlayerInitGetNextByte
  284. PtPlayerInitSpcWaitLoop3:
  285. CMP.w $2140
  286. BNE PtPlayerInitSpcWaitLoop3
  287. PtPlayerInitAddLoop:
  288. ADC.b #$03
  289. BEQ PtPlayerInitAddLoop
  290. PtPlayerInitDoTransfer:
  291. PHA
  292. REP #$20
  293. LDA.b [PtPlayerDataPointerLo],y
  294. INY
  295. INY
  296. TAX
  297. LDA.b [PtPlayerDataPointerLo],y
  298. INY
  299. INY
  300. STA.w $2142
  301. SEP #$20
  302. CPX.w #$0001 ;whats this?
  303. LDA.b #$00
  304. ROL A
  305. STA.w $2141
  306. ADC.b #$7F
  307. PLA
  308. STA.w $2140
  309. cpx.w #$0001 ;fix to be able to upload apucode during active nmi
  310. bcc PtPlayerInitDone
  311. PtPlayerInitSpcWaitLoop4:
  312. CMP.w $2140
  313. BNE PtPlayerInitSpcWaitLoop4
  314. BVS PtPlayerInitGetByte
  315. PtPlayerInitDone:
  316. SEP #$20
  317. ; lda.b #%10000001
  318. ; sta.w $4200
  319. /*
  320. lda.b #$7f ;init some variables
  321. sta.b PtPlayerMainVolL
  322. sta.b PtPlayerMainVolR
  323. lda.b #%00001111
  324. sta.b PtPlayerChannelEnable
  325. lda.b #$00
  326. sta.b PtPlayerEchoVolL
  327. sta.b PtPlayerEchoVolR
  328. sta.b PtPlayerChannelEchoEnable
  329. lda.b #$01
  330. sta.b CGIntroPlaySongNumber
  331. */
  332. ; PLP
  333. lda.b InterruptEnableFlags ;reenable irqs
  334. ; sta.w $4200
  335. inc.b SpcHandlerState ;go to idle state
  336. ;init some variables
  337. lda.b #$a0
  338. sta.w SpcSongSpeed ;set speed to default
  339. lda.b #$0f
  340. sta.w SpcSongChMask ;set song channel mask to default
  341. jsr ClearSpcReportBuffer
  342. RTS
  343. ClearSpcReportBuffer:
  344. php
  345. rep #$31
  346. lda.w #$0000 ;clear with y-position at line 255
  347. ldx.w #16
  348. ClearSpcReportBufferLoop:
  349. sta.l (SpcReportBuffer &$ffff + $7e0000-2),x
  350. dex
  351. dex
  352. bne ClearSpcReportBufferLoop
  353. plp
  354. rts
  355. ;check if there's a new command in the fifo, else return
  356. ;fifo buffer organization is:
  357. ;each entry: 1 command byte, 3 argument bytes
  358. ;fifo has 16 entries/64bytes total
  359. SpcIdle:
  360. sep #$20
  361. stz.w $2140 ;clear port0
  362. lda.b SpcCmdFifoStart
  363. cmp.b SpcCmdFifoEnd ;check if fifo is empty
  364. beq SpcIdleFifoEmpty
  365. ;theres a spc command present:
  366. rep #$31
  367. and.w #$3f ;limit fifo pointer to 64 bytes
  368. tax
  369. lda.w SpcCmdFifo,x ;get command
  370. sta.b SpcHandlerState ;store command/state and argument 1
  371. lda.w SpcCmdFifo+2,x ;get command
  372. sta.b SpcHandlerArgument1 ;store arguments 1 and 2
  373. lda.b SpcHandlerState ;directly execute fetched command
  374. and.w #$1f ;except when its an idle command
  375. cmp.w #1 ;because this would allow for unlimited nesting and possibly stack overflow
  376. beq SpcIdleFifoEmpty
  377. asl a
  378. tax
  379. jsr (SpcHandlerSubroutineJumpLUT,x)
  380. sep #$20
  381. lda.b SpcCmdFifoStart ;goto next fifo entry next frame
  382. clc
  383. adc.b #4
  384. and.b #$3f ;16x4byte entries maximum
  385. sta.b SpcCmdFifoStart
  386. SpcIdleFifoEmpty:
  387. rts
  388. SpcUploadSong:
  389. sep #$20
  390. lda.b #SpcCmdUploadSong ;send "upload song" command
  391. sta.w $2140
  392. lda.b #3
  393. sta.b SpcHandlerState ;goto "wait for spc to ack song upload" state
  394. rts
  395. SpcUploadSongWait:
  396. sep #$20
  397. lda.w $2140
  398. cmp.b #SpcCmdUploadSong ;wait until spc has ack'd upload song command
  399. bne SpcUploadSongWaitExit ;else try again next frame
  400. ;upload song here
  401. ; stz.w $4200
  402. lda.b SpcHandlerArgument0 ;get song number to upload
  403. sta.b PtPlayerCurrentSong
  404. rep #$31 ;multiply song number by 3 and use as index into song pointertable
  405. and.w #$00ff
  406. sta.b PtPlayerDataPointerLo
  407. asl a
  408. clc
  409. adc.b PtPlayerDataPointerLo
  410. tax
  411. lda.l (PtPlayerSongPointertable+BaseAdress),x ;store pointer to song
  412. sta.b PtPlayerDataPointerLo
  413. lda.l (PtPlayerSongPointertable+$c00001),x
  414. sta.b PtPlayerDataPointerHi
  415. ; sep #$20
  416. ; sta.b PtPlayerDataPointerBa
  417. ; rep #$31
  418. ldy.w #$0000
  419. lda.b [PtPlayerDataPointerLo],y ;get song length
  420. dec a ;substract length word
  421. dec a
  422. sta.w PtPlayerSmplBufferPosLo
  423. iny ;increment source pointer to actual song offset
  424. iny
  425. sep #$20
  426. SpcUploadSongTransfer1:
  427. lda.b [PtPlayerDataPointerLo],y ;write 3 bytes to ports
  428. sta.w $2141
  429. iny
  430. lda.b [PtPlayerDataPointerLo],y
  431. sta.w $2142
  432. iny
  433. lda.b [PtPlayerDataPointerLo],y
  434. sta.w $2143
  435. iny
  436. lda.b #SpcCmdUploadSongT1 ;write ack transfer 1 to port0
  437. sta.w $2140
  438. SpcUploadSongTransfer1WaitLoop: ;wait for spc to write transfer 1 ack back
  439. cmp.w $2140
  440. bne SpcUploadSongTransfer1WaitLoop
  441. SpcUploadSongTransfer2:
  442. lda.b [PtPlayerDataPointerLo],y ;write 3 bytes to ports
  443. sta.w $2141
  444. iny
  445. lda.b [PtPlayerDataPointerLo],y
  446. sta.w $2142
  447. iny
  448. lda.b [PtPlayerDataPointerLo],y
  449. sta.w $2143
  450. iny
  451. lda.b #SpcCmdUploadSongT2 ;write ack transfer 1 to port0
  452. sta.w $2140
  453. SpcUploadSongTransfer2WaitLoop: ;wait for spc to write transfer 1 ack back
  454. cmp.w $2140
  455. bne SpcUploadSongTransfer2WaitLoop
  456. cpy.w PtPlayerSmplBufferPosLo ;check if transfer length is exceeded
  457. bcc SpcUploadSongTransfer1
  458. lda.b #SpcCmdUploadSongDone ;send "upload song complete" commadn if transfer is done
  459. sta.w $2140
  460. lda.b #1
  461. sta.b SpcHandlerState ;return to idle
  462. lda.b InterruptEnableFlags ;reenable irqs
  463. ; sta.w $4200
  464. SpcUploadSongWaitExit:
  465. lda.b SpcUploadedFlag
  466. ora.b #$80 ;set song uploaded flag.
  467. sta.b SpcUploadedFlag
  468. rts
  469. ;stops currently playing song/stream
  470. SpcStopSong:
  471. php
  472. rep #$31
  473. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  474. and.w #$ff
  475. tax
  476. sep #$20
  477. ; sta.w (SpcCmdFifo+1),x
  478. lda.b #SpcFifoCmdStopSong
  479. sta.w SpcCmdFifo,x
  480. lda.b SpcCmdFifoEnd
  481. clc
  482. adc.b #4
  483. and.b #$3f ;16x4byte entries maximum
  484. sta.b SpcCmdFifoEnd
  485. plp
  486. rts
  487. ;in: a,8bit: SE number to play
  488. ; 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)
  489. SpcPlaySoundEffect:
  490. php
  491. rep #$31
  492. pha ;push SE number
  493. phx ;push arguments
  494. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  495. and.w #$ff
  496. tax
  497. pla ;get arguments
  498. sta.w (SpcCmdFifo+2),x ;store in fifo arguments 2,3
  499. pla ;fetch song number again
  500. sep #$20
  501. sta.w (SpcCmdFifo+1),x
  502. lda.b #SpcFifoCmdPlaySE
  503. sta.w SpcCmdFifo,x
  504. lda.b SpcCmdFifoEnd
  505. clc
  506. adc.b #4
  507. and.b #$3f ;16x4byte entries maximum
  508. sta.b SpcCmdFifoEnd
  509. plp
  510. rts
  511. ;same as above, but doesn't use x as input
  512. SpcPlaySoundEffectSimple:
  513. php
  514. rep #$31
  515. phx ;push arguments
  516. pha ;push SE number
  517. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  518. and.w #$ff
  519. tax
  520. lda.w #0
  521. sta.w (SpcCmdFifo+2),x ;store in fifo arguments 2,3
  522. pla ;fetch song number again
  523. sep #$20
  524. sta.w (SpcCmdFifo+1),x
  525. lda.b #SpcFifoCmdPlaySE
  526. sta.w SpcCmdFifo,x
  527. lda.b SpcCmdFifoEnd
  528. clc
  529. adc.b #4
  530. and.b #$3f ;16x4byte entries maximum
  531. sta.b SpcCmdFifoEnd
  532. plx
  533. plp
  534. rts
  535. ;in: a,8bit: song number to play
  536. SpcPlaySong:
  537. php
  538. rep #$31
  539. pha ;push song number
  540. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  541. and.w #$ff
  542. tax
  543. pla ;fetch song number again
  544. sep #$20
  545. sta.w (SpcCmdFifo+1),x
  546. lda.b #SpcFifoCmdUploadSong
  547. sta.w SpcCmdFifo,x
  548. lda.b SpcCmdFifoEnd
  549. clc
  550. adc.b #4
  551. and.b #$3f ;16x4byte entries maximum
  552. sta.b SpcCmdFifoEnd
  553. stz.w SpcStreamVolume ;mute eventually playing stream, stop stream
  554. lda.b SpcUploadedFlag
  555. and.b #$7f ;clear song uploaded flag. will be set once song upload has been completed later on
  556. sta.b SpcUploadedFlag
  557. ; lda.b SpcCurrentStreamSet ;useful, but messes up if sampleset + song dont fit into spc ram
  558. ; jsr SpcIssueSamplePackUpload
  559. plp
  560. rts
  561. ;in: a,8bit: streamset number to play
  562. SpcPlayStream:
  563. php
  564. sep #$20
  565. pha
  566. rep #$31
  567. stz.w SpcStreamFrame
  568. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  569. and.w #$ff
  570. tax
  571. sep #$20
  572. pla ;store frameset number
  573. sta.w (SpcCmdFifo+1),x
  574. lda.b #SpcFifoCmdStreamBrr
  575. sta.w SpcCmdFifo,x
  576. lda.b SpcCmdFifoEnd
  577. clc
  578. adc.b #4
  579. and.b #$3f ;16x4byte entries maximum
  580. sta.b SpcCmdFifoEnd
  581. sep #$20
  582. stz.w SpcStreamVolume ;mute eventually playing stream, stop stream
  583. plp
  584. rts
  585. ;in: a,8bit: sample pack number to upload
  586. SpcIssueSamplePackUpload:
  587. php
  588. rep #$31
  589. pha ;push song number
  590. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  591. and.w #$ff
  592. tax
  593. pla ;fetch song number again
  594. sep #$20
  595. sta.w (SpcCmdFifo+1),x
  596. lda.b #SpcFifoCmdUploadSamplePack
  597. sta.w SpcCmdFifo,x
  598. lda.b SpcCmdFifoEnd
  599. clc
  600. adc.b #4
  601. and.b #$3f ;16x4byte entries maximum
  602. sta.b SpcCmdFifoEnd
  603. lda.b SpcUploadedFlag
  604. and.b #$bf ;clear sample pack uploaded flag. will be set once song upload has been completed later on
  605. sta.b SpcUploadedFlag
  606. plp
  607. rts
  608. SpcStreamData:
  609. sep #$20
  610. lda.b #$7f ;turn on streaming volume
  611. sta.w SpcStreamVolume
  612. lda.b SpcHandlerArgument0 ;get frameset number to stream
  613. sta.b SpcCurrentStreamSet ;multiply by 5 to get pointer into frameset table
  614. rep #$31
  615. and.w #$ff
  616. sta.b SpcTempBuffer
  617. asl a
  618. asl a
  619. clc
  620. adc.b SpcTempBuffer
  621. tax
  622. lda.l (StreamSetLut+BaseAdress+3),x ;get number of frames for this set
  623. sta.w $2141 ;write number of frames to stream to spc
  624. sep #$20
  625. lda.b #SpcCmdReceiveStream ;send "upload song" command
  626. sta.w $2140
  627. lda.l $2140
  628. cmp.b #SpcCmdReceiveStreamComplete ;don't switch to streamer yet if spc is still finishing the last transfer.(only applicable if last command was streaming)
  629. beq SpcStreamDataWaitSpcLastStream
  630. lda.b #7
  631. sta.b SpcHandlerState ;goto "wait for spc to ack song upload" state
  632. SpcStreamDataWaitSpcLastStream:
  633. rts
  634. SpcStreamDataReturnIdle:
  635. sep #$20
  636. lda.b HdmaFlags
  637. and.b #$7f ;disable spc stream on hdma channel 7
  638. sta.b HdmaFlags
  639. lda.b #1 ;return to idle if spc signalizes that transfer is complete
  640. sta.b SpcHandlerState
  641. SpcStreamDataExit:
  642. rts
  643. SpcStreamDataWait:
  644. sep #$20
  645. lda.w $2140
  646. cmp.b #SpcCmdReceiveStreamComplete ;check if transfer complete
  647. beq SpcStreamDataReturnIdle
  648. cmp.b #SpcCmdReceiveStream ;wait until spc has ack'd upload song command
  649. bne SpcStreamDataExit ;else try again next frame
  650. lda.b SpcCurrentStreamSet ;get current frameset number
  651. rep #$31
  652. and.w #$ff
  653. sta.b SpcTempBuffer ;multiply by 5
  654. asl a
  655. asl a
  656. clc
  657. adc.b SpcTempBuffer
  658. tax
  659. lda.l (StreamSetLut+BaseAdress),x ;store offset of first frame in set
  660. sta.b SpcTempBuffer+2
  661. lda.l (StreamSetLut+BaseAdress+1),x
  662. sta.b SpcTempBuffer+3
  663. lda.w $2141 ;get frame request number
  664. ;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.
  665. sta.b SpcTempBuffer+5 ;store frame request number
  666. sta.w SpcStreamFrame
  667. pha
  668. lda.w SpcStreamVolume ;only write current frame if stream hasnt been stopped. otherwise external routines might be confused when transitioning between streams
  669. and.w #$ff
  670. bne DontClearSpcStreamFrame
  671. stz.w SpcStreamFrame
  672. DontClearSpcStreamFrame:
  673. pla
  674. SpcStreamCalcFrameOffsetLoop:
  675. cmp.w #SpcFramesPerBank ;check if number of frames exceeds bank limit
  676. bcc SpcStreamCalcFrameOffsetNoBankWrap
  677. sep #$20 ;if it does, increase bank
  678. inc.b SpcTempBuffer+4
  679. rep #$31 ;and substract one bank full of samples from total amount
  680. sec
  681. sbc.w #SpcFramesPerBank
  682. bra SpcStreamCalcFrameOffsetLoop ;do this until we're in the bank the frame actually is in
  683. SpcStreamCalcFrameOffsetNoBankWrap:
  684. asl a ;multiply by 144
  685. asl a
  686. asl a
  687. asl a ;first multiply by 16
  688. sta.b SpcTempBuffer+2
  689. asl a ;then by 128
  690. asl a
  691. asl a
  692. clc
  693. adc.b SpcTempBuffer+2 ;this is x*144
  694. sta.b SpcTempBuffer+2 ;and save in pointer
  695. ;line 1, command
  696. lda.w #36/2
  697. sta.b SpcTempBuffer ;set scanline counter
  698. lda.w #SpcScanlineWaitCount ;store 1 in frame count
  699. ldx.w #0 ;clear hdma table pointer
  700. txy ;clear brr source counter
  701. sta.l HdmaSpcBuffer,x
  702. lda.w #SpcCmdSubmitStreamNumber ;send "submit frame #"-cmd
  703. sta.l HdmaSpcBuffer+1,x
  704. lda.b SpcTempBuffer+5 ;get frame submit number
  705. sta.l HdmaSpcBuffer+2,x
  706. lda.w SpcStreamVolume
  707. sta.l HdmaSpcBuffer+4,x ;store volume
  708. inx
  709. inx
  710. inx
  711. inx
  712. inx
  713. ;line 2, waitloop & frame transmit
  714. SpcStreamSetupHdmaTableLoop:
  715. lda.w #1
  716. sta.l HdmaSpcBuffer,x ;one line
  717. lda.b [SpcTempBuffer+2],y ;brr data to ports $2140-$2143
  718. sta.l HdmaSpcBuffer+1,x
  719. iny
  720. iny
  721. lda.b [SpcTempBuffer+2],y
  722. sta.l HdmaSpcBuffer+3,x
  723. inx
  724. inx
  725. inx
  726. inx
  727. inx
  728. ; iny
  729. ; iny
  730. iny
  731. iny
  732. lda.w #1
  733. sta.l HdmaSpcBuffer,x ;one line
  734. lda.b [SpcTempBuffer+2],y ;brr data to ports $2140-$2143
  735. sta.l HdmaSpcBuffer+1,x
  736. iny
  737. iny
  738. lda.b [SpcTempBuffer+2],y
  739. sta.l HdmaSpcBuffer+3,x
  740. inx
  741. inx
  742. inx
  743. inx
  744. inx
  745. ; iny
  746. ; iny
  747. iny
  748. iny
  749. dec.b SpcTempBuffer
  750. bne SpcStreamSetupHdmaTableLoop
  751. ;this doesnt work right. reason is that the the stream data sometimes contains "false" commands.
  752. ;write spc command here: (only play soundeffect, stop song/stream is allowed here)
  753. stz.b SpcTempBuffer ;clear spc command field
  754. stz.b SpcTempBuffer+2
  755. /*
  756. lda.b SpcCmdFifoStart
  757. cmp.b SpcCmdFifoEnd ;check if fifo is empty
  758. beq SpcStreamFifoEmpty
  759. ;theres a spc command present:
  760. rep #$31
  761. and.w #$3f ;limit fifo pointer to 64 bytes
  762. tax
  763. lda.w SpcCmdFifo,x ;get command
  764. and.w #$ff
  765. cmp.w #SpcCmdPlaySoundEffect
  766. beq SpcStreamFifoExecCmd
  767. cmp.w #SpcCmdStopSong
  768. beq SpcStreamFifoExecCmdExit
  769. bra SpcStreamFifoEmpty
  770. SpcStreamFifoExecCmdExit:
  771. sep #$20
  772. lda.b #1
  773. 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.
  774. rts
  775. SpcStreamFifoExecCmd:
  776. ;state
  777. lda.w SpcCmdFifo,x ;get command
  778. sta.b TempBuffer ;store command/state and argument 1
  779. lda.w SpcCmdFifo+2,x ;get command
  780. sta.b TempBuffer+2 ;store arguments 1 and 2
  781. sep #$20
  782. lda.b SpcCmdFifoStart ;goto next fifo entry next frame
  783. clc
  784. adc.b #4
  785. and.b #$3f ;16x4byte entries maximum
  786. sta.b SpcCmdFifoStart
  787. SpcStreamFifoEmpty:
  788. rep #$31
  789. */
  790. lda.w #1
  791. sta.l HdmaSpcBuffer,x ;one line
  792. lda.b SpcTempBuffer
  793. sta.l HdmaSpcBuffer+1,x
  794. lda.b SpcTempBuffer+2
  795. sta.l HdmaSpcBuffer+3,x
  796. inx
  797. inx
  798. inx
  799. inx
  800. inx
  801. ;terminate hdma table:
  802. lda.w #0
  803. sta.l HdmaSpcBuffer,x
  804. lda.w #HdmaSpcBuffer & $ffff
  805. sta.l $4372 ;hdma source offset
  806. sep #$20
  807. lda.b HdmaFlags
  808. ora.b #$80 ;enable spc stream on hdma channel 7
  809. sta.b HdmaFlags
  810. lda.b #$7e ;hdma source bank
  811. sta.l $4374
  812. lda.b #%00000100 ;hdma config, direct, 4 regs write once
  813. sta.l $4370
  814. lda.b #$40 ;bbus target, apu port $2140-$2143
  815. sta.l $4371
  816. rts
  817. ;in: SpcSongSpeed,8bit: song speed(timer duration. default is #$a0. lower=faster, higher=slower
  818. SpcSetSongSpeed:
  819. php
  820. rep #$31
  821. ; pha ;push speed
  822. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  823. and.w #$ff
  824. tax
  825. ; pla ;fetch speed again
  826. sep #$20
  827. lda.w SpcSongSpeed
  828. sta.w (SpcCmdFifo+1),x
  829. lda.b #SpcFifoCmdSetSpeed
  830. sta.w SpcCmdFifo,x
  831. lda.b SpcCmdFifoEnd
  832. clc
  833. adc.b #4
  834. and.b #$3f ;16x4byte entries maximum
  835. sta.b SpcCmdFifoEnd
  836. ; stz.w SpcStreamVolume ;mute eventually playing stream, stop stream
  837. ; lda.b SpcCurrentStreamSet ;useful, but messes up if sampleset + song dont fit into spc ram
  838. ; jsr SpcIssueSamplePackUpload
  839. plp
  840. rts
  841. ;in: SpcSongSpeed,8bit: song speed(timer duration. default is #$a0. lower=faster, higher=slower
  842. SpcSetSongChannelMask:
  843. php
  844. rep #$31
  845. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  846. and.w #$ff
  847. tax
  848. sep #$20
  849. lda.w SpcSongChMask
  850. sta.w (SpcCmdFifo+1),x
  851. lda.b #SpcFifoCmdSetChMask
  852. sta.w SpcCmdFifo,x
  853. lda.b SpcCmdFifoEnd
  854. clc
  855. adc.b #4
  856. and.b #$3f ;16x4byte entries maximum
  857. sta.b SpcCmdFifoEnd
  858. plp
  859. rts
  860. ;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
  861. SpcSetReportType:
  862. php
  863. rep #$31
  864. lda.b SpcCmdFifoEnd ;get current position in spc command fifo buffer
  865. and.w #$ff
  866. tax
  867. sep #$20
  868. lda.w SpcReportType
  869. and.b #$07 ;8 types max
  870. sta.w (SpcCmdFifo+1),x
  871. lda.b #SpcFifoCmdSetReportType
  872. sta.w SpcCmdFifo,x
  873. lda.b SpcCmdFifoEnd
  874. clc
  875. adc.b #4
  876. and.b #$3f ;16x4byte entries maximum
  877. sta.b SpcCmdFifoEnd
  878. plp
  879. rts
  880. ;legacy code:
  881. PtPlayerInit:
  882. PtPlayerMainHandler:
  883. PtPlayerUploadVolEcho:
  884. rts
  885. ;plays sound effect with panning set to current objects x-position
  886. SpcPlaySoundEffectObjectXPos:
  887. php
  888. rep #$31
  889. pha
  890. ldx.b ObjectListPointerCurrent
  891. lda.w ObjEntryXPos,x ;get upper 4 nibbles of x-pos
  892. lsr a ;remove subpixel prec
  893. lsr a
  894. lsr a
  895. lsr a
  896. lsr a ;use bits 6-4 for panning
  897. and.w #$7f ;clear sign
  898. ora.w #$0F ;set max volume
  899. xba
  900. tax
  901. pla
  902. sep #$20
  903. jsr SpcPlaySoundEffect
  904. plp
  905. rts