Metropoli BBS
VIEWER: crys.asm MODE: TEXT (CP437)
;**************************************************************************
;*	Player de mod, cela fait office d'exemple d'utilisation en
;*	assembleur d'utilisation des routines et vous permet de juger de
;*	la qualité (ou des défauts) des routines de CRYSTAL...
;*
;* Programmé par Sébastien Granjoux
;* Commencé en février 93
;* Dernière modif 10/04/95

IDEAL

P386N
MODEL	SMALL

PUBLIC	main

VERNB	EQU	"2.74"
DATE	EQU	"11/06/95"
DATENG	EQU	"06/11/95"

EXTRN	SetMode3:near
EXTRN	ResetMode:near
EXTRN	SetPage:near
EXTRN	UseCpkBlk:near
EXTRN	UpdCpkBlk:near
EXTRN	PutVu:near

EXTRN	GetMixRate:near
EXTRN	GetVoiceByte:near
EXTRN	GetName:near
EXTRN	GetTempo:near
EXTRN	GetModInf:near
EXTRN	GetPattern:near
EXTRN	GetVoice:near

EXTRN	USESPK:far
EXTRN	USEGUS:far
EXTRN	USESP:far
EXTRN	USESB:far
EXTRN	USEDAC:far
EXTRN	USEADL:far
EXTRN	CHANGEVOL:far
EXTRN	DETECTSND:far
EXTRN	FLOADMOD:far
EXTRN	UNLOADMOD:far
EXTRN	SETMOD:far
EXTRN	MAKEMOD:far
EXTRN	STARTMOD:far
EXTRN	STOPMOD:far
EXTRN	TOGGLEVOC:far
EXTRN	LOCKMOD:far
EXTRN	SETMODPOS:far
EXTRN	GETMODPOS:far
EXTRN	SETMODCALL:far

DEBUG	EQU	1

INCLUDE "CRYSERR.INC"
INCLUDE "CRYSID.INC"

DEV_NAME_LEN	EQU	32
NB_SAMPLE	EQU	31

DATASEG

INCLUDE		"CRYSFR.MSG"
INCLUDE		"CRYSENG.MSG"

LIST_EFFET	DB 'ARPEGGIO        '
		DB 'PORTAMENTO UP   '
		DB 'PORTAMENTO DOWN '
		DB 'TONE PORTAMENTO '
		DB 'VIBRATO         '
		DB 'PORTAMENTO+SLIDE'
		DB 'VIBRATO+SLIDE   '
		DB 'TREMOLO         '
		DB 'PHASOR EFFECT   '
		DB 'PLAY SAMPLE PART'
		DB 'VOLUME SLIDE    '
		DB 'POSITION JUMP   '
		DB 'SET VOLUME      '
		DB 'PATTERN BREAK   '
		DB '                '
		DB 'SET SPEED       '
		DB 'SET BPM         '
		DB 'TREMOR          '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB '                '
		DB 'SET FILTER      '
		DB 'FINE PORT UP    '
		DB 'FINE PORT DOWN  '
		DB 'SET GLISSANDO   '
		DB 'SET VIBRATO     '
		DB 'SET FINETUNE    '
		DB 'LOOP            '
		DB 'SET TREMOLO     '
		DB 'CALL BACK       '
		DB 'RETTRIG SAMPLE  '
		DB 'FINE SLIDE UP   '
		DB 'FINE SLIDE DOWN '
		DB 'NOTE CUT        '
		DB 'NOTE DELAY      '
		DB 'PATTERN DELAY   '
		DB '                '

LIST_NOTE	DB 'C-0','C#0','D-0','D#0','E-0','F-0'
		DB 'F#0','G-0','G#0','A-0','A#0','B-0'
		DB '   '

FIRST_ERROR	EQU	1
LAST_ERROR	EQU	22

Old_int9	DD 0

Device		DW THE_BEST
Port		DW 0
Irq		DB 0
Dma		DB 0
MixSpeed	DW 0
MasterVol	DB 63
ModVoice	DB 0
StartTime	DD 0
StartMem	DW 0
VBLChrono	DD 1
PlayChrono	DD 1
LastChrono	DB 0
Mode		DB 2	      ;	Pause SaveOnQuit Config X   X X MainScreen
VuMeters	DB 32 DUP (0)
Notes		DB 32*3 DUP (0)
CutVoices	DW 0
SeqLength	DB 0

BIOS_SEG	EQU	40h
BIOS_CHRONO	EQU	6Ch

DevFrq		DW	0,1900,2200,2200,0,2200,1700

Filename	DB 128+4 DUP (0)
Buffer		DB 128 DUP (0)

ExecBlk		DW	0
		DW	OFFSET CmdLine
		DW	SEG CmdLine
		DD	-1
		DD	-1

CmdLine		DB	00,0Dh
OldStack	DD	0
ComSpecMsg	DB	'COMSPEC',0
DefaultCom	DB	'C:\COMMAND.COM',0

MusicName	DB 32 DUP (0)
Samples		DB 32*32 DUP (0);
NullStr		DB 0

STRUC T_MODINF
	music	DW	OFFSET MusicName
	device	DW	0
	freq	DW	0
	min	DW	0
	sec	DW	0
	pos	DW	0
	seq	DW	0
	pat	DW	0
	line	DW	0
	tempo	DW	0
	bpm	DW	0
	vol	DW	0
	mem	DW	0
	cpu	DW	0
