********Routine de Gestion du Hard sonore*********
***Prog exemple

start
	lea	mus,a0
	lea	son,a1
	bsr	ems_init
	move.l	$6c,oldirq
	move.l	#irq,$6c
.loop
	btst	#6,$bfe001
	bne.s	.loop
	move.l	ems_sample,a0
	move.l	12(a0),stru
	move.w	16(a0),stru+4
	lea	stru,a0
	bsr.s	ems_left
	bra.s	.loop
	move.l	oldirq,$6c
	move.w	#$f,$dff096
	rts
irq
	movem.l	d0-7/a0-7,-(sp)
	bsr	ems_play
	movem.l	(sp)+,d0-7/a0-7
	dc.w	$4ef9
oldirq	dc.l	0
stru
	dc.l	0
	dc.w	0
	dc.w	200
	dc.w	64

*	Source	:	DH0:Langage/Source/LastPlayer.asm
*
*	Objet	:       Player EMS Version 1.24 (Custom)
*
*	Date	: 	22/03/91  17:36:46
*
*	Custom pour OMD.

*********************************************
*** NewPlayer EMS de Modules Format brute ***
** Version 1.24 Spread interdit sous peine **
** d'exil a Gorcki. Thomas Van Pimmel ASOC **
** 		22-MAR-91		   **
*********************************************

***************1598 octets*******************

** Description des Sous-programmes : ********

;	- ems_init	(a0,a1) (music,son)	;format brut EMS
;	- ems_play	()			;routine sous irq
;	- ems_stop	()			;stop ems + canaux
;	- ems_left	(a0) (SampleStruct)	;joue canal gauche
;	- ems_right 	(a0) (SampleStruct)	;joue canal droit
;	- ems_mono	(a0) (  ""    ""  )	;joue canaux g/d

*********************************************
*** Déclaration des constantes **************
*********************************************
;-- DMA
c_per = 6
c_len = 4
c_vol = 8

;-- EMS
len  = 4		;snd length
rep  = 6		;repeat
repl = 8		;replen
vol = 10		;volume
per = 12		;period

;-- Autres
MAGIC = $369d26
VALDIV = 1		;division du volume
WAIT = 5		;temporisation raster

*********************************************
****************** PGM **********************
*********************************************

***SP's
ems_stop	;sans param
	clr.w	ems_forbid
	move.w	#$f,$dff096
	rts
ems_left	;(a0 samplestruct)
	**allouer canal
	or.w	#%1000,ems_alloc
	move.l	a0,ems_queryL		;requête gauche
	move.w	#VALDIV,ems_voldiv	;diminuer volume
	rts
ems_rigth	;(a0 samplestruct)
	**allouer canal
	or.w	#%0100,ems_alloc
	move.l	a0,ems_queryR		;requête droite
	move.w	#VALDIV,ems_voldiv	;diminuer volume
	rts
ems_mono	;(a0 samplestruct)
	bsr.s	ems_left
	bra.s	ems_rigth
** initialisation d'une partition
** a0 format brut music
** a1 format brut son
** IRQ possible ; durée négligeable
ems_init
	;EMS off
	move.l	4.w,a6
	move.b	$212(a6),ems_hertz+1	;frequence en hertz
	clr.w	ems_forbid
	clr.w	ems_posi
	clr.w	ems_mesure
	;init des variables principales
	move.l	a0,ems_part		;save mus ptr
	move.w	2(a0),d0
	subq.w	#1,d0
	move.w	d0,ems_length
	addq.w	#6,a0
	moveq	#0,d0			;clr d0
	move.b	(a0),d0			;1er partition
	move.l	a0,ems_seq		;table séquences
	add.w	#128,a0
	move.l	a0,ems_sample		;table des sons
	move.l	a0,a2
	add.w	#12*15,a2
	lsl.l	#5,d0
	lsl.l	#5,d0
	;=>	mulu	#1024,d0
	add.l	d0,a2
	move.l	a2,ems_actual		;partition actuelle
	;init table des sons
	moveq	#14,d0			;15 sons
