;***************************************************************************
;*	Ce module contient les fonctions qui jouent les MOD sans s'occuper
;*	toutefois de la restitution sonore en elle mˆme
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 02/01/95
;* Modification le 02/01/95

IDEAL
P386N

PUBLIC	SETMODPOS
PUBLIC	GETMODPOS
PUBLIC	PEEKMOD
PUBLIC	SETMOD
PUBLIC	STARTMOD
PUBLIC	STOPMOD
PUBLIC	MAKEMOD
PUBLIC	TOGGLEVOC
PUBLIC	LOCKMOD
PUBLIC	CHANGEVOL
PUBLIC	DETECTSND

PUBLIC	Line
PUBLIC	Position

INCLUDE "CRYSLOAD.INC"
INCLUDE "CRYSDEV.INC"
INCLUDE "CRYSERR.INC"

SEGMENT CODE PARA PUBLIC USE16 'CODE'
ASSUME cs:CODE,ds:CODE


DEFAULT_FRQ	EQU	1860
Comments:
SoundBuf	DB BUF_LEN DUP (?)
		DB BUF_LEN DUP (?)
SoundPtr	DW BUF_LEN
SoundPage	DW 0
VoicesLen	DW 0

DeviceStart:
	REPT	16
	DW  OFFSET NulDev
	ENDM
DeviceEnd:

Status		DB 0	; 0 en marche 1-7 inutilis‚
IntMask		DW 0	; masque d'interruption des 2 controleurs
OldIrq		DD 0

UsedDevice	DW 0
NbVoice		DB 0
MixRate		DW 0



Instrument1	INSTRUMENT MAX_INST DUP (?)
Voice1          VOICE MAX_VOICE DUP (?)
PatternSeg      DW 0
Sequence	DW MAX_PART DUP (0)
LastPos		DW 0

Position	DW OFFSET Sequence	; Ces deux variables doivent se suivre
Line		DD 0			; dans cet ordre pour SET/GETMODPOS

PatternDelay	DB 0
Tempo		DB 6
Frame		DB 1
Bpm		DB 125
MasterVol	DB 255

NoteTab		DW 1AC0h,1940h,17D0h,1680h
		DW 1530h,1400h,12E0h,11D0h,10D0h,0FE0h,0F00h,0E28h

LOW_NOTE	EQU	1Ch
HIGH_NOTE	EQU	1AC0h

Notes		DW HIGH_NOTE+39 DUP (?)	;tables de conversion des note amiga
VolumeTab	DB VOL_TAB_LEN DUP (?)       ;tables de multiplication

EffectTab       DW OFFSET set_arpeggio
		DW OFFSET set_portamento_up
		DW OFFSET set_portamento_down
		DW OFFSET set_portamento_tone
		DW OFFSET set_vibrato
		DW OFFSET set_portamento_volume
		DW OFFSET set_vibrato_volume
		DW OFFSET set_tremolo
		DW OFFSET set_nul_effect
		DW OFFSET set_play_end_part
		DW OFFSET set_volume_slide
		DW OFFSET position_jump
		DW OFFSET set_volume
		DW OFFSET pattern_break
		DW OFFSET set_extended_effect
		DW OFFSET set_tempo

		DW OFFSET set_bpm
		DW OFFSET set_tremor
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect


;*************************************************************************
;*	Cette routine est appel‚ par chaque driver au d‚but et sert …
;*	mettre leur adresse de d‚but dans la table des devices
;*
;* Entr‚e:
;*	Dans la pile l'adresse du driver
;*
;* Sortie:
;*	AX	code d'erreur si C=1

PROC	Usedevice

	pop	bx	;r‚cupŠre l'adresse du driver
	push	di
	mov     ax,CODE
	mov	es,ax
	mov	di,OFFSET DeviceStart
	mov	ax,OFFSET NulDev
	mov	cx,OFFSET DeviceStart-OFFSET DeviceEnd
	repne	scasw
	mov	ax,TOO_MANY_DEV
	cmp	di,OFFSET DeviceEnd
	cmc
	jb	@@error
	mov	[es:di-2],bx
	xor	ax,ax
@@error:
	pop	di
	retf

ENDP

;**************************************************************************
;*	Cette routine recherche la pr‚sence d'une carte sonore dans les
;*	variables d'environnement et renvoit la carte trouv‚ avec ses
;*	paramŠtre
;*
;* Entr‚e:
;*      adresse de la variable(16 bits) contenant la carte … detecter
;*	adresse de la variable(16 bits) contenant l'adresse du port
;*	adresse de la variable(8 bits) contenant l'IRQ
;*	adresse de la varibale(8 bits) contenant le DMA
;*
;* Sortie:
;*	Les diff‚rentes variables sont compl‚t‚ si elles ‚taient nulles
;*	code d'erreur

PROC	Detectsnd FAR
LOCAL	port:WORD,irq:BYTE,dma:BYTE,dev:WORD,devadr:WORD,find:WORD=varloc

	enter	varloc,0
	push	es
	push	ds
	push	di
	push	si

	mov	[find],0
	lds	di,[ss:bp+18]
	mov	ax,[ds:di]
	mov	[dev],ax
	mov	ax,CODE
	mov	ds,ax
	ASSUME	ds:CODE

	mov	ah,62h
	int	21h
	mov	es,bx
	mov	ax,[es:2Ch]
	mov	es,ax

	mov	si,OFFSET DeviceStart
	mov	[devadr],si

@@next_dev:
	mov	bx,[ds:si]
	cmp	bx,OFFSET NulDev
	je	@@no_drv
	mov	ax,[dev]
	cmp	ax,0
	je	@@search_dev
@@search_id:
	cmp	[(DEVICE PTR ds:bx).id],ax
	je	@@search_dev
	add	si,2
	mov	bx,[ds:si]
	cmp	bx,OFFSET NulDev
	jne	@@search_id
@@no_drv:
	mov	ax,DRV_NOT_FOUND
	jmp	@@error

@@search_dev:
	mov	cx,0ffffh
	add	bx,2
	xor	di,di
@@next_var:
	mov	si,bx
	lodsb
	cmp     al,'$'
	je	@@find_all
@@get_next:
	scasb
	je	@@find_one
@@not_dev:
	dec	di
	xor	al,al
	repne	scasb
	cmp	[byte ptr es:di],0
	jne	@@next_var
	cmp	[find],0
	je	@@not_found
	jmp	@@find_all