ENDS

ModInf		T_MODINF <OFFSET MusicName,?>
SampInf		DW OFFSET Samples+1*32,OFFSET Samples+17*32
		DW OFFSET Samples+2*32,OFFSET Samples+18*32
		DW OFFSET Samples+3*32,OFFSET Samples+19*32
		DW OFFSET Samples+4*32,OFFSET Samples+20*32
		DW OFFSET Samples+5*32,OFFSET Samples+21*32
		DW OFFSET Samples+6*32,OFFSET Samples+22*32
		DW OFFSET Samples+7*32,OFFSET Samples+23*32
		DW OFFSET Samples+8*32,OFFSET Samples+24*32
		DW OFFSET Samples+9*32,OFFSET Samples+25*32
		DW OFFSET Samples+10*32,OFFSET Samples+26*32
		DW OFFSET Samples+11*32,OFFSET Samples+27*32
		DW OFFSET Samples+12*32,OFFSET Samples+28*32
		DW OFFSET Samples+13*32,OFFSET Samples+29*32
		DW OFFSET Samples+14*32,OFFSET Samples+30*32
		DW OFFSET Samples+15*32,OFFSET Samples+31*32
		DW OFFSET Samples+16*32,OFFSET Samples

STRUC T_VUINF
	inst		DW	0
	samp		DW	0
	vol		DW	0
	note		DW	0
	effect		DW	0
ENDS

VumeterInf	T_VUINF <0,OFFSET NullStr,0,OFFSET Notes,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+1*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+2*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+3*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+4*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+5*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+6*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+7*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+8*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+9*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+10*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+11*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+12*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+13*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+14*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+15*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+16*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+17*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+18*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+19*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+20*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+21*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+22*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+23*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+24*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+25*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+26*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+27*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+28*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+29*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+30*3,OFFSET NullStr>
		T_VUINF <0,OFFSET NullStr,0,OFFSET Notes+31*3,OFFSET NullStr>

MainBuffer	DD 32*5 DUP (0)
HeadBuffer	DD 16 DUP (0)

NBLANG		EQU	2

Language  	DW	OFFSET English
		DW	OFFSET French

PlayerName	DD      0

CODESEG

PROC	main

	mov	ax,es		; Recupérer la place déjà prise par le player
	dec	ax
	mov	es,ax
	mov	cx,[es:3]
	inc	ax
	mov	es,ax
	mov	ah,48h		; Récupérer la mémoire libre
	mov	bx,0FFFFh
	int	21h
	add	bx,cx
	mov	[StartMem],bx

	push	es
	mov	ax,[es:2Ch]
	mov	es,ax
	xor	di,di
	mov	cx,0ffffh
	xor	al,al
@@next_envstr:
	repne	scasb
	scasb
	jne	@@next_envstr
	cmp	[word ptr es:di],1
	jb	@@no_name
	add	di,2
	mov     [word ptr ds:OFFSET PlayerName],di
	mov	[word ptr ds:OFFSET PlayerName+2],es
@@no_name:
	push	ds
	pop	es
	pop	ds

	call	Usegus
	call	Usesp
	call	Usesb
	call	Usedac
	call	Usespk
	call	Useadl

	mov	si,80h
	mov	di,OFFSET Filename
	call	getarg
	push	es
	pop	ds
	push	ax

	call	LoadConfig
	jc	error

	pop	ax
	cmp	al,1
	jae	@@mod_file_ok
	mov	ax,BAD_ARG
	jmp	error
@@mod_file_ok:

	mov	si,OFFSET Filename
	mov	di,si
	mov	bx,OFFSET Irq
@@get_arg:
	lodsb
	cmp	al,'-'
	je	@@get_switch
	cmp	al,','
	je	@@get_sup
	or	al,al
	je	@@line_used

@@get_file:
	stosb
	lodsb
	or	al,al
	jne	@@get_file
	jmp	@@get_arg

@@get_sup:
	mov	ax,BAD_ARG
	cmp	bx,OFFSET Dma
	ja	error
	call	get_dec
	jc	@@no_sup
	mov	[bx],al
@@no_sup:
	inc	si
	inc	bx
	jmp	@@get_arg

@@get_switch:
	mov	bx,OFFSET Irq
	lodsw
	cmp	ax,'RF'
	je	@@get_freq
	cmp	ax,'BS'
	je	@@get_sb
	cmp	ax,'KS'
	je	@@get_spk
	cmp	ax,'CD'
	je	@@get_dac
	cmp	ax,'SG'
	je	@@get_gus
	cmp	ax,'PS'
	je	@@get_sp
	cmp	ax,'DA'
	je	@@get_adlib
	cmp	ax,'LN'
	je	@@get_null
	mov	ax,BAD_ARG
	jmp	error
@@get_freq:
	call	get_dec
	inc	si
	mov	[MixSpeed],ax
	jmp	@@get_arg
@@get_spk:
	mov	[Device],PC_SPEAKER
	lodsb
	or	al,al
	je	@@get_arg
	mov	ax,BAD_ARG
	jmp	error
@@get_dac:
	mov	[Device],DAC_ON_LPT
	jmp	@@get_device
@@get_sb:
	mov	[Device],SOUNDBLASTER
	jmp	@@get_device
@@get_sp:
	mov	[Device],SOUNDPRO
	jmp	@@get_device