.loop
	tst.w	len(a0)
	beq.s	.jmp
	clr.w	(a1)
	move.l	a1,(a0)
	moveq	#0,d1
	move.w	len(a0),d1
	lsl.l	#1,d1
	add.l	d1,a1
.jmp
	add.w	#12,a0
	dbf	d0,.loop
	;-- EMS On
	move.w	#1,ems_forbid		;permit
	rts

*******This is THE player of EMS*************
ems_play				;pas d'arguments
	*****restorer allocation gauche
	tst.w	ems_lenL
	beq.s	.jmp
	subq.w	#1,ems_lenL
	bne.s	.jmp
	move.w	#%1000,$dff096
	and.w	#%0111,ems_alloc
.jmp
	*****restorer allocation droite
	tst.w	ems_lenR
	beq.s	.jmp2
	subq.w	#1,ems_lenR
	bne.s	.jmp2
	move.w	#%100,$dff096
	and.w	#%1011,ems_alloc
.jmp2
ems_cmp	cmp.w	#6,ems_count
	bcs	ems_notyet		;traitements intermédiaires
	clr.w	ems_count
	******permit?
	tst.w	ems_forbid
	bne.s	ems_permit
	rts				;retour
ems_permit
	******oui :
	lea	ems_com(pc),a0		;efface commandes
	clr.l	(a0)
	clr.l	4(a0)
	clr.l	8(a0)
	clr.l	12(a0)
;---là tous les six de balayage
;---A5 partition, A0 dma, d2 dma value, d0 compteur boucle, 
;-- d1 flag occupation, d3 ctrl register
;-- d4-6 intermédiaires, d7 val dma fin
;-couper les voies
	move.l	ems_actual(pc),a5
	move.w	ems_mesure(pc),d0
	lsl.w	#4,d0			;*16
	add.w	d0,a5
	;---
	moveq	#3,d0			;4 voies
	move.w	ems_alloc(pc),d1
	moveq	#1,d2
	moveq	#0,d3
	moveq	#0,d7
ems_cut
	move.b	2(a5),d4		;instr
	lsr.b	#4,d4
	tst.b	d4
	beq.s	ems_nosamplechg		;pas de chgment instr
	btst	d3,d1
	bne.s	ems_nosamplechg		;autre son en cours
	or.w	d2,d7
ems_nosamplechg
	addq.w	#1,d3			;ctrl reg
	lsl.w	#1,d2			;dma
	tst.l	(a5)+			;next
	dbf	d0,ems_cut
	move.w	d7,$dff096		;couper
	bsr	ems_initwait		;temporisation dma

***************coeur de la routine**************
;documentation de ems_snd
	sub.w	#16,a5		;retour debut partition
	moveq	#3,d0
	move.w	ems_alloc(pc),d1
	moveq	#0,d3
	move.w	ems_voldiv(pc),d5
	lea	ems_snd(pc),a1
	lea	$dff0a0,a4
	lea	ems_com(pc),a3	;table des commandes spéciales
ems_loop
	clr.l	(a1)		;par default pas de son
	btst	d3,d1		;allocation?
	bne	ems_isallocate
	moveq	#0,d2
	move.b	2(a5),d2
	lsr.b	#4,d2
	tst.b	d2
	beq.s	ems_noaddrs	;pas de son spécial
	**********************************************nouveau son
	*mulu	#12,d2
	subq.w	#1,d2
	move.w	d2,d4
	lsl.w	#2,d4		;*4
	lsl.w	#3,d2		;*8
	add.w	d4,d2		;=> *12
	move.l	ems_sample(pc),a0	;table des sons
	add.w	d2,a0
	move.l	(a0),(a1)	;addrs (pas de tst validité du son)
	move.w	len(a0),len(a1)
	move.w	rep(a0),rep(a1)
	move.w	repl(a0),repl(a1)
	move.w	vol(a0),d4
	lsr.w	d5,d4		;si volume diminué
	move.w	d4,vol(a1)
	move.w	d4,c_vol(a4)
	**********************************************période
