/*
 * MIDIMOD.C - Amiga Module to MIDI file converter
 * (c)opyright Andrew Scott 1993
 *
 * Turbo C 2.0
 *
 * Description: Takes a .mod file and has a good go at converting it to
 *              a .mid file. Equivalents to certain .mod samples can be
 *              set to default to particular MIDI instruments. Multiple
 *              MIDI instrument tables should be supported. Note that .mod
 *              and .mid extensions are at the end of the filename.
 *
 * Author: Andrew Scott (Adrenalin Software)
 *
 * Date: 14/3/1993 ver 0.1
 *       20/4/1993 ver 0.2
 *
 **********************************************************************
 *
 * SAS/C 6.51
 *
 * UpDated: 23/Jan/1994 Raul Sobon (Amiga Version  ooooooooooh Yeah!)
 *			15/Feb/1994 Fixed up bugs in midi generation etc..
 *						ReqTools implemented
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>   /* don't forget to link in appropriate libraries */

#include "textwin.h" /* Simple text-windowing environment */
#include "midimod.h" /* Dialog/Info box messages and definitions */

bfile	MidFile, ModFile;
char	SongName[128];
samps	Samples;
unsigned long PosLog[128];
int		DrumChann = 9, TempoType = 1, PosI = 0;
string	MidFN, ModFN;
int		numoftracks=0;


unsigned char Def_Map_filename[]={ DEF_MAPFILE };

void OutByte(bfile f, char b)
/* Post: The byte b has been written to the buffer of the file f */
{
	if (f->o == BUFFSIZE) {
		fwrite(f->b, 1, BUFFSIZE, f->f);
		f->o = 0;
  	}
	f->b[f->o++] = b;
}

void FlushOut(bfile f)
/* Pre: f was opened for writing */
/* Post: The file f has has its buffer flushed */
{
	if (f->o > 0)
		fwrite(f->b, 1, f->o, f->f);
	f->o = 0;
}

void CloseOut(bfile f)
/* Pre: f was opened for writing */
/* Post: The file f has been flushed and is now closed */
{
	FlushOut(f);
	fclose(f->f);
	f->f = NULL;
}

int OpenOut(bfile f, string fn)
/* Returns: NZ if the file f has been opened for writing with the name fn */
{
	if (f->f != NULL)
		CloseOut(f);
	f->f = fopen(fn, "wb");
	f->o = 0;
	return f->f != NULL;
}

unsigned long Beatle(bfile f)
/* Returns: bfile-tell (btell=beatle). The offset from the start */
{
	return ftell(f->f) + f->o;
}

unsigned char InByte(bfile f)
/* Pre: f was opened for reading */
/* Returns: The next byte from the file f */
{
	if (f->o == BUFFSIZE && !feof(f->f)) {
		f->r = fread(f->b, 1, BUFFSIZE, f->f);
		if (f->r < BUFFSIZE)
			f->b[f->r] = 0;
		f->o = 0;
	}
	if (f->o < f->r)
		 return f->b[f->o++];
	return f->b[f->o];
}

void CloseIn(bfile f)
/* Post: The file f is now closed */
{
	fclose(f->f);
	f->f = NULL;
}

int OpenIn(bfile f, string fn)
/* Returns: NZ if the file f has been opened for reading with the name fn */
{
	if( f->f )
		CloseIn(f);
	f->f = fopen(fn, "rb");
	f->o = f->r = BUFFSIZE;
	return f->f != NULL;
}

void Inskipp(bfile f, unsigned long n) /* Stainless-steel rat for Pres */
/* Pre: f was opened for reading */
/* Post: f's file pointer has skipped forward n bytes */
{
	n += f->o;
	while (n >= BUFFSIZE && !feof(f->f)) {
		f->r = fread(f->b, 1, BUFFSIZE, f->f);
		if (f->r < BUFFSIZE)
			f->b[f->r] = 0;
		n -= BUFFSIZE;
	}
	f->o = n; /* hmmm.. may cause an error if was eof.. X-fingers */
}

struct bpos FPos(bfile f)
/* Returns: All necessary information regarding file f's status */
{
	struct bpos x;

	x.d = *f;
	x.p = ftell(f->f);
	return x;
}

void FGoto(bfile f, struct bpos x)
/* Pre: x was the status of f previously */
/* Post: File f has had its status changed to x */
{
	fseek(f->f, x.p, SEEK_SET);
	*f = x.d;
}

int WriteVLQ(bfile f, unsigned long i)
/*
 * Returns: # of bytes written after a variable-length-quantity equivalent
 *    of i has been written to the file f.
 */
{
	int x = 0;
	unsigned long buffer;

	buffer = i & 127;
	while ((i >>= 7) > 0)
		buffer = ((buffer << 8) | 128) + (i & 127);
	while (1) {
		OutByte(f, buffer & 255);
		x++;
		if (buffer & 128)
			buffer >>= 8;
		else
			return x;
	}
}

string InitFile(bfile f, string deffn, string t, int inpm)
/* Returns: NULL if file is unacceptable, the filename otherwise. The
 *    filename corresponds to file f, type t, with default filename deffn.
 *    Will open an input file if inpm is NZ. deffn will be freed.
 */
{
	int r = 0;
	string newfn;

	_IF[1] = t;
	if (deffn==NULL)
		*(deffn = (string) malloc(1)) = 0;

	sprintf(  _IF[0],"Select %s", t );
	newfn = FileSelect( _IF , deffn );
	if( deffn )
		free(deffn);

	if( newfn ) {				//======== RAUL FIX ==|
		if (! *newfn) {			// PREVIOUS ENFORCER ERROR HERE
			free(newfn);
			return NULL;
		}
		if (inpm)
			r = OpenIn(f, newfn);
		else
		if (fclose(fopen(newfn, "r"))==EOF || InfoBoxOld(_OUTE)=='y')
			r = OpenOut(f, newfn);
		if (!r) {
			free(newfn);
			return NULL;
		}
	}
	return newfn;
}

int MKTest(bfile f)
/* Returns: The number of samples in the Module file f */
{
	unsigned long offset;
	int i = 15;
	char s[4];

	offset = ftell(f->f);
	if (!fseek(f->f, 1080, SEEK_SET)) {
		fread(s, 1, 4, f->f);
		if (!memcmp(s,"M.K.",4) || !memcmp(s,"M!K!",4) || !memcmp(s,"FLT4",4))
			i = 31;
		else if (!memcmp(s,"FLT8",4))
			i = 0;
	}
	fseek(f->f, offset, SEEK_SET);
	return i;
}