@@get_gus:
	mov	[Device],GUS
	jmp	@@get_device
@@get_null:
	mov	[Device],NO_DEVICE
	jmp	@@get_device
@@get_adlib:
	mov	[Device],ADLIB
@@get_device:
	call	get_hex
	inc	si
	jc	@@get_arg
	mov	[Port],ax
	jmp	@@get_arg

@@line_used:
	xor	al,al
	stosb

	push    ds
	push	OFFSET Device
	push	ds
	push	OFFSET Port
	push	ds
	push	OFFSET Irq
	push	ds
	push	OFFSET Dma
	call	Detectsnd
	jnc	@@ok
	cmp	ax,DRV_NOT_FOUND
	je	error
@@ok:

	mov	di,OFFSET Filename
	xor	al,al
	repne	scasb
	dec	di
	mov	eax,[es:di-4]
	and	eax,0DFDFDFFFh
	cmp	eax,'DOM.'
	je	@@loadmod
	sub	di,4
	mov	cx,4
	mov	al,'.'
	repne	scasb
	je	@@loadmod
	mov	[byte ptr es:di],al
	mov	[dword ptr es:di+1],'DOM'

@@loadmod:
	push	ds
	push	OFFSET Filename
	call    far Floadmod
	jc	error

@@loadok:

	call	putcard		; Affiche la carte utilisé

	call	GetMusInf

	cmp	[MixSpeed],0
	jne	@@keep_freq
	mov	bx,[Device]
	add	bx,bx
	mov	ax,[OFFSET DevFrq+bx]
	mov	[MixSpeed],ax
@@keep_freq:
	push	[MixSpeed]
	push	[word ptr ds:OFFSET Device]
	push	[word ptr ds:OFFSET Port]
	push	[word ptr ds:OFFSET Irq]
	push	[word ptr ds:OFFSET Dma]

	call	far Setmod
	jc	error

	call	PutDevInf

	call	setmode3

	call	PutAllScr


	push	es		; Sauvegarde l'interruption clavier
	mov	ax,3509h
	int	21h
	mov	[word ptr ds:OFFSET Old_int9],bx
	mov	[word ptr ds:OFFSET Old_int9+2],es
	pop	es
	push	ds		; Utilise une interruption clavier simplifiée
	mov	ax,cs
	mov	ds,ax
	cli
	mov	dx,OFFSET hitkey
	mov	ax,2509h
	int	21h
	sti
	pop	ds

	call	far MakeMod
	call	far MakeMod

	mov	bx,16
	call	waitVBL
test_loop:
	push	bx

	call    UpdModInf

	mov	al,[Mode]
	and	al,83h
	cmp	al,2
	jmp	$+2

	mov	al,[cs:Key]
	or	al,al
	je	@@loop_end
	cmp	al,1
	je	@@loop_end
	cmp	al,17
	jbe	@@loop_end
	cmp	al,61
	je	@@loop_end
	cmp	al,60
	je	@@loop_end
	cmp	al,59
	je	@@loop_end
	cmp	al,69
	je	@@loop_end
	cmp	al,66
	je	@@loop_end
	cmp	al,79
	je	@@loop_end
	cmp	al,70
	je	@@loop_end
	cmp	al,78
	je	@@loop_end
	cmp	al,74
	je	@@loop_end
	cmp	al,75
	je	@@backward
	cmp	al,77
	je	@@forward
	jmp	@@loop_end
@@loop_end:
	xor	ecx,ecx
	call	waitVBL
	add	[VBLChrono],ecx
	pop	bx
	dec	bx
	jne	test_loop


	call	far StartMod
	call	GetTime
	mov	[ds:StartTime],eax

	call	WaitVBL
main_loop:
	push	bx

	call	far MakeMod
	call	far MakeMod

	call	UpdModInf

	mov	al,[Mode]
	and	al,83h
	cmp	al,2
	jne	@@no_refresh
	call	UpdVuMeter
@@no_refresh:

	mov	al,[cs:Key]
	or	al,al
	je	@@end_main
	cmp	al,1
	je	@@exit
	cmp	al,17
	jbe	@@mute
	cmp	al,61
	je	@@sample
	cmp	al,60
	je	@@vumeter
	cmp	al,59
	je	@@help
	cmp	al,69
	je	@@pause
	cmp	al,63
	je	@@dosshell
	cmp	al,64
	je	@@nextmod
	cmp	al,65
	je	@@newdev
	cmp	al,66
	je	@@newlang
	cmp	al,79
	je	@@end_pat
	cmp	al,70
	je	@@lock_pat
	cmp	al,78
	je	@@plus
	cmp	al,74
	je	@@minus
	cmp	al,75
	je	@@backward
	cmp	al,77
	je	@@forward

@@end_main:
	test	[Mode],80h
	jnz	@@no_chrono

	xor	ecx,ecx
	call	waitVBL
	mov	eax,[PlayChrono]
	shr	eax,4
	sub	eax,ecx
	sub	[PlayChrono],eax

@@no_chrono:
	pop	bx
	jmp	main_loop

@@help:
	mov	[cs:Key],0
	and	[Mode],0F0h
	or	[Mode],1
	call	PutHelpScr
	jmp	@@end_main

@@sample:
	mov	[cs:Key],0
	and	[Mode],0F0h
	or	[Mode],3
	call	PutSampScr
	jmp	@@end_main