@@find_one:
	repe	cmpsb
        dec	di
        lodsb
	cmp	al,'='
	jne	@@not_dev
@@search_char:
	cmp	[byte ptr es:di],0
	je	@@not_dev
	mov	ah,[es:di]
	inc	di
	cmp	ah,'a'
	jb	@@no_maj
	cmp	ah,'z'
	ja	@@no_maj
	sub	ah,20h
@@no_maj:
	cmp     ah,al
	jne	@@search_char
@@get_par:
	lodsb
	cmp	al,'p'
	je	@@get_info
	cmp	al,'i'
	je	@@get_info
	cmp	al,'d'
	je	@@get_info
	cmp	al,'t'
	je	@@get_info
	cmp	al,'$'
	je	@@find_all
	cmp	al,'!'
	je	@@get_end
	jmp	@@search_char
@@get_info:
	mov	ah,[es:di]
	inc	di
	or	ah,ah
	je	@@not_dev
	cmp	ah,'0'
	jb	@@get_info
	cmp	ah,'9'
	ja	@@get_info

	dec	di
	cmp	al,'p'
	je	@@get_port
	cmp	al,'i'
	je	@@get_irq
	cmp	al,'d'
	je	@@get_dma
	cmp	al,'t'
	je	@@get_type
@@get_port:
	xor	dx,dx
	xor	ah,ah
@@next_digit:
	mov	al,[es:di]
	sub	al,'0'
	jl	@@no_digit
	cmp	al,'9'
	jbe	@@under10
	sub	al,6
	cmp	al,10
	jb	@@no_digit
	cmp	al,16
	jae	@@no_digit
@@under10:
	shl     dx,4
	add	dx,ax
	inc	di
	jmp    	@@next_digit

@@no_digit:
	mov	[port],dx
	jmp	@@get_par

@@get_dma:
	mov	al,[es:di]
	sub	al,'0'
	mov	[dma],al
	jmp	@@get_par

@@get_irq:
	mov	ax,[es:di]
	sub	ax,'00'
	cmp	ah,9
	ja	@@no_2digit
	mov	al,ah
	add	al,10
@@no_2digit:
	mov	[irq],al
	jmp	@@get_par

@@get_type:
	mov	dl,[es:di]
	lodsw
	cmp	al,dl
	ja	@@not_dev
	cmp	ah,dl
	jb	@@not_dev
	jmp	@@get_par

@@get_end:
	mov	[find],1
	jne	@@get_par

@@find_all:

	mov	bx,[ds:bx-2]

	lds	di,[ss:bp+18]
	mov	[ds:di],bx

	mov	bx,[port]
	lds	di,[ss:bp+14]
	mov	[ds:di],bx

	mov	dl,[irq]
	lds	di,[ss:bp+10]
	mov	[ds:di],dl

	mov     dh,[dma]
	lds	di,[ss:bp+6]
	mov	[ds:di],dh

@@found:
	pop	si
	pop	di
	pop	ds
	pop	es
	leave
	clc
	ret	4*4

@@not_found:
	mov	ax,DEV_NOT_FOUND
	cmp	[dev],0
	jne	@@error
	mov	si,[devadr]
	add	si,2
	mov	[devadr],si
	jmp	@@next_dev

@@error:

	pop	si
	pop	di
	pop	ds
	pop	es
	leave
	stc

	ret	4*4

ENDP


;***************************************************************************
;*	Cette fonction initialise les tables du programme suivant les
;*	paramŠtre pass‚ par le programme principale
;*
;* Entr‚e:
;*
;*	Dans la pile en suivant cet ordre (en pascal)
;*
;*      CX	frequence en centaine de Hz (0 valeur par d‚faut)
;*      BX	numero de l'appareil de sortie du son
;*      DX	numero du port de l'appareil
;*	AL	numero de l'irq (0 valeur par d‚faut)
;*	AH	numero du canal DMA

PROC	Setmod FAR

	push	ds
	push	es
	push	si
	push	di
	push	bp
	mov	bp,sp

	mov	ax,CODE
	mov	ds,ax

	mov     ax,[ss:bp+20]
	mov	bx,OFFSET DeviceStart
	mov	si,[ds:bx]
	cmp	si,0FFFFh
	je	@@no_driver
@@search_dev:
	cmp	ax,[(DEVICE PTR ds:si).id]
	je	@@find_dev
	add	bx,2
	mov	si,[ds:bx]
	cmp	si,0FFFFh
	jne	@@search_dev
@@no_driver:
	mov	[UsedDevice],OFFSET NulDev
	mov	ax,DRV_NOT_FOUND
	stc
	jmp	@@error

@@find_dev:
	mov	[UsedDevice],si

	mov	ax,[(DEVICE PTR ds:si).make]
	sub	ax,OFFSET makedev+3
	mov	[cs:OFFSET makedev+1],ax

	mov     ax,[(DEVICE PTR ds:si).setbpm]
	sub	ax,OFFSET bpmeffect+3
	mov	[cs:OFFSET bpmeffect+1],ax

	mov	[byte ptr cs:OFFSET switch_makemod],1Eh

	mov	ax,[ss:bp+18]
	mov	[(DEVICE PTR ds:si).port],ax
	mov	al,[ss:bp+16]
	mov	[(DEVICE PTR ds:si).irq],al
	mov	al,[ss:bp+14]
	mov	[(DEVICE PTR ds:si).dma],al

	mov	ax,[ss:bp+22]
	or	ax,ax
	jne	@@no_default
	mov     ax,DEFAULT_FRQ
@@no_default:
	mov	[MixRate],ax

	mov     cl,[NbVoice]
	mov	al,SIZE VOICE
	mul	cl
	add	ax,OFFSET Voice1
	mov	[cs:OFFSET nbvoicetest+2],ax

	mov	bx,OFFSET Voice1
	mov	al,MAX_VOICE
@@clear_voice:
	mov	[(VOICE PTR ds:bx).mute],00h	; Met les voix off
	mov	[(VOICE PTR ds:bx).replen],MIN_REPEAT
	mov	[(VOICE PTR ds:bx).samplen],MIN_REPEAT
	mov	[(VOICE PTR ds:bx).effet],OFFSET retour
	add	bx,SIZE VOICE
	dec	al
	jne	@@clear_voice

	mov	ah,[ds:OFFSET NbVoice]
	xor	al,al
	mov	[word ptr ds:OFFSET Line],ax
	mov	bx,OFFSET Voice1