string SimplifyName(string s)
/*
 * Returns: A string similar to s, but has had any nasty headers removed
 *    any leading spaces or trailing spaces, and all made lower-case with
 *    any intermediate spaces replaced by underbar-characters
 */
{
	string t, r, x;

	x = strchr(s, ':');
	if (x != NULL && x-s == 5 && tolower(s[0])=='s' && tolower(s[1])=='t' &&
	 s[2]=='-') {
		r = x = (string) malloc(18);
		t = s + 6;
		while (*(x++) = *(t++)); /* remove soundtracker header */
	} else
		strcpy(r = (string) malloc(1+strlen(s)), s); /* strdup? */
	for (t = r; *t == ' '; t++);
	x = r;
	while (*(x++) = *(t++)); /* remove leading spaces */
	if (*r) {
		x--;
		while (*(--x) == ' ') /* remove trailing spaces */
			*x = 0;
	}
	for (x = r; *x; x++) /* fill intermediate spaces with _ */
		if (*x == ' ')
			*x = '_';
	if( r ){
		t = r = (string) realloc(r, strlen(r) + 1);
	}
	for (; *t; t++)
		*t = tolower(*t); /* make the lot lower-case */
	return r;
}

string GetLine(FILE *f)
/* Returns: Next line from file f, NULL on error/eof */
{
	string s, t;
	int c;

	if ((t = s = (string) malloc(MAXSTRING))==NULL) {
		InfoBox(_OOME);
		return NULL;
	}
	while ((c = fgetc(f)) != EOF && c != '\n')
		*(t++) = c;
	if (s == t) {
		free(s);
		return NULL;
	}
	*t = 0;
	return (string) realloc(s, t-s+1);
}

int ReadModSpecs(bfile f, string n, samps s)
/*
 * Returns: Z if f is not a supported Amiga Module, else n is set to
 * be the name of the Module and s is set to hold sample information
 */
{
	unsigned char b, c;
	int i, okmodule;
	string t1;
	samp *t2;

	for (i = 20, t1 = n; i--; *(t1++) = InByte(f));
	okmodule = !*n || isprint(*n);
	*t1 = 0;
	c = s->n = MKTest(f);
	okmodule = okmodule && c;
	for (t2 = s->s; c--; t2++) {
		for (i = 22, t1 = t2->n; i--; *(t1++) = InByte(f));
		okmodule = okmodule && (!*(t2->n) || isprint(*(t2->n)));
		*t1 = 0;
		b = InByte(f);
		t2->l = 256 * b + InByte(f);
		if (t2->l < 4)
			t2->l = 0;    /* if the sample is this small, not worth processing */
		b = InByte(f);
		t2->v = InByte(f);
		InByte(f);
		InByte(f);
		b = InByte(f);
		if (256 * b + InByte(f) > 1 && t2->l)
			t2->l = -1;    /* looping: plays 'forever' */
		t2->m = 0;
	}

	return !feof(f->f) && okmodule;
}

void ScanSamples(samps s)
/*
 * Post: Sample data for ModFile has been scanned and samples in s have
 * been given "reasonable" values for volume shifting and transpositions
 * I hope :)
 */
{
	samp *sam;
	unsigned int maxpat = 0, i, j, k;
	unsigned char x;
	signed char c[SCANSIZE];      /* look at first SCANSIZE bytes of sample */
	signed char max, min, *p;
	unsigned long offset, len, lenarry[31];
	long sum;
	double ratio, junk;

	offset = ftell(ModFile->f);
	fseek(ModFile->f, 42, SEEK_SET);
	for (i = 0; i < s->n; i++) {    /* need to get actual lengths */
		fread(&x, 1, 1, ModFile->f);
		lenarry[i] = 256 * x;
		fread(&x, 1, 1, ModFile->f);
		lenarry[i] += x;
		lenarry[i] *= 2;
		fseek(ModFile->f, 28, SEEK_CUR);
	}
	fseek(ModFile->f, 20 + 30 * s->n, SEEK_SET);
	fread(&x, 1, 1, ModFile->f);
	fread(c, 1, 129, ModFile->f);
	for (; x; x--)
		if (c[x] > maxpat)
			maxpat = c[x];
	len = 1024L * (maxpat + 1) + 30 * s->n + ((s->n > 30) ? 4 : 0) + 150;
	fseek(ModFile->f, len, SEEK_SET);
	for (i = 0, sam = s->s; i < s->n; i++, sam++) {
		sam->t[0] = 0; /* set transposition values to 0 */
		sam->t[1] = 0;
		sam->t[2] = 0;
		sam->a[0] = 0;
		if (!sam->l) {
			sam->a[1] = 1; /* no sample = no volume shifting */
			sam->a[2] = 1;
			fseek(ModFile->f, lenarry[i], SEEK_CUR);
		} else {
			len = min(lenarry[i], SCANSIZE);
			if (!(j = len = fread(c, 1, len, ModFile->f)))
				len = 1;
			fseek(ModFile->f, lenarry[i] - j, SEEK_CUR);
			min = 127;
			max = -128;
			sum = 0;
			for (p = c; j--; p++) {
				sum += *p;
				if (*p > max)
					max = *p;
				if (*p < min)
					min = *p;
			}
			ratio = 1.0 * sum / len;  /* get average .. normally ~0 */
			if (fabs(max - ratio) > fabs(min - ratio))
				ratio = fabs(min - ratio) / 64.0;
			else
				ratio = fabs(max - ratio) / 64.0;
			j = k = 1;
			while (k++ < 15)    /* now find decent rational approx. */
				if (fabs(modf(ratio * k, &junk)-.5) > fabs(modf(ratio * j, &junk)-.5))
					j = k;
			if (!(sam->a[1] = ratio * j + 0.5)) {
				sam->a[1] = 1;   /* if really small scaling needed.. */
				sam->a[2] = 16;
			} else
				sam->a[2] = j;
		}
	}
	fseek(ModFile->f, offset, SEEK_SET);
}

