;	(Octa)MED module load routines, by Teijo Kinnunen
;	MED V3.00 module support added		22-Jan-1991
;	upgraded for V3.20 (OctaMED V2.00)	02-Aug-1991
;	and for OctaMED Pro V3.00		02-Apr-1992
;	(bug fix)				31-May-1992
;	OctaMED Pro V5 support (MMD2)		18-May-1993
;	OctaMED Pro V6 support (cmd pages)	16-Jan-1995
;	2 bug fixes (Thanks to Peter Kunath.)	14-Feb-1995

;	$VER: loadmod_a 6.1 (14.02.1995)

;	Function: d0 = _LoadModule(a0)
;	a0 = module name
;	d0 = pointer to loaded module, zero if load failed

	XDEF	_LoadModule
	XDEF	_UnLoadModule
	XDEF	_RelocModule

mmd_songinfo	EQU	8
mmd_blockarr	EQU	16
mmd_expdata	EQU	32
mmd_songsleft	EQU	51
msng_numblocks	EQU	504
msng_pseqs	EQU	508
msng_numsamples	EQU	787

	CODE
_LoadModule:
		movem.l a2-a4/a6/d2-d6,-(sp)
	PRSDF
		moveq	#0,d6		;d6 = return value (zero = error)
		move.l  a0,a4		;a4 = module name
		movea.l 4,a6
		lea     dosname(pc),a1
		moveq	#0,d0
		jsr     -$228(a6)	;OpenLibrary()
		tst.l   d0
		PRSDE
		beq     xlm1
		move.l  d0,a3		;a3 = DOSBase
		move.l  d0,a6
		move.l  a4,d1		;name = d1
		move.l  #1005,d2	;accessmode = MODE_OLDFILE
		jsr     -$1e(a6)	;Open()
		move.l  d0,d4		;d4 = file handle
		beq     xlm2
		move.l  d4,d1
		moveq   #0,d2
		moveq   #1,d3		;OFFSET_END
		jsr     -$42(a6)	;Seek(fh,0,OFFSET_END)
		move.l  d4,d1
		moveq	#-1,d3		;OFFSET_BEGINNING
		jsr     -$42(a6)	;Seek(fh,0,OFFSET_BEGINNING)
		move.l  d0,d5		;d5 = file size
		movea.l 4,a6
		moveq   #2,d1		;get chip mem
		jsr     -$c6(a6)	;AllocMem()
		tst.l   d0
		beq.s   xlm3
		move.l  d0,a2		;a2 = pointer to module
		move.l  d4,d1	;file
		move.l  d0,d2	;buffer
		move.l  d5,d3	;length
		move.l  a3,a6
		jsr     -$2a(a6)	;Read()
		cmp.l   d5,d0
		bne.s   xlm4		;something wrong...
		cmp.l	#'MMD2',(a2)	;Pro V5 module?
		beq.s	id_ok
		cmp.l	#'MMD1',(a2)	;Pro module?
		beq.s	id_ok
		cmp.l   #'MMD0',(a2)
		bne.s   xlm4		;this is not a module!!!
id_ok		movea.l a2,a0
		bsr.s   _RelocModule
		move.l  a2,d6		;no error...
		bra.s   xlm3
xlm4		move.l  a2,a1		;error: free the memory
		move.l  d5,d0
		movea.l 4,a6
		jsr     -$d2(a6)	;FreeMem()
xlm3		move.l  a3,a6		;close the file
		move.l  d4,d1
		jsr     -$24(a6)	;Close(fhandle)
xlm2		move.l  a3,a1		;close dos.library
		movea.l 4,a6
		jsr     -$19e(a6)
xlm1		move.l  d6,d0		;push return value
		movem.l (sp)+,a2-a4/a6/d2-d6	;restore registers
		rts			;and exit...
dosname		dc.b	'dos.library',0

;	Function: _RelocModule(a0)
;	a0 = pointer to module

; This function is a bit strangely arranged around the small reloc-routine.
reloci		move.l	24(a2),d0
		beq.s	xloci
		movea.l	d0,a0
		moveq   #0,d0
		move.b  msng_numsamples(a1),d0	;number of samples
		subq.b  #1,d0
relocs		bsr.s   relocentr
		move.l	-4(a0),d3	;sample ptr
		beq.s	nosyn
		move.l	d3,a3
		tst.w	4(a3)
		bpl.s	nosyn		;type >= 0
		move.w	20(a3),d2	;number of waveforms
		lea	278(a3),a3	;ptr to wf ptrs
		subq.w	#1,d2
relsyn		add.l	d3,(a3)+
		dbf	d2,relsyn
nosyn		dbf     d0,relocs
xloci		rts
norel		addq.l	#4,a0
		rts
relocentr	tst.l   (a0)
		beq.s   norel
		add.l   d1,(a0)+
		rts