@@vumeter:
	mov	[cs:Key],0
	and	[Mode],0F0h
	or	[Mode],2
	call	PutVuScr
	call	UpdVuMeter
	jmp	@@end_main

@@pause:
	mov	[cs:Key],0
	xor	[Mode],80h
	test	[Mode],80h
	jz	@@unpause
	call	far StopMod
	jmp	@@end_main
@@unpause:
	call	far StartMod
	jmp	@@end_main

@@mute:
	mov	[cs:Key],0
	sub	al,2
	push	ax
	mov	cl,al
	mov	ax,1
	shl	ax,cl
	xor	[ds:CutVoices],ax
	call	TOGGLEVOC
	jmp     @@end_main

@@lock_pat:
	mov	[cs:Key],0
	call 	LOCKMOD
	jmp	@@end_main

@@end_pat:
	mov	[cs:Key],0
	call    GETMODPOS
	and	ax,0FFC0h
	add	ax,64
	movzx	bx,[ds:SeqLength]
	shl	bx,6
	cmp	ax,bx
	je	@@end_main
	push	ax
	call	SETMODPOS
	jmp	@@end_main

@@plus:
	mov	[cs:Key],0
	cmp	[ds:MasterVol],63
	je	@@end_main
	inc	[ds:MasterVol]
	push	[word ptr ds:MasterVol]
	call	CHANGEVOL
	jmp	@@end_main

@@minus:
	mov	[cs:Key],0
	cmp	[ds:MasterVol],0
	je	@@end_main
	dec	[ds:MasterVol]
	push	[word ptr ds:MasterVol]
	call	CHANGEVOL
	jmp	@@end_main

@@forward:
	mov	[cs:Key],0
	call	GETMODPOS
	inc	ax
	movzx	bx,[ds:SeqLength]
	shl	bx,6
	cmp	ax,bx
	je	@@end_main
	push	ax
	call	SETMODPOS
	jmp	@@end_main

@@backward:
	mov	[cs:Key],0
	call	GETMODPOS
	or	ax,ax
	je	@@end_main
	dec	ax
	push	ax
	call	SETMODPOS
	jmp	@@end_main

@@dosshell:
	push	es
	mov	ah,62h
	int	21h
	mov	es,bx
	mov	es,[es:2Ch]
	mov	si,OFFSET ComSpecMsg
	xor	di,di
	mov	cx,0ffffh
@@search_comspec:
	rep	cmpsb
	cmp	[byte ptr ds:si-1],0
	jne	@@next_string
	cmp	[byte ptr es:di-1],'='
	je	@@find_comspec
@@next_string:
	mov	si,OFFSET ComSpecMsg
	xor	al,al
	repne	scasb
	cmp	[byte ptr es:di],0
	jne	@@search_comspec

	push	ds
	pop	es
	mov     di,OFFSET DefaultCom

@@find_comspec:
	push	ds
	mov	[word ptr cs:OFFSET OldStack+2],ss
	mov	[word ptr cs:OFFSET OldStack],sp

	push	ds		; Reprend l'ancienne interruption clavier
	cli
	mov	ax,2509h
	lds	dx,[dword ptr ds:OFFSET Old_int9]
	int	21h
	sti
	pop	ds

	call	resetmode

	push	es
	push	ds
	pop	es
	pop	ds
	mov	ax,4B00h
	mov	bx,OFFSET ExecBlk
	mov	dx,di
	int	21h

	lss	sp,[cs:OFFSET OldStack]
	pop	ds
	pop	es

	call	putcard		; Affiche la carte utilisé

	call	setmode3

	call	PutAllScr

	push	ds
	push	cs
	pop	ds
	mov	dx,OFFSET hitkey
	mov	ax,2509h
	cli
	int	21h
	sti
	pop	ds
	mov	[cs:Key],0

	jmp	@@no_chrono

@@nextmod:
	mov	[cs:Key],0
	call	far Stopmod
	call	far UnLoadMod

	push	ds
	push	OFFSET Filename
	call    far Floadmod
	jnc	@@reloadok

@@newerror:
	push	ax
	push	ds		; Reprend l'ancienne interruption clavier
	cli
	mov	ax,2509h
	lds	dx,[dword ptr ds:OFFSET Old_int9]
	int	21h
	sti
	pop	ds

	call	resetmode
	pop	ax
	jmp	error

@@reloadok:

	push	es
	call	GetMusInf
	pop	es

	push	[MixSpeed]
	push	[word ptr ds:OFFSET Device]
	push	[word ptr ds:OFFSET Port]
	push	[word ptr ds:OFFSET Irq]
	push	[word ptr ds:OFFSET Dma]

	call	far Setmod
	jc	@@newerror

	push	es
	call	PutDevInf
	pop	es

	call	far MakeMod
	call	far MakeMod

	and	[Mode],7Fh
	call	StartMod

	jmp	@@no_chrono

@@newdev:
	mov	[cs:Key],0
	call	StopMod
@@next_dev:
	inc	[ds:Device]
	cmp	[ds:Device],8
	jbe	@@good_dev
	mov	[ds:Device],1
