;****************************************************************************
;*	Ce module permet de charger des fichiers au format MOD
;*	Comme toutes les fonctions de ce projet on utilise la convention
;*	d'appel pascal
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 24/12/94
;* Modification le 02/01/95

IDEAL
P386N

PUBLIC	LOADMOD

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

SEGMENT CSEG PARA PUBLIC USE16 'CODE'

ASSUME	cs:CSEG

MODFLAGPOS	EQU     438h
SILENT		EQU	0

AmigaNote	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
		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

;***************************************************************************
;*	Charge un fichier MOD en m‚moire
;*
;* Entr‚e:
;*	DS:DX	adresse longue du nom du fichier mod
;*	CS:BX	adresse du driver de fichier utilis‚
;*
;* Sortie:
;*	AX	code d'erreur si C=1 et AX diff‚rent de zero
;*

PROC    loadmod FAR
LOCAL	nbinst:BYTE,nbmodvoice:BYTE,nulsamp:WORD,nulused:WORD=locvar

	push	ds
	push	si
	push	di
	enter	locvar,0

	mov	si,SEG Instrument1
	mov	ds,si
	mov	si,OFFSET Instrument1
	mov	cl,MAX_INST
@@voidsample:
	mov	[(INSTRUMENT PTR ds:si).adrseg],0
	add	si,SIZE INSTRUMENT
	dec	cl
	jne	@@voidsample
	mov	[ds:PatternSeg],0

	lds	dx,[ss:bp+12]

	call	open
	jc      @@error
	mov	bx,ax

	xor	cx,cx
	mov	dx,MODFLAGPOS
	call	seek
	jc	@@error

	mov	ax,SEG Comments
	mov	ds,ax
	mov	cx,4
	mov	dx,OFFSET Comments
	call	read
	jc	@@error

	mov	cx,0FFFFh
	mov	dx,-(MODFLAGPOS+4)
	call	seek
	jc	@@error

	mov	[nbmodvoice],4
	mov	[nbinst],15
	cmp	[dword ptr ds:OFFSET Comments],'.K.M'
	je	@@mod31
	cmp	[dword ptr ds:OFFSET Comments],'!K!M'
	je	@@mod31
	cmp	[dword ptr ds:OFFSET Comments],'4TLF'
	je	@@mod31
	cmp	[dword ptr ds:OFFSET Comments],'NHC4'
	je	@@mod31
	cmp	[dword ptr ds:OFFSET Comments],'NHC6'
	je	@@mod6
	cmp	[dword ptr ds:OFFSET Comments],'8TLF'
	je	@@mod8
	cmp	[dword ptr ds:OFFSET Comments],'ATCO'
	je	@@mod8
	cmp	[dword ptr ds:OFFSET Comments],'NHC8'
	jne	@@loadheader
@@mod8:
	add	[nbmodvoice],2
@@mod6:
	add	[nbmodvoice],2
@@mod31:
	add	[nbinst],16
@@loadheader:

	mov	cx,20
	mov	dx,OFFSET Comments
	call	read
	jc	@@error
	mov	[byte ptr ds:OFFSET Comments+20],0

	mov	cl,[nbinst]
	mov	di,OFFSET Instrument1
	mov	ax,SEG Instrument1
	mov	es,ax
	mov	si,OFFSET Comments+32

@@next_inst:
	shl	ecx,16
	mov	cx,30
	mov	dx,si
	call	read
	jc	@@error

	mov	al,[ds:si+25]
	cmp	al,64
	jb	@@volume_ok
	mov	al,63
@@volume_ok:
	mov	[(INSTRUMENT PTR es:di).volume],al

	mov	ax,TOO_BIG_SAMP
	mov   	dx,[ds:si+22]
	rol	dx,8
	cmp	dx,32768-(SAMPLE_BORDER+MIN_REPEAT)/2
	jae	@@error
	add	dx,dx
	mov	[(INSTRUMENT PTR es:di).length],dx

	mov	ax,[ds:si+28]
	rol	ax,8
	add	ax,ax
	cmp	ax,2
	ja	@@true_rep
	xor	ax,ax
