#include <stdio.h>
#include <midi.h>
#include <dx7voice.h>

Dx7Voice *dx7readVoice();
char *VoiceFile();

#define	LEN32BV	128
#define VoiceFile(x) x

static char *lfoWave[] = { "tri ", "saw-", "saw+", "squa", "sine", "samp", };
static char *on[] = { "on ","off" };
static char *curve[] = {"-lin", "-exp", "+exp", "+lin"};
static char *mode[] = {"r", "f"};

char	*drule	=
"|========================================================================|\n";

#define p fprintf

/*
** For each dx7 voice file, pretty print something like the Yamaha table
** Handles both single voice and 32 voice dumps.
*/
main(ac,av)
char *av[];
{
	int i=1;

	if (i==ac)
	    vpr(0, "stdin", stdout);
	else {
	    for (; i < ac; i++) {
		char *s = VoiceFile(av[i]);
		int fh = -1;
		if (s)
		    fh = open(s, 0);
		if (fh) {
		    if (i>1)
			printf("\n\n");
		    vpr(fh, av[i], stdout);
		    close(fh);
		} else {
		    MidiError("%s: ",av[0]);
		    perror(av[i]);
		}
	    }
	}
}

vpr(ifh, name, ofp)
char	*name;
FILE	*ofp;
{
	unsigned char buf[256], *bp, *vp;
	int fmt, i, vn, op, detune;
	Dx7Voice v;

	while (read(ifh, buf, 1) == 1 && *buf != SX_CMD);
	if (*buf != SX_CMD) {
	    fprintf(stderr, "No voice dump found in %s\n", name);
	    return;
	}
	if (read(ifh, &buf[1], 5) != 5) {		/* get rest of header */
	    fprintf(stderr, "No header in %s\n", name);
	    return;
	}
	if (buf[1] != ID_YAMAHA) {
bad:
	    fprintf(stderr, "Header problem in: %x %x %x %x %x %x\n",
	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
	    return;
	}
	fmt = buf[3];
	if ((fmt != DX7_SXF_1V  || buf[4] != 0x01 || buf[5] != 0x1B)
	 && (fmt != DX7_SXF_32V || buf[4] != 0x20 || buf[5] != 0x00))
	    goto bad;
	if (fmt == DX7_SXF_1V) {
	    if (read(ifh, &v, sizeof v) != sizeof v) {
		perror("DX7_SXF_1V read");
		return;
	    }
	    pvdx7(&v, stdout);
	} else {
	    for (vn = 0; vn < 32; vn++) {
		if (i)
		    printf("\n\n");
		if (read(ifh, bp = buf, LEN32BV) != LEN32BV) {
		    perror("DX7_SXF_32V read");
		    return;
		}
		/* copy condensed bulk format into DX7 voice format */
		vp = (u_char *) &v; 
		for (op = 6; --op >= 0; ) {
		    for (i = 11; --i >= 0; *vp++ = *bp++);
		    *vp++ = (*bp & 0x03);		/* LC */
		    *vp++ = (*bp++ >> 2);		/* RC */
		    *vp++ = (*bp & 0x07);		/* RS */
		    detune = (*bp++ >> 3);		/* PD */
		    *vp++ = (*bp & 0x03);		/* AMS */
		    *vp++ = (*bp++ >> 2);		/* KVS */
		    *vp++ = *bp++;
		    *vp++ = (*bp & 0x01);		/* M */
		    *vp++ = (*bp++ >> 1);		/* FC */
		    *vp++ = *bp++;
		    *vp++ = detune;
		}
		for (i = 9; --i >= 0; *vp++ = *bp++);
		*vp++ = (*bp & 0x07);		/* FB */
		*vp++ = (*bp++ >> 3);		/* OKS */
		for (i = 4; --i >= 0; *vp++ = *bp++);
		*vp++ = (*bp & 0x01);		/* LFKS */
		*vp++ = ((*bp >> 1) & 0x07);	/* LFKS */
		*vp++ = (*bp++ >> 4);		/* LPMS */
		for (i = 11; --i >= 0; *vp++ = *bp++);
		pvdx7(&v, stdout);
	    }
	}
}

#define sens(n) ((Dx7Operator *)&(v->op[n][0]))->modSensitivity

pvdx7(v, o)
Dx7Voice *v;
FILE *o;
{
	int j;

	p(o,"Voice Name: %10.10s\n",v->name);
	p(o, drule);
	p(o,
"| algo  feed |---------------L F O---------------|  mod sensitivity      |\n");
	p(o,
"| rithm back |wave  speed delay  pmd   amd  sync | pitch amplitude       |\n");
	p(o,
"|  %3d   %3d  %s  %4d  %4d  %4d  %4d   %3d   %3d  [%d %d %d %d %d %d]    |\n",
	 v->algorithm+1, v->feedback, lfoWave[v->lfoWave], v->lfoSpeed,
	 v->lfoDelay, v->lfoPmd, v->lfoAmd, v->lfoSync, v->modSensitivityPitch,
	 sens(0), sens(1), sens(2), sens(3), sens(4), sens(5));
	p(o, drule);
	p(o,
"| mod freq de  ----rate---  ---level--- kbd --curve-- depth kbd  out vel |\n");
	p(o,
"|op   c  f tune 1  2  3  4   1  2  3  4 brk  L    R    L  R rate lvl sens|\n");
	for (j = 0; j < 6; j++) {
		p(o,"|%d ", j+1);
		dx7PrintOperator(v->op[5 - j], o);
		p(o, "   |\n");
	}
	p(o, drule);
	p(o,
"| -----pitch EG----  transpose                                           |\n");
	p(o,
"| rate %3d%3d%3d%3d %3s                                                  |\n",
	 v->pitchRate[0], v->pitchRate[1], v->pitchRate[2], v->pitchRate[3],
	 itop(v->transpose+24));
	p(o,
"| level%3d%3d%3d%3d                                                      |\n",
	 v->pitchLevel[0], v->pitchLevel[1], v->pitchLevel[2],
	 v->pitchLevel[3]);
	p(o, drule);
}

dx7PrintOperator(op,o)
Dx7Operator *op;
FILE *o;
{
	p(o,"%s %2d %2d  %2d ",
	 mode[op->oscMode],		/* 0 ~ 1 */
	 op->oscFreqCoarse,		/* 0 ~ 31 */
	 op->oscFreqFine,		/* 0 ~ 99 */
	 op->oscDetune-7);
	p(o,"%2d %2d %2d %2d  %2d %2d %2d %2d ",
	 op->rate[0], op->rate[1], op->rate[2], op->rate[3],
	 op->level[0], op->level[1], op->level[2], op->level[3]);
	p(o, "%3s %4s %4s %2d %2d   %1d  %2d  %1d",
	 itop(op->kbdBreakPoint + 9),
	 curve[op->kbdLCurve],		/* 0 ~ 3 */
	 curve[op->kbdRCurve],
	 op->kbdLDepth,
	 op->kbdRDepth,
	 op->kbdRateScale,		/* 0 ~ 7 */
	 op->outputLevel,		/* 0 ~ 99 */
	 op->keyVelSensitivity,		/* 0 ~ 7 */
	 0);				/* 0 ~ 14 */
}
