*************************************************
* LightForce Intro Custom Music Player	V1.3	*
* for use with Delitracker/EaglePlayer		*
*						*
* Composed by ??? in 1988.			*
* Ripped and Adapted by Mr.STYCKX on 3 Aug 1994	*
*						*
* Supports :	Volume				*
*		Pattern	Jump			*
*		SongEnd				*
*		GetPosNbr	(25.02.95)	*
*						*
* 17.03.96 :	DTP_Balance			*
*		EP_Voices			*
*		EP_StructInit (Analyzer)	*
* 07.04.96 :	v1.3, bugs fixed		*
*		problems with Vol and Per in	*
*		the analyzers (flicking)	*
*************************************************


	opt	o+

	output	ram:CUST.LightForce



LF_TEST		=	 0		; 0 => BUILD COMPLETE CUSTOM MODULE
					; 1 => BUILD SMALL CODE FOR TESTING

lf_SampleAdr	=	$2a3a2		; position originale des samples


	SECTION LF_Player,Code

	incdir	"Include:"
	include	"misc/DeliPlayer.i"
	include	"misc/EaglePlayer.i"


	IFEQ	LF_TEST-0			; COMPLETE VERSION



	PLAYERHEADER PlayerTagArray

	dc.b '$VER: LightForce Intro (1988) custom player V1.3, '
	dc.b 'ripped and adapted by Mr.STYCKX (94-96)',0

	EVEN

PlayerTagArray
	dc.l	DTP_CustomPlayer,1		; CustomPlayer - Tag (important !!!)
	dc.l	DTP_Flags,PLYF_CUSTOM!PLYF_SONGEND

	dc.l	DTP_PlayerVersion,1<<16+3	; v1.3
	dc.l	EP_PlayerVersion,4
	dc.l	DTP_PlayerName,PName
	dc.l	DTP_Creator,CName

	dc.l	DTP_InitPlayer,InitPlay		; alloc audio
	dc.l	DTP_EndPlayer,EndPlay		; free audio
	dc.l	DTP_InitSound,lf_init		; init custom data
	dc.l	DTP_EndSound,lf_end		; clear DMA

	dc.l	DTP_Interrupt,lf_play

	dc.l	DTP_Volume,lf_Volume
	dc.l	DTP_Balance,lf_Volume

	dc.l	DTP_NextPatt,lf_NextPos
	dc.l	DTP_PrevPatt,lf_PrevPos
	dc.l	EP_GetPositionNr,lf_GetPos

	dc.l	EP_Voices,lf_SetVoices
	dc.l	EP_StructInit,lf_StructInit

	dc.l	EP_Flags,EPB_Songend!EPB_Voices!EPB_Analyzer!EPB_Volume!EPB_Balance!EPB_NextPatt!EPB_PrevPatt

	dc.l	TAG_DONE


PName	dc.b	"LightForce Custom v1.3",0
CName	dc.b	"Used in LightForce intros (1988)",$a
	dc.b	"Adapted by Mr.STYCKX (07/04/96)",0

	EVEN


lf_StructAnalyzer			; transmis à EaglePlayer pour gérer
	ds.l	UPS_SizeOF		; les analyzers



*-----------------------------------------------------------------------*
;
; Init Player

InitPlay
	move.l	dtg_SongEnd(a5),lf_SongEnd

	move.l	dtg_AudioAlloc(a5),a0		; Function
	jmp	(a0)

*-----------------------------------------------------------------------*
;
; End Player

EndPlay
	move.l	dtg_AudioFree(a5),a0		; Function
	jmp	(a0)

*-----------------------------------------------------------------------*

DO_SONGEND	MACRO
	move.l	lf_SongEnd(pc),a0
	jsr	(a0)			; previent le player de la fin du module
	ENDM


	ELSEIF				; TESTVERSION

;-------
; Small code to test the player under a debugger


DO_SONGEND	MACRO
	ENDM				; ne fait rien


	bsr	lf_init			; 27702


wait1	cmpi.b	#$fe,$DFF006
	bne.s	wait1
wait2	cmpi.b	#$ff,$DFF006
	bne.s	wait2

	btst	#6,$BFE001
	beq	lf_end

	move.w	#$f00,$dff180
	bsr	lf_play			; 276ac
	move.w	#$456,$dff180

	bra.s	wait1


lf_StructAnalyzer			; inutilisé en DEBUG
	ds.l	UPS_SizeOF


	ENDC				; LF_TEST



*-----------------------------------------------------------------------*
;
; Init Custom Replay Routine

lf_init
	movem.l	d0-d1/a0-a1,-(sp)

	moveq	#7-1,d0			; 7 samples a reloger
	lea	lf_Data(pc),a0
	move.l	#lf_Sample,d1
	cmp.l	(a0),d1
	beq.s	.done			; si samples deja reloges