int SetDefaults(samps s, string fn)
/*
 * Returns: NZ if the samples in s have been sucessfully allocated default
 *    values corresponding to definitions in the DEF_MAPFILE file, and from
 *    a .mm file corresponding to the filename fn
 */
{
	FILE *f;
	char i, m[MAXSTRING+200];
	int d, e[6], v;
	samp *sam;
	string n, t;
	bfile mmf;

printf("setdef\n");

printf("sd: strlen(fn)=%d\n",strlen(fn));
	t = strchr(strcpy(m, fn), '.');
	if (t==NULL) {
		i = strlen(m);
		m[i] = '.';
	}
	else
		i = t-m;

	m[++i] = 'm';
	m[++i] = 'm';
	m[++i] = 0;
	mmf->f = NULL;
	if( OpenIn(mmf, m) ) {
printf("sd: p1\n");
		for (i = s->n, sam = s->s; i--; sam++) {
printf("sd: p2\n");
			sam->m = InByte(mmf);
			sam->t[0] = (signed char) InByte(mmf);
			sam->t[1] = (signed char) InByte(mmf);
			sam->t[2] = (signed char) InByte(mmf);
			sam->a[0] = (signed char) InByte(mmf);
			sam->a[1] = (signed char) InByte(mmf);
			sam->a[2] = (signed char) InByte(mmf);
		}
		CloseIn(mmf);
printf("sd-00\n");
	}
	else {
printf("sd: scansamples()\n");
		ScanSamples(s);
	}
printf("sd: scansamples() end.\n");

	if( !(f = fopen( Def_Map_filename , "rt")) ) {
printf("fopen=%d\n",f=fopen( Def_Map_filename , "r") );
		_NOFIL[2] = Def_Map_filename;
		InfoBox(_NOFIL);
printf("sd-0\n");
		return 0;
	}
	i = s->n;
printf("sd-1\n");
	for (sam = s->s; i--; sam++) {
		if (sam->l) {
			n = SimplifyName(sam->n);
			t = GetLine(f);
			e[3] = 0;       /* These are the default volume constants */
			e[4] = 1;
			e[5] = 1;
			sscanf(t, "%s %d %d %d %d %d %d %d", m, &d, &e[0], &e[1], &e[2],
				&e[3], &e[4], &e[5]);
			if ((v = strcmp(m, n))>0) {
				rewind(f);
				if(t) free(t);
				t = GetLine(f);
				e[3] = 0;
				e[4] = 1;
				e[5] = 1;
				sscanf(t, "%s %d %d %d %d %d %d %d", m, &d, &e[0], &e[1], &e[2],
					&e[3], &e[4], &e[5]);
				v = strcmp(m, n);
			}
			if(t) free(t);
			while (v < 0 && (t = GetLine(f)) != NULL) {
				e[3] = 0;
				e[4] = 1;
				e[5] = 1;
				sscanf(t, "%s %d %d %d %d %d %d %d", m, &d, &e[0], &e[1], &e[2],
					&e[3], &e[4], &e[5]);
				if(t) free(t);
				v = strcmp(m, n);
			}
			if (!v) {
				sam->m = d;
				sam->t[0] = e[0];
				sam->t[1] = e[1];
				sam->t[2] = e[2];
				sam->a[0] = e[3];
				sam->a[1] = e[4];
				sam->a[2] = e[5];
			}
			if(n) free(n);
		}
	}
	fclose(f);
	return 1;
}

void SaveDefaults(samps s, string fn)
/*
 * Post: The samples attributes in s have been written to a .mm file
 *   corresponding to the filename fn
 */
{
	char m[MAXSTRING];
	string t;
	char i;
	bfile mmf;
	samp *sam;

	t = strchr(strcpy(m, fn), '.');
	if (t==NULL) {
		i = strlen(m);
		m[i] = '.';
	} else
		i = t-m;
	m[++i] = 'm';
	m[++i] = 'm';
	m[++i] = 0;
	mmf->f = NULL;
	if (!OpenOut(mmf, m))
		return;
	for (i = s->n, sam = s->s; i--; sam++) {
		OutByte(mmf, sam->m);
		OutByte(mmf, sam->t[0]);
		OutByte(mmf, sam->t[1]);
		OutByte(mmf, sam->t[2]);
		OutByte(mmf, sam->a[0]);
		OutByte(mmf, sam->a[1]);
		OutByte(mmf, sam->a[2]);
	}
	CloseOut(mmf);
}

void NullArryFree(string *sp)
/* Post: The NULL-terminated array sp is gone */
{
	string *t;

	t = sp;
	while (*t != NULL)
		free(*(t++));
	free(sp);
}

int Instrument( void )
/* Returns: MIDI instrument selected from file DEF_INSFILE */
{
	static int w = 0, doff = -1;
	static string *sp = NULL;
	int c;

	if (sp == NULL) {
		FILE *f;
		string *t, s;
		int x, i = 1;

		if ((f = fopen(DEF_INSFILE, "rt"))==NULL) {
			_NOFIL[2] = DEF_INSFILE;
			InfoBox(_NOFIL);
			return -1;
		}
		if ((t = sp = (string *) malloc(257 * sizeof(string)))==NULL) {
			InfoBox(_OOME);
			return -1;
		}
		while ((s = GetLine(f)) != NULL)
			if (x = strlen(s)) { /* ignore blank lines */
				i++;
				if (x > w)
					w = x;
				*(t++) = s;
				if (doff < 0 && *s=='D')  /* take note of first drum position */
					sscanf(s, "D%d ", &doff);
			}
		*t = NULL;
		sp = (string *) realloc(sp, i * sizeof(string)); /* i <= 257 */
		fclose(f);
	}
	c = ScrollChoice("MIDI Instruments", sp, w);
	if (c>127)
		c += doff;
	return c;
}

string MIDIVal(samp *sam)
/* Returns: a string representing the MIDI instrument *sam */
{
	string s;

	s = (string) malloc(5);
	if (sam->m < 128)
		sprintf(s, "%4d", (int)(sam->m+1) );
	else
		sprintf(s, "D%3d", sam->m - 128);
	return s;
}

string TransVal(samp *sam)
/* Returns: a string representing the transpose amount of *sam */
{
	string s;

	s = (string) malloc(15);
	if (!sam->t[1])
		sprintf(s, "          %4d", sam->t[0]);
	else if (!sam->t[2])
		sprintf(s, "     %4d,%4d", sam->t[0], sam->t[1]);
	else
		sprintf(s, "%4d,%4d,%4d", sam->t[0], sam->t[1], sam->t[2]);
	return s;
}

string VolumeVal(samp *sam)
/* Returns: a string representing the volume shifting formula for *sam */
{
	string s;

	s = (string) malloc(17);
	if (sam->a[0] < 0)
		sprintf(s, "(? -%3d)*%3d/%3d", abs(sam->a[0]), sam->a[1], sam->a[2]);
	else
		sprintf(s, "(? +%3d)*%3d/%3d", sam->a[0], sam->a[1], sam->a[2]);
	return s;
}

string NullVal(samp *sam)
/* Returns: an empty string */
{
	string s;

	*(s = (string) malloc(1)) = 0;
	return s;
}

int Sample(samps s, string (*MIDIVal)(samp *x), int w)
/* Returns: Sample selected from list of samples, -1 on error */
{
	string *sp, *t, p;
	samp *sam;
	int i;

	if ((t = sp = (string *) malloc((s->n + 1) * sizeof(string)))==NULL) {
		InfoBox(_OOME);
		return -1;
	}
	for (i = s->n, sam = s->s; i--; sam++) {
		*t = (string) malloc(25 + w);
		p = MIDIVal(sam);
		sprintf(*t, "%c%-22s %s", (sam->l) ? '*' : ' ', sam->n, p);
		free(p);
		t++;
	}
	*t = NULL;
	i = ScrollChoice("Select Sample", sp, 24 + w);
	NullArryFree(sp);
	return i;
}