@@good_dev:
	mov	[Port],0
	mov	[Irq],0
	mov	[Dma],0
	push    ds
	push	OFFSET Device
	push	ds
	push	OFFSET Port
	push	ds
	push	OFFSET Irq
	push	ds
	push	OFFSET Dma
	call	Detectsnd
	jc	@@next_dev

	push	[MixSpeed]
	push	[word ptr ds:OFFSET Device]
	push	[word ptr ds:OFFSET Port]
	push	[word ptr ds:OFFSET Irq]
	push	[word ptr ds:OFFSET Dma]

	call	far Setmod
	jc	@@next_dev

	push	es
	call	PutDevInf
	pop	es

	call	PutHeadScr

	call	far MakeMod
	call	far MakeMod

	and	[Mode],7Fh
	call	StartMod

	jmp	@@no_chrono

@@newlang:
	mov	[cs:Key],0

	mov	ax,[Language]
	or	[Mode],40h
	xchg	[OFFSET Language+2],ax
	mov	[Language],ax

	call	PutAllScr

	jmp	@@end_main

@@exit:
	call	far Stopmod


	push	ds		; Reprend l'ancienne interruption clavier
	cli
	mov	ax,2509h
	lds	dx,[dword ptr ds:OFFSET Old_int9]
	int	21h
	sti
	pop	ds

	call	resetmode

	call	Unloadmod

	test	[Mode],40h
	jz	@@dont_save
	call	SaveConfig
@@dont_save:

	mov	ax,4c00h
	int	21h

error:
	cmp	ax,256
	jbe	@@dos_error
	sub	ax,246
@@dos_error:
	mov	bx,_DATA
	mov	ds,bx
	mov	bx,[ds:Language]
	mov	bx,[ds:bx]
	sub	ax,FIRST_ERROR
	jb	@@unknow
	cmp	ax,LAST_ERROR
	ja	@@unknow
	add	bx,ax
	add	bx,ax
	add	bx,2
	mov     dx,[ds:bx]
	mov	ah,09h
	int	21h
	mov	ax,bx
	shl	bx,1
	mov	ah,4ch
	int	21h

@@unknow:
	mov	dx,[ds:bx]
	mov	ah,09h
	int	21h
	mov	ax,4cffh
	int	21h

ENDP

;***************************************************************************
;*	Convertit un nombre sous forme de chaine de caractère en ds:si
;*	en binaire dans ax,ds:si pointant sur la fin du nombre
;*
;* Entrée:
;*	DS:SI	représentation décimal du nombre
;* Sortie:
;*	AX	nombre
;*	C=1	si la chaine n'est pas un nombre

PROC	get_dec

	xor	ax,ax
	xor	dh,dh
	mov	dl,[ds:si]
	sub	dl,'0'
	jl	@@error
	cmp	dl,9
	ja	@@error

@@next_digit:
	inc	si

	lea	ax,[eax*4+eax]
	shl	ax,1
	add     ax,dx

	mov	dl,[ds:si]
	sub	dl,'0'
	jl	@@no_digit
	cmp	dl,9
	jbe	@@next_digit

@@no_digit:
	clc
	ret
@@error:
	stc
	ret
ENDP

;***************************************************************************
;*	Convertit un nombre sous forme de chaine de caractère en ds:si
;*	en binaire dans ax,ds:si pointant sur la fin du nombre
;*
;* Entrée:
;*	DS:SI	représentation hexadécimal du nombre
;* Sortie:
;*	AX	nombre
;*	C=1	si la chaine n'est pas un nombre

PROC	get_hex

	xor	ax,ax
	xor	dh,dh
	mov	dl,[ds:si]
	sub	dl,'0'
	jl	@@error
	cmp	dl,9
	jbe	@@next_digit
	and	dl,1fh
	xor	dl,18h
	inc	dl
	cmp	dl,0fh
        ja	@@error
@@next_digit:
	inc	si

	shl	ax,4
	add     ax,dx

	mov	dl,[ds:si]
	sub	dl,'0'
	jl	@@no_digit
	cmp	dl,9
	jbe	@@next_digit
	and	dl,1fh
        xor	dl,18h
	inc	dl
	cmp	dl,0fh
        jbe	@@next_digit
@@no_digit:
	clc
	ret
@@error:
	stc
	ret
ENDP

Key	DB	0

;***************************************************************************
;*      interruption qui remplace l'interruption 09, elle est très simple
;*	pour éviter que le programme reste trop longtemps avec les
;*	interruption coupées.

PROC    hitkey FAR

	push    ax

	in      al,60h
	or      al,al
	js      @@relache

	mov     [cs:OFFSET Key],al

	mov     al,61h
	out     20h,al

	pop     ax
	iret

@@relache:
	mov     al,61h
	out     20h,al

	pop     ax
	iret

ENDP


SCREEN_POS	DW 640

;***************************************************************************
;*	Ecrit un nombre en EAX sur 32 bits en chaine de caractère
;*	correspondant à se représentation hexadécimal
;*
;* Entrée:
;*	EDX	nombre à convertir

PROC	writelong	FAR

	push	es
	mov	ax,0b800h
	mov	es,ax
	mov	di,[cs:SCREEN_POS]
	add	di,16

	mov	ax,'h'
	std
	stosb

	mov	cl,4
@@next_digit:
	movzx	ax,dl
	shr	edx,8
	shl	ax,4
	shr	al,4
	xchg	al,ah
	and	ax,0f0fh
	add	ax,3030h
	cmp	al,3Ah
	jb	@@al_ok
	add	al,7
@@al_ok:
	cmp	ah,3Ah
	jb	@@ah_ok
	add	ah,7