@@next_voice:
	mov	[(VOICE PTR ds:bx).mute],0FFh	; Met les voix on
	add	bx,SIZE VOICE
	dec	ah
	jne	@@next_voice

	mov	dx,[(DEVICE PTR ds:si).init]
	call	dx
	jc	@@error

	mov	al,[ds:Bpm]
	mov	dx,[(DEVICE PTR ds:si).setbpm]
	call	dx

	mov	dx,0057h   ; increment=1024/(Periode Amiga*cycle paula*frequence de mixage)
	mov	ax,642Ah   ; dx:ax=16/2.79365*10^-6
	div	[MixRate]  ; MinRate minimum=87=>870Hz
	mov	cx,ax

	mov	bx,LOW_NOTE-17
@@next_note:
	mov	dx,cx
	shr	dx,10
	mov	ax,cx
	shl	ax,6
	cmp	dx,bx
	jae	@@overflow
	div     bx		; divise 1024*(2.79365e-7*frequence)
@@put_note:
	shl	bx,1
	mov	[ds:bx+OFFSET Notes],ax
	shr	bx,1
	inc	bx
	cmp	bx,HIGH_NOTE+39
	jne	@@next_note

	call	far Makemod
	sub	[cs:SoundPtr],BUF_LEN

	mov	ax,NO_ERROR
	clc

@@error:
	leave
	pop	di
	pop	si
	pop	es
	pop	ds

	ret	10

@@overflow:
	mov	ax,0ffffh
	jmp	@@put_note

ENDP

;**************************************************************************
;*      initialise le son

PROC    Startmod FAR

	push	ds
	push	es
	push	si
	push	di

	mov	ax,CODE
	mov	ds,ax
	mov	si,[UsedDevice]

	mov	bl,[(DEVICE PTR ds:si).irq]
	call	getirq
	mov	[word ptr cs:OFFSET OldIrq],ax
	mov	[word ptr cs:OFFSET OldIrq+2],dx


	in	al,0A1h
	mov	ah,al
	in	al,21h
	mov	[ds:IntMask],ax
	mov	cl,[(DEVICE PTR ds:si).irq]
	cmp	cl,8
	jb	@@first_pic
	mov	ch,al
	mov	al,254
	and	cl,7
	rol	al,cl
	and	ah,al
	mov	al,cl
	or	al,60h
	out	0A0h,al
	xchg	al,ah
	out	0A1h,al
	push	ax

	mov	al,ch
	mov	cl,2
@@first_pic:
	mov	ah,254
	rol	ah,cl
	and	ah,al
	mov	al,cl
	or	al,60h
	out	20h,al
	xchg	al,ah
	out	21h,al
	push	ax

	mov	dx,[(DEVICE ptr ds:si).start]
	call	dx

	pop	ax
	out	21h,al
	mov	al,ah
	out	20h,al
	cmp	[(DEVICE PTR ds:si).irq],8
	jb	@@only_one
	pop	ax
	out	0A1h,al
	mov	al,ah
	out	0A0h,al
@@only_one:
	or	[ds:Status],1

	pop	di
	pop	si
	pop	es
	pop	ds
	ret
ENDP

;*************************************************************************
;*	Calcul de la musique sous interruption

PROC	IMakeMod

	sti
	pushad
	mov	ax,[cs:SoundPtr]
	mov	bx,[cs:SoundPage]
	mov	cx,[cs:VoicesLen]
	add	cx,cx
	sub	cx,bx
	neg	cx
	js	@@loop
	cmp	ax,bx
	jae	@@not_now
	cmp	ax,cx
	jb	@@not_now

@@make_now:
	call far MAKEMOD
	popad
	iret

@@loop:
	cmp	ax,bx
	jb	@@make_now
	and	cx,BUF_LEN-1
	cmp	ax,cx
	jae	@@make_now

@@not_now:
	popad
	iret

ENDP

;*************************************************************************
;*	Calcul la musique

PROC	MAKEMOD	FAR

switch_makemod:
	push	ds
	mov	[byte ptr cs:OFFSET switch_makemod],0CBh
	push	es
	push	ebp
	push	esi
	push	edi

	mov	ax,CODE
	mov	ds,ax

	mov	ecx,BUF_LEN*65536

	mov	ax,[SoundPtr]
	mov	bx,[SoundPage]
	mov     cx,bx
	add	cx,[VoicesLen]

	cmp	cx,BUF_LEN
	ja	@@loop		; c'est bien ja et pas jae !!!
	je	@@always_ok
	cmp	ax,cx
	jae	@@ok
@@always_ok:
	cmp	ax,bx
	jb	@@ok

@@fin:
	mov	[byte ptr cs:OFFSET switch_makemod],1Eh
	pop	edi
	pop	esi
	pop	ebp
	pop	es
	pop	ds
	ret
@@loop:
	and	cx,65535-BUF_LEN
	cmp	ax,bx
	jae	@@fin
	cmp	ax,cx
	jb	@@fin
	rol	ecx,16

@@ok:
	mov	ebp,ecx

	dec     [ds:Frame]
	jne	@@no_new_note

	mov     al,[cs:OFFSET Tempo]
	mov	[ds:OFFSET Frame],al

	cmp	[byte ptr ds:OFFSET PatternDelay],0
	je	@@no_delay
	dec	[byte ptr ds:OFFSET PatternDelay]
	jmp	@@no_new_note

@@no_delay:

	les	di,[Line]
	xor	al,al
	mov	ah,[NbVoice]

	cmp	di,ax
	jb     @@same_pattern

	sub	di,ax

	mov	si,[Position]
	cmp	si,[LastPos]
	jb	@@not_end_seq
	mov	si,OFFSET Sequence
@@not_end_seq:
	mov	ax,[ds:si]
lock_pat:
	add	si,2
	mov	[Position],si
	mov	[word ptr ds:OFFSET Line+2],ax
	mov	es,ax

@@same_pattern:


	mov	si,OFFSET Voice1