int ChooseChannels(samps s)
/*
 * Returns: The number of different channels needed to play instruments. If
 *    that number is not greater than 16, upto 16 channels will be allocated
 *    to the samples.
 */
{
	unsigned char c, d = 0, i[128], m, n, numchan;
	samp *sam1, *sam2;

	n = s->n;
	sam1 = s->s;
	memset(i, 0, 128);
	for (n = s->n, sam1 = s->s; n--; sam1++) {
		sam1->c = -1;
		if (sam1->l)
			if (sam1->m > 127) {
				d = 1;
				sam1->c = DrumChann;
			} else
				i[sam1->m] = 1;
		else
			sam1->m = 0;
	}
	for (numchan = d, n = 128; n--; numchan += i[n]);
	if (numchan > 16)
		return numchan;
	/* Ok.. now we must go through and set channels appropriately */
	m = s->n;
	sam1 = s->s;
	c = 0;
	while (m--) {
		if (sam1->c < 0) {
			sam1->c = c;
			n = m;
			sam2 = sam1 + 1;
			while (n--) {
				if (sam2->c < 0)
					if (sam2->m == sam1->m || ! sam2->l)
						sam2->c = c;
				sam2++;
			}
			if (++c == DrumChann && d)
				c++;
		}
		sam1++;
	}
	return numchan;
}

void MapSamples(samps s)
/* Post: The samples s have been allocated appropriate instruments, we hope */
{
	int i, j;

	do
		if ((i = Sample(s, MIDIVal, 4))>=0 && (j = Instrument())>=0)
			s->s[i].m = j;
	while (i>=0);
}

void SaveSamp(samp sam)
/* Post: The sample sam has been updated in the DEF_MAPFILE file */
{
	FILE *f1, *f2;
	string s, n;
	int v, d;
	char m[MAXSTRING];

	if (!sam.l)
		return;
	if ((f1 = fopen( Def_Map_filename, "rt")) == NULL) {
		_NOFIL[2] = Def_Map_filename;
		InfoBox(_NOFIL);
		return;
	}
	f2 = fopen("temp.tmp", "wt");
	n = SimplifyName(sam.n);
	v = 1;
	while (v > 0 && (s = GetLine(f1)) != NULL) {
		sscanf(s, "%s %d", m, &d);
		if ((v = strcmp(n, m)) <= 0) {
			fprintf(f2, "%s %d %d %d %d %d %d %d\n", n, sam.m, sam.t[0], sam.t[1],
				sam.t[2], sam.a[0], sam.a[1], sam.a[2]);
			free(n);
			n = NULL;
			if (v)
				fprintf(f2, "%s\n", s);
		} else
			fprintf(f2, "%s\n", s);
		free(s);
	}
	while ((s = GetLine(f1))!=NULL) {
		fprintf(f2, "%s\n", s);
		free(s);
	}
	if (n != NULL) {
		fprintf(f2, "%s %d %d %d %d %d %d %d\n", n, sam.m, sam.t[0], sam.t[1],
			sam.t[2], sam.a[0], sam.a[1], sam.a[2]);
		free(n);
	}
	fclose(f2);
	fclose(f1);
	if (unlink( Def_Map_filename )<0 || rename("temp.tmp", Def_Map_filename)<0)
		InfoBox(_NOSAV);
}

void SaveSamples(samps s)
/* Post: The desired sample attributes of s have been saved to disk */
{
	int i;

	do
		if ((i = Sample(s, NullVal, 0))>=0)
			SaveSamp(s->s[i]);
	while (i>=0);
}

void Transpositions(samps s)
/* Post: All necessary transpositions have been applied to the samples s */
{
	int i;

	do {
		if ((i = Sample(s, TransVal, 16))>=0) {
			char s1[41];
			string s2;
			samp *sam;

			sam = s->s + i;
			if (!sam->t[1])
				sprintf(s1, "%d", sam->t[0]);
			else if (!sam->t[2])
				sprintf(s1, "%d,%d", sam->t[0], sam->t[1]);
			else
				sprintf(s1, "%d,%d,%d", sam->t[0], sam->t[1], sam->t[2]);
			s2 = DialogBox(_TRAQ, s1);
			sam->t[1] = 0;
			sam->t[2] = 0;
			sscanf(s2, "%d,%d,%d", &sam->t[0], &sam->t[1], &sam->t[2]);
			free(s2);
			if ((sam->t[0] || sam->t[1]) && sam->m > 127)
				InfoBox(_TRANWRN);
			if (sam->t[0]<-128 || sam->t[0]>127 || sam->t[1]<-128 ||
			 sam->t[1]>127 || sam->t[2]<-128 || sam->t[2]>127) {
				InfoBox(_TRANE);
				sam->t[0] = 0;
				sam->t[1] = 0;
				sam->t[2] = 0;
			}
		}
	} while (i>=0);
}

void VolumeShifts(samps s)
/* Post: All volume shifting formulae have been defined for the samples s */
{
	int i;

	do
		if ((i = Sample(s, VolumeVal, 16))>=0) {
			char s1[41];
			string s2;
			samp *sam;

			sam = s->s + i;
			sprintf(s1, "%d,%d,%d", sam->a[0], sam->a[1], sam->a[2]);
			s2 = DialogBox(_VSHQ, s1);
			if (sscanf(s2, "%d,%d,%d", &sam->a[0], &sam->a[1], &sam->a[2])!=3 ||
			 sam->a[0] > 127 || sam->a[0] < -128 || sam->a[1] > 127 ||
			 sam->a[1] < 0 || sam->a[2] > 127 || sam->a[2] < 1) {
				InfoBox(_VSHE);
				sam->a[0] = 0;
				sam->a[1] = 1;
				sam->a[2] = 1;
			}
			free(s2);
		}
	while (i>=0);
}

void SetDrumChannel( void )
/* Post: Drum channel is set to desired value - 1 */
{
	string s;
	char s2[3];

	sprintf(s2, "%d", DrumChann+1);
	s = DialogBox(_DCQ, s2);
	if (sscanf(s, "%d", &DrumChann))
		DrumChann--;        /* Drum channel is stored as value - 1 */
}

void SetTempoType( void )
/* Post: Tempo interpretting will either be extended or normal */
{
	char inp;

	while ((inp = InfoBoxOld(TempoType ? _TTQ1 : _TTQ0)) != '0' && inp != '1');
	TempoType = inp - '0';
}

unsigned char NoteValue(unsigned int n)
/* Returns: MIDI note equivalent of MOD period-lengths */
{
	static unsigned int t[72] = {
		1712, 1616, 1525, 1440, 1357, 1281, 1209, 1141, 1077, 1017, 961, 907,
		856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
		428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
		214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113,
		107, 101, 95, 90, 85, 80, 76, 71, 67, 64, 60, 57,
		53, 50, 48, 45, 42, 40, 38, 36, 34, 32, 30, 28
		};
	signed char a = 0, m = 35, b = 71;

	if (!n)
		return 0;
	for (; b-a > 1; m = (a + b) / 2) /* binary search */
		if (t[m] < n)
			b = m;
		else
			a = m;
	if (n - t[b] < t[a] - n) /* choose closest value */
		return (unsigned char)(b + 36);
	return (unsigned char)(a + 36);
}