@@ah_ok:
	xchg	al,ah
	dec	di
	stosb
	dec	di
	mov	al,ah
	stosb
	dec	cl
	jne	@@next_digit

	cld

	add	di,19
	mov	al,' '
	stosb
	inc	di

	pop	es

	cmp	di,4000
	jb	@@ok
	mov	di,0
@@ok:
	mov	[cs:SCREEN_POS],di

	ret

ENDP



;***************************************************************************
;*	Cette routine sépare les arguments de la ligne de commande par un
;*	zero,deplus les switchs sont mis en majuscule.Les switchs doivents
;*	commencer par '-','/' ou '+' et le '/' est toujours transformé en '-'
;*	deplus les virgules se retrouve toujours en début de mots.Enfin
;*	si une chaine est mis entre '"' elle n'est pas modifié.
;*
;* Entrée:
;*	DS:SI	adresse de la ligne de commande
;*      ES:DI	adresse du buffer devant contenir la ligne modifié
;* Sortie:
;*	AL	nombre d'arguments sans les switchs

PROC	getarg

	lodsb
	mov	cl,al
	xor	ch,ch

@@search_letter:
	dec	cl
	jl	@@nothing_left
	lodsb
	cmp	al,' '
	je	@@search_letter
	cmp	al,09
	je	@@search_letter
	inc	ch
	cmp	al,'+'
	je	@@switch
	cmp	al,'-'
	je	@@switch
	cmp	al,'/'
	jne	@@letter
	mov	al,'-'
@@switch:
	stosb
	dec	ch

@@majuscule:
	dec	cl
	jl	@@nothing_left
	lodsb
	mov	ah,al
	and	ah,0dfh
	cmp	ah,'A'
	jb	@@search_white
	cmp	ah,'Z'
	ja	@@search_white
	mov	al,ah
	stosb
	jmp	@@majuscule

@@string:
	stosb
	dec	cl
	jl	@@nothing_left
	lodsb
	cmp	al,'"'
	jne	@@string

@@letter:
	stosb
	lodsb
	dec	cl
	jl	@@nothing_left

@@search_white:
	cmp	al,'"'
	je	@@string
	cmp	al,' '
	je	@@find_white
	cmp	al,09
	je	@@find_white
	cmp	al,','
	jne	@@letter
	mov	ah,al
	xor	al,al
	stosw
	cmp	[byte ptr ds:si],','
        jne	@@search_letter
	stosb
	jmp	@@search_letter

@@find_white:
	xor	al,al
	stosb
	jmp	@@search_letter

@@nothing_left:
	xor	ax,ax
	stosw
	mov	al,ch

	ret

ENDP

;**************************************************************************
;*	Affiche une ligne de texte donnant la carte sonore utilisé
;*
;* Attention:
;*	Les variables Device,Port,Irq et DMA doivent être définis ainsi
;*	que des messages

PROC	putcard

	mov	bx,[ds:Language]
	add	bx,4
	mov	bx,[ds:bx]
	mov	cl,[byte ptr ds:Device]
	or	cl,cl
	je	@@find_dev
@@next_dev:
	mov	ax,[ds:bx]
	add	bx,ax
	dec	cl
	jne	@@next_dev
@@find_dev:
	mov	cx,[ds:bx]
	mov	dx,[ds:bx+2]
	mov	ah,09h
	int	21h

	mov	dx,[ds:bx+4]
	mov	ah,09h
	int	21h

        add	bx,6
	cmp	cx,8
	je	@@thats_all

	mov	ah,09h
	mov	dx,[ds:bx]
	add	bx,2
	int	21h

	push	bx
	mov	bx,[ds:Port]
	or	bh,bh
	je	@@no_first_digit

	mov	dl,bh
	add	dl,'0'
	mov	ah,02h
	int	21h

	mov	dl,bl
	shr	dl,4
	and	dl,0fh
	add	dl,'0'
	cmp	dl,'9'
	jbe	@@no_hexa
	add	dl,7
@@no_hexa:
	mov	ah,02h
	int	21h

	and	bl,0fh
@@no_first_digit:
	mov	dl,bl
	add	dl,'0'
	mov	ah,02h
	int	21h
	pop	bx

	cmp	cx,10
	jle	@@thats_all

	mov	ah,09h
	mov	dx,[ds:bx]
	add	bx,2
	int	21h

	mov	dl,[ds:Irq]
	cmp	dl,10
	jb	@@first_pic
	push	dx
	mov	dl,'1'
	mov	ah,02h
	int	21h
	pop	dx
	sub	dl,10
@@first_pic:
	add	dl,'0'
	mov	ah,02h
	int	21h

	cmp	cx,12
	jle	@@thats_all

	mov	ah,09h
	mov     dx,[ds:bx]
	add	bx,2
	int	21h

	mov	dl,[ds:Dma]
	add	dl,'0'
	mov	ah,02h
	int	21h

@@thats_all:

	mov	ah,09h
	mov	dx,[ds:bx]
	int	21h

	ret

ENDP

;****************************************************************************
;*	Rafraichie les informations après un LOADMOD

PROC	GetMusInf

	push	ds
	pop	es
	mov	di,OFFSET MusicName
	mov	bl,0
	call	GetName

	call	GetModInf
	mov	[ModVoice],ah
	mov	[SeqLength],al
	xor	ah,ah
	mov	[ModInf.seq],ax

	mov	bl,1
	mov	di,OFFSET Samples+32
