#include <stdio.h>
#include <midi.h>
#d MAX 30
#d FNULL (FILE *)0

static MpuCmd m[MAX];
static unsigned char mbuf[MAX][10];
static long time[MAX];

static int OpenFiles = 0;
static int Period = MPU_CLOCK_PERIOD;

static
mintime(f,n) FILE *f[]; {
	long t = 9999;
	Int i;
	loop(i,n) if (f[i] && time[i] < t) t = time[i];
	return t;
}

static
Get(f,i) FILE *f[]; {
	if (GetMpuCmd(f[i],&m[i])) {
		strcpy(mbuf[i],m[i].mpu_cmd), m[i].mpu_cmd = mbuf[i];
		if (m[i].time_tag == RT_TCIP) {
			time[i] += Period;
			return Get(f,i);
		}
		time[i] += m[i].mpu_time;
		if (*mbuf[i] == RT_TCWME) return Get(f,i);
	  } else OpenFiles--, close(fileno(f[i])), f[i] = (FILE *)NULL;
}

static
Put(f,i,nmin)
	FILE *f;
{
	if (nmin) time[i] = 0;
	m[i].time_tag = (unsigned char)time[i];
	m[i].mpu_time = time[i];
	time[i] = 0;
	PutMpuCmd(f,&m[i]);
}

static
deduct(n,t) {
	Int i;
	loop(i,n) time[i] -= t;
}

MidiMerge(f, n, out)
	FILE *f[];	/* array of input files */
	int n;		/* number of files in 'f' */
	FILE *out;	/* where to write output */
/*
** Read midi data from the 'n' files in 'f' and merge it
** in time order, writing the result on 'out'.
** Every '2*Period' ticks a counter ('cum', below) overflows
** telling us to output a timing clock with measure end.
*/
{
	Int i, t=0, cum = 0;
	OpenFiles = n;
	loop(i,n) Get(f,i);
	while (OpenFiles) {
		while ((t = mintime(f,n)) >= Period) {
			deduct(n,Period);
			cum += Period;
			PutTCIP(out); /* Timing clock in play */
			if (cum >= 2*Period) PutTCWME(out,0), cum = 0;
			t = 0;
		}
	    Again:
		cum += t;
		if (cum >= 2*Period) { /* put out TimingClockWithMeasureEnd */
			cum = t - (cum - 2*Period);
			PutTCWME(out,cum);
			deduct(n,cum);
			t -= cum; if (t > 0) goto Again;
			cum = 0;
		} else {
			int nmin = 0;	/* if true, there's > 1 min (simultaneous) */
			loop(i,n)
				if (f[i] && time[i] == t) Put(out,i,nmin++), Get(f,i);
				else time[i] -= t;
		}
	}
}