@@autre_voix:

	mov	ax,[(VOICE PTR ds:si).play]
	mov	[(VOICE PTR ds:si).oldnote],ax

	mov     edx,[dword ptr es:di]   ;charge la voix
	mov	cl,dl
	and	cl,7Fh
	jz	@@no_note

	ror     edx,19
	mov     bl,dl
        rol     edx,19
	and     bl,31
	cmp     bl,3
	je      @@no_loadcurwp
	mov	[(dword ptr (VOICE ptr ds:si).adrvoc)],0
	or	[(VOICE ptr ds:si).gusinf],2
@@no_loadcurwp:
	movzx	bx,cl
	and	bl,0Fh
	add	bx,bx
	mov	ax,[OFFSET NoteTab+bx]
	shr	cl,4
	shr	ax,cl
	mov	[(VOICE PTR ds:si).note1],ax
	mov	[(VOICE PTR ds:si).play],ax
@@no_note:

	shr	edx,7
	mov	bx,dx
	and	bx,3Fh
	je	@@no_inst

	cmp	bl,[(VOICE ptr ds:si).inst]
	je	@@same_inst
	mov	[(VOICE ptr ds:si).inst],bl
	or	[(VOICE ptr ds:si).gusinf],01h
@@same_inst:
	or	[(VOICE ptr ds:si).gusinf],00ch	; nouvel instrument

	shl	bx,3 	; CAR SIZE INSTRUMENT=8
	add     bx,OFFSET Instrument1-SIZE INSTRUMENT
	mov	eax,[dword ptr (INSTRUMENT ptr ds:bx).adrseg]
	mov	[(dword ptr (VOICE ptr ds:si).adrvoc)+4],eax
	mov	eax,[dword ptr (INSTRUMENT PTR ds:bx).length]
	mov	[(dword ptr (VOICE ptr ds:si).samplen)],eax
@@no_inst:

	shr	edx,6
	mov	al,dl
	and	al,3Fh
	jz	@@no_vol
	or	[(VOICE ptr ds:si).gusinf],8
	inc	al
	mov	[(VOICE ptr ds:si).volume],al
@@no_vol:

	shr	edx,6
	mov	bl,dl
	and     bx,1Fh
	mov	[(VOICE PTR ds:si).effnb],bl
	add	bx,bx
	mov	ax,[OFFSET EffectTab+bx]
	mov	[(VOICE PTR ds:si).effet],ax

	shr	edx,5
	mov	[(VOICE PTR ds:si).extra],dl

	add     di,4
	add     si,SIZE VOICE

nbvoicetest:
	cmp  	si,OFFSET Voice1	; Code automodifi‚
	jb      @@autre_voix

	mov     [word ptr ds:OFFSET Line],di

@@no_new_note:
	mov	si,OFFSET Voice1

makedev:
	DB	0E9h
	DW	0


ENDP

;***************************************************************************
;*	Proc‚dure d'initialisation des diff‚rents effets

PROC	set_nul_effect

	mov	[(VOICE ptr ds:di).effnb],0eh
	mov	[(VOICE ptr ds:di).effet],OFFSET retour
	ret
ENDP


PROC	set_arpeggio
	mov	al,[(VOICE ptr ds:di).extra]

	or	al,al
	je    	set_nul_effect

	mov	cx,[(VOICE PTR ds:di).note1]

	mov     bx,OFFSET TAB_ARPEGE-2
@@not_find:
	add     bx,2
	cmp     cx,[ds:bx]
	jb      @@not_find

	sub	cx,[ds:bx]
	neg	cx
	mov	[(VOICE ptr ds:di).note1],cx
	mov	[(VOICE ptr ds:di).note2],cx
	mov     cx,bx
	shl     eax,12
	shr	ax,11
	add     bx,ax
	mov     ax,[ds:bx]

	add     [(VOICE ptr ds:di).note1],ax
	shr     eax,15
	and	ax,001eh
	mov     bx,cx
	add     bx,ax
	mov     ax,[ds:bx]
	add     [(VOICE ptr ds:di).note2],ax
	mov     [(VOICE ptr ds:di).effet],OFFSET arpeggio

	ret

ENDP

PROC	set_portamento_up

	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_port
	mov	al,[(VOICE PTR ds:di).oldport]
@@new_port:
	mov   	[(VOICE PTR ds:di).oldport],al
	xor	ah,ah
	mov     [(VOICE ptr ds:di).note2],ax
	mov     [(VOICE ptr ds:di).effet],OFFSET portamento_up

	ret

ENDP

PROC	set_portamento_down

	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_port
	mov	al,[(VOICE PTR ds:di).oldport]
@@new_port:
	mov   	[(VOICE PTR ds:di).oldport],al
	xor	ah,ah
	mov	[(VOICE ptr ds:di).note2],ax;
	mov	[(VOICE ptr ds:di).effet],OFFSET portamento_down

	ret

ENDP

PROC	set_portamento_tone

	mov	dx,[(VOICE ptr ds:di).oldnote]
	mov	[(VOICE ptr ds:di).play],dx;
	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_port
	mov	al,[(VOICE PTR ds:di).oldport]
@@new_port:
	mov   	[(VOICE PTR ds:di).oldport],al
	xor	ah,ah
	mov     [(VOICE ptr ds:di).note2],ax		; la partie haute est toujours … 0

	cmp   	dx,[(VOICE ptr ds:di).note1]
	jb      @@tone_down
	mov     [(VOICE ptr ds:di).effet],OFFSET portamento_tone_up
	ret

@@tone_down:
	mov     [(VOICE ptr ds:di).effet],OFFSET portamento_tone_down
	ret

ENDP

PROC	set_vibrato

	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_vibrato
	mov	al,[(VOICE ptr ds:di).oldvib]
@@new_vibrato:
	mov	[(VOICE PTR ds:di).oldvib],al
	mov	ah,al
	and	al,0fh
	shr	ah,2
	and	ah,3ch
	mov	[(VOICE ptr ds:di).vitesse],ah
	mov	[(VOICE ptr ds:di).amplit],al

	mov	[(VOICE ptr ds:di).effet],OFFSET vibrato

	ret

ENDP

PROC	set_portamento_volume

	mov	dx,[(VOICE ptr ds:di).oldnote]
	mov	[(VOICE ptr ds:di).play],dx;
	mov	al,[(VOICE PTR ds:di).oldport]
	xor	ah,ah
	mov     [(VOICE ptr ds:di).note2],ax		; la partie haute est toujours … 0
	cmp   	dx,[(VOICE ptr ds:di).note1]
	jb      @@tone_down

	mov	al,[(VOICE ptr ds:di).extra]
	test	al,0f0h
	je	@@up_vol_down
	shr	al,4
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET portamento_up_volume_up
	ret