ems_noaddrs
	move.w	(a5),d2
	tst.w	d2
	beq.s	ems_noper
	move.w	d2,c_per(a4)
	move.w	d2,per(a1)	;mieux que per(couilles)
ems_noper
	*************commandes
	moveq	#0,d2
	move.b	2(a5),d2	;commandes
	and.b	#$f,d2
ems_force			;saut de retour si cmd break ou speed
	move.b	3(a5),d4	;args
	tst.b	d2
	beq	ems_retval	;pas de commandes
	and.w	#$ff,d4
	move.w	d2,d6
	subq.w	#7,d6
	blt	ems_retval
	lsl.w	#2,d6
	pea	ems_retval
	lea	ems_jmpt(pc),a0
	move.l	(a0,d6.w),a2
	jmp	(a2)
;--EMS ne contient ni rétansorbe ni colorant. Etonnant non?
ems_vol
	lsr.w	d5,d4
	move.w	d4,c_vol(a4)
	move.w	d4,vol(a1)
	rts
ems_repeat
	move.w	len(a1),repl(a1)
	clr.w	rep(a1)
	rts
ems_speed
	tst.w	d4
	beq.s	ems_retval
	move.w	d4,ems_cmp+2
	rts
ems_led
	tst.w	d4
	beq.s	ems_ledof
	bset	#1,$bfe001
	rts
ems_ledof
	bclr	#0,$bfe001
	rts
ems_break
	move.w	d4,ems_cbreak
	move.w	#63,ems_mesure
	rts
ems_spécial
	move.w	d2,(a3)
	move.w	d4,2(a3)
	rts
ems_isallocate		;break et speed à traiter même si alloc
	moveq	#0,d2
	move.b	2(a5),d2	;commandes
	and.b	#$f,d2
	cmp.b	#8,d2
	beq	ems_force
	cmp.b	#9,d2
	beq	ems_force
ems_retval
	addq.w	#1,d3		;ctrl
	add.w	#14,a1		;ems_snd
	add.w	#$10,a4		;dma
	tst.l	(a5)+		;partitions
	tst.l	(a3)+
	dbf	d0,ems_loop
	addq.w	#1,ems_mesure
	cmp.w	#64,ems_mesure
	bne.s	ems_suite
	*******chg patern
	move.w	ems_cbreak(pc),ems_mesure
	clr.w	ems_cbreak
	move.l	ems_seq(pc),a0
	addq.w	#1,ems_posi
	move.w	ems_posi(pc),d0
	cmp.w	ems_length(pc),d0
	bls.s	.ok
	clr.w	ems_posi
	moveq	#0,d0
.ok
	moveq	#0,d1
	move.b	(a0,d0.w),d1
	lsl.l	#5,d1
	lsl.l	#5,d1
	add.l	ems_part,d1
	add.l	#128+12*15+6,d1
	move.l	d1,ems_actual
ems_suite
	********************************
	or.w	#$8000,d7
	bsr	ems_makewait		;attendre dma
;initialisation du DMA
	lea	$dff0a0,a0
	lea	ems_snd(pc),a1
	moveq	#3,d0
ems_docloop
	move.l	(a1),d1
	tst.l	d1
	beq.s	ems_nosample
	move.l	d1,(a0)			;addrs
	move.w	len(a1),c_len(a0)
ems_nosample
	add.w	#$10,a0
	add.w	#14,a1
	dbf	d0,ems_docloop
	move.w	d7,$dff096		;boum!
	rts
*********************************************************
**************** 	IFNE	6	*****************
*********************************************************
ems_notyet				;traitement repeat et replen
	tst.w	ems_count
	bne.s	ems_norepeat
	moveq	#3,d0
	lea	$dff0a0,a0
	lea	ems_snd(pc),a1
ems_shit
	move.l	(a1),d1
	tst.l	d1
	beq.s	ems_no
	clr.l	(a1)
	moveq	#0,d2
	move.w	rep(a1),d2
	lsl.l	#1,d2
	add.l	d2,d1
	move.l	d1,(a0)
	move.w	repl(a1),c_len(a0)