.rel	sub.l	#lf_SampleAdr,(a0)
	add.l	d1,(a0)
	addq.w	#8,a0
	dbf	d0,.rel

.done
	lea	lf_Pos(pc),a1		; 277a8
	lea	lf_Pattern(pc),a0	; 287ea
	move.l	a0,lf_CurPattern
	move.l	a1,lf_CurPos
	clr.w	lf_PosNbr

	movem.l	(sp)+,d0-d1/a0-a1
	rts


*-----------------------------------------------------------------------*
;
; Clear Audio Reg.

lf_end
	move.w	#$f,$dff096
	clr.w	$dff0a8
	clr.w	$dff0b8
	clr.w	$dff0c8
	clr.w	$dff0d8

	rts

*-----------------------------------------------------------------------*
;
; Set Volume

lf_Volume
	IFEQ	LF_TEST-0

	move.w	dtg_SndLBal(a5),d0	; Vol Left
	mulu	dtg_SndVol(a5),d0	; Vol Max
	lsr.w	#6,d0
	move.w	d0,lf_MasterVolA	; final Vol Left
	move.w	d0,lf_MasterVolD

	move.w	dtg_SndRBal(a5),d0
	mulu	dtg_SndVol(a5),d0
	lsr.w	#6,d0
	move.w	d0,lf_MasterVolB
	move.w	d0,lf_MasterVolC

	ENDC
	rts


*-----------------------------------------------------------------------*
;
; Set DMA Voices

lf_SetVoices
	move.w	d0,lf_DMA_EP	; bit=1 <=> voice is ON
	rts


*-----------------------------------------------------------------------*
;
; Returns address of the UPS structure to EaglePlayer

lf_StructInit
	lea	lf_StructAnalyzer(pc),a0
	rts


*-----------------------------------------------------------------------*
;
; Goto Next Position

lf_NextPos
	addq.w	#1,lf_PosNbr
	move.l	lf_CurPos(pc),a1
	adda.w	#$10,a1			; next pos
	tst.w	(a1)
	bpl.s	.notend
	DO_SONGEND			; previent le player
	lea	lf_Pos(pc),a1
	clr.w	lf_PosNbr
.notend	lea	lf_Pattern(pc),a0	; pattern pos=0
	move.l	a0,lf_CurPattern
	move.l	a1,lf_CurPos
	rts


*-----------------------------------------------------------------------*
;
; Goto Prev Position

lf_PrevPos
	move.l	lf_CurPos(pc),a1
	lea	lf_Pos(pc),a0
	cmpa.l	a0,a1
	beq.s	.firstpos
	subq.w	#1,lf_PosNbr
	suba.w	#$10,a1			; prev pos
	lea	lf_Pattern(pc),a0	; pattern pos=0
	move.l	a0,lf_CurPattern
	move.l	a1,lf_CurPos
.firstpos
	rts


*-----------------------------------------------------------------------*
;
; Return Position Number

lf_GetPos
	moveq	#0,d0
	move.w	lf_PosNbr(pc),d0
	rts


*-----------------------------------------------------------------------*
;
; Custom Player Routine Called Every 1/50 s

lf_play					; 276ac
	movem.l	d0-d4/a0-a3,-(sp)

	not.w	lf_VblCount
	bne.s	l276D8

	lea	lf_StructAnalyzer(pc),a0
	clr.w	UPS_Voice1Per(a0)	; pas de nouvelle note, donc on met
	clr.w	UPS_Voice2Per(a0)	; les périodes à 0.
	clr.w	UPS_Voice3Per(a0)
	clr.w	UPS_Voice4Per(a0)

	move.w	lf_DMA_EP(pc),d1	; $f par défaut
	not.w	d1
	and.w	#$f,d1			; voix éteintes par EaglePlayer
	or.w	lf_DMA_OFF,d1		; voix éteintes par la replay
	move.w	d1,$DFF096
;;	move.w	d1,lf_StructAnalyzer+UPS_DMACon	; supprimé (provoque un clignotement)

	movem.l	(sp)+,d0-d4/a0-a3
	rts


l276D8
	lea	lf_StructAnalyzer(pc),a0
	move.w	#-1,UPS_Enabled(a0)
	move.w	#UPSB_Adr!UPSB_Len!UPSB_Per!UPSB_Vol!UPSB_DMACon,UPS_Flags(a0)

	move.l	lf_CurPattern(pc),a0
	move.l	lf_CurPos(pc),a1

	addq.w	#8,a0			; next pattern pos
	tst.w	(a0)
	bpl.s	l2770E
	lea	lf_Pattern(pc),a0	; pattern pos=0 et augmente pos
	addq.w	#1,lf_PosNbr
	adda.w	#$10,a1			; next pos
	tst.w	(a1)
	bpl.s	l2770E