unsigned long NoteLength(unsigned char n, unsigned int l, unsigned int b)
/* Returns: # of ticks to play note length l at pitch n, b beats/min */
{
    unsigned long  idx;

	static float t[84] = {
		3.200e-3, 3.020e-3, 2.851e-3, 2.691e-3, 2.540e-3, 2.397e-3,
		2.263e-3, 2.136e-3, 2.016e-3, 1.903e-3, 1.796e-3, 1.695e-3,
		1.600e-3, 1.510e-3, 1.425e-3, 1.345e-3, 1.270e-3, 1.197e-3,
		1.131e-3, 1.068e-3, 1.008e-3, 9.514e-4, 8.980e-4, 8.476e-4,
		8.000e-4, 7.551e-4, 7.127e-4, 6.727e-4, 6.350e-4, 5.993e-4,
		5.657e-4, 5.339e-4, 5.040e-4, 4.757e-4, 4.490e-4, 4.238e-4,
		4.000e-4, 3.775e-4, 3.564e-4, 3.364e-4, 3.175e-4, 2.997e-4,
		2.828e-4, 2.670e-4, 2.520e-4, 2.378e-4, 2.245e-4, 2.119e-4,
		2.000e-4, 1.888e-4, 1.782e-4, 1.682e-4, 1.587e-4, 1.498e-4,
		1.414e-4, 1.335e-4, 1.260e-4, 1.189e-4, 1.122e-4, 1.059e-4,
		1.000e-4, 9.439e-5, 8.909e-5, 8.409e-5, 7.937e-5, 7.492e-5,
		7.071e-5, 6.674e-5, 6.300e-5, 5.946e-5, 5.612e-5, 5.297e-5,
		5.000e-5, 4.719e-5, 4.454e-5, 4.204e-5, 3.969e-5, 3.746e-5,
		3.536e-5, 3.337e-5, 3.150e-5, 2.973e-5, 2.806e-5, 2.649e-5
		}; /* multipliers for each pitch: 12th roots of 2 apart */

	idx = (n - 36);
	if( idx < 0 ) idx = 0;
	if( idx > 84 ) idx = 84;

	return ( idx * b * l); /* better not slide out of this range :( */
}

void WriteHeader(bfile mf, unsigned char n)
/* Post: The MIDI header has been written to mf, with #tracks = n */
{
	static unsigned char MIDIH[14] = {
		77, 84, 104, 100, 0, 0, 0, 6, 0, 1, 0, 255, 0, 192
	};
	int i = 0;

	MIDIH[11] = n+1;
	while (i < 14)
		OutByte(mf, MIDIH[i++]);
}

unsigned int Trk0Info(bfile mf, string s)
/*
 * Returns: the number of bytes written as track 0 so far, given mf as the
 *    output MIDI file. s is the name of the tune.
 */
{
	unsigned char name[]= {"*File Copyright (c) 1994 ProJeCT23 SoftWare"};

	static unsigned char TRK0I[63] = {
		0, 255, 2, 42, 70, 105, 108, 101, 32, 67, 111, 112, 121, 114, 105, 103,
		104, 116, 32, 40, 99, 41, 32, 49 ,57, 57, 51, 32, 65, 100, 114, 101, 110,
		97, 108, 105, 110, 32, 83, 111, 102, 116, 119, 97, 114, 101,
		0, 255, 88, 4, 3, 2, 24, 8,
		0, 255, 89, 2, 0, 0,
		0, 255, 3
		}; /* standard header + copyright message */
	unsigned int i = 0;

	strncpy( &TRK0I[3], name, strlen( name ) );

	while (i < 63)
		OutByte(mf, TRK0I[i++]);
	i = 64 + strlen(s);
	OutByte(mf, strlen(s));
	while (*s)
		OutByte(mf, *(s++));
	return i;
}

void AddToLog(unsigned long a, unsigned long b)
/* Post: a (file position) and b (number) have been added to the log */
{
	PosLog[PosI++] = b;
	PosLog[PosI++] = a;
}

void WriteLog(FILE *f)
/* Post: PosLog has been written into file f */
{
	unsigned long x, y;
	unsigned char c[4];

	if (!PosI)
		return;
	x = ftell(f);
	while (PosI) {
		fseek(f, PosLog[--PosI], SEEK_SET);
		y = PosLog[--PosI];
		c[3] = y & 255;
		y >>= 8;
		c[2] = y & 255;
		y >>= 8;
		c[1] = y & 255;
		y >>= 8;
		c[0] = y;
		fwrite(c, 1, 4, f);
	}
	fseek(f, x, SEEK_SET);
}

unsigned char RestrictVol(int v)
/* Returns: A volume in the range 0..127 */
{
	if (v < 0)
		return 0;
	else
		return (unsigned char)( (v > 127) ? 127 : v );
}





