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