ems_no
	add.w	#$10,a0
	add.w	#14,a1
	dbf	d0,ems_shit
	bra.s	ems_jmpquery
ems_norepeat
	bsr	ems_querys	;son en +
ems_jmpquery
	***************************************commandes spéciales
	lea	ems_com(pc),a0
	lea	$dff0a0,a1
	lea	ems_snd(pc),a2
	moveq	#3,d0
	move.w	ems_alloc(pc),d1
	moveq	#0,d2
ems_cmd
	btst	d2,d1
	bne	ems_nofree
	move.w	(a0),d3
	tst.b	d3
	beq	ems_nofree
	pea	ems_nofree
	cmp.b	#7,d3
	beq.s	ems_voldown
	cmp.b	#12,d3
	beq.s	ems_down
	cmp.b	#13,d3
	beq.s	ems_vib
	cmp.b	#11,d3
	beq.s	ems_up
	rts
	***************************commandes 1/50eme
ems_voldown
	move.w	2(a0),d3
	sub.w	d3,vol(a2)
	bgt.s	.rts
	clr.w	vol(a2)
	clr.l	(a0)
.rts
	move.w	vol(a2),c_vol(a1)
	rts
ems_up
	*rts
	move.w	2(a0),d3
	move.w	per(a2),d4
	sub.w	d3,d4
	cmp.w	#$70,d4
	blt.s	.rts
	move.w	d4,per(a2)
	move.w	d4,c_per(a1)
.rts
	rts
ems_down
	move.w	2(a0),d3
	move.w	per(a2),d4
	add.w	d3,d4
	cmp.w	#$6b0,d4
	bgt.s	.rts
	move.w	d4,per(a2)
	move.w	d4,c_per(a1)
.rts
	rts
ems_vib
	move.w	2(a0),d4
	move.w	per(a2),d5
	move.w	ems_count(pc),d3
	btst	#0,d3
	bne.s	ems_d
	sub.w	d4,d5
	move.w	d5,c_per(a1)
	rts
ems_d
	add.w	d4,d5
	move.w	d5,c_per(a1)
	rts
ems_nofree
	tst.l	(a0)+
	add.w	#$10,a1
	add.w	#14,a2
	addq.w	#1,d2
	dbf	d0,ems_cmd
	****************************************restorer volume?
	tst.w	ems_alloc
	bne.s	.rts
	tst.w	ems_voldiv
	beq.s	.rts
	clr.w	ems_voldiv
	lea	$dff0a0,a1
	lea	ems_snd(pc),a0
	moveq	#3,d0
.loop
	move.w	vol(a0),c_vol(a1)
	add.w	#$10,a1
	add.w	#14,a0
	dbf	d0,.loop
.rts
	********counter ++
	addq.w	#1,ems_count
	rts
	*****************************Extension player
ems_querys
	tst.l	ems_queryL
	beq.s	ems_tstR
	tst.l	ems_queryR
	beq	ems_makeL
	*******là les deux query sont ON
	move.l	ems_queryR(pc),a0
	cmp.l	ems_queryL(pc),a0
	bne	ems_makeL	;pas deux sons identiques
	move.w	#%1100,$dff096	;couper 2&3
	bsr	ems_initwait
	*****droit
	lea	$dff0c0,a1
	bsr	ems_makewait
	bsr	ems_calcmagic
	move.w	d5,ems_lenR
	move.w	d5,ems_lenL
	*****gauche
	move.l	ems_queryL(pc),a0
	lea	$dff0d0,a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.w	(a0)+,(a1)+
	****go!
	move.w	#%1100+$8000,$dff096
	clr.l	ems_queryR
	clr.l	ems_queryL
	clr.l	ems_com+8
	clr.l	ems_com+12
	rts
	*******query rigth
ems_tstR
	tst.l	ems_queryR
	bne.s	ems_makeR
	rts