void ConvertMOD(bfile f1, bfile f2, string tn, samps smp)
/*
 * Post: The Amiga MODfile f1 has been converted and written to MIDI file f2,
 *    using instrument mappings smp. Tune has a name tn.
 */
{
	unsigned char b, length, pattern[128];
	string n, t;
	unsigned int i, j, k, tempdone = 0;
	samp *sam;
	struct bpos p1, p2;

	p1 = FPos(f1);
	length = InByte(f1);
	InByte(f1);
	for (i = 0; i < 128; pattern[i++] = InByte(f1));
	Inskipp(f1, (smp->n > 15) ? 4 : 0);
//	WriteHeader(f2, smp->n);
	WriteHeader(f2, numoftracks );				// RAUL addition
	p2 = FPos(f1);
	for (i = 0, sam = smp->s - 1; i <= smp->n; sam++, i++) {
		unsigned long cnt, inst, timer, delay[4];
		unsigned char c;

		//====== RAUL addition, if sample has length then convert that sample
		if( sam->l ) {
			OutByte(f2, 77);		// "MKtr"
			OutByte(f2, 84);
			OutByte(f2, 114);
			OutByte(f2, 107);
			inst = Beatle(f2); /* store this position so can set AFTERWARDS - hehe */
			OutByte(f2, 0);
			OutByte(f2, 0);
			OutByte(f2, 0);
			OutByte(f2, 0);
			if (!i)
				cnt = Trk0Info(f2, tn);
			else {
				OutByte(f2, 0);
				OutByte(f2, 255);
				OutByte(f2, 3);
				b = strlen(n = sam->n);
				OutByte(f2, b);
				cnt = 7 + b;
				while (b--)
					OutByte(f2, *(n++));
				c = sam->c;
				OutByte(f2, 0);
				OutByte(f2, 0xC0 + c); /* set channel */
				if( sam->m == 0 )
					OutByte(f2, 0 );
				else
					OutByte(f2, (sam->m > 127) ? 126 : (sam->m));
			}
		}

		timer = 0;
		if (sam->l || !i) {
			unsigned int bpm, ticks, l, effect, h;
			unsigned char sampnum, lastsam[4] = {0}, vol[4];
			signed char patbreak;
			unsigned long x, pause;
			int note, lastslide, slideto;
			int n[4][48][2]; /* note data for a song position */
			int lastn[4]; /* last note on a particular channel */

			sprintf(_CNVPOS[2]+7, "%d", i); /* some compilers hate this */
			DrawBox(_CNVPOS);
			memset(lastn, 0, 4 * sizeof(int));
			memset(vol, 0, 4);
			memset(delay, 0, 4 * sizeof(long));
			bpm = 125;
			ticks = 6;
			lastslide = slideto = 0;
			patbreak = 0;
			for (h = 48; h--; )
				for (k = 4; k--; )
					n[k][h][0] = 0;
			for (l = 0; l < length; l++) {
				if (pattern[l]<=pattern[l-1] || !l) {
					FGoto(f1, p2);
					x = (unsigned) 1024 * pattern[l];
				} else
					x = (unsigned) 1024 * (pattern[l]-pattern[l-1]-1);
				Inskipp(f1, x);
				j = 64;
				if (patbreak>0)
					patbreak = 1-patbreak;
				while (j--) {
					pause = 0;
					if (patbreak)
						Inskipp(f1, 16);
					else
						for (k = 0; k < 4; k++) {
							n[k][0][1] = sam->v;
							sampnum = InByte(f1);
							note = ((sampnum & 15) << 8) + InByte(f1);
							effect = InByte(f1);
							sampnum = (sampnum & ~15) + (effect >> 4);
							if (!i)
								note = 0;
							if ((note || sampnum) && delay[k]) { /* stop old note */
								cnt += 3 + WriteVLQ(f2, timer);
								timer = 0;
								OutByte(f2, 0x80 + c); /* note off */
								OutByte(f2, ENOTE(lastn[k], 0));
								OutByte(f2, RestrictVol(EVOL(vol[k])));
								if (sam->t[1]) {
									cnt += 4;
									OutByte(f2, 0);
									OutByte(f2, 0x80 + c);
									OutByte(f2, ENOTE(lastn[k], 1));
									OutByte(f2, RestrictVol(EVOL(vol[k])));
									if (sam->t[2]) {
										cnt += 4;
										OutByte(f2, 0);
										OutByte(f2, 0x80 + c);
										OutByte(f2, ENOTE(lastn[k], 2));
										OutByte(f2, RestrictVol(EVOL(vol[k])));
									}
								}
								delay[k] = 0;
							}
							if (!note && sampnum == i) /* check "defaults" */
								note = lastn[k];
							else if (!sampnum)
								if (lastsam[k] == i)
									sampnum = i;
								else
									note = 0;
							else {
								if (sampnum != i)
									note = 0;
								lastsam[k] = sampnum;
							}
							n[k][0][0] = note;
							effect = ((effect & 15) << 8) + InByte(f1);

							switch (effect & 0xF00) {
								case 0x000: { /* arpeggio */
									int nv;

									if (!i || !effect || sam->m > 127)
										break;
									if (!note)
										if (!delay[k])
											break;
										else {
											nv = NoteValue(lastn[k]);
											n[k][47][0] = lastn[k];
											n[k][47][1] = vol[k];
											if (effect & 0x0F0)
												n[k][16][0] = -(nv + ((effect & 0x0F0) >> 4));
											n[k][16][1] = vol[k];
											if (effect & 0x00F)
												n[k][32][0] = -(nv + (effect & 0x00F));
											n[k][32][1] = vol[k];
										}
									else {
										nv = NoteValue(note);
										n[k][47][0] = note;
										n[k][47][1] = sam->v;
										if (effect & 0x0F0)
											n[k][16][0] = -(nv + ((effect & 0x0F0) >> 4));
										n[k][16][1] = sam->v;
										if (effect & 0x00F)
											n[k][32][0] = -(nv + (effect & 0x00F));
										n[k][32][1] = sam->v;
									}
									break;
									}
								case 0x300: /* slide to */
									if (!note && !slideto || note==lastn[k] || sam->m > 127)
										break;
									if (effect & 0x0FF)
										lastslide = effect & 0x0FF;
									else
										lastslide = abs(lastslide);
									if (note)
										slideto = note;
									if (slideto > lastn[k]) {
										n[k][0][0] = lastn[k] + lastslide*(ticks-1);
										if (n[k][0][0] > 856)
											n[k][0][0] = 856;
										if (n[k][0][0] > slideto)
											n[k][0][0] = slideto;
									} else {
										n[k][0][0] = lastn[k] - lastslide*(ticks-1);
										if (n[k][0][0] < 113)
											n[k][0][0] = 113;
										if (n[k][0][0] < slideto)
											n[k][0][0] = slideto;
									}
									n[k][0][1] = vol[k];
									break;
								case 0x100: /* slide up */
								case 0x200: /* slide down */
									if (!(effect & 0x0FF) || sam->m > 127)
										break;
									if (effect & 0x200)
										lastslide = effect & 0x0FF;
									else
										lastslide = -(effect & 0x0FF);
									if (!note)
										if (!delay[k])
											break;
										else {
											n[k][0][0] = lastn[k] + lastslide;
											n[k][0][1] = vol[k];
										}
									else
										n[k][0][0] += lastslide;
									if (n[k][0][0] > 856)
										n[k][0][0] = 856;
									else if (n[k][0][0] < 113)
										n[k][0][0] = 113;
									break;
								case 0x400: /* vibrato */
								case 0x700: /* tremolo */
									/* ignore these effects.. not convertable */
									break;
								case 0x500: /* slide to & volume slide */
									if ((note || slideto) && note!=lastn[k] && sam->m < 128) {
										if (note)
											slideto = note;
										if (slideto > lastn[k]) {
											n[k][0][0] = lastn[k] + lastslide*(ticks-1);
											if (n[k][0][0] > 856)
												n[k][0][0] = 856;
											if (n[k][0][0] > slideto)
												n[k][0][0] = slideto;
										} else {
											n[k][0][0] = lastn[k] - lastslide*(ticks-1);
											if (n[k][0][0] < 113)
												n[k][0][0] = 113;
											if (n[k][0][0] < slideto)
												n[k][0][0] = slideto;
										}
									} else
										n[k][0][0] = 0;
									note = 0;
								case 0x600: /* vibrato & volume slide */
								case 0xA00: { /* volume slide */
									int v;

									if (!note)
										v = vol[k];
									else
										v = sam->v;
									v += (ticks-1)*(effect & 0x0F0); /* can't really slide */
									v -= (ticks-1)*(effect & 0x00F);
									if (v > 127)
										v = 127;
									else if (v < 0)
										v = 0;
									n[k][0][1] = v;
									break;
									}
								case 0x900: /* set offset: pretend it's retrigger */
									if ((!n[k][0][0] || !sampnum) && delay[k]) {
										n[k][0][0] = lastn[k];
										n[k][0][1] = vol[k];
									}
									break;
								case 0xB00: /* position jump: ignore, but break anyway */
									patbreak = 1;
									break;
								case 0xD00: /* pattern break */
									patbreak = 1 + 10 * (effect & 0x0F0) + (effect & 0x00F);
									break;
								case 0xC00: /* set volume */
									{
										int vol = effect;				// CHANGE BY RAUL
										if( vol == 0x40 ) vol=0x3f;
										vol = vol&0x3f;
										n[k][0][1] = vol<<1;
									//	n[k][0][1] = effect&0x7f;
									}
									break;
								case 0xF00: { /* set tempo */
									int temp;

									temp = effect & 0x0FF;
									if (!temp)
										temp = 1;
									if (temp < 32) {
										ticks = temp;
										if (TempoType) {  /* Tempos act strangely so .. */
											bpm = 750 / temp;
											x = 80000 * temp;
										}
									} else {
										bpm = temp;
										x = 60000000 / temp;
									}
									if (i)
										break; /* only write tempo on track 0 */
									cnt += 6 + WriteVLQ(f2, timer);
									timer = 0;
									OutByte(f2, 255); /* meta-event */
									OutByte(f2, 81); /* set tempo */
									OutByte(f2, 3);
									OutByte(f2, x >> 16);
									OutByte(f2, (x >> 8) & 0xFF);
									OutByte(f2, x & 0xFF);
									tempdone = 1;
									break;
									}
								case 0xE00: /* extended effects */
									switch (effect & 0x0F0) {
										case 0x010: /* fine slide up */
											if (!(effect & 0x00F) || sam->m > 127)
												break;
											if (!note)
												if (!delay[k])
													break;
												else {
													n[k][h][0] = lastn[k] + (effect & 0x00F);
													n[k][h][1] = vol[k];
												}
											else
												n[k][h][0] += effect & 0x00F;
											break;
										case 0x020: /* fine slide down */
											if (!(effect & 0x00F) || sam->m > 127)
												break;
											if (!note)
												if (!delay[k])
													break;
												else {
													n[k][h][0] = lastn[k] - (effect & 0x00F);
													n[k][h][1] = vol[k];
												}
											else
												n[k][h][0] -= effect & 0x00F;
											break;
										case 0x000: /* set filter on/off */
										case 0x030: /* glissando on/off */
										case 0x040: /* set vibrato wave */
										case 0x050: /* set finetune */
										case 0x060: /* pattern loop */
										case 0x070: /* set tremolo wave */
										case 0x080: /* un-used */
										case 0x0F0: /* invert loop */
											/* can't do these in MIDI.. ignore */
											break;
										case 0x0A0: /* fine volume slide up */
										case 0x0B0: { /* fine volume slide down */
											int v;

											v = sam->v;
											if (effect & 0x0A0)
												v += effect & 0x00F;
											else
												v -= effect & 0x00F;
											if (v<0)
												v = 0;
											else if (v>127)
												v = 127;
											n[k][0][1] = v;
											break;
											}
										case 0x090: { /* retrigger sample */
											int a, b, c;

											if (!note && !delay[k] || !(effect & 0x00F))
												break;
											a = effect & 0x00F;
											if (!(ticks / a))
												break;
											if (!note) {
												n[k][0][0] = lastn[k];
												n[k][0][1] = vol[k];
											}
											c = 0;
											b = 1;
											a *= 48;
											while (c < 48) {
												n[k][c][0] = note;
												n[k][c][1] = n[k][0][1];
												c = b * a / ticks;
												b++;
											}
											break;
											}
										case 0x0C0: { /* cut sample */
											int a;

											if (!note && !delay[k])
												break;
											a = 48 * (effect & 0x00F) / ticks;
											if (a > 47)
												break;
											if (note)
												n[k][a][0] = note;
											else
												n[k][a][0] = lastn[k];
											n[k][a][1] = 0;
											break;
											}
										case 0x0D0: { /* delay sample */
											int a;

											if (!note || !(effect & 0x00F))
												break;
											a = 48 * (effect & 0x00F) / ticks;
											n[k][0][0] = 0;
											if (a > 47)
												break;
											n[k][a][0] = note;
											n[k][a][1] = n[k][a][0];
											break;
											}
										case 0x0E0: /* pattern pause */
											pause = 48 * (effect & 0x00F);
											break;
									}
									break;
								/* else dunno what it does.. disbelieve it ;) */
							}
						}
					for (h = 0; h<48; h++) {
						for (k = 0; k < 4; k++)
							if (n[k][h][0]) {
								if (delay[k]) { /* turn off old note on same channel */
									cnt += 3 + WriteVLQ(f2, timer);
									timer = 0;
									OutByte(f2, 0x80 + c); /* note off */
									OutByte(f2, ENOTE(lastn[k], 0));
									OutByte(f2, RestrictVol(EVOL(vol[k])));
									if (sam->t[1]) {
										cnt += 4;
										OutByte(f2, 0);
										OutByte(f2, 0x80 + c);
										OutByte(f2, ENOTE(lastn[k], 1));
										OutByte(f2, RestrictVol(EVOL(vol[k])));
										if (sam->t[2]) {
											cnt += 4;
											OutByte(f2, 0);
											OutByte(f2, 0x80 + c);
											OutByte(f2, ENOTE(lastn[k], 2));
											OutByte(f2, RestrictVol(EVOL(vol[k])));
										}
									}
									delay[k] = 0;
								}
								lastn[k] = n[k][h][0];
								n[k][h][0] = 0;
								vol[k] = n[k][h][1];
								cnt += 3 + WriteVLQ(f2, timer);
								timer = 0;
								OutByte(f2, 0x90 + c); /* note on */
								OutByte(f2, ENOTE(lastn[k], 0));
								OutByte(f2, RestrictVol(EVOL(vol[k])));
								if (sam->t[1]) {
									cnt += 4;
									OutByte(f2, 0);
									OutByte(f2, 0x90 + c);
									OutByte(f2, ENOTE(lastn[k], 1));
									OutByte(f2, RestrictVol(EVOL(vol[k])));
									if (sam->t[2]) {
										cnt += 4;
										OutByte(f2, 0);
										OutByte(f2, 0x90 + c);
										OutByte(f2, ENOTE(lastn[k], 2));
										OutByte(f2, RestrictVol(EVOL(vol[k])));
									}
								}
								delay[k] = NoteLength(ANOTE(lastn[k]), sam->l, bpm);
							} else if (delay[k]==1) {
								delay[k] = 0;
								cnt += 3 + WriteVLQ(f2, timer);
								timer = 0;
								OutByte(f2, 0x80 + c); /* note off */
								OutByte(f2, ENOTE(lastn[k], 0));
								OutByte(f2, RestrictVol(EVOL(vol[k])));
								if (sam->t[1]) {
									cnt += 4;
									OutByte(f2, 0);
									OutByte(f2, 0x80 + c);
									OutByte(f2, ENOTE(lastn[k], 1));
									OutByte(f2, RestrictVol(EVOL(vol[k])));
									if (sam->t[2]) {
										cnt += 4;
										OutByte(f2, 0);
										OutByte(f2, 0x80 + c);
										OutByte(f2, ENOTE(lastn[k], 2));
										OutByte(f2, RestrictVol(EVOL(vol[k])));
									}
								}
							} else if (delay[k]>0)
								delay[k]--;
						timer++;
					}
					timer += pause;
					if (patbreak<0)
						patbreak++;
					else if (patbreak>0) {
						patbreak = 1 - patbreak;
						while (j) {
							j--;
							Inskipp(f1, 16); /* 16 bytes / song position */
						}
					}
				}
			}
			for (k = 0; k < 4; k++)
				if (delay[k]) {
					cnt += 3 + WriteVLQ(f2, timer);
					timer = 0;
					OutByte(f2, 0x80 + c); /* note off */
					OutByte(f2, ENOTE(lastn[k], 0));
					OutByte(f2, RestrictVol(EVOL(vol[k])));
					if (sam->t[1]) {
						cnt += 4;
						OutByte(f2, 0);
						OutByte(f2, 0x80 + c);
						OutByte(f2, ENOTE(lastn[k], 1));
						OutByte(f2, RestrictVol(EVOL(vol[k])));
						if (sam->t[2]) {
							cnt += 4;
							OutByte(f2, 0);
							OutByte(f2, 0x80 + c);
							OutByte(f2, ENOTE(lastn[k], 2));
							OutByte(f2, RestrictVol(EVOL(vol[k])));
						}
					}
				}
		}
		if(!i && !tempdone) {
			cnt += 7;
			OutByte(f2, 0); /* give the default 128 bpm if none done yet */
			OutByte(f2, 255);
			OutByte(f2, 81);
			OutByte(f2, 3);
			OutByte(f2, 7);
			OutByte(f2, 39);
			OutByte(f2, 14);
		}
		if( sam->l ) {								// RAUL addition
			cnt += 3 + WriteVLQ(f2, timer);
			OutByte(f2, 255);
			OutByte(f2, 47);
			OutByte(f2, 0);
			AddToLog(inst, cnt); /* process this later */
			FGoto(f1, p2);
		}
	}
	ClearWin();
	FlushOut(f2);
	WriteLog(f2->f);
	FGoto(f1, p1);
}

