org #1000 run #1000 nolist ; V1.2 - Modified automodification address according to new player ; V1.1 - No retriggered sound bug corrected ; Play a Starkos Song using the Player ; and manage digidrums. ; In this code, samples are 8-bits in memory ; but each bytes is converted into 4-bits ; through a conversion table before being ; sent to the PSG. ; Read PLAYERS text for more info about how to ; include digidrums with Starkos songs. PLAYER equ #9000 ;Address of the ASM player SONG equ #4000 ADDRUM equ #2000 ;Address of the samples ADSNARE equ #2500 SZDRUM equ #280 ;Size of the samples SZSNARE equ #1f0 CONVTAB equ #12*256 ;Convertion table (see at the end). ;The low byte must be 0 !! JPPSG equ PLAYER+#3ac ;Address of the jump to the code that ;modifies the PSG regs. R8SET equ PLAYER+#70e ;Address of instruction that holds the ;value of the REG8. R9SET equ PLAYER+#75f R10SET equ PLAYER+#7b0 NODIGI equ PLAYER+#b ;Address of the no of the sample to play NOCHAN equ PLAYER+#c ;Address of the instr giving the channel where the sample is (1/2/3) di ld hl,#c9fb ld (#38),hl ; ld hl,(JPPSG+1) ;Save the adress of the code that send values to PSG ld (ADCODPSG+1),hl ld a,#c9 ;And bypass it by writing a RET. ld (JPPSG),a ld de,SONG ;Initialize song call PLAYER ; ;Main loop SYNC ld bc,#7f10 out (c),c ld a,#54 out (c),a call VSYNC ld bc,#7f10 out (c),c ld a,#4b out (c),a ; call PLAYER+3 ;Play song call ISDIGIDR ;Is there any new digidrum triggered ? call PREPDIGI ;Prepare the digidrum being played / to be played. call SENDPSG ;Send the song PSG values to the PSG. ;A channel must be shut down if sample on it. call PLAYSPL ;Play the sample. ; KEY ld a,5+64 ;If space pressed, reset. call ROUTOUCH cp #7f jp z,0 jp SYNC ;Check if any new digidrum has been triggered. ISDIGIDR ld (REG7VAL+1),a ;The player gives the value of Reg7 through A to the ;PSG code. We save it. ; ld a,(NODIGI) or a ;A new digidrum detected ? If no, get out. ret z ; ;Digidrum detected ! Let's find its adress and size. ld l,a ;Connect the no of digidrum in the TABDIGI table. ld h,0 add hl,hl add hl,hl ld de,TABDIGI-4 ;-4 because sample 0 doesn't exist. add hl,de ld e,(hl) inc hl ld d,(hl) inc hl ld (PTSPL+1),de ;and get the address and size of the sample. ld e,(hl) inc hl ld d,(hl) ld (ENDSPL+1),de ; ld a,1 ;Enable sample. ld (PLAYDIGI+1),a ret ;If a digidrum must be played, we must prepare the PSG ;registers. Find the mask to OR with the REG7, in order ;to stop the sound/noise on the voice where the sample ;is played. PREPDIGI PLAYDIGI ld a,0 ;Play digidrum ? 0=no 1=yes or a jr z,PLAYNODG ;Played on which channel ? (1/2/3) ld a,(NOCHAN) cp 1 jr z,DIGICH1 cp 2 jr z,DIGICH2 DIGICH3 ld hl,R10SET ;Adress in the player of the instruction ;that manages channel 3 volume. ;See (**) below. ld b,%00100100 ;Mask to be ORed. Channel 3 shut down. jr DIGICHMOD DIGICH2 ld hl,R9SET ;Same thing, for channel 2. ld b,%00010010 jr DIGICHMOD DIGICH1 ld hl,R8SET ;Same thing, for channel 1. ld b,%00001001 DIGICHMOD add a,8-1 ;Calculate the PSG volume register (8/9/10) ld (VOLREG+1),a ;where the digidrum is found. ld a,b ld (REG7MASK+1),a ld a,(hl) ;(**) Modify the values stored in the player inc hl ;for it not to send the song volume value to the inc hl ;PSG because it could interfer with our sample. ld (hl),a ld (PTVSET+1),hl ret PLAYNODG xor a ;No sample is played, so we set the mask to 0. ld (REG7MASK+1),a ;No channel to shut down. ret ;Play (or continue playing) sample. PLAYSPL ld a,(PLAYDIGI+1) ;Play digidrum only if asked ! or a ret z ld a,#c0 ;Select volume register VOLREG ld bc,#f400 ;for the digidrum channel. out (c),c ld b,#f6 out (c),a defb #ed,#71 ;out (c),0 ld c,120 ;8khz=160 samples per VBL. 6Khz=120 per VBL. ld de,CONVTAB PTSPL ld hl,0 ;Points on the sample adress. LOOPSPL ld e,(hl) ;Read a sample, and convert it into inc hl ;4 bits. ld a,(de) ld b,#f4 out (c),a ld b,#f6 ld a,#80 out (c),a defb #ed,#71 defs 115,0 ;8Khz -> waiting 80 nops is ok. 6khz -> 115. dec c ;Next one ! jp nz,LOOPSPL ; ld (PTSPL+1),hl ; ex de,hl ;Check if we haven't reach the end of the sample ENDSPL ld hl,0 xor a sbc hl,de jr z,ENDSP1 ret nc ;RET if end not reached. ENDSP1 ld (PLAYDIGI+1),a ;End of the sample reached. ; dec a ;Force the volume reg to be refreshed PTVSET ld (0),a ;next VBL (=255). ret ;Send the value to the PSG ;Use a mask with the REG7 of the PSG, in order ;to stop the sound on the channel where the ;digidrum is played. When no digidrum is played, ;the mask is null. SENDPSG REG7VAL ld a,0 REG7MASK or 0 ld h,a ADCODPSG jp 0 ;Jump to the code in the player that send ;values to PSG. ;Scan a keyboard line. ;A=no line+64 ROUTOUCH LD BC,#F782 OUT (C),C LD BC,#F40E OUT (C),C LD BC,#F6C0 OUT (C),C defb #ed,#71 LD BC,#F792 OUT (C),C LD B,#F6 OUT (C),A LD B,#F4 IN A,(C) LD BC,#F782 OUT (C),C dec b defb #ed,#71 RET ;Vsync VSYNC ld b,#f5 VSYN2 in a,(c) rra jr nc,VSYN2 VSYN3 ld b,#f5 in a,(c) rra jr c,VSYN3 ret ;Table containing the adress of the samples (1,2,3,...) ;and the end adress of each. TABDIGI defw ADDRUM,ADDRUM+SZDRUM defw ADSNARE,ADSNARE+SZSNARE list ;Code End ! nolist ;Convertion table, from 8 bits to 4 bits value. org CONVTAB defb 1, 1, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 7, 7, 8 defb 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9 defb 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11 defb 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 defb 11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12 defb 12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13 defb 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 defb 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 defb 13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14 defb 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14 defb 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14 defb 14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15 defb 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 defb 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 defb 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 defb 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 list ;Table End ! nolist