@@next_sample:
	push	bx
	push	di
	call    GetName
	pop	di
	pop	bx
	add	di,32
	inc	bl
	cmp	bl,32
	jne	@@next_sample

	mov	ah,48h
	mov	bx,0FFFFh
	int	21h
	mov	ax,[ds:StartMem]
	sub	ax,bx
	shr	ax,6
	mov	[ModInf.mem],ax

	ret

ENDP

;****************************************************************************
;*	Rafraichie les informations après un SETMOD
;*

PROC	PutDevInf

	mov	bx,[ds:Language]
	add	bx,4
	mov	bx,[ds:bx]
	mov	cl,[byte ptr ds:Device]
	or	cl,cl
	je	@@find_dev
@@next_dev:
	mov	ax,[ds:bx]
	add	bx,ax
	dec	cl
	jne	@@next_dev
@@find_dev:
	mov	ax,[ds:bx+4]
	mov	[ModInf.device],ax

	mov	cx,10000
	call	GetMixRate
	lea	ax,[eax*4+eax]
	add	ax,ax
	mov	[ModInf.freq],ax

	ret

ENDP


;****************************************************************************
;*	Lit le compteur horaire du BIOS

PROC	GetTime

	push	ds
	mov	ax,BIOS_SEG
	mov	ds,ax
	mov	eax,[ds:BIOS_CHRONO]
	pop	ds
	mov	[ds:StartTime],eax

	ret

ENDP

;****************************************************************************
;*	Affiche tous l'ecran

PROC	PutAllScr

	call	PutHeadScr
	mov	al,[ds:Mode]
	and	al,0Fh
	cmp	al,1
	je	@@help_mode
	cmp	al,2
	je	@@vu_mode
	call	PutSampScr
	jmp	@@refresh_ok
@@vu_mode:
	call	PutVuScr
	jmp	@@refresh_ok
@@help_mode:
	call	PutHelpScr
@@refresh_ok:

	ret

ENDP

;****************************************************************************
;*	Affiche le header
;*

PROC PutHeadScr

	mov	bx,[ds:Language]
	mov	bx,[ds:bx+2]
	mov	si,[ds:bx+2]
	push	bx
	mov	bx,OFFSET HeadBuffer
	mov	dx,1800h
	call	UseCpkBlk

	pop	bx
	mov	si,[ds:bx]
	mov	bx,OFFSET HeadBuffer
	xor	dx,dx
	call	UseCpkBlk

	ret
ENDP


;****************************************************************************
;*	Affiche les vu metres

PROC	PutVuScr

	mov	bx,[ds:Language]
	mov	bx,[ds:bx+2]
	mov	si,[ds:bx+4]
	mov	bx,OFFSET MainBuffer
	mov	dx,500h
	call	UseCpkBlk
	movzx	ax,[ModVoice]
	shl	ax,1
	mov	bx,SIZE T_VUINF
	mul	bx
	mov	bx,ax
	mov	[word ptr ds:bx+OFFSET MainBuffer],0
	ret

ENDP

;****************************************************************************
;*	Affiche l'ecran d'aide

PROC	PutHelpScr

	mov	bx,[ds:Language]
	mov	bx,[ds:bx+2]
	mov	si,[ds:bx+8]
	mov	bx,OFFSET MainBuffer
	mov	dx,500h
	call	UseCpkBlk
	ret

ENDP

;****************************************************************************
;*	Affiche l'ecran des samples

PROC	PutSampScr

	mov	bx,[ds:Language]
	mov	bx,[ds:bx+2]
	mov	si,[ds:bx+6]
	mov	bx,OFFSET MainBuffer
	mov	dx,500h
	call	UseCpkBlk

	mov	si,OFFSET SampInf
	mov	bx,OFFSET MainBuffer
	call	UpdCpkBlk

	ret

ENDP

;****************************************************************************
;*	Rafraichissement des informations après un MAKEMOD
;*	Le rafraichissement se fait directement à l'ecran.

PROC	UpdModInf

	movzx	ax,[ds:MasterVol]
	mov	[ModInf.vol],ax


	call	GetTempo
	xor	dx,dx
	xchg	dl,ah
	mov	[ModInf.tempo],ax
	mov	[ModInf.bpm],dx

	call	GetPattern
	xor	dh,dh
	mov	[ModInf.line],dx
	mov	dl,ah
	mov	[ModInf.pos],dx
	xor	ah,ah
	mov	[ModInf.pat],ax

	push	ds
	mov	ax,BIOS_SEG
	mov	ds,ax
	mov	eax,[ds:BIOS_CHRONO]
	pop	ds
	sub	eax,[ds:StartTime]
	xor	dx,dx
	mov	bx,1092
	div	bx
	mov	[ModInf.min],ax

	mov	ax,dx
	xor	dx,dx
	shl	ax,4
	mov	bx,291
	div	bx
	mov	[ModInf.sec],ax
	mov	di,OFFSET Buffer

	mov	eax,[ds:PlayChrono]
	lea	eax,[eax*4+eax]
	lea	eax,[eax*4+eax]
	shl	eax,2
	xor	edx,edx
	div	[ds:VBLChrono]
	sub	ax,100
	neg	ax
	mov	bl,al
	inc	bl
	sub	bl,[ds:LastChrono]
	cmp	bl,2
	jae	@@no_hyster
	mov	al,[ds:LastChrono]
