#ident " @(#)mread.c 1.1 91/09/17 Copyright 1991, Sun Microsystems, Inc."
/*
 * Copyright (c) 1991 by Sun Microsystems, Inc.
 *		Extensions by stp@nomad, 5/92
 */
/*
 *	mread.c--a simple reader/printer for MIDI
 *		Based on Glenn Scott's midiread, this finds the delays in msec 
 *		itself using gettimeofday() and has a trivial output format, e.g.,
 *		delta-msec	cmd bytes
 *			48: 	90 24 47 
 *			926: 	90 24 00 
 */
#include <sys/types.h>
#include <sys/stropts.h>
#include <sys/stream.h>
#include <sys/errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include "option.h"
#include "../sys/midi.h"
#include <sys/time.h>

extern errno;
#define ARG_OUTPUT		 8
#define ARG_DEVICE		16
#define ARG_USAGE		32
#define ARG_BINARY		64
#define	mp_error(str) \
	{ fprintf(stderr, "ERROR: %s\n", str); fflush(stderr); exit(-1); }
#define	mp_msg(str) \
	{ fprintf(stderr, str); fflush(stderr); }

struct option Options[] = {
	{ "-device",			1, (char **) 0, 0, 0, ARG_DEVICE },
	{ "-output",			1, (char **) 0, 0, 0, ARG_OUTPUT },
	{ "-u",					0, 			 0, 0, 0, ARG_USAGE },
	{ "-b",					0, 			 0, 0, 0, ARG_BINARY },
	{ 0 },
};

int MidiFd=0, binary=0;
MidiVariables vars;
MidiParameters params;
struct timeval timeValue, startTime;

main(argc, argv) char *argv[]; {
	char *device = "/dev/midir";
	int fd, fdsave = -1, fdin = -1, i;
	unsigned char buf[2];
	struct option *o;
	void SigInt();

	signal(SIGINT, SigInt);
	argv++;
	while (*argv) {
		if ((o = Option(Options, &argc, argv))) {
			switch (o->index) {
			case ARG_OUTPUT:
				if ((fdsave = creat(o->args[0], 0666)) < 0)
					perror(o->args[0]);
				break;
			case ARG_DEVICE:
				device = o->args[0];
				break;
			case ARG_BINARY:
				binary = 1;
				break;
			case ARG_USAGE:
				printUsage();
				exit(0);
				break;
			default:
				printf("unknown option %s\n", *argv);
			}
		} else {
			printf("unknown option %s\n", *argv);
			argv++;
		}
	}
	if ((MidiFd = fd = open(device, O_RDONLY)) < 0) {
		perror(device);
		exit(1);
	}

#ifdef REMOVED
	bzero((char *) &params, sizeof(params));
	if (MidiGetParameters(fd, &params) == 0)
			mp_error("reading parameters.");
	MidiPrintParams(&params);

	params.midi.clockRate.tv_sec = 0;
	params.midi.clockRate.tv_usec = 1000;	/* clock = 1ms / tick */
	params.midi.option.internalClock = 1;	/* use internal clock */
	if (MidiPutParameters(fd, &params) != 0)
			mp_error("writing parameters.");
#endif
	if (gettimeofday(&startTime, NULL) != 0)
			mp_error("reading the time of day.");
/*
	fprintf(stderr, "t0=%u.%u\n", startTime.tv_sec, timeValue.tv_usec);
 */
	Idle(fdsave, fd);		/* run monitor loop */
}


/******************************
 * Read/Write Loop
 */
Idle(fdsave, fd) {
	fd_set rfds;
	register u_char *ptr;
	u_char *MidiGet();
	register MidiMessage msg;
	register int delay=0, now;

	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);

	while (1) {
		while (select(fd + 1, &rfds, 0, 0, 0) ==-1 && errno == EINTR)
			; /* WAIT */

		if (FD_ISSET(fd, &rfds)) {
											/* read message and data buffer */
			if ((ptr = (u_char *)MidiGet(fd, &msg))) {
				if (fdsave != -1) {			/* if save to file */
					MidiWrite_(fdsave, &msg, ptr);
					fsync(fdsave);
				}
				if (gettimeofday(&timeValue, NULL) != 0)
					mp_error("reading the time of day.");
											/* get msec time */
				now = ((timeValue.tv_sec - startTime.tv_sec)*1000) 
						+ (timeValue.tv_usec/1000);
				if (delay != 0)
					delay = now - delay;	/* calc delta time */
/* removed verbosity
				if(MidiGetVars(fd, &vars) == 0)
					mp_error("reading parameters.");
				MidiPrintVars(&vars);
*/
				if (msg.mc_type == 0)		/* if MIDI command message */
					if (binary)
						MidiDumpMsg(&msg, ptr, delay);		/* write it */
					else
						MidiPrintMsg(&msg, ptr, delay);		/* print it */

				free(ptr);					/* release buffer */
				delay = now;				/* cache time */
				exitTest(&msg, ptr);		/* test data whether to exit */
			}
		}
	}
}

