/* MED-stmod.c: SoundTracker 2.x module load/save & ST-song save functions
		© 1989, 1990 by Teijo Kinnunen */
#include "med.h"
#include "medproto.h"

extern struct Kappale far song;
extern UBYTE samplenum,blocks;
extern struct Gadget far gadget3[];
extern struct Soitin *sample[];
extern struct Lohko *lohko[];
extern BPTR fh;

static void __regargs ConvertToST(UBYTE,UBYTE *);

char *STModLoader(char *name)
{
	struct ST24Mod stsong = { 0 };
	UBYTE scntr,*cnvblk;
	long modlen,samplelen = 0,readlen;
	if(*name == '\0') return(AskName());
	if(!(fh = Open2(name,MODE_OLDFILE))) return(DISKERR);
	if(AlustaKappale(TRUE)) return(nomem);
	NollaaVarit();
	blocks = 0;
	Ilmoita("Loading ST/NT-module...");
	Seek(fh,0,OFFSET_END);
	modlen = Seek(fh,0,OFFSET_BEGINNING);
	if(Read(fh,(void *)&stsong,sizeof(struct ST24Mod)) <
		sizeof(struct ST24Mod)) return(DISKERR);
	modlen -= sizeof(struct ST24Mod); /* length of the remaining part */
	for(scntr = 0; scntr < 31; scntr++) {
		samplelen += stsong.sample[scntr].length * 2;
	}
	modlen -= samplelen;
	if(modlen < 0) return("Not a valid module.");
	if(!(cnvblk = AllocMem(1028,MEMF_PUBLIC))) return(nomem);
	Ilmoita("Loading blocks...");
	while(modlen > 0) {	/* Load the song */
		if(blocks >= 100) break; /* too many blocks */
		if(AllocBlock((UWORD)blocks,4,64)) {
			FreeMem(cnvblk,1028);
			return(nomem);
		}
		blocks++;
		TulostaLohkoJaSoitin();
		if(modlen > 1024) readlen = 1024;
		else { readlen = modlen; memset((void *)cnvblk,0,1028); }
		if(Read(fh,cnvblk+4,readlen) < readlen) {
			FreeMem(cnvblk,1028);
			return(DISKERR);
		}
		modlen -= readlen;
		ConvertTo200(cnvblk,(UBYTE *)lohko[blocks-1],TRUE);
	}
	FreeMem(cnvblk,1028);
	song.numblocks = blocks;
	song.deftempo = 6;
	song.songlen = stsong.songlen;
	song.flags |= FLAG_VOLHEX|FLAG_STSLIDE;
	memcpy((char *)(song.playseq),(char *)(stsong.playseq),128);
	for(scntr = 0; scntr < 31; scntr++) {
		strcpy(song.sample[scntr].sname,stsong.sample[scntr].name);
		song.sample[scntr].svol = stsong.sample[scntr].volume;
		song.sample[scntr].rep = stsong.sample[scntr].repeat;
		song.sample[scntr].replen = stsong.sample[scntr].replen;
	}
	StripPaths();
	PaivitaNaytto(TRUE);
	DispVolAndSldType();
	SetTempo(6);
	Ilmoita("Loading samples...");
	samplenum = 0;
	PaivitaSoittimennimi();
	for(scntr = 0; scntr < 31; scntr++) {
		samplelen = stsong.sample[scntr].length * 2;
		if(samplelen) {
			if(NewInstrument(samplelen,samplenum)) return(nomem);
			if(Read(fh,(char *)(sample[samplenum]) +
				sizeof(struct Soitin),samplelen) <
				  samplelen) return(DISKERR);
		}
		SeurSoitin();
	}
	samplenum = 0;
	PaivitaSoittimennimi();
	Close(fh); fh = 0L;
	Ilmoita("Module loaded.");
	return(NOERR);
}