@@up_vol_down:
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET portamento_up_volume_down
	ret

	ret

@@tone_down:
	mov	al,[(VOICE ptr ds:di).extra]
	test	al,0f0h
	je	@@down_vol_down
	shr	al,4
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET portamento_down_volume_up
	ret

@@down_vol_down:
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET portamento_down_volume_down
	ret

ENDP


PROC	set_vibrato_volume

	mov	al,[(VOICE ptr ds:di).oldvib]
	mov	ah,al
	and	al,0fh
	shr	ah,2
	and	ah,3ch
	mov	[(VOICE ptr ds:di).vitesse],ah
	mov	[(VOICE ptr ds:di).amplit],al

	mov	al,[(VOICE ptr ds:di).extra]
	test	al,0f0h
	je	@@vol_down
	shr	al,4
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET vibrato_volume_up
	ret

@@vol_down:
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET vibrato_volume_down
	ret

ENDP

PROC	set_tremolo

	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_tremolo
	mov	al,[(VOICE PTR ds:di).oldtrem]
@@new_tremolo:
	mov	[(VOICE PTR ds:di).oldtrem],al
	mov	ah,al
	and	al,0fh
	shr	ah,2
	and	ah,3ch
	mov	[(VOICE ptr ds:di).vitesse],ah
	mov	[(VOICE ptr ds:di).amplit],al
	mov	[(VOICE PTR ds:di).sinpos],ah
	mov	al,[(VOICE PTR ds:di).volume]
	mov	[byte ptr (VOICE PTR ds:di).note2],al
	mov	[(VOICE ptr ds:di).effet],OFFSET tremolo

	ret

ENDP

PROC	set_play_end_part

	xor	eax,eax
	mov	ah,[(VOICE ptr ds:di).extra]
	cmp	ax,[(VOICE ptr ds:di).samplen]
	jb	@@ok
	mov	ax,[(VOICE ptr ds:di).samplen]
@@ok:
	mov	[(dword ptr (VOICE ptr ds:di).adrvoc)],eax
	or	[(VOICE ptr ds:di).gusinf],2	; ne changer que curadr

	mov	[(VOICE ptr ds:di).effet],OFFSET retour
	ret

ENDP

PROC	set_volume_slide

	mov	al,[(VOICE ptr ds:di).extra]
	or	al,al
	jne	@@new_slide
	mov	al,[(VOICE PTR ds:di).oldslid]
@@new_slide:
	mov	[(VOICE PTR ds:di).oldslid],al
	test	al,0f0h
	je	@@vol_down
	shr	al,4
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET volume_up
	ret

@@vol_down:
	mov	[(VOICE ptr ds:di).extra],al
	mov	[(VOICE ptr ds:di).effet],OFFSET volume_down
	ret

ENDP

PROC	position_jump

	movzx	ax,[(VOICE ptr ds:di).extra]
	add	ax,ax
	add	ax,OFFSET Sequence
	mov	[ds:OFFSET Position],ax
	mov	ah,[ds:OFFSET NbVoice]
	xor	al,al
	mov	[word ptr ds:OFFSET Line],ax

	mov	[(VOICE ptr ds:di).effet],OFFSET retour

	ret

ENDP

PROC	set_volume

	mov	al,[(VOICE ptr ds:di).extra]
	cmp	al,3Fh
	jbe	@@volume_ok
	mov	al,3Fh
@@volume_ok:
	or	[(VOICE ptr ds:di).gusinf],8
	mov	[(VOICE ptr ds:di).volume],al
	mov	[(VOICE ptr ds:di).effet],OFFSET retour
	ret

ENDP


PROC	pattern_break

	mov	al,[(VOICE ptr ds:di).extra]
        and	al,63
	add	al,64
	mov	cl,[ds:OFFSET NbVoice]
	mul	cl
	mov	cl,2
	shl	ax,cl
	mov	[ds:OFFSET Line],ax

	mov     [(VOICE ptr ds:di).effet],OFFSET retour
	ret

ENDP

Effets_etendus	DW OFFSET set_nul_effect
		DW OFFSET set_fine_portamento_up
		DW OFFSET set_fine_portamento_down
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET OFFSET set_loop
		DW OFFSET set_nul_effect
		DW OFFSET set_nul_effect
		DW OFFSET set_retrig_sample
		DW OFFSET set_fine_slide_volume_up
		DW OFFSET set_fine_slide_volume_down
		DW OFFSET set_cut_note
		DW OFFSET set_delay_note
		DW OFFSET set_pattern_delay
		DW OFFSET set_nul_effect

PROC	set_extended_effect

	mov	al,[(VOICE ptr ds:di).extra]
	mov	bl,al
	and	ax,0fh
	shr	bx,4
	and	bx,0fh
	mov 	[(VOICE ptr ds:di).effnb],bl
	add	[(VOICE ptr ds:di).effnb],20h
	shl	bx,1
	mov	bx,[ds:bx+OFFSET Effets_etendus]
	jmp	bx
ENDP

PROC	set_fine_portamento_up

	mov	bx,[(VOICE ptr ds:di).play]
	sub     bx,ax
	cmp     bx,LOW_NOTE
	jae     @@suite
	mov     bx,LOW_NOTE
@@suite:
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
	mov     [(VOICE ptr ds:di).play],bx

	ret
ENDP

PROC	set_fine_portamento_down

	mov	bx,[(VOICE PTR ds:di).play]
	add     bx,ax
	cmp     bx,HIGH_NOTE
	jbe     @@suite
	mov     bx,HIGH_NOTE
@@suite:
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
	mov     [(VOICE ptr ds:di).play],bx

	ret

ENDP

PROC set_loop

	or	al,al
	je	@@setloop

	cmp	[(VOICE ptr ds:di).compte],0
	je	@@begin_loop
	dec	[(VOICE ptr ds:di).compte]
	je	@@end_loop

@@loop:
	mov	ax,[(VOICE PTR ds:di).looppos]
	mov	[ds:OFFSET Line],ax

@@end_loop:
	mov	[(VOICE ptr ds:di).looppos],0
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
	ret

@@begin_loop:
	mov	[(VOICE ptr ds:di).compte],al
	jmp	@@loop