int main(int argc, char *argv[])
{
	int c;

	printf("Mod2midi converter © 1994 Feb, by Raul Sobon\n");

	MainWindow("MOD2MIDI 1.1 - Amiga Sound/Protracker to MIDI converter",
		4, "File", 'f', "Samples", 's', "Options", 'o', "Help", 'h');

/*	SetMenu(0, 6, "Dest. midi",'d',0, "Source mod",'s',1, "------------",-1,-1,
		"Convert",'c',2, "------------",-1,-1, "Quit",'q',99);
	SetMenu(1, 5, "Map samples",'m',3, "Transposing",'t',6, "Volume shift",'v',9,
		"------------",-1,-1, "Save info",'s',4);
	SetMenu(2, 2, "Drum channel",'d',7, "Tempo type",'t',8);
	SetMenu(3, 1, "About",'a',5);
*/
	MidFile->f = ModFile->f = NULL;
	MidFN = ModFN = NULL;
	if (argc>2) {
		strcpy(MidFN = (string) malloc(strlen(argv[2])+1), argv[2]);
		if (fclose(fopen(MidFN, "r"))==EOF || InfoBoxOld(_OUTE)=='y')
			OpenOut(MidFile, MidFN);
		if (MidFile->f==NULL) {
			free(MidFN);
			MidFN = NULL;
		}
	}
	if (argc>1) {
		strcpy(ModFN = (string) malloc(strlen(argv[1])+1), argv[1]);
		if (OpenIn(ModFile, ModFN))
			if (!ReadModSpecs(ModFile, SongName, Samples))
				InfoBox(_MODE);
			else if (!SetDefaults(Samples, ModFN))
				CloseIn(ModFile);
		if (ModFile->f==NULL) {
			free(ModFN);
			ModFN = NULL;
		}
	}

//	c = Choice();

	InfoBox(_ABOUT);

	do {
		c = Choice();
		switch(c) {
			case 0:
				MidFN = InitFile(MidFile, MidFN, "MIDI file below.", 0);
				break;
			case 1:
				if (ModFile->f != NULL)
					SaveDefaults(Samples, ModFN); /* make sure defaults are saved */
				ModFN = InitFile(ModFile, ModFN, "MOD file below.", 1);
				if (ModFN != NULL) {
printf("x1\n");
					if (!ReadModSpecs(ModFile, SongName, Samples)){
printf("x2\n");
						InfoBox(_MODE);
					}
					else
					if (!SetDefaults(Samples, ModFN)) {
printf("x3\n");
						CloseIn(ModFile);
					}
				}
				break;
			case 2:
				if (MidFile->f != NULL && ModFile->f != NULL)
					if ( (numoftracks=ChooseChannels(Samples)) <= 16)
						ConvertMOD(ModFile, MidFile, SongName, Samples);
					else
						InfoBox(_TMC);
				else
					InfoBox(_CNVE);
				break;
			case 3:
				if (ModFile->f != NULL)
					MapSamples(Samples);
				else
					InfoBox(_MODM);
				break;
			case 4:
				if (ModFile->f != NULL)
					SaveSamples(Samples);
				else
					InfoBox(_MODM);
				break;
			case 5:
				InfoBox(_ABOUT);
				break;
			case 6:
				if (ModFile->f != NULL)
					Transpositions(Samples);
				else
					InfoBox(_MODM);
				break;
			case 7:
				SetDrumChannel();
				break;
			case 8:
				SetTempoType();
				break;
			case 9:
				if (ModFile->f != NULL)
					VolumeShifts(Samples);
				else
					InfoBox(_MODM);
				break;
		}
	} while (c != 99);
	if (ModFile->f != NULL) {
		CloseIn(ModFile);
		SaveDefaults(Samples, ModFN);
	}
	free(ModFN);
	if (MidFile->f != NULL)
		CloseOut(MidFile);
	free(MidFN);
	EndWindows();
	exit(0);
}