static void __regargs ConvertToST(UBYTE block,UBYTE *bgto)
{
	extern UWORD periodit[];
	register UWORD cnt,cnt2,per;
	register UBYTE instrG_V,nnum,*to,*from;
	memset(bgto,0,1024);
	for(cnt = 0; cnt < 64; cnt++) {
		to = bgto + 16 * cnt;
		from = &lohko[block]->music[cnt * lohko[block]->numtracks * 3];
		if(cnt > lohko[block]->lines) {
			*(to-1) = 0;
			*(to-2) &= 0xf0;
			*(to-2) |= 0x0d; /* insert pattern break */
			break;
		}
		for(cnt2 = 0; cnt2 < 4; cnt2++) {
			nnum = *from++;
			instrG_V = 0;
			if(nnum & 0x80) instrG_V = 1;
			if(nnum & 0x40) instrG_V += 2;
			if(!(nnum &= 0x3f)) per = 0;
			else per = periodit[nnum - 1];
			if(instrG_V) per |= (instrG_V << 12);
			*to++ = (UBYTE)(per >> 8);
			*to++ = (UBYTE)(per & 0xff);
			nnum = *from++; /* Reuse the register variables */
			instrG_V = *from++;
			*to = nnum & 0xf0; /* some command conversions: */
			switch(nnum & 0x0f) { /* vv F00 -> D00 */
				case 0xF: switch(instrG_V) {
						case 0: *to |= 0xD; break;
						case 0xF8: *to |= 0xE;
							instrG_V = 1; break;
						case 0xF9: *to |= 0xE;
							instrG_V = 0; break;
						case 0xFD: *to |= 0x3;
							instrG_V = 0xff; break;
						case 0xFF: *to |= 0xC;
							instrG_V = 0; break;
						default: *to |= nnum;
					  }
					  break;
				case 0xD: *to |= 0x0A; break; /* Dxx->Axx */
				default:  *to |= nnum;
			}
			to++;
			*to++ = instrG_V;
		}
	}
}

char *SaveSTMod(char *name)
{
	UBYTE oldexists = 0,scnt,*convblk,lastused = 0;
	ULONG null = NULL;
	struct ST24Mod mod;
	if(*name == '\0') return(AskName());
	if(IsHere(name)) {
		oldexists = 1;
		Ilmoita(fileex);
		if(!Continue()) return(notsaved);
	}
	if(!(fh = Open2(name,MODE_NEWFILE))) return(DISKERR);
	Ilmoita("Saving ST/NT-module...");
	memset((void *)(&mod),0,sizeof(mod));
	strcpy(mod.songname,name);
	for(scnt = 0; scnt < 32; scnt++) {
		strcpy(mod.sample[scnt].name,song.sample[scnt].sname);
		mod.sample[scnt].length = sample[scnt]->length / 2;
		if(sample[scnt]) mod.sample[scnt].volume = song.sample[scnt].svol;
		mod.sample[scnt].repeat = song.sample[scnt].rep;
		if(song.sample[scnt].replen < 2) mod.sample[scnt].replen = 1;
		else mod.sample[scnt].replen = song.sample[scnt].replen;
	}
	mod.songlen = song.songlen;
	memcpy(mod.playseq,song.playseq,128);
	mod.mk = ((long)'M')<<24|((long)'.')<<16|((long)'K')<<8|'.';
	mod.I_dont_know_what_this_byte_is = 0x78; /* that's it!! */
	if(Write(fh,(char *)(&mod),sizeof(mod)) < sizeof(mod)) return(DISKERR);
	convblk = AllocMem(1024,MEMF_PUBLIC);
	if(!convblk) return(nomem);
	Ilmoita("Saving blocks...");
	for(scnt = 0; scnt < song.songlen; scnt++) /* find last used block */
		if(song.playseq[scnt] > lastused) lastused = song.playseq[scnt];
	for(scnt = 0; scnt <= lastused; scnt++) {
		ConvertToST(scnt,convblk);
		if(Write(fh,convblk,1024) != 1024) {
			FreeMem(convblk,1024);
			return(DISKERR);
		}
	}
	FreeMem(convblk,1024);
	Ilmoita("Saving samples...");
	for(scnt = 0; scnt < 32; scnt++) {
		if(sample[scnt] && sample[scnt]->length > 4) {
			if(Write(fh,(char *)(&null),4) != 4) return(DISKERR);
			if(Write(fh,(char *)sample[scnt] + sizeof(struct
				Soitin) + 4,sample[scnt]->length - 4) !=
				sample[scnt]->length - 4)
				return(DISKERR);
		}
	}
	if(fh) Close(fh);
	fh = 0L;
	if(!oldexists) InsertSavedFile(name);
	Ilmoita("Module saved.");
	return(NOERR);
}
