;**************************************************************************
;* 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