/* dxget.c -- program to get Yamaha exclusive messages and write to file */

/*****************************************************************************
*	    Change Log
*  Date	    | Change
*-----------+-----------------------------------------------------------------
* 13-Jun-86 | Created Change Log
*****************************************************************************/

#include "cext.h"
#include "stdio.h"
#include "mpu.h"
#include "midicode.h"
#include "userio.h"
#include "cmdline.h"

#define buffsize 17000
byte midibuff[buffsize];

extern int xbufftai;
extern int xbuffmask;
extern byte *xbuff;
extern byte *buff;

int xflag;	/* for debugging */

int debptr;

/****************************************************************************
* Data for command line parsing
****************************************************************************/
#define nswitches 8
private char *switches[nswitches] = 
    { "-help", "-miditrace", "-m", "-trace", "-t", "-block", "-d", "-debug" };

#define noptions 1
private char *options[noptions] = { "-tune" };

/*****************************************************************************
*	Routines local to this module
*****************************************************************************/
private void instruct();
private boolean output();

/****************************************************************************
*				instruct
* Effect: prints instructions for this routine
****************************************************************************/

private void instruct()
{
printf("This program will let you save DX7 and TX816 voice programs.\n");
printf("To save DX7 programs, you must connect\n");
printf("	DX7 MIDI OUT to MPU 401 MIDI IN.\n");
printf("For TX816 programs, connect TX816 MIDI OUT to MPU 401 MIDI IN,\n");
printf("	and set the OUT SLOT (leftmost display) to the module\n");
printf("	from which you want data.\n");
printf("For DX7: push the orange FUNCTION key, then the green 8.  Push 8\n");
printf("	repeatedly until the display says SYS INFO AVAIL or\n");
printf("	SYS INFO UNAVAIL.  If the display says SYS INFO UNAVAIL,\n");
printf("	push YES to change the display to SYS INFO AVAIL.\n");
printf("	Now, select a voice with the INTERNAL or CARTRIDGE button\n");
printf("	followed by a (green) number.\n");
printf("For ALL DX7 voices: after getting the SYS INFO AVAIL display,\n");
printf("	push 8 again to get MIDI TRANSMIT ?.  Push YES.\n");
printf("For TX816: Hold down SELECT until you see UT in the display.\n");
printf("	Let up on SELECT and then push it once more to get the\n");
printf("	flashing dU.  Push YES to dump all data from this module.\n");
printf("	Hold down SELECT until you see digits in the display.\n");
printf("After data is dumped, dxget will tell you what it got and write\n");
printf("	data to a file.	 Use dxput to copy a file to a dx module.\n");
}

/****************************************************************************
*				main
* Effect: main program -- prompt user for information and get data
****************************************************************************/
void main(argc, argv)
    int argc;
    char *argv[];
{
    FILE *fp;		/* the output file */
    int done = false;	/* flag is true when user is done */
    byte *msg;		/* message pointer */
    char filename[100];	/* the output file name */
    char *s;		/* the file name in the command line */

    cl_init(switches, nswitches, options, noptions, argv, argc);
    if (cl_switch("-help")) instruct();
    /* get input file name: */
	filename[0] = 0;	/* empty string */
	if ((s = cl_arg(1)) != NULL) strcpy(filename, s);

    while (!done) {
	if (askbool("Do you want instructions", true)) instruct();
	
	fp = fileopen(filename, "dx7", "w", "file name");

	musicinit();
	if (!midi_buffer(midibuff, buffsize)) printf("midi_buffer error\n");
	while (getkey(false) != -1) ;
	exclusive(true);	/* tell mpu401 to send exclusive data */

	printf("\nReady for your data. Type space when you are done...\n");

	done = false;
	while (!done) {
	    if (kbhit()) done = (getch() == ' ');
	    mpu_error_check();	/* look for buffer overflow */
	}

	musicterm();

	msg = midibuff;
	if (xbufftai == 0) printf("No data!  Please start again.\n");
	else while (output(fp, &msg, midibuff + xbufftai))
	     /* write messages */;
	fclose(fp);
	printf("DONE\n");

	done = !askbool("Do you want to send another file", false);
	filename[0] = 0;	/* force prompt for new file name */
    }
}

/****************************************************************************
*				output
* Inputs:
*	FILE *fp: the file to write
*	byte **msg: pointer to the message to write
*	byte *msg_tail: points to byte after last byte of recorded data
* Outputs:
**	byte **msg: is advanced to byte after the last byte of the message
*	returns true if there is more data to output
* Effect: 
*	write data file using recorded data
* Assumes:
*	fp is opened for writing
*	msg_tail > *msg
****************************************************************************/

private boolean output(fp, msg, msg_tail)
    FILE *fp;
    byte **msg;
    byte *msg_tail;
{
    byte *this_msg = *msg;	/* local message pointer */
    int datalen;		/* number of bytes in message */
    int cksum;			/* check sum of message */
    int n;			/* counts bytes printed on one line */

/*	printf("*msg %x, this_msg %x, msg_tail %x\n",
 *		*msg, this_msg, msg_tail);
 *	printf("%d bytes to go.\n", msg_tail - this_msg);
 */
    excldesc(this_msg);
/*	for (i = *base; i < how_many; i+=4) {
 *	    if (kbhit() && (getch() == ' ')) break;
 *	    printf("%d: %x %x %x %x\n",
 *		i, 
 *		midibuff[i],
 *		midibuff[i+1],
 *		midibuff[i+2],
 *		midibuff[i+3]);
 *	}
 */
	this_msg = *msg;
/*	printf("parity check\n");*/
    datalen = (this_msg[4] << 7) + this_msg[5];
/*	printf("datalen %x\n", datalen);*/
    cksum = 0;
    for (n = 6; n < datalen+6; n++) {
	cksum = (cksum + this_msg[n]) & 0x7f;
    }
/*	printf("computed check sum %x, actual check sum %x\n",
		cksum, midibuff[datalen+6]);*/
    if ((cksum + this_msg[datalen+6]) & 0x7f != 0) {
	fprintf(stderr, "Data has been garbled -- please start over.\n");
	return false;
    }
    n = 0;
    do {	/* always print first byte, */
		/* then terminate after printing MIDI_EOX */
	fprintf(fp, "%x ", *this_msg);
	if (n >= 15) {		/* print 16 bytes per line */
	    n = 0;
	    fprintf(fp, "\n");
	} else n++;
	this_msg++;
    } while (this_msg < msg_tail && *(this_msg-1) != MIDI_EOX) ;
    fprintf(fp, "\n\n");
    *msg = this_msg;
    return this_msg < msg_tail;
}