@@setloop:
	mov     ax,[ds:OFFSET Line]
	xor	bh,bh
	mov	bl,[NbVoice]
	shl	bx,2
	sub	ax,bx
	mov	[(VOICE PTR ds:di).looppos],ax
	mov	[(VOICE PTR ds:di).effet],OFFSET retour
	ret

ENDP

PROC set_retrig_sample

	mov	[(VOICE PTR ds:di).vitesse],al
	mov	[(VOICE PTR ds:di).extra],al
	mov	[(VOICE PTR ds:di).effet],OFFSET retrig_sample

	ret

ENDP

PROC set_fine_slide_volume_up

	mov     ah,[(VOICE ptr ds:di).volume]
	add     ah,al
	cmp     ah,3Fh
	jbe     @@ok
	mov     ah,3Fh
@@ok:
	mov     [(VOICE ptr ds:di).volume],ah
	or	[(VOICE ptr ds:di).gusinf],8
	mov	[(VOICE ptr ds:di).effet],OFFSET retour

	ret

ENDP

PROC set_fine_slide_volume_down

	mov     ah,[(VOICE ptr ds:di).volume]
	sub     ah,al
	jge     @@ok
	xor     ah,ah
@@ok:
	mov     [(VOICE ptr ds:di).volume],ah
	or	[(VOICE ptr ds:di).gusinf],8
	mov	[(VOICE ptr ds:di).effet],OFFSET retour

	ret

ENDP

PROC set_cut_note

	xor	ah,ah
	mov	[(VOICE PTR ds:di).note2],ax
	mov	[(VOICE PTR ds:di).effet],OFFSET cut_note

	ret

ENDP

PROC set_delay_note

	xor	ah,ah
	mov	[(VOICE PTR ds:di).note2],ax
	xchg	ah,[(VOICE PTR ds:di).volume]
	or	[(VOICE PTR ds:di).gusinf],4
	mov	[(VOICE PTR ds:di).amplit],ah
	mov	[(VOICE PTR ds:di).effet],OFFSET delay_note

	ret

ENDP

PROC	set_pattern_delay

	mov	[ds:PatternDelay],al
	mov	[(VOICE PTR ds:di).effet],OFFSET retour

	ret

ENDP

PROC	set_tempo

	mov	al,[(VOICE ptr ds:di).extra]

	mov     [ds:OFFSET Tempo],al
	mov	[ds:OFFSET Frame],al
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
	ret

ENDP

PROC	set_bpm

	mov	al,[(VOICE ptr ds:di).extra]
	mov	[ds:OFFSET Bpm],al
bpmeffect:
	DB	0E8h
	DW	0
	mov	[(VOICE ptr ds:di).effet],OFFSET retour
	ret

ENDP

PROC    set_tremor
	mov	al,[(VOICE ptr ds:di).extra]
	mov	ah,al
	shr	al,4
        inc	al
	mov	[(VOICE PTR ds:di).note2],ax
	mov	[(VOICE PTR ds:di).effet],OFFSET tremor_on

ENDP

;***************************************************************************
;*      Procedures gerant les differents effets

PROC retour
	ret
ENDP

TAB_ARPEGE:
		DW  1AC0h,1940h,17D0h,1680h,1530h
		DW  1400h,12E0h,11D0h,10D0h,0FE0h
		DW  0F00h,0E28h,0D60h,0CA0h,0BE8h
		DW  0B40h,0A98h,0A00h,0970h,08E8h
		DW  868h,7F0h,780h,714h,6B0h,650h
		DW  5F4h,5A0h,54Ch,500h,4B8h,474h
		DW  43Ah,3F8h,3C0h,38Ah
;TAB_ARPEGE:	DW  358h,328h,2fah,2d0h,2a6h,280h
		DW  25ch,23ah,21ah,1fch,1e0h,1c5h
		DW  1ach,194h,17dh,168h,153h,140h
		DW  12eh,11dh,10dh,0feh,0f0h,0e2h
		DW  0d6h,0cah,0beh,0b4h,0aah,0a0h
		DW  097h,08fh,087h,07fh,078h,071h
		DW  06Bh,065h,05Fh,05Ah,055h,050h
		DW  04Bh,047h,043h,03Fh,03Ch,038h
		DW  035h,032h,02Fh,02Dh,02Ah,028h
		DW  025h,023h,021h,01Fh,01Eh,01Ch
		DW  000h,01Ch,01Ch,01Ch,01Ch,01Ch
		DW  01Ch,01Ch,01Ch,01Ch,01Ch,01Ch
		DW  01Ch,01Ch,01Ch,01Ch

PROC	arpeggio

	mov	ax,[(VOICE ptr ds:di).play]
	xchg	ax,[(VOICE ptr ds:di).note1]
	xchg	ax,[(VOICE ptr ds:di).note2]
	mov	[(VOICE ptr ds:di).play],ax

	ret
ENDP

PROC portamento_up

	mov	ax,[(VOICE ptr ds:di).play]
	sub     ax,[(VOICE ptr ds:di).note2]
	jc	@@bug1992
	cmp     ax,LOW_NOTE
	jae     @@suite
@@bug1992:
	mov     ax,LOW_NOTE
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	ret

ENDP

PROC portamento_down

	mov	ax,[(VOICE ptr ds:di).play]
	add     ax,[(VOICE ptr ds:di).note2]
	cmp     ax,HIGH_NOTE
	jbe     @@suite
	mov     ax,HIGH_NOTE
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	ret

ENDP

PROC portamento_tone_up

	mov     bx,[(VOICE ptr ds:di).note1]
	mov     ax,[(VOICE ptr ds:di).play]
	sub     ax,[(VOICE ptr ds:di).note2]
	jc	@@bug1992
	cmp     ax,bx
	jae     @@suite
@@bug1992:
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	ret

ENDP

PROC portamento_tone_down

	mov     ax,[(VOICE ptr ds:di).play]
	add     ax,[(VOICE ptr ds:di).note2]
	mov     bx,[(VOICE ptr ds:di).note1]
	cmp     ax,bx
	jbe     @@suite
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	ret
ENDP

SINUS           DB  000h,018h,031h,04ah,061h,078h,08dh,0a1h
		DB  0b4h,0c5h,0d4h,0e0h,0ebh,0f4h,0fah,0fdh
		DB  0ffh,0fdh,0fah,0f4h,0ebh,0e0h,0d4h,0c5h
		DB  0b4h,0a1h,08dh,078h,061h,04ah,031h,018h