@@true_rep:
	cmp	dx,ax
	jae	@@lenrepok
	mov	ax,dx
@@lenrepok:
	mov	[(INSTRUMENT PTR es:di).replen],ax

	add	di,SIZE INSTRUMENT
	mov	[byte ptr ds:si+22],0
	add	si,32
	shr	ecx,16
	dec	cl
	jne	@@next_inst

	mov	ax,SEG Sequence
	mov	ds,ax
	mov	dx,OFFSET Sequence+512-130
	mov	si,dx
	mov	cx,130
	call	read
	jc	@@error

	cmp	[nbinst],15
	je	@@no_flag
	xor	cx,cx
	mov	dx,4
	call	seek
	jc	@@error
@@no_flag:

	shl	ebx,16
	mov     cl,128 ; pour certain mod [ds:si] n'est pas significatif (PRELUDE)
	mov	di,OFFSET Sequence
	lodsw
	push	ax
@@nb_pattern:
	lodsb
	mul	[nbmodvoice]
	shl	ax,4
	cmp     bx,ax
	jae     @@no_new_pattern
	mov     bx,ax
@@no_new_pattern:
	stosw
	dec     cl
	jne     @@nb_pattern

	movzx	ax,[nbmodvoice]
	shl	ax,4
	add	bx,ax

	call	allocmem ; reserve de la place pour les patterns
	jc      @@error
	mov	[ds:PatternSeg],ax

	pop	cx
	xor	ch,ch
	mov	[ds:LastPos],cx
	add	[ds:LastPos],cx
	mov	si,OFFSET Sequence
	add	[ds:LastPos],si
@@changepat:
	add	[word ptr ds:si],ax
	add	si,2
	dec	cl
	jne	@@changepat

	mov	si,ax
	mov	ds,si
	mov	ax,CSEG
	mov	es,ax

	mov	cx,bx
	shl	ecx,2+16
	mov	cx,4		; lecture en 4 fois
@@readpat:
	push	cx
	shr	ebx,16
	shr	ecx,16
	xor	dx,dx
	call	read
	jc	@@error

	shl	ebx,16
	mov	ax,ds
	shr	cx,4
	add	ax,cx
	push	ax
	mov	ax,cx
	shl	ecx,16+4
	mov	cx,ax

	xor	si,si
	shl	cx,2
@@changenote:
	lodsd
	mov	di,OFFSET AmigaNote+22-24
	rol	ax,8
	mov	bx,ax
	and	bx,0FFFh
	je	@@nonote
	mov	al,0F0h
@@search_oct:
	add	al,10h
	add	di,24
	cmp	bx,[es:di]
	jb	@@search_oct

	sub	di,22+2
@@search_note:
	inc	al
	add	di,2
	cmp	bx,[es:di]
	jb	@@search_note
	dec	al
@@nonote:
	mov	[ds:si-4],al
	shr	eax,8
	shr	al,4
	rol	ax,4
	shr	ah,1
	and	ah,0F8h
	ror	eax,8
	call	@@convert_speed
	mov	[ds:si-2],ax
	rol	eax,8
	shl	ax,7
	or	[ds:si-4],al
	and	ah,1Fh
	mov	[ds:si-3],ah

	loop	@@changenote

	pop	ds
	pop	cx
	dec	cx
	jne	@@readpat


	shl	ebx,16
	mov	bx,SAMPLE_BORDER+MIN_REPEAT  ;cr‚er un sample nul
	add	bx,15
	shr	bx,4
	call	allocmem
	jc	@@error
	mov	es,ax
	mov	[nulsamp],ax

	mov	cx,SAMPLE_BORDER+MIN_REPEAT
	xor	di,di
	mov	ax,SILENT
	rep	stosb

	mov	[nulused],0

	mov	ax,SEG Instrument1
	mov	es,ax
	mov	di,OFFSET Instrument1
	mov     cl,[nbinst]           ;lecture des samples
