/*
**	TRANSPOSE -- Transpose Midi note on/off events
**	psl 2/87
*/
#include	<stdio.h>
#include	<libmidi.h>

#define	MAXMAP	MIDI_MAX_CHANS

int	bcnts[]	= { 4, 4, 4, 4, 3, 3, 4, 2, };

main(argc, argv)
char	*argv[];
{
	char *cp;
	int trans, dt, b1, b2, b3, b4;
	int bcnt, type, stat, chan;

	if (argc != 2) {
syntax:
	    fprintf(stderr, "Usage: %s # <file\n", argv[0]);
	    fprintf(stderr, "# is the transposition in half steps.\n");
	    fprintf(stderr, "#o is the transposition in octaves.\n");
	    fprintf(stderr, "12, +12, 1o, & +1o all mean up one octave.\n");
	    fprintf(stderr, "-12 & -1o both mean down one octave.\n");
	    exit(2);
	}
	cp = argv[1];
	if (*cp == '+')
	    cp++;
	trans = atoi(cp);
	while (*cp == '-' || ('0' <= *cp && *cp <= '9'))
	    cp++;
	if (*cp == 'o')
	    trans *= 12;
	if (trans < -127 || 127 < trans)
	    goto syntax;
	chan = -1;
	dt = 0;
	while ((b1 = getc(stdin)) != EOF) {	/* b1 is normally timing */
	    if (b1 == RT_TCIP) {
		putc(b1, stdout);
		continue;
	    }
	    dt += b1;				/* b1 is timing */
	    if ((b2 = getc(stdin)) == EOF) {	/* b2 can be status */
		fprintf(stderr, "EOF after timing byte (0x%x)\n", b1);
		exit(1);
	    }
	    if ((b2 & M_CMD) == 0)		/* not a status byte */
		b3 = b2;
	    else {				/* a status byte */
		type = (b2 >> 4) & 0x7;
		if (bcnts[type] == 2) {		/* these aren't key events */
		    dt = putdt(dt);		/* so dump 'em & go back */
		    putc(b2, stdout);
		    continue;
		}
		stat = b2 & M_CMD_MASK;
		chan = b2 & M_CHAN_MASK;
		bcnt = bcnts[type];
		if ((b3 = getc(stdin)) == EOF) {
		    fprintf(stderr, "EOF after %x (mode)\n", b2);
		    exit(1);
		}
	    }
	    if (bcnt == 4) {
		if ((b4 = getc(stdin)) == EOF) {
		    fprintf(stderr, "EOF before last byte of command.\n");
		    fprintf(stderr, "0x%x, 0x%x, 0x%x, ...\n", dt, b2, b3);
		    exit(1);
		}
	    }
	    if (stat == CH_KEY_ON || stat == CH_KEY_OFF) {
		b3 += trans;
		if (b3 > 127)
		    b3 = 127;
		if (b3 < 0)
		    b3 = 0;
	    }
	    dt = putdt(dt);
	    putc(stat | chan, stdout);
	    putc(b3, stdout);
	    if (bcnt == 4)
		putc(b4, stdout);
	}
}

putdt(dt)
{
	while (dt >= 240) {
	    putc(RT_TCIP, stdout);
	    dt -= 240;
	}
	putc(dt, stdout);
	return(0);
}