PROC vibrato

	mov	al,[byte ptr (VOICE ptr ds:di).sinpos]
	shr	al,2
	and	al,1fh
	mov	bx,OFFSET SINUS
	xlat
	mul	[(VOICE PTR ds:di).amplit]
	shr	ax,7
	mov	bx,[(VOICE PTR ds:di).note1]
	cmp	[(VOICE PTR ds:di).sinpos],0
	jg	@@add
	neg	ax
@@add:
	add	bx,ax
	cmp	bx,HIGH_NOTE
	jle	@@high_ok
	mov	bx,HIGH_NOTE
@@high_ok:
	cmp	bx,LOW_NOTE
	jge	@@low_ok
	mov	bx,LOW_NOTE
@@low_ok:
	mov	[(VOICE PTR ds:di).play],bx
	mov	al,[(VOICE PTR ds:di).vitesse]
	add	[(VOICE PTR ds:di).sinpos],al

	ret

ENDP

PROC portamento_up_volume_up

	mov     ax,[(VOICE ptr ds:di).play]
	sub     ax,[(VOICE ptr ds:di).note2]
	mov     bx,[(VOICE ptr ds:di).note1]
	cmp     ax,bx
	jae     @@suite
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	jmp	volume_up

ENDP

PROC portamento_down_volume_up

	mov     ax,[(VOICE ptr ds:di).play]
	add     ax,[(VOICE ptr ds:di).note2]
	mov     bx,[(VOICE ptr ds:di).note1]
	cmp     ax,bx
	jbe     @@suite
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	jmp	volume_up
ENDP

PROC portamento_up_volume_down

	mov     ax,[(VOICE ptr ds:di).play]
	sub     ax,[(VOICE ptr ds:di).note2]
	mov     bx,[(VOICE ptr ds:di).note1]
	cmp     ax,bx
	jae     @@suite
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	jmp	volume_down

ENDP

PROC portamento_down_volume_down

	mov     ax,[(VOICE ptr ds:di).play]
	add     ax,[(VOICE ptr ds:di).note2]
	mov     bx,[(VOICE ptr ds:di).note1]
	cmp     ax,bx
	jbe     @@suite
	mov     ax,bx
	mov     [(VOICE ptr ds:di).effet],OFFSET retour
@@suite:
	mov     [(VOICE ptr ds:di).play],ax

	jmp	volume_down
ENDP

PROC vibrato_volume_up

	mov	al,[(VOICE ptr ds:di).sinpos]
	shr	al,2
	and	al,1fh
	mov	bx,OFFSET SINUS
	xlat
	mul	[(VOICE PTR ds:di).amplit]
	shr	ax,6
	mov	bx,[(VOICE PTR ds:di).note1]
	cmp	[(VOICE PTR ds:di).sinpos],0
	jg	@@add
	neg	ax
@@add:
	add	bx,ax
	mov	[(VOICE PTR ds:di).play],bx
	mov	al,[(VOICE PTR ds:di).vitesse]
	add	[(VOICE PTR ds:di).sinpos],al

	jmp	volume_up

	ret

ENDP

PROC vibrato_volume_down

	mov	al,[(VOICE ptr ds:di).sinpos]
	shr	al,2
	and	al,1fh
	mov	bx,OFFSET SINUS
	xlat
	mul	[(VOICE PTR ds:di).amplit]
	shr	ax,6
	mov	bx,[(VOICE PTR ds:di).note1]
	cmp	[(VOICE PTR ds:di).sinpos],0
	jg	@@add
	neg	ax
@@add:
	add	bx,ax
	mov	[(VOICE PTR ds:di).play],bx
	mov	al,[(VOICE PTR ds:di).vitesse]
	add	[(VOICE PTR ds:di).sinpos],al

	jmp	volume_down

	ret

ENDP

PROC tremolo

	mov	al,[(VOICE ptr ds:di).sinpos]
	shr	al,2
	and	al,1fh
	mov	bx,OFFSET SINUS
	xlat
	mul	[(VOICE PTR ds:di).amplit]
	shr	ax,7

	mov	bl,[byte ptr (VOICE PTR ds:di).note2]
	cmp	[(VOICE PTR ds:di).sinpos],0
	jg	@@add
	neg	ax
@@add:
	or	[(VOICE PTR ds:di).gusinf],8
	mov	bh,[(VOICE PTR ds:di).vitesse]
	add	[(VOICE PTR ds:di).sinpos],bh
	add	bx,ax
	jl	@@volume_min
	cmp	bl,3Fh
	ja	@@volume_max

	mov	[(VOICE PTR ds:di).volume],bl
	ret

@@volume_min:
	mov	[(VOICE PTR ds:di).volume],0
	ret

@@volume_max:
	mov	[(VOICE PTR ds:di).volume],3Fh
	ret
ENDP

PROC volume_up
	or	[(VOICE ptr ds:di).gusinf],8
	mov     al,[(VOICE ptr ds:di).volume]
	add     al,[(VOICE ptr ds:di).extra]
	cmp     al,3Fh
	jbe     @@ok
	mov     al,3Fh
@@ok:
	mov     [(VOICE ptr ds:di).volume],al

	ret

ENDP

PROC volume_down
	or	[(VOICE ptr ds:di).gusinf],8
	mov     al,[(VOICE ptr ds:di).volume]
	sub     al,[(VOICE ptr ds:di).extra]
	jge     @@ok
	xor     al,al
@@ok:
	mov     [(VOICE ptr ds:di).volume],al

	ret

ENDP

PROC	retrig_sample

	dec	[(VOICE PTR ds:di).vitesse]
	je	@@retrig
	ret

@@retrig:
	mov	[(dword ptr (VOICE PTR ds:di).adrvoc)],0
	or      [(VOICE ptr ds:di).gusinf],02h
	mov	al,[(VOICE PTR ds:di).extra]
	mov	[(VOICE PTR ds:di).vitesse],al

	ret

ENDP

PROC	cut_note

	dec	[(VOICE PTR ds:di).note2]
	je	@@cut_note
	ret

@@cut_note:
	or	[(VOICE PTR ds:di).gusinf],4
	mov	[(VOICE PTR ds:di).volume],0
	mov	[(VOICE PTR ds:di).effet],OFFSET retour

	ret