@@sample:
	shl     ecx,16
	mov	cx,[(INSTRUMENT PTR es:di).length]
	or	cx,cx
	jne	@@res_mem

	mov	ax,[nulsamp]
	mov	[(INSTRUMENT PTR es:di).adrseg],ax
	mov	[(INSTRUMENT PTR es:di).replen],MIN_REPEAT
	mov	[(INSTRUMENT PTR es:di).length],MIN_REPEAT
	mov	[nulused],1
	jmp	@@no_sample
@@res_mem:
	mov	bx,cx
	add	bx,SAMPLE_BORDER+MIN_REPEAT
	add	bx,15
	shr	bx,4
	call	allocmem
	jc	@@error
	mov	[(INSTRUMENT PTR es:di).adrseg],ax

	shr	ebx,16
	mov	ds,ax
	xor	ax,ax
	call	read
	jc      @@error
	shl	ebx,16

;	mov	si,[(INSTRUMENT PTR es:di).length]
;@@unsignedsamp:
;	add	[byte ptr ds:si-1],128
;	dec	si
;	jne	@@unsignedsamp

	mov	cx,SAMPLE_BORDER+MIN_REPEAT
	mov	bx,[(INSTRUMENT PTR es:di).length]
	mov	si,bx
	sub	si,[(INSTRUMENT PTR es:di).replen]

	cmp	[(INSTRUMENT PTR es:di).replen],2
	ja	@@next_byte
	mov	[(INSTRUMENT PTR es:di).replen],MIN_REPEAT
	mov	[byte ptr ds:si],SILENT
	add	[(INSTRUMENT PTR es:di).length],MIN_REPEAT
	dec	cx
	inc	bx
@@next_byte:
	lodsb
	mov	[ds:bx],al
	inc	bx
	dec	cx
	jne	@@next_byte

@@no_sample:
	add     di,SIZE INSTRUMENT
	shr     ecx,16
	dec     cl
	jne     @@sample

	shr	ebx,16
	call	close
	jc      @@error

	mov	al,[nbmodvoice]
	mov	[es:NbVoice],al
	mov	al,6
	mov	[es:Tempo],al
	mov	al,125
	mov	[es:Bpm],al

	cmp	[nulused],0
	jne	@@nul_used
	mov	es,[nulsamp]
	call	freemem
@@nul_used:
	xor	ax,ax
	clc
	jmp	@@ok
@@error:
	stc
@@ok:
	leave
	pop	di
	pop	si
	pop	ds
	ret	4

@@convert_speed:
	mov	bl,al
	and	bl,0F8h
	cmp	bl,78h
	jne	@@no_speed
	cmp	ah,1Fh
	jbe	@@no_speed
	add	al,8
@@no_speed:
	retn
ENDP

ENDS
END

;***************************************************************************
;*      LibŠre la m‚moire prise par la fonction loadmod utilise en ds:di
;*      l'adresse des instruments et en ds:si l'adresse de la partition

PROC    Unloadmod FAR

	push	ds

	mov	ax,SEG PatternSeg
	mov	ds,ax
	mov     ax,[ds:PatternSeg]
	or	ax,ax
	je	@@not_alloc
	mov	es,ax
	call	freemem
@@not_alloc:

	mov	bx,OFFSET Instrument1
	mov	cl,MAX_INST
@@sample:
	mov     ax,[(INSTRUMENT PTR ds:bx).adrseg]
	or	ax,ax
	je      @@no_sample
	mov     es,ax
	call	freemem
@@no_sample:
	add 	bx,SIZE INSTRUMENT
	dec	cl
	jne	@@sample

	pop	ds

	ret

ENDP

ENDS
END