/**************************************
 * Print Routines
 */
MidiPrintMsg(ms, data, del) MidiMessage *ms; u_char *data; int del; {
	register int i, len;

	len = ms->mc_size;
	printf("%4u:  ", del);
	for  (i = 0; i < len; i++)
		printf("%02x ", data[i]);
	printf("\n");

}

MidiDumpMsg(ms, data, del) MidiMessage *ms; u_char *data; int del; {

	write(0, &del, sizeof(int));			/* write delta time */
	write(0, &(ms->mc_size), sizeof(short));/* write data size */
	write(0, data, ms->mc_size);			/* write data */
}


void SigInt() {
	printf("SIGINT\n");
	ioctl(MidiFd, I_FLUSH, FLUSHR);
	exit(1);
}


MidiPrintParams(i) MidiParameters *i; {

	printf("\tclk %d+%-d//%d  %s-%s-%4s id=%02x, recv=%5d\n",
				 i->midi.clockRate.tv_sec, i->midi.clockRate.tv_usec, 
				 i->midi.clockModulus,
				 i->midi.option.internalClock? "intc" : "extc",
				 i->midi.option.autoStart ? "astrt" : "",
				 i->midi.option.autoStop ? "astop" : "",
				 i->midi.id, i->midi.recvBufferSize);
	printf("\tinput: %-10s %-10s\n\toutput: %-10s %-10s\n",
				 i->input.option.runningStatus ? "runningS" : "",
				 i->input.option.loopBack ? "loopback" : "",
				 i->output.option.runningStatus ? "runningS" : "",
				 i->output.option.loopBack ? "loopback" : "");
/*
	printf("\tsmpte %d+%-d %4s %4s %4s %4s %4s %4s\n",
				 i->smpte.clockRate.tv_sec,
				 i->smpte.clockRate.tv_usec,
				 ((i->smpte.type == smpte_f24) ? "F24" :
					((i->smpte.type == smpte_f25) ? "F25" :
					 ((i->smpte.type == smpte_f30) ? "F30" :
						((i->smpte.type == smpte_f30drop) ? "F30D" :
						 itoa((int) i->smpte.type))))),
				 i->smpte.option.internalClock ? "intc" : "extc",
				 i->smpte.option.autoStart ? "astrt" : "",
				 i->smpte.option.autoStop ? "astop" : "",
				 i->smpte.option.dropFrame ? "drop" : "",
				 i->smpte.option.reverse ? "srev" : "");
*/
}

MidiPrintVars(d) MidiVariables *d; {

	printf("\tmidi vars: t=%5.5d, p=%d, %5s\n",
				 d->midi.clockTick, d->midi.songPointer,
				 d->midi.flag.running ? "running" : "not running");
/*
	printf("\trealtime: %5s-%5s-%5s-%5s-%5s-%5s-%5s-%5s\n",
				 d->realtime.midiClock ? "Clock" : "",
				 d->realtime.midiStart ? "Start" : "",
				 d->realtime.midiStop ? "Stop" : "",
				 d->realtime.midiContinue ? "Continue" : "",
				 d->realtime.midiActive ? "Active" : "",
				 d->realtime.midiReset ? "Reset" : "",
				 d->realtime.midiMTC ? "MTC" : "",
				 d->realtime.midiSongPointer ? "SongPointer" : "");
	printf("\tsmpte: %02d:%02d:%02d:%02d:%02d %5s %d\n",
				 d->smpte.hours, d->smpte.minutes, d->smpte.seconds,
				 d->smpte.frames, d->smpte.fraction,
				 d->smpte.flag.running ? "running" : "not running",
				 d->smpte.flag.qframe);
*/
}

/******************************
 *  Exit function: exit when lowest note 
 *	on kbd (1c) is played loud (7f)
 */
exitTest(ms, data) MidiMessage *ms; u_char *data; {

	if (ms->mc_type == 0)
		if (ms->mc_size == 3)
			if (data[0] == 0x90)
				if (data[1] == 0x1c)
					if (data[2] == 0x7f)
					exit(0);
}


printUsage() {		/* print a pretty usage message */

	fprintf(stderr, "\n *\n %s\n %s\n %s\n *\n\n",
		"*  mread [ -device slot ] [ -output file_name ]",
		"*	[ -u (usage) -b (binary out) ]",
		"*	[ reads MIDI from /dev/midir ] [ runs until killed with ^C ]");
}