ENDP


PROC	delay_note

	dec	[(VOICE PTR ds:di).note2]
	je	@@delay_note
	ret

@@delay_note:
	or	[(VOICE PTR ds:di).gusinf],8
	mov	al,[(VOICE PTR ds:di).amplit]
	mov	[(VOICE PTR ds:di).volume],al
	mov	[(VOICE PTR ds:di).effet],OFFSET retour

	ret

ENDP

PROC	tremor_on

	dec	[(byte ptr (VOICE PTR ds:di).note2)]
	je	@@cut_note
	ret

@@cut_note:
	mov	al,[(byte ptr ((VOICE PTR ds:di).note2)+1)]
	and	al,0Fh
	inc	al
	mov	[(byte ptr (VOICE PTR ds:di).note2)],al
	mov	al,[(VOICE PTR ds:di).volume]
	mov     [(VOICE PTR ds:di).amplit],al
	mov	[(VOICE PTR ds:di).volume],0
	or	[(VOICE PTR ds:di).gusinf],4
	mov	[(VOICE PTR ds:di).effet],OFFSET tremor_off

	ret
ENDP

PROC	tremor_off

	dec	[(byte ptr (VOICE PTR ds:di).note2)]
	je	@@delay_note
	ret

@@delay_note:
	mov	al,[(byte ptr ((VOICE PTR ds:di).note2)+1)]
	shr	al,4
	inc	al
	mov	[(byte ptr (VOICE PTR ds:di).note2)],al
	or	[(VOICE PTR ds:di).gusinf],8
	mov	al,[(VOICE PTR ds:di).amplit]
	mov	[(VOICE PTR ds:di).volume],al
	mov	[(VOICE PTR ds:di).effet],OFFSET tremor_on

	ret

ENDP

;*************************************************************************
;*      termine le son

PROC    Stopmod FAR

	push	es
	push	ds
	push	si
	push	di

	mov	ax,CODE
	mov	ds,ax

	test	[Status],1
	je	@@no_stop

	mov	si,[UsedDevice]
	mov	dx,[(DEVICE ptr ds:si).stop]
	call	dx

	cli
	mov	bl,[(DEVICE PTR ds:si).irq]
	mov	ax,[word ptr ds:OFFSET OldIrq]
	mov	dx,[word ptr ds:OFFSET OldIrq+2]
	call	setirq

	mov	ax,[cs:IntMask]
	out	21h,al
	mov	al,ah
	out	0A1h,al
	sti
@@no_stop:

	pop	di
	pop	si
	pop	ds
	pop	es
	ret

ENDP

;************************************************************************
;*      RecupŠre l'octet courant de la voix
;*
;* Entr‚e:
;*	Dans la pile le numero de la voix … ‚teindre (0 … 31)
;*
;* Sortie:
;*	Octet courant

PROC	PeekMod far

	push	ds
	push	bp
	mov	bp,sp

	mov	al,[ss:bp+8]
	cmp	al,MAX_VOICE
	jae	@@error

	mov	bx,CODE
	mov	ds,bx

	mov	bx,[UsedDevice]
	mov	dx,[(DEVICE ptr ds:bx).getbyte]
	call	dx

	clc
	jmp	@@ok

@@error:
	stc
	mov	ax,NO_VOICE
@@ok:
	leave
	pop	ds
	ret	2

ENDP


;************************************************************************
;*	Eteint/Allume une voix
;*
;* Entr‚e:
;*	Dans la pile le numero de la voix … ‚teindre (0 … 31)

PROC	Togglevoc FAR

	push	ds
	push	bp
	mov	bp,sp

	mov	al,[ss:bp+8]
	cmp	al,MAX_VOICE
	jae	@@error

	mov	bx,CODE
	mov	ds,bx

	mov	bl,SIZE VOICE
	mul	bl
	mov	bx,ax

	not	[(VOICE PTR ds:bx+OFFSET Voice1).mute]

	xor	ax,ax
	clc
	jmp	@@ok

@@error:
	stc
	mov	ax,NO_VOICE
@@ok:
	leave
	pop	ds
	ret	2

ENDP

;***************************************************************************
;*      Change le volume globale de la musique
;*
;* Entr‚e:
;*	Dans la pile,le nouveau volume
;*

PROC	Changevol FAR

	push	bp
	mov	bp,sp

	mov     al,[ss:bp+6]
	and	al,63
	shl	al,2
	mov	[cs:MasterVol],al

	leave

	ret	2

ENDP

;***************************************************************************
;*	Laisse boucler la musique sur le pattern courant
;*

PROC    LockMod FAR

	xor	[byte ptr cs:OFFSET lock_pat+2],2

	ret

ENDP

;***************************************************************************
;*	RecupŠre la S‚quence et la ligne courante
;*
;* Sortie
;*	AX	ligne courante+position dans la s‚quence*64

PROC	GetModPos FAR

	mov	eax,[dword ptr cs:OFFSET Position]
	sub	ax,OFFSET Sequence+2
	sar	ax,1
@@good_pos:
	rol	eax,16
	mov	dh,[cs:NbVoice]
	cmp	ah,dh
	jb	@@no_overflow
	sub	ah,dh
	add     eax,10000h
@@no_overflow:
	div	dh
	mov	ah,al
	shr	eax,10

	ret


ENDP

;***************************************************************************
;*      Positionne la musique … endroit donn‚e
;*
;* Entr‚e:
;*	Dans la pile la ligne+le numero de la sequence*64

PROC	SetModPos FAR

	pop	edx
	xor	eax,eax
	pop	ax
	push	edx
	shl	eax,10
	mov	al,ah
	mov	dh,[cs:NbVoice]
	mul	dh
	add	ah,dh
	rol	eax,16
	add	ax,ax
	add	ax,OFFSET Sequence
	mov	[dword ptr cs:OFFSET Position],eax

	ret

ENDP

NulDev		DEVICE <00h,'$',OFFSET setnul,OFFSET setnul,OFFSET nulfnc,OFFSET nulfnc,OFFSET defbpm,0,0,0>

;***************************************************************************
;*	Initialise le device nulle, court circuite la fonction MakeMod

PROC	setnul

	mov	[byte ptr cs:OFFSET switch_makemod],0CBh
	clc
nulfnc:
	ret
ENDP

ENDS

END