_RelocModule:
		movem.l	a2-a4/d2-d4,-(sp)
		movea.l a0,a2
		move.l  a2,d1		;d1 = ptr to start of module
		bsr.s	relocp
		movea.l mmd_songinfo(a2),a1
		bsr.s	reloci
		move.b	mmd_songsleft(a2),d4
rel_lp		bsr.s	relocb
		cmp.b	#'2',3(a2)	;MMD2?
		bne.s	norelmmd2
		bsr.w	relocmmd2sng
norelmmd2	move.l	mmd_expdata(a2),d0	;extension struct
		beq.s	rel_ex
		move.l	d0,a0
		bsr.s	relocentr	;ptr to next module
		bsr.s	relocentr	;InstrExt...
		addq.l	#4,a0		;skip sizes of InstrExt
; We reloc the pointers of MMD0exp, so anybody who needs them can easily
; read them.
		bsr.s	relocentr	;annotxt
		addq.l	#4,a0		;annolen
		bsr.s	relocentr	;InstrInfo
		addq.l	#8,a0
		bsr.s	relocentr	;rgbtable (not useful for most people)
		addq.l	#4,a0		;skip channelsplit
		bsr.s	relocentr	;NotationInfo
		bsr.s	relocentr	;songname
		addq.l	#4,a0		;skip song name length
		bsr.s	relocentr	;MIDI dumps
		bsr.s	relocmdd
		subq.b	#1,d4		;songs left..?
		bcs.s	rel_ex
		move.l	d0,a0
		move.l	(a0),d0
		beq.s	rel_ex
		move.l	d0,a2
		bsr.s	relocp
		movea.l 8(a2),a1
		bra.s	rel_lp
rel_ex		movem.l	(sp)+,d2-d4/a2-a4
		rts

relocp		lea	mmd_songinfo(a2),a0
		bsr.s	relocentr
		addq.l	#4,a0
		bsr.s	relocentr
		addq.l	#4,a0
		bsr.s	relocentr
		addq.l	#4,a0
		bra.s	relocentr

relocb		move.l	mmd_blockarr(a2),d0
		beq.s	xlocb
		movea.l	d0,a0
		move.w  msng_numblocks(a1),d0
		subq.b  #1,d0
rebl		bsr	relocentr
		dbf     d0,rebl
		cmp.b	#'T',3(a2)	;MMD0 (= MCNT)
		beq.s	xlocb
		cmp.b	#'1',3(a2)	;test MMD type
		bge.s	relocbi
xlocb		rts

relocmdd	move.l	d0,-(sp)
		tst.l	-(a0)
		beq.s	xlocmdd
		movea.l	(a0),a0
		move.w	(a0),d0		;# of msg dumps
		addq.l	#8,a0
mddloop		beq.s	xlocmdd
		bsr	relocentr
		bsr.s	relocdmp
		subq.w	#1,d0
		bra.s	mddloop
xlocmdd		move.l	(sp)+,d0
		rts

relocdmp	move.l	-4(a0),d3
		beq.s	xlocdmp
		exg.l	a0,d3		;save
		addq.l	#4,a0
		bsr	relocentr	;reloc data pointer
		move.l	d3,a0		;restore
xlocdmp		rts

relocbi		move.w	msng_numblocks(a1),d0
		move.l	a0,a3
biloop		subq.w	#1,d0
		bmi.s	xlocdmp
		move.l	-(a3),a0
		addq.l	#4,a0
		bsr	relocentr	;BlockInfo ptr
		tst.l	-(a0)
		beq.s	biloop
		move.l	(a0),a0
		bsr	relocentr	;hldata
		bsr	relocentr	;block name
		addq.l	#4,a0		;skip blocknamelen
		bsr	relocentr	;pagetable
		tst.l	-(a0)
		bne.s	relocpgtbl
		bra.s	biloop
; take care of the new features of MMD2s
relocmmd2sng	move.l	mmd_songinfo(a2),a0
		lea	msng_pseqs(a0),a0
		bsr	relocentr	;playseqtable
		bsr	relocentr	;sectiontable
		bsr	relocentr	;trackvols
		move.w	2(a0),d0	;numpseqs
		move.l	-12(a0),a0	;get back to playseqtable
		subq.w	#1,d0
psqtblloop	bsr	relocentr
		dbf	d0,psqtblloop
		rts
relocpgtbl	movea.l	(a0),a4		;page table list hdr
		move.w	(a4),d2
		subq.w	#1,d2
		lea	4(a4),a0
pgtblloop	bsr	relocentr
		dbf	d2,pgtblloop
		bra	biloop


;	Function: _UnLoadModule(a0)
;	a0 = pointer to module
_UnLoadModule:
		move.l  a6,-(sp)
		move.l  a0,d0
		beq.s   xunl
		movea.l 4,a6
		move.l  4(a0),d0
		beq.s   xunl
		movea.l a0,a1
		jsr     -$d2(a6)	;FreeMem()
xunl		move.l	(sp)+,a6
		rts