l27702					; restart song
	DO_SONGEND			; previent le player
	lea	lf_Pos(pc),a1		; 277a8
	lea	lf_Pattern(pc),a0	; 287ea
	clr.w	lf_PosNbr

l2770E	moveq	#3,d1			; 4 voix
	clr.w	lf_DMA_OFF		; voix a eteindre
	moveq	#1,d4			; bit DMA voix 0
	lea	lf_VoiceHardA(pc),a3

l27720	move.w	(a1)+,d2		; Pattern nbr
	move.w	d2,d3
	lsl.w	#8,d2
	add.w	d3,d2
	add.w	d3,d2			; mulu #$102,d2
	move.w	(a1)+,d3		; Periode increment
	move.w	d2,d0
	adda.w	d0,a0

	move.w	(a0),d2			; sample nbr
	lsl.w	#3,d2
	lea	lf_Data(pc),a2		; 2a320
	adda.w	d2,a2
	move.l	(a2),(a3)+		; start
	addq.w	#6,a2
	move.w	(a2),(a3)+		; len

	move.w	2(a0),d2
	add.w	d3,d2
	add.w	d2,d2
	lea	lf_Per(pc),a2		; 2a358
	adda.w	d2,a2
	move.w	(a2),(a3)+		; periode
	move.w	4(a0),(a3)+		; volume

	move.w	6(a0),d2		; ON/OFF
	suba.w	d0,a0
	tst.w	d2
	bne.s	l27780
	or.w	d4,lf_DMA_OFF		; voice OFF on next VBL
l27780	add.w	d4,d4			; decale bit DMA
	dbf	d1,l27720

	lea	-$10(a1),a1		; repointe debut pos actuelle
	move.l	a0,lf_CurPattern
	move.l	a1,lf_CurPos



	lea	lf_VoiceHardA(pc),a0
	lea	$dff0a0,a1
	lea	lf_MasterVolA(pc),a2
	lea	lf_StructAnalyzer(pc),a3
	moveq	#4-1,d1			; 4 voix
CopyHard
	move.l	(a0),(a1)+		; start
	move.l	(a0)+,UPS_Voice1Adr(a3)
	move.w	(a0),(a1)+		; len
	move.w	(a0)+,UPS_Voice1Len(a3)
	move.w	(a0),(a1)+		; per
	move.w	(a0)+,UPS_Voice1Per(a3)	; nouvelle période -> met à jour analyzer

	move.w	(a0)+,d2		; replay vol 
	move.w	d2,UPS_Voice1Vol(a3)
	mulu	(a2)+,d2		; mastervol
	lsr.w	#6,d2
	move.w	d2,(a1)+

	addq.w	#6,a1			; next DMA channel
	lea	UPS_Modulo(a3),a3
	dbf	d1,CopyHard

	move.w	lf_DMA_EP(pc),d1	; $f par défaut
	move.w	d1,lf_StructAnalyzer+UPS_DMACon
	or.w	#$8200,d1
	move.w	d1,$DFF096

	clr.w	lf_StructAnalyzer+UPS_Enabled

	movem.l	(sp)+,d0-d4/a0-a3
	rts


*-----------------------------------------------------------------------*

lf_VblCount	dc.w	0		; vaut 0 ou ffff
lf_CurPos	dc.l	0
lf_CurPattern	dc.l	0

lf_DMA_OFF	dc.w	0		; voix à éteindre à la VBL suivante
lf_DMA_EP	dc.w	%1111		; voix actives depuis EaglePlayer

lf_VoiceHardA	dcb.b	4+2+2+2,0	; start, len, per et vol
lf_VoiceHardB	dcb.b	4+2+2+2,0
lf_VoiceHardC	dcb.b	4+2+2+2,0
lf_VoiceHardD	dcb.b	4+2+2+2,0

lf_MasterVolA	dc.w	64		; 0 .. 64
lf_MasterVolB	dc.w	64
lf_MasterVolC	dc.w	64
lf_MasterVolD	dc.w	64


lf_SongEnd	dc.l	0		; adresse de fonction
lf_PosNbr	dc.w	0		; position 

lf_Pos		incbin	b:LightForce/LightForce.pos	; 277a8
lf_Pattern	incbin	b:LightForce/LightForce.pat	; 287ea
lf_Data		incbin	b:LightForce/LightForce.dat	; 2a320
lf_Per		=	lf_Data+$38			; 2a358


	SECTION	samples,DATA_C

lf_Sample	incbin	b:LightForce/LightForce.smp	; 2a3a2


	END