ems_makeR
	*******là query rigth est à ON
	move.w	#%0100,$dff096	;couper 2
	bsr	ems_initwait
	lea	$dff0c0,a1
	move.l	ems_queryR(pc),a0
	bsr	ems_makewait
	bsr.s	ems_calcmagic
	move.w	d5,ems_lenR
	move.w	#%0100+$8000,$dff096
	clr.l	ems_queryR
	clr.l	ems_com+8
	rts
ems_makeL
	*******là query left est à ON
	move.w	#%1000,$dff096	;couper 2
	bsr	ems_initwait
	lea	$dff0d0,a1
	move.l	ems_queryL(pc),a0
	bsr	ems_makewait
	bsr.s	ems_calcmagic
	move.w	d5,ems_lenL
	move.w	#%1000+$8000,$dff096
	clr.l	ems_queryL
	clr.l	ems_com+12
	rts
ems_calcmagic	;calcul durée en 1/50eme + init canaux
	;d0 = periode
	;d1 = len
	move.l	(a0)+,(a1)+	;add
	move.w	(a0)+,d1	;len
	move.w	(a0)+,d0	;per
	move.w	d1,(a1)+
	move.w	d0,(a1)+
	move.w	(a0)+,(a1)+	;vol
	****analyse période
	moveq	#0,d5
	move.w	d0,d5		;per
	move.l	#MAGIC,d6	;cst
	divu	d5,d6		;octets/seconde
	and.l	#$ffff,d6	;clr reste
	moveq	#0,d4
	move.w	ems_hertz,d4
	divu	d4,d6		;octets/50eme ou 60eme
	and.l	#$ffff,d6	;clr reste
	*****
	move.w	d1,d5		;len en mots
	lsl.l	#1,d5		;len en octet
	divu	d6,d5		;d5 nb 50eme
	*****fin int
	rts
*************Temporisation
ems_initwait
	move.b	$dff006,d0	;raster
	addq.b	#WAIT,d0	;nb de lignes attentes
	move.w	d0,ems_raster
	rts
ems_makewait
	move.w	ems_raster(pc),d0
.loop
	move.b	$dff006,d6
	cmp.b	d0,d6
	bls.s	.loop
	rts

*********************************************
***********VARIABLES EMS ********************
*********************************************

;-- jmp table
ems_jmpt				;switch/case
	dc.l	ems_spécial
	dc.l	ems_break
	dc.l	ems_speed
	dc.l	ems_led
	dc.l	ems_spécial
	dc.l	ems_spécial
	dc.l	ems_spécial
	dc.l	ems_vol
	dc.l	ems_repeat
;-- Longwords
ems_part	dc.l	0	;addrs format brut music
ems_seq		dc.l	0	;addrs table sequences
ems_actual	dc.l	0	;addrs partition actuelle
ems_sample	dc.l	0	;addrs table sons
ems_queryL	dc.l	0	;requête gauche
ems_queryR	dc.l	0	;idem droit
ems_com		ds.l	4	;table des commandes enregistrées
;-- Words
ems_hertz	dc.w	0	;freq du courant en hertz
ems_lenR	dc.w	0	;long droit
ems_lenL	dc.w	0	;long son en 1/50
ems_length	dc.w	0	;longueur du morceau
ems_cbreak	dc.w	0	;valeur du break ou zero
ems_posi	dc.w	0	;position dans sequence
ems_raster	dc.w	0	;ligne d'attente
ems_voldiv	dc.w	0	;valeur rotation volume
ems_mesure	dc.w	0	;start mesure
ems_alloc	dc.w	%0000	;flag ocupation des voies
ems_count	dc.w	0	;irq count
ems_forbid	dc.w	0	;indic forbid/permit (1/0)
;-- Tables
;-- Table id pour chaque voie
ems_snd		dc.l	0	;addrs
		dc.w	0	;length
		dc.w	0	;rep
		dc.w	0	;repl
		dc.w	0	;vol
		dc.w	0	;per
		;autres voies
		ds.b	14*3
	section	dd,data_c
mus	incbin	dh2:rawdata/demo.mus
son	incbin	dh2:rawdata/demo.son
