/* MED - music editor © 1989, 1990 by Teijo Kinnunen */
/* med-mod.c: module loading/saving */
#include "med.h"
#include "medproto.h"
#define MMD0ID ((long)'M'<<24|(long)'M'<<16|(long)'D'<<8|(long)'0')
extern UBYTE blocks;
extern BPTR fh;
extern struct Kappale far song;
extern struct Lohko *lohko[];
extern struct Soitin *sample[];
static void ReadMMD0song(struct MMD0song *);
static BOOL FWrite(char *,LONG);
static BOOL FRead(char *,LONG);

static BOOL FWrite(char *p,LONG len)
{
	if(Write(fh,p,len) == len) return(FALSE); else return(TRUE);
}

static BOOL FRead(char *p,LONG len)
{
	if(Read(fh,p,len) == len) return(FALSE); else return(TRUE);
}

struct MMD0song *MakeMMD0song()
{
	struct MMD0song *sng = (struct MMD0song *)AllocMem(
		sizeof(struct MMD0song),MEMF_CLEAR);
	UWORD cnt;
	if(!sng) return(0L);
	for(cnt = 0; cnt < 63; cnt++) {
		sng->sample[cnt].rep = song.sample[cnt].rep;
		sng->sample[cnt].replen = song.sample[cnt].replen;
		sng->sample[cnt].midich = song.sample[cnt].midich;
		sng->sample[cnt].midipreset = song.sample[cnt].midipreset;
		sng->sample[cnt].svol = song.sample[cnt].svol;
		sng->sample[cnt].strans = song.sample[cnt].strans;
	}
	memcpy((void *)(&sng->songlen),(void *)(&song.songlen),264);
	for(cnt = 0; cnt < 16; cnt++) sng->trkvol[cnt] = song.trkvol[cnt];
	sng->mastervol = song.mastervol;
	sng->numblocks = blocks;
	return(sng);
}

char *SaveMod(char *name)
{
	UBYTE oldexists = 0,cnt,lastsample = 0;
	LONG array[100];
	LONG currpos = 0; /* current file position (no Seek() required) */
	LONG blkarrpos,smplarrpos,len;
	struct MMD0 mmd0 = { 0 };
	struct MMD0song *msng;
	if(*name == '\0') return(AskName());
	if(IsHere(name)) {
		Ilmoita(fileex);
		oldexists = 1;
		if(!Continue()) return(notsaved);
	}
	for(cnt = 0; cnt < 63; cnt++)
		if(sample[cnt]) lastsample = cnt;
	if(!(fh = Open2(name,MODE_NEWFILE))) return(DISKERR);
	Ilmoita("Saving module...");
	mmd0.id = MMD0ID;
	mmd0.actplayline = -1;
	if(FWrite((char *)(&mmd0),sizeof(struct MMD0))) return(DISKERR);
	currpos += sizeof(struct MMD0);
	if(!(msng = MakeMMD0song())) return(nomem);
	msng->numsamples = lastsample + 1;
	mmd0.song = (struct MMD0song *)currpos;
	if(FWrite((char *)msng,sizeof(struct MMD0song))) {
		FreeMem((void *)msng,sizeof(struct MMD0song));
		return(DISKERR);
	}
	currpos += sizeof(struct MMD0song);
	FreeMem((void *)msng,sizeof(struct MMD0song));
	blkarrpos = currpos; /* remember... */
	if(FWrite((char *)array,4 * blocks)) return(DISKERR);
	currpos += 4 * blocks; /* the array doesn't yet contain */
	smplarrpos = currpos; /* anything useful */
	if(FWrite((char *)array,4 * (lastsample + 1))) return(DISKERR);
	currpos += 4 * (lastsample + 1);
	for(cnt = 0; cnt < blocks; cnt++) {
		array[cnt] = currpos;
		len = lohko[cnt]->numtracks * 3 * (lohko[cnt]
			->lines + 1);
		if(FWrite((char *)lohko[cnt],MMDBLKHDRSZ)) return(DISKERR);
		if(FWrite(lohko[cnt]->music,len)) return(DISKERR);
		currpos += len + MMDBLKHDRSZ;
	}
	Seek(fh,blkarrpos,OFFSET_BEGINNING); /* write the block ptrs */
	if(FWrite((char *)array,4 * blocks)) return(DISKERR);
	Seek(fh,0,OFFSET_END); /* all right, and now back to the end */
	for(cnt = 0; cnt <= lastsample; cnt++)
		if(sample[cnt]) {
			array[cnt] = currpos;
			len = sample[cnt]->length + sizeof(struct Soitin);
			if(FWrite((char *)sample[cnt],len)) return(DISKERR);
			currpos += len;
		} else array[cnt] = 0L;
	Seek(fh,smplarrpos,OFFSET_BEGINNING); /* and the sample ptrs */
	if(FWrite((char *)array,4 * (lastsample + 1))) return(DISKERR);
	Seek(fh,0,OFFSET_END);
	mmd0.blockarr = (struct Lohko **)blkarrpos;
	mmd0.smplarr = (struct Soitin **)smplarrpos;
	mmd0.modlen = Seek(fh,0,OFFSET_BEGINNING);
	if(FWrite((char *)(&mmd0),sizeof(struct MMD0))) return(DISKERR);
	Close(fh); fh = 0L;
	if(!oldexists) InsertSavedFile(name);
	Ilmoita("Module saved.");
	return(NOERR);
}