@@no_hyster:
	mov	[ds:LastChrono],al
	xor	ah,ah
	cmp	al,100
	jb	@@under100
	xor	al,al
@@under100:
	mov	[ModInf.cpu],ax

	mov	si,OFFSET ModInf
	mov	bx,OFFSET HeadBuffer
	call	UpdCpkBlk

	ret
ENDP


;****************************************************************************
;*	Rafraichie les vu metres
;*

PROC	UpdVuMeter

	xor	bx,bx
	mov	di,OFFSET VumeterInf
@@next_voice:
	push	bx
	call    GetVoice
	pop	bx

	xor	ah,ah
	mov	al,ch
	mov	[(T_VUINF PTR ds:di).vol],ax
	mov	al,dl
	or	ax,ax
	je	@@no_new_inst
	mov	[(T_VUINF PTR ds:di).inst],ax
	shl	ax,5
	add	ax,OFFSET Samples
	mov	[(T_VUINF PTR ds:di).samp],ax
@@no_new_inst:
	shr	dx,8
	shl	dx,4
	add	dx,OFFSET LIST_EFFET
	mov	[(T_VUINF PTR ds:di).effect],dx

	mov	al,cl
	cmp	al,12
	je	@@no_note
	and	cx,0Fh
	lea	si,[ecx*2+ecx]
	mov	dx,[si+OFFSET LIST_NOTE]
	mov	si,bx
	add	si,si
	lea	si,[si+bx+OFFSET Notes]
	shr	al,4
	add	al,'0'
	mov	[ds:si+2],al
	mov	[ds:si],dx
@@no_note:

	push	di
	mov     ax,1
	mov	cl,bl
	shl	ax,cl
	test	[CutVoices],ax
	jnz	@@mute_voice
	call	GetVoiceByte
	xor	bh,bh
	mov	ah,[ds:OFFSET VuMeters+bx]
	shr	ah,2
	shr	al,2
	sub	al,ah
	add	[ds:OFFSET VuMeters+bx],al
	mov	cl,[ds:OFFSET VuMeters+bx]
	shr	cl,4
	mov	ch,16
	mov	dh,bl
	add	dh,6
	mov	dl,62
	call	PutVu
@@mute_voice:
	pop	di
	add	di,SIZE T_VUINF

	inc	bl
	cmp	bl,[ModVoice]
	jne	@@next_voice

	mov	si,OFFSET VuMeterInf
	mov	bx,OFFSET MainBuffer
	call	UpdCpkBlk

	ret

ENDP

VER_RETRACE	EQU	3dah


;****************************************************************************
;*	Attend une VBL en comptant dans CX

PROC	WaitVBL

		mov	dx,VER_RETRACE
@@wait1:
		inc	ecx
		in	al,dx
		test	al,8
		jnz	@@wait1

@@wait2:
		inc	ecx
		in	al,dx
		test	al,8
		jz	@@wait2

		ret
ENDP

;***************************************************************************
;*	Charge la configuration placé en overlay à la fin du programme
;*
;* 	la configuration occupe 8 octet et doit commencer par 'Cset'
;*	pour l'instant seul le premier bit est définis
;*	0 anglais
;*	1 francais

PROC	LoadConfig

	cmp	[dword ptr PlayerName],0
	je	@@no_name
	push	ds
	lds	dx,[PlayerName]
	mov	ax,3D00h
	int	21h
	pop	ds
	jc	@@error
	mov	bx,ax
	mov	ax,4202h
	mov	cx,0FFFFh
	mov	dx,0FFF8h
	int	21h

	mov	ah,3Fh
	mov	cx,8
	mov	dx,OFFSET Buffer
	int	21h

	mov	ah,3Eh
	int	21h

	cmp	[dword ptr ds:Buffer],'tesC'
	jne	@@no_name
	mov	eax,[dword ptr ds:Buffer+4]
	test	al,1
	jz	@@default_lang
	mov    	ax,[Language]
	xchg	[Language+2],ax
	mov	[Language],ax
@@default_lang:
	or	[Mode],20h

@@no_name:
	clc
	ret

@@error:
	ret

ENDP

;***************************************************************************
;*	Sauve la configuartion placé en overlay à la fin du programme

PROC	SaveConfig

	test	[Mode],40h
	jz	@@no_name
	cmp	[dword ptr PlayerName],0
	je	@@no_name
	push	ds
	lds	dx,[PlayerName]
	mov	ax,3D01h
	int	21h
	jc	@@error
	pop	ds
	mov	bx,ax
	mov	ax,4202h
	xor	dx,dx
	xor	cx,cx
	test	[Mode],20h
	jz	@@addconfig
	dec	cx
	mov	dx,0FFF8h
@@addconfig:
	int	21h

	mov	[dword ptr ds:OFFSET Buffer],'tesC'
	xor	eax,eax
	mov	dx,[Language]
;	cmp	dx,OFFSET English
	je	@@english
	inc	ax
@@english:
	mov	[dword ptr ds:OFFSET Buffer+4],eax

	mov	ah,40h
	mov	cx,8
	mov	dx,OFFSET Buffer
	int	21h

	mov	ah,3Eh
	int	21h

@@no_name:
	clc
	ret

@@error:
	ret


ENDP

STACK	400h

END

[ RETURN TO DIRECTORY ]