static void ReadMMD0song(struct MMD0song *sng)
{
	UWORD cnt;
	for(cnt = 0; cnt < 63; cnt++) {
		song.sample[cnt].rep = sng->sample[cnt].rep;
		song.sample[cnt].replen = sng->sample[cnt].replen;
		song.sample[cnt].midich = sng->sample[cnt].midich;
		song.sample[cnt].midipreset = sng->sample[cnt].midipreset;
		song.sample[cnt].svol = sng->sample[cnt].svol;
		song.sample[cnt].strans = sng->sample[cnt].strans;
	}
	memcpy((void *)(&song.songlen),(void *)(&sng->songlen),264);
	for(cnt = 0; cnt < 16; cnt++) song.trkvol[cnt] = sng->trkvol[cnt];
	song.mastervol = sng->mastervol;
}

char *LoadMod()
{
	struct MMD0 mmd0;
	union { struct MMD0song sng; LONG array[100]; } sd; /* some data */
	UWORD cnt;
	UBYTE blks,samples;
	Ilmoita("Loading module...");
	VapautaSoittimet();
	if(FRead((char *)(&mmd0),sizeof(struct MMD0))) return(DISKERR);
	Seek(fh,(LONG)(mmd0.song),OFFSET_BEGINNING);
	if(FRead((char *)(&sd.sng),sizeof(struct MMD0song))) return(DISKERR);
	ReadMMD0song(&sd.sng);
	blks = sd.sng.numblocks;
	samples = sd.sng.numsamples;
	Seek(fh,(LONG)(mmd0.blockarr),OFFSET_BEGINNING);
	if(FRead((char *)(&sd.array),blks * 4)) return(DISKERR);
	blocks = 0;
	for(cnt = 0; cnt < blks; cnt++) {
		struct MMD0Block blkhdr; /* just a header */
		Seek(fh,sd.array[cnt],OFFSET_BEGINNING);
		if(FRead((char *)(&blkhdr),MMDBLKHDRSZ)) return(DISKERR);
		if(AllocBlock((UWORD)blocks,blkhdr.numtracks,
			(UWORD)((UWORD)blkhdr.lines + 1))) return(nomem);
		blocks++;
		if(FRead(lohko[cnt]->music,3 * ((UWORD)blkhdr.lines + 1) *
			blkhdr.numtracks)) return(DISKERR);
	}
	Seek(fh,(LONG)(mmd0.smplarr),OFFSET_BEGINNING);
	if(FRead((char *)(&sd.array),samples * 4)) return(DISKERR);
	for(cnt = 0; cnt < samples; cnt++) {
		struct Soitin shdr; /* header again */
		if(sd.array[cnt]) {
			stcu_d(song.sample[cnt].sname,cnt + 1);
			Seek(fh,sd.array[cnt],OFFSET_BEGINNING);
			if(FRead((char *)(&shdr),sizeof(struct Soitin))) return(DISKERR);
			if(NewInstrument(shdr.length,(UBYTE)cnt)) return(nomem);
			if(FRead((char *)sample[cnt] + sizeof(struct Soitin),
				shdr.length)) return(DISKERR);
			sample[cnt]->type = shdr.type;
		}
	}
	song.flags &= ~FLAG_INSTRSATT;
	Ilmoita("Module loaded.");
	return(NOERR);
}
