/*
	$Id: readmidi.cpp,v 1.8 2000/01/22 17:52:22 greglee Exp $

    TiMidity -- Experimental MIDI to WAVE converter
    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#ifndef NO_STRING_H
#    include <string.h>
#else
#    include <strings.h>
#endif

#ifndef __WIN32__
#    include <unistd.h>
#endif

#include <ctype.h>

#include "gtim.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "controls.h"
#include "tables.h"
#include "effects.h"

int32   quietchannels = 0;

/* to avoid some unnecessary parameter passing */
static MidiEventList *evlist;
static int32 event_count;
static FILE *fp;
static uint32 at;

/* taken from tplus --gl */
static int midi_port_number;

#if MAXCHAN <= 16
#    define MERGE_CHANNEL_PORT(ch) ((int)(ch))
#else
#    define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4))
#endif


/* These would both fit into 32 bits, but they are often added in
   large multiples, so it's simpler to have two roomy ints */
static int32 sample_increment, sample_correction;	/*samples per MIDI delta-t */

unsigned char sfxdrum1[100] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 48, 49, 47, 50,
    0, 46, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 44, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 79, 80,
    81, 82, 83, 84, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 76, 77, 78, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

unsigned char sfxdrum2[100] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 59, 60, 41,
    42, 46, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 63, 64, 65, 66, 67, 68, 69, 69,
    72, 70, 0, 0, 0, 0, 0, 0, 52, 53,
    54, 56, 57, 58, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 73, 74, 75, 71, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

#ifdef tplus
#define MAX_XG_DRUM_SETUP 6
static char rhythm_part[MAX_XG_DRUM_SETUP];	/* for GS */
static char drum_setup_xg[MAX_XG_DRUM_SETUP];	/* for XG */
#endif

/* Computes how many (fractional) samples one MIDI delta-time unit contains */
static void
compute_sample_increment (int32 tempo, int32 divisions)
{
    double  a;
    a = (double) (tempo) * (double) (play_mode->rate) * (65536.0 /
							 1000000.0) /
	(double) (divisions);

    sample_correction = (int32) (a) & 0xFFFF;
    sample_increment = (int32) (a) >> 16;

    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
	       "Samples per delta-t: %d (correction %d)", sample_increment,
	       sample_correction);
}

#ifdef tplus
static int
tf_getc (void)
{
    uint8   b;
    if (fread (&b, 1, 1, fp) != 1)
	return EOF;
    return (uint8) b;
}

/* Read variable-length number (7 bits per byte, MSB first) */
static int32
getvl (void)
{
    int32   l;
    int     c;

    errno = 0;
    l = 0;

    /* 1 */
    if ((c = tf_getc ()) == EOF)
	goto eof;
    if (!(c & 0x80))
	return l | c;
    l = (l | (c & 0x7f)) << 7;

    /* 2 */
    if ((c = tf_getc ()) == EOF)
	goto eof;
    if (!(c & 0x80))
	return l | c;
    l = (l | (c & 0x7f)) << 7;

    /* 3 */
    if ((c = tf_getc ()) == EOF)
	goto eof;
    if (!(c & 0x80))
	return l | c;
    l = (l | (c & 0x7f)) << 7;

    /* 4 */
    if ((c = tf_getc ()) == EOF)
	goto eof;
    if (!(c & 0x80))
	return l | c;

    /* Error */
    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
	       "\"%s\": Illegal Variable-length quantity format.",
	       current_filename);
    return -2;

  eof:
    if (errno)
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "\"%s\": read_midi_event: %s",
		   current_filename, strerror (errno));
    else
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "Warning: \"%s\": Short midi file.", current_filename);
    return -1;
}

#else

/* Read variable-length number (7 bits per byte, MSB first) */
static uint32
getvl (void)
{
    uint32  l = 0;
    uint8   c;
    for (;;) {
	fread (&c, 1, 1, fp);
	l += (c & 0x7f);
	if (!(c & 0x80))
	    return l;
	l <<= 7;
    }
}
#endif

/**********************************/
struct meta_text_type *meta_text_list = NULL;

static void
free_metatext ()
{
    struct meta_text_type *meta;
    while (meta_text_list) {
	meta = meta_text_list;
	meta_text_list = meta->next;
	free (meta->text);
	meta->text = NULL;
	free (meta);
	meta = NULL;
    }
}

static int
metatext (int type, uint32 leng, char *mess)
{
    static int continued_flag = 0;
    int     c;
    uint32  n;
    unsigned char *p = (unsigned char *) mess;
    struct meta_text_type *meta, *mlast;
    char   *meta_string;

    /* if (at > 0 && (type == 1||type == 5||type == 6||type == 7)) { */
    if (type == 5 || (at > 0 && (type == 1 || type == 6 || type == 7))) {
	meta =
	    (struct meta_text_type *)
	    safe_malloc (sizeof (struct meta_text_type));
	if (leng > 72)
	    leng = 72;
	meta_string = (char *) safe_malloc (leng + 8);
	if (!leng) {
	    continued_flag = 1;
	    meta_string[leng++] = '\012';
	}
	else
	    for (n = 0; n < leng; n++) {
		c = *p++;
		if (!n && (c == '/' || c == '\\')) {
		    continued_flag = 1;
		    meta_string[0] = '\012';
		    if (c == '/') {
			meta_string[1] = ' ';
			meta_string[2] = ' ';
			meta_string[3] = ' ';
			meta_string[4] = ' ';
			leng += 4;
			n += 4;
		    }
		}
		else {
		    /*meta_string[n] = (isprint(c) || isspace(c)) ? c : '.'; */
		    meta_string[n] = ((c > 0x7f) || isprint (c)
				      || isspace (c)) ? c : '.';
		    if (c == '\012' || c == '\015')
			continued_flag = 1;
		    if (c == '\015')
			meta_string[n] = '\012';
		}
	    }
	if (!continued_flag) {
	    meta_string[leng++] = '\012';
	}
	meta_string[leng] = '\0';
	meta->type = type;
	meta->text = meta_string;
	meta->time = at;
	meta->next = NULL;
/*
while at==0
1. head = meta1; head->next = NULL
2. for ...: mlast = head
   if ...: not <
   else ...: meta2->next = NULL
	     head->next = meta2
   so: (meta1, meta2)
3. for ...: mlast = meta2
   if ...:
   else: meta3->next = NULL
	 meta2->next = meta3
   so: (meta1, meta2, meta3)
*/
	if (meta_text_list == NULL) {
	    meta->next = meta_text_list;
	    meta_text_list = meta;
	}
	else {
	    for (mlast = meta_text_list; mlast->next != NULL;
		 mlast = mlast->next)
		if (mlast->next->time > meta->time)
		    break;
	    if (mlast == meta_text_list && meta->time < mlast->time) {
		meta->next = meta_text_list;
		meta_text_list = meta;
	    }
	    else {
		meta->next = mlast->next;
		mlast->next = meta;
	    }
	}
	return 1;
    }
    else
	return 0;
}

static const char *effect_name[] = {
/*  0H */ "no effect",
/*  1H */ "Hall",
/*  2H */ "Room",
/*  3H */ "Stage",
/*  4H */ "Plate",
/*  5H */ "Delay L,C,R",
/*  6H */ "Delay L,R",
/*  7H */ "Echo",
/*  8H */ "Cross Delay",
/*  9H */ "Early Refl",
/*  AH */ "Gate Reverb",
/*  BH */ "Reverse Gate",
/*  CH */ "0C",
/*  DH */ "0D",
/*  EH */ "0E",
/*  FH */ "0F",
/* 10H */ "White Room",
/* 11H */ "Tunnel",
/* 12H */ "Canyon",
/* 13H */ "Basement",
/* 14H */ "Karaoke",
/* 15H */ "",
/* 16H */ "",
/* 17H */ "",
/* 18H */ "",
/* 19H */ "",
/* 1AH */ "",
/* 1BH */ "",
/* 1CH */ "",
/* 1DH */ "",

/* 30-39 */ "", "", "", "", "", "", "", "", "", "",
/* 40-49 */ "", "", "", "", "", "", "", "", "", "",
/* 50-59 */ "", "", "", "", "", "", "", "", "", "",
/* 60-63 */ "", "", "", "",
/* 40H */ "no effect",
/* 41H */ "Chorus",
/* 42H */ "Celeste",
/* 43H */ "Flanger",
/* 44H */ "Symphonic",
/* 45H */ "Rotary Speaker",
/* 46H */ "Tremolo",
/* 47H */ "Auto Pan",
/* 48H */ "Phaser",
/* 49H */ "Distortion",
/* 4AH */ "Overdrive",
/* 4BH */ "Amp Simulator",
/* 4CH */ "3Band Mono EQ",
/* 4DH */ "2Band Stereo EQ",
/* 4EH */ "Auto Wah",
/* 4FH */ "4F",
/* 50H */ "Pitch Change",
/* 51H */ "Aural Exciter",
/* 52H */ "Touch Wah",
/* 53H */ "Compressor",
/* 54H */ "Noise Gate",
/* 55H */ "Voice Cancel",
/* 56H */ "2way Rotary Speaker",
/* 57H */ "Ensemble Detune",
/* 58H */ "Ambience",
/* 59H */ "59H",
/* 5AH */ "5AH",
/* 5BH */ "5BH",
/* 5CH */ "5CH",
/* 5DH */ "Talking Mod",
/* 5EH */ "Lo-Fi",
/* 5FH */ "Dist+Delay",
/* 60H */ "Comp+Dist+Delay",
/* 61H */ "Wah+Dist+Delay"
};


static int reverb_block[][17] = {
/*	   reverb-time|				  dry/wet|   feedback-level|
 *	        diffusion|			    rev-delay|
 *	          init.-delay|			         density|
 *	               HPF-cutoff|		      er/rev-balance|
 *	                   LPF-cutoff|			      high-damp|
 */
	{ HALL1,    18, 10,  8, 13, 49,  0,  0,  0,  0, 40,  0, 4, 50, 8, 64, 0 },
	{ HALL2,    25, 10, 28,  6, 46,  0,  0,  0,  0, 40, 13, 3, 74, 7, 64, 0 },
	{ ROOM1,     5, 10, 16,  4, 49,  0,  0,  0,  0, 40,  5, 3, 64, 8, 64, 0 },
	{ ROOM2,    12, 10,  5,  4, 38,  0,  0,  0,  0, 40,  0, 4, 50, 8, 64, 0 },
	{ ROOM3,     9, 10, 47,  5, 36,  0,  0,  0,  0, 40,  0, 4, 60, 8, 64, 0 },
	{ STAGE1,   19, 10, 16,  7, 54,  0,  0,  0,  0, 40,  0, 3, 64, 6, 64, 0 },
	{ STAGE2,   11, 10, 16,  7, 51,  0,  0,  0,  0, 40,  2, 2, 64, 6, 64, 0 },
	{ PLATE,    25, 10,  6,  8, 49,  0,  0,  0,  0, 40,  2, 3, 64, 5, 64, 0 },
	{ WHITEROOM, 9,  5, 11,  0, 46, 30, 50, 70,  7, 40, 34, 4, 64, 7, 64, 0 },
	{ TUNNEL,   48,  6, 19,  0, 44, 33, 52, 70, 16, 40, 20, 4, 64, 7, 64, 0 },
	{ CANYON,   59,  6, 63,  0, 45, 34, 62, 91, 13, 40, 25, 4, 64, 4, 64, 0 },
	{ BASEMENT,  3,  6,  3,  0, 34, 26, 29, 59, 15, 40, 32, 4, 64, 8, 64, 0 },
	{ 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};

static int chorus_block[][17] = {
	{ CHORUS1, 6, 54, 77, 106, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0 },
	{ CHORUS2, 8, 63, 64, 30, 0, 28, 62, 42, 58, 64, 46, 64, 10, 0, 0, 0 },
	{ CHORUS3, 4, 44, 64, 110, 0, 28, 64, 46, 66, 64, 46, 64, 10, 0, 0, 0 },
	{ CHORUS4, 9, 32, 69, 104, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 1, 0 },
	{ CELESTE1, 12, 32, 64, 0, 0, 28, 64, 46, 64, 127, 40, 68, 10, 0, 0, 0 },
	{ CELESTE2, 28, 18, 90, 2, 0, 28, 62, 42, 60, 84, 40, 68, 10, 0, 0, 0 },
	{ CELESTE3, 4, 63, 44, 2, 0, 28, 64, 46, 68, 127, 40, 68, 10, 0, 0, 0 },
	{ CELESTE4, 8, 29, 64, 0, 0, 28, 64, 51, 66, 127, 40, 68, 10, 0, 1, 0 },
	{ FLANGER1, 14, 14, 104, 2, 0, 28, 64, 46, 64, 96, 40, 64, 10, 4, 0, 0 },
	{ FLANGER2, 32, 17, 26, 2, 0, 28, 64, 46, 60, 96, 40, 64, 10, 4, 0, 0 },
	{ FLANGER3, 4, 109, 109, 2, 0, 28, 64, 46, 64, 127, 40, 64, 10, 4, 0, 0 },
	{ SYMPHONIC, 12, 25, 16, 0, 0, 28, 64, 46, 64, 127, 46, 64, 10, 0, 0, 0 },
	{ PHASER1, 8, 111, 74, 104, 0, 28, 64, 46, 64, 64, 6, 1, 64, 0, 0, 0 },
	{ PHASER2, 8, 111, 74, 108, 0, 28, 64, 46, 64, 64, 5, 1, 4, 0, 0, 0 },
	{ 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};

static int variation_block[][17] = {
/*	      reverb-time|					dry/wet|	  feedback-level|
 *	              diffusion|				    rev-delay|
 *		          init.-delay|					   density|
 *		                 HPF-cutoff|				 er/rev-balance|
 *		                     LPF-cutoff|				   high-damp|
 */
	{ HALL1,        18,   10,    8,   13, 49,    0,    0,  0,  0,  40,   0,   4,  50,   8, 64, 0 },
	{ HALL2,        25,   10,   28,    6, 46,    0,    0,  0,  0,  40,  13,   3,  74,   7, 64, 0 },
	{ ROOM1,         5,   10,   16,    4, 49,    0,    0,  0,  0,  40,   5,   3,  64,   8, 64, 0 },
	{ ROOM2,        12,   10,    5,    4, 38,    0,    0,  0,  0,  40,   0,   4,  50,   8, 64, 0 },
	{ ROOM3,         9,   10,   47,    5, 36,    0,    0,  0,  0,  40,   0,   4,  60,   8, 64, 0 },
	{ STAGE1,       19,   10,   16,    7, 54,    0,    0,  0,  0,  40,   0,   3,  64,   6, 64, 0 },
	{ STAGE2,       11,   10,   16,    7, 51,    0,    0,  0,  0,  40,   2,   2,  64,   6, 64, 0 },
	{ PLATE,        25,   10,    6,    8, 49,    0,    0,  0,  0,  40,   2,   3,  64,   5, 64, 0 },
	{ DELAYLCR,   3333, 1667, 5000, 5000, 74,  100,   10,  0,  0,  32,   0,  60,  28,  64, 46, 64 },
	{ DELAYLR,    2500, 3750, 3752, 3750, 87,   10,    0,  0,  0,  32,   0,  60,  28,  64, 46, 64 },
	{ ECHO,       1700,   80, 1780,   80, 10, 1700, 1780,  0,  0,  40,   0,  60,  28,  64, 46, 64 },
	{ CROSSDELAY, 1700, 1750,  111,    1, 10,    0,    0,  0,  0,  32,   0,  60,  28,  64, 46, 64 },
	{ ER1,           0,   19,    5,   16, 64,    0,   46,  0,  0,  32,   5,   0,  10,   0, 0, 0 },
	{ ER2,           2,    7,   10,   16, 64,    3,   46,  0,  0,  32,   5,   2,  10,   0, 0, 0 },
	{ GATEREVERB,    0,   15,    6,    2, 64,    0,   44,  0,  0,  32,   4,   3,  10,   0, 0, 0 },
	{ REVERSEGATE,   1,   19,    8,    3, 64,    0,   47,  0,  0,  32,   6,   3,  10,   0, 0, 0 },
	{ KARAOKE1,     63,   97,    0,   48,  0,    0,    0,  0,  0,  64,   2,   0,   0,   0, 0, 0 },
	{ KARAOKE2,     55,  105,    0,   50,  0,    0,    0,  0,  0,  64,   1,   0,   0,   0, 0, 0 },
	{ KARAOKE3,     43,  110,   14,   53,  0,    0,    0,  0,  0,  64,   0,   0,   0,   0, 0, 0 },
	{ CHORUS1,       6,   54,   77,  106,  0,   28,   64, 46, 64,  64,  46,  64,  10,   0, 0, 0 },
	{ CHORUS2,       8,   63,   64,   30,  0,   28,   62, 42, 58,  64,  46,  64,  10,   0, 0, 0 },
	{ CHORUS3,       4,   44,   64,  110,  0,   28,   64, 46, 66,  64,  46,  64,  10,   0, 0, 0 },
	{ CHORUS4,       9,   32,   69,  104,  0,   28,   64, 46, 64,  64,  46,  64,  10,   0, 1, 0 },
	{ CELESTE1,     12,   32,   64,    0,  0,   28,   64, 46, 64, 127,  40,  68,  10,   0, 0, 0 },
	{ CELESTE2,     28,   18,   90,    2,  0,   28,   62, 42, 60,  84,  40,  68,  10,   0, 0, 0 },
	{ CELESTE3,      4,   63,   44,    2,  0,   28,   64, 46, 68, 127,  40,  68,  10,   0, 0, 0 },
	{ CELESTE4,      8,   29,   64,    0,  0,   28,   64, 51, 66, 127,  40,  68,  10,   0, 1, 0 },
	{ FLANGER1,     14,   14,  104,    2,  0,   28,   64, 46, 64,  96,  40,  64,  10,   4, 0, 0 },
	{ FLANGER2,     32,   17,   26,    2,  0,   28,   64, 46, 60,  96,  40,  64,  10,   4, 0, 0 },
	{ FLANGER3,      4,  109,  109,    2,  0,   28,   64, 46, 64, 127,  40,  64,  10,   4, 0, 0 },
	{ SYMPHONIC,    12,   25,   16,    0,  0,   28,   64, 46, 64, 127,  46,  64,  10,   0, 0, 0 },
	{ ROTARYSPEAKER,81,   35,    0,    0,  0,   24,   60, 45, 54, 127,  33,  52,  30,   0, 0, 0 },
	{ TREMOLO,      83,   56,    0,    0,  0,   28,   64, 46, 64, 127,  40,  64,  10,  64, 0, 0 },
	{ AUTOPAN,      76,   80,   32,    5,  0,   28,   64, 46, 64, 127,  40,  64,  10,   0, 0, 0 },
	{ PHASER1,       8,  111,   74,  104,  0,   28,   64, 46, 64,  64,   6,   1,  64,   0, 0, 0 },
	{ PHASER2,       8,  111,   74,  108,  0,   28,   64, 46, 64,  64,   5,   1,   4,   0, 0, 0 },
	{ DISTORTION,   40,   20,   72,   53, 48,    0,   43, 74, 10, 127, 120,   0,   0,   0, 0, 0 },
	{ OVERDRIVE,    29,   24,   68,   45, 55,    0,   41, 72, 10, 127, 104,   0,   0,   0, 0, 0 },
	{ AMPSIMULATOR, 39,    1,   48,   55,  0,    0,    0,  0,  0, 127, 112,   0,   0,   0, 0, 0 },
	{ EQ3BAND,      70,   34,   60,   10, 70,   28,   46,  0,  0, 127,   0,   0,   0,   0, 0, 0 },
	{ EQ2BAND,      28,   70,   46,   70,  0,    0,    0,  0,  0, 127,  34,  64,  10,   0, 0, 0 },
	{ AUTOWAH,      70,   56,   39,   25,  0,   28,   66, 46, 64, 127,   0,   0,   0,   0, 0, 0 },
	{ PITCHCHANGE,  64,    0,   74,   54, 64,    0,    0,  0,  0,  64,   1, 127, 127, 127, 0, 0 },
	{ AURALEXCITER, 44,   30,   48,    0,  0,    0,    0,  0,  0, 127,   0,   0,   0,   0, 0, 0 },
	{ TOUCHWAH,     36,    0,   30,    0,  0,   28,   66, 46, 64, 127,   0,   0,   0,   0, 0, 0 },
	{ TOUCHWAH_DIST,36,    0,   30,    0,  0,   28,   66, 46, 64, 127,  30,   0,   0,   0, 0, 0 },
	{ COMPRESSOR,    6,    2,  100,    4, 96,    0,    0,  0,  0, 127,   0,   0,   0,   0, 0, 0 },
	{ NOISEGATE,     0,   11,   82,   50,  0,    0,    0,  0,  0, 127,   3,   0,   0,   0, 0, 0 },
	{ VOICECANCEL,   0,    0,    0, 0, 0,  0,    0,    0,  0, 64,   8,  25,   0,   0,   0, 0 },
	{ 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};


static int
sysex (uint32 len, uint8 *syschan, uint8 *sysa, uint8 *sysb)
{
    unsigned char *s = (unsigned char *) safe_malloc (len);
    int     id, model, ch, port, adhi, adlo, cd, dta, dtb, dtc;
    if (len != fread (s, 1, len, fp)) {
	free (s);
	return 0;
    }
    if (len < 5) {
	free (s);
	return 0;
    }
    id = s[0];
    port = s[1];
    model = s[2];
    adhi = s[3];
    adlo = s[4];
    if (id == 0x7e && port == 0x7f && model == 0x09 && adhi == 0x01) {
	ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "GM System On", len);
	GM_System_On = 1;
	free (s);
	return 0;
    }
    ch = adlo & 0x0f;
    *syschan = (uint8) ch;
    if (id == 0x7f && len == 7 && port == 0x7f && model == 0x04
	&& adhi == 0x01) {
	ctl->cmsg (CMSG_TEXT, VERB_DEBUG, "Master Volume %d",
		   s[4] + (s[5] << 7));
	free (s);
	*sysa = s[4];
	*sysb = s[5];
	return ME_MASTERVOLUME;
    }
    if (id >= 0x7e && len > 4 && model == 0x08
	&& adhi == 0x0a) {
	ctl->cmsg (CMSG_TEXT, VERB_NORMAL, "Key signature %d rt=%d",
		s[4] - 0x40 + s[5] * 16, (s[0] == 0x7f));

	free (s);
	*sysa = s[4] - 0x40 + s[5] * 16;
	*sysb = (s[0] == 0x7f);
	return 0;
    }
    if (len < 8) {
	free (s);
	return 0;
    }
    port &= 0x0f;
    ch = (adlo & 0x1f); /* channel 0-31 for multipart */
    *syschan = (uint8) ch;
    cd = s[5];
    dta = s[6];
    if (len >= 8)
	dtb = s[7];
    else
	dtb = -1;
    if (len >= 9)
	dtc = s[8];
    else
	dtc = -1;
    free (s);
/* model 0x59 for mu100; model 0x57 for vl70-m; 0x27 master tuning */
    if (id == 0x43 && model == 0x4c) {
	if (!adhi && !adlo && cd == 0x7e && !dta) {  /* also, cd==0,1,2,3 Master Tune
							cd==4 Master Volume
							cd==5 Master Attenuator
							cd==6 Transpose
							cd==7D, 7F
						      */
	    ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "XG System On", len);
	    XG_System_On = 1;
#ifdef tplus
	    vol_table = xg_vol_table;
#endif
	}
	else if (adhi == 2 && adlo == 1) {   /* Effect 1 */
	    int look, parm;

	    if (cd < MAX_PARAMETER_DEFAULT) xg_parameter[cd] = dta;
	    if (cd == 0||cd == 0x20||cd == 0x40||(cd > 0x40 && cd < 0x56)) xg_parameter[cd+1] = dtb;

	    switch (cd) {
	    case 0x00:	/* reverb type MSB */
		XG_System_reverb_type = (dta << 4) | dtb;
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Reverb: %s %d", (dta<0x62)? effect_name[dta]:"?", dtb+1);

		if (!XG_System_reverb_type) break;
		for (look = 0; reverb_block[look][0] ; look++) {
			if (reverb_block[look][0] == XG_System_reverb_type) break;
		}
		if (reverb_block[look][0]) {
			for (parm = 1; parm <= 10; parm++) xg_parameter[parm+1] = reverb_block[look][parm];
			for (parm = 11; parm <= 16; parm++) xg_parameter[parm+1+4] = reverb_block[look][parm];
		}
		else
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Reverb: Can't find parameter.");
		break;
	    case 0x0C:	/* Reverb Return */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Reverb return %d", dta);
		break;
	    case 0x20:
		XG_System_chorus_type = (dta << 4) | dtb;
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Chorus: %s %d", (dta<0x62)? effect_name[dta]:"?", dtb+1);

		if (!XG_System_chorus_type) break;
		for (look = 0; chorus_block[look][0] ; look++) {
			if (chorus_block[look][0] == XG_System_chorus_type) break;
		}
		if (chorus_block[look][0]) {
			for (parm = 1; parm <= 10; parm++) xg_parameter[parm-1+0x22] = chorus_block[look][parm];
			for (parm = 11; parm <= 16; parm++) xg_parameter[parm-1+0x22+4] = chorus_block[look][parm];
		}
		else
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Chorus: Can't find parameter.");
		break;
	    case 0x40:
		XG_System_variation_type = (dta << 4) | dtb;
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Variation: %s %d", (dta<0x62)? effect_name[dta]:"?", dtb+1);

		for (look = 0; variation_block[look][0] ; look++) {
			if (variation_block[look][0] == XG_System_variation_type) break;
		}
		if (variation_block[look][0]) {
			for (parm = 1; parm <= 10; parm++) {
				xg_parameter[2*(parm-1)+0x42] = variation_block[look][parm] >> 8;
				xg_parameter[2*(parm-1)+0x42+1] = variation_block[look][parm] & 0xff;
			}
			for (parm = 11; parm <= 16; parm++) xg_parameter[parm-11+0x70] = variation_block[look][parm];
		}
		else
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Variation: Can't find parameter.");
		break;
	    case 0x4A:	/* variation feedback */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Var. Feedback %d", dtb);
		break;
	    case 0x54:	/* variation dry/wet */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Var. Drylevel %d", dtb);
		break;
	    case 0x56:
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Variation return %d", dta);
		break;
	    case 0x5a:
		/* dta==0 Insertion; dta==1 System */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion type %s", dta? "SYSTEM" : "INSERTION");
		break;
	    case 0x5b:
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion chan %d", dta + 1);
		break;
	    default:
		/* ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Effect 1 %xH %d", cd, dta); */
		break;
	    }
	    return 0;
	}
	else if (adhi == 2 && adlo == 0x40) { /* Multi EQ */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Multi EQ %d", dta);
	}
	else if (adhi == 3 && adlo == 0) {	/* Insertion Effect 1 */
	    int look, parm;

	    if (cd < MAX_INSERTION_PARAMETER) xg_insertion1_parameter[cd] = dta;
	    if (cd == 0||cd >= 0x30) xg_insertion1_parameter[cd+1] = dtb;

	    switch (cd) {
	        case 0x00:
		    XG_insertion1_type = (dta << 4) | dtb;
		    ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				    "Insertion 1: %s %d", (dta<0x62)? effect_name[dta]:"?", dtb+1);
		    if (!XG_insertion1_type) break;
		    for (look = 0; variation_block[look][0] ; look++) {
			if (variation_block[look][0] == XG_insertion1_type) break;
		    }
		    if (variation_block[look][0]) {
			for (parm = 1; parm <= 10; parm++) {
				xg_insertion1_parameter[parm-1+0x02] = variation_block[look][parm] & 0xff;
				xg_insertion1_parameter[2*(parm-1)+0x30] = variation_block[look][parm] >> 8;
				xg_insertion1_parameter[2*(parm-1)+0x30+1] = variation_block[look][parm] & 0xff;
			}
			for (parm = 11; parm <= 16; parm++) xg_insertion1_parameter[parm-11+0x20]
			       	= variation_block[look][parm];
		    }
		    else
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion 1: Can't find parameter.");
		    break;
	        case 0x0C:
		    ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion 1 chan %d", dta+1);
		    break;
		default:
		    break;
	    }
	}
	else if (adhi == 3 && adlo == 1) {	/* Insertion Effect 2 */
	    int look, parm;

	    if (cd < MAX_INSERTION_PARAMETER) xg_insertion2_parameter[cd] = dta;
	    if (cd == 0||cd >= 0x30) xg_insertion2_parameter[cd+1] = dtb;

	    switch (cd) {
	        case 0x00:
		    XG_insertion2_type = (dta << 4) | dtb;
		    ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				    "Insertion 2: %s %d", (dta<0x62)? effect_name[dta]:"?", dtb+1);
		    if (!XG_insertion2_type) break;
		    for (look = 0; variation_block[look][0] ; look++) {
			if (variation_block[look][0] == XG_insertion2_type) break;
		    }
		    if (variation_block[look][0]) {
			for (parm = 1; parm <= 10; parm++) {
				xg_insertion2_parameter[parm-1+0x02] = variation_block[look][parm] & 0xff;
				xg_insertion2_parameter[2*(parm-1)+0x30] = variation_block[look][parm] >> 8;
				xg_insertion2_parameter[2*(parm-1)+0x30+1] = variation_block[look][parm] & 0xff;
			}
			for (parm = 11; parm <= 16; parm++) xg_insertion2_parameter[parm-11+0x20]
			       	= variation_block[look][parm];
		    }
		    else
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion 2: Can't find parameter.");
		    break;
	        case 0x0C:
		    ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Insertion 2 chan %d", dta+1);
		    break;
		default:
		    break;
	    }
	}
	else if (adhi == 4) {	/* Unique Effect */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Unique Effect %d", dta);
	}

/* eg:
 * F0 sysex
 * 43 id
 * 1n port n
 * 4C model
 * 08 adhi
 * 0m adlo = channel m
 * 04 cd [receive channel] / 0C [adjust velocity sensitivity depth]
 * dd dta = new midi receive channel [7F mutes]
 * F7
 */
#if 0
	else if (adhi == 0x0A && cd <= 40) {  /* A/D */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "A/D %d", dta);
	}
#endif
	else if (adhi == 8/* && cd <= 40*/) {  /* multipart */
	    *sysa = dta & 0x7f;
	    switch (cd) {
	    case 0x01:		/* bank select MSB */
		return ME_TONE_KIT;
		break;
	    case 0x02:		/* bank select LSB */
		return ME_TONE_BANK;
		break;
	    case 0x03:		/* program number */
			/** MIDIEVENT(at, ME_PROGRAM, lastchan, a, 0); **/
		return ME_PROGRAM;
		break;
	    case 0x04:		/* program number */
		if (ch == *sysa) return 0;
		channel[ch].receive = *sysa;
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Chan %d -> Chan %d", *sysa + 1, ch + 1);
		return ME_RECEIVE_CHANNEL;
		break;
#if 0
	    case 0x05:		/* mono/poly mode */
	    case 0x06:		/* Same Note Number Key On Assign */
#endif
	    case 0x07:		/* Part mode */
		if (*sysa < 2)
		ctl->cmsg (CMSG_TRACE, VERB_VERBOSE, "Chan %d mode %s", ch+1,
			      *sysa? "Drum":"Melodic");
		else ctl->cmsg (CMSG_TRACE, VERB_VERBOSE, "Chan %d mode DRUMS%c", ch+1,
			      *sysa - 1 + '0');
		/* Warning: Setting .kit doesn't do anything now. */
		if (!*sysa) channel[ch].kit = 0;
		else /*if (*sysa == 2)*/ channel[ch].kit = 127; /*?? 2 is def. for chan 10 */
		drum_setup_xg[*sysa] = ch;
		if (*sysa) *sysa = 127;
		return ME_TONE_KIT;
		break;
	    case 0x08:		/*  */
		if (dta-64 >= -24 && dta-64 <= 24)
		    channel[ch].transpose = (char) (dta - 64);
		ctl->cmsg (CMSG_TRACE, VERB_VERBOSE,
			   "transpose channel %d by %+d", (adlo & 0x0f) + 1,
			   dta - 64);
		break;
#if 0
	    case 0x09:		/* detune 1st bit */
	    case 0x0a:		/* detunr 2nd bit */
#endif
	    case 0x0b:		/* volume */
		return ME_MAINVOLUME;
		break;
	    case 0x0c:		/* Velocity Sense Depth */
		return ME_VELOCITY_SENSE_DEPTH;
		break;
	    case 0x0d:		/* Velocity Sense Offset */
		return ME_VELOCITY_SENSE_OFFSET;
		break;
	    case 0x0e:		/* pan */  /* if dta==0, random pan */
#ifdef tplus
		if (!dta) return ME_RANDOM_PAN;
#endif
		return ME_PAN;
		break;
#if 0
	    case 0x0F:	/* Note Limit Low */
	    case 0x10:	/* Note Limit High */
#endif
	    case 0x11:	/* Dry Level */
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Dry level %d, chan %d", *sysa, ch + 1);
		return ME_DRYLEVEL;
	    case 0x12:		/* chorus send */
		return ME_CHORUSDEPTH;
	    case 0x13:		/* reverb send */
		return ME_REVERBERATION;
	    case 0x14:		/* variation send */
		return ME_CELESTE_EFFECT;
	    case 0x15:	/* Vibrato Rate */
		return ME_VIBRATO_RATE;
	    case 0x16:	/* Vibrato Depth */
		return ME_VIBRATO_DEPTH;
	    case 0x17:	/* Vibrato Delay */
		return ME_VIBRATO_DELAY;
	    case 0x18:		/* filter cutoff */
		return ME_BRIGHTNESS;
	    case 0x19:		/* filter resonance */
		return ME_HARMONICCONTENT;

/*
1.2.2 Modulation This message is used primarily to control the depth of vibrato,
but the depth of the following 7 types of effect can be controlled. The effect
of this message can be changed by the following parameters.

    " Multi Part Parameter
       	1. MW PITCH CONTROL
       	2. MW FILTER CONTROL
       	3. MW AMPLITUDE CONTROL
       	4. MW LFO PMOD DEPTH
       	5. MW LFO FMOD DEPTH
       	6. MW LFO AMOD DEPTH
    " Effect1 Parameter
       	7. MW VARIATION CONTROL DEPTH (Valid when Variation Effect is assigned
       	to a part as Insertion)

       	By default, an LFO Pitch Modulation (PMOD) effect will apply.
       	Control# Parameter Data Range
       	1 Modulation 0...127

       	If the Multi Part parameter Rcv MODULATION = OFF, that part will not
       	receive Modulation. If the receive channel is a drum part, effects 5
       	and 6 will not apply.
*/

/*
nn 1D 1 28 - 58 MW PITCH CONTROL -24...0...+24 [semitones]		 40
nn 1E 1 00 - 7F MW LOW PASS FILTER CONTROL -9600...0...+9450[cent]	 40
nn 1F 1 00 - 7F MW AMPLITUDE CONTROL -100...0...+100 [%]		 40
nn 20 1 00 - 7F MW LFO PMOD DEPTH 0...127				 0A
nn 21 1 00 - 7F MW LFO FMOD DEPTH 0...127				 00
nn 22 1 00 - 7F MW LFO AMOD DEPTH 0...127 (Not valid for VL)		 00
nn 23 1 28 - 58 BEND PITCH CONTROL -24...0...+24 [semitones]		 42
*/

	    case 0x1D:	/* MW Pitch Control */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW pitch control %d semitones",
		       	*syschan+1, dta-64);
		break;
	    case 0x1E:	/* MW Filter Control */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW filter control %d cents",
		       	*syschan+1, (dta-64)*(9600/64));
		break;
	    case 0x1F:	/* MW Amplitude Control */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW amp control %d%%",
		       	*syschan+1, (dta-64)*(100/64));
		return ME_TREMOLO_EFFECT;
	    case 0x20:	/* MW LFO PMod Depth */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW pitch depth %d (10)",
		       	*syschan+1, dta);
		return ME_MW_PMOD;
	    case 0x21:	/* MW LFO FMod Depth */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW filter depth %d (0)",
		       	*syschan+1, dta);
		return ME_MW_FMOD;
	    case 0x22:	/* MW LFO AMod Depth */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW amp depth %d (0)",
		       	*syschan+1, dta);
		return ME_MW_AMOD;


	    case 0x30:	/* Rcv Pitch Bend */
	    case 0x31:	/* Rcv Channel Pressure */
	    case 0x32:	/* Rcv Program Change */
	    case 0x33:	/* Rcv Control Change */
	    case 0x34:	/* Rcv Poly Pressure */
	    case 0x35:	/* Rcv Note Message */
	    case 0x36:	/* Rcv RPN */
	    case 0x37:	/* Rcv NRPN */
	    case 0x38:	/* Rcv Modulation */
	    case 0x39:	/* Rcv Volume */
	    case 0x3A:	/* Rcv Pan */
	    case 0x3B:	/* Rcv Expression */
	    case 0x3C:	/* Rcv Hold1 */
	    case 0x3D:	/* Rcv Portamento */
	    case 0x3E:	/* Rcv Sostenuto */
	    case 0x3F:	/* Rcv Soft */
	    case 0x40:	/* Rcv Bank Select */
	ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "Rcv %x dta=%d", cd, dta);
		break;

	    case 0x59:	/* AC1 Controller Number */
	ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "AC1 Controller %d", dta);
		break;
/*
nn 70 1 28 - 58 BEND PITCH LOW CONTROL -24&+24 [semitone] (VL only) 3E
nn 71 1 00 - 7F FILTER EG DEPTH -64&+63 (VL only) 40
*/
	    default:
		break;
	    }
	    return 0;
	}
#if 0
	else if (adhi == 9) {  /* VL parameters */
	    *sysa = dta & 0x7f;
	    switch (cd) {
	    case 0x01:		/* bank select MSB */

09 0p 00 1 00 - 01 NOTE ASSIGN OFF/ON 01
      01 1 NOT USED --
      02 1 NOT USED --
      03 1 00 - 62 PRESSURE CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      04 1 00 - 7F DEPTH 			-64&+63 		   40
      05 1 00 - 62 EMBOUCHURE CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      06 1 00 - 7F DEPTH 			-64&+63 		   40
      07 1 00 - 62 TONGUING CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      08 1 00 - 7F DEPTH 			-64&+63 		   40
      09 1 00 - 62 SCREAM CONTROL NO. 		off - 95, AT, VELOCITY, PB 00
      0A 1 00 - 7F DEPTH 			-64&+63 		   40
      0B 1 00 - 62 BREATH NOISE CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      0C 1 00 - 7F DEPTH 			-64&+63 		   40
      0D 1 00 - 62 GROWL CONTROL NO. 		off - 95, AT, VELOCITY, PB 00
      0E 1 00 - 7F DEPTH 			-64&+63 		   40
      0F 1 00 - 62 THROAT FORMANT CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      10 1 00 - 7F DEPTH 			-64&+63 		   40
      11 1 00 - 62 HARMONIC ENHANCER CONTROL NO.off - 95, AT, VELOCITY, PB 00
      12 1 00 - 7F DEPTH 			-64&+63 		   40
      13 1 00 - 62 DAMPING CONTROL NO. 		off - 95, AT, VELOCITY, PB 00
      14 1 00 - 7F DEPTH 			-64&+63 		   40
      15 1 00 - 62 ABSORPTION CONTROL NO. 	off - 95, AT, VELOCITY, PB 00
      16 1 00 - 7F DEPTH 			-64&+63 		   40

	    }
	}
#endif
	else if((adhi & 0xF0) == 0x30) {	/* Drum Setup (0x31, 0x32, 0x33 also drum setups) */
	    int drumchan = drum_setup_xg[(adhi & 0x03) + 1];
	    int note = adlo;

	    if (drumchan < 0 && channel[9].kit) drumchan = 9;

	    if (drumchan >= 0 && drumchan < 16 && channel[drumchan].kit)
		switch (cd) {
			case 0x00:	/* Pitch Coarse */
				drumpitch[drumchan][note] = dta;
				break;
			case 0x01:	/* Pitch Fine */
				break;
			case 0x02:	/* Level */
				drumvolume[drumchan][note] = dta;
				break;
			case 0x03:	/* Alternate Group */
				break;
			case 0x04:	/* Pan */
				drumpanpot[drumchan][note] = dta;
				break;
			case 0x05:	/* Reverb Send */
				drumreverberation[drumchan][note] = dta;
				break;
			case 0x06:	/* Chorus Send */
				drumchorusdepth[drumchan][note] = dta;
				break;
			case 0x07:	/* Variation Send */
				drumvariationsend[drumchan][note] = dta;
				break;
			case 0x08:	/* Key Assign */
			case 0x09:	/* Rcv Note Off */
			case 0x0A:	/* Rcv Note On */
				break;
			case 0x0B:	/* Filter Cutoff Frequency */
				drumcutoff[drumchan][note] = dta;
				break;
			case 0x0C:	/* Filter Resonance */
				drumresonance[drumchan][note] = dta;
				break;
			case 0x0D:	/* EG Attack */
				drumattack[drumchan][note] = dta;
				break;
			case 0x0E:	/* EG Decay1 */
				drumdecay[drumchan][note] = dta;
	    			ctl->cmsg(CMSG_TRACE, VERB_DEBUG,
			    		"Drum decay ch%d note%d =%d", drumchan+1, note, dta);
				break;
			case 0x0F:	/* EG Decay2 */
				break;
#if 0
			...
			case 0x50:	/* High Pass Filter Cutoff Frequency */
			case 0x60:	/* Velocity Pitch Sense */
			case 0x61:	/* Velocity LPF Cutoff Sense */
#endif
			default:
				break;
		}
	} /* end drum setup */

	else if(adhi  == 0x70) {
	    /* default channel is 0 */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "VL channel %d", dta+1);
	}

//ent == cd
//p == adlo (channel?)
//val[4] == adlo (channel?)
//val[3] == adhi
//val[6] == dta
	return 0;
    }

    else if (id == 0x43 && model == 0x49) {
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "MU100 setup ad %d", adhi);
		/*
00 00 12 1 00 - 01 VOICE MAP MU basic, MU100 Native 01
		 */
    }
    else if (id == 0x43 && model == 0x59) {
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "VL setup ad %d", adhi);
    }
/*
    id = s[0];
    port = s[1];
    model = s[2];
    adhi = s[3];
    adlo = s[4];	addr_h = val[4];
    cd = s[5];		addr_m = val[5];
    dta = s[6];		addr_l = val[6];
*/
    else if (id == 0x41 && model == 0x42 && adhi == 0x12 && adlo == 0x40) {
	int     chan;

	if (dtc < 0)
	    return 0;
	if (!cd && dta == 0x7f && !dtb && dtc == 0x41) {
	    ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "GS System On", len);
	    GS_System_On = 1;
#ifdef tplus
	    vol_table = gs_vol_table;
#endif
	    return 0;
	}

	chan = cd & 0x0f;
	if (!chan) chan = 9;
	else if (chan < 10) chan--;
	chan = MERGE_CHANNEL_PORT (chan);
	*syschan = chan;
	*sysa = dtb; /* ?? */
	*sysb = dtc;

	if ( (cd & 0xf0) == 0x10) {

	    switch (dta) {
#if 0
	        case 0x00:	/* Tone Number */
	        case 0x02:	/* Rx. Channel */
	        ...
	        case 0x13:	/* MONO/POLY Mode */
#endif
		case 0x15:
		    channel[chan].kit = dtb? 127:0;
		    if (dtb) rhythm_part[dtb-1] = chan;
		    if (*sysa) *sysa = 127;
		    return ME_TONE_KIT;
		case 0x19: return ME_MAINVOLUME;
			   
		case 0x1A: return ME_VELOCITY_SENSE_DEPTH;	/* Velocity Sense Depth */
		case 0x1B: return ME_VELOCITY_SENSE_OFFSET;	/* Velocity Sense Offset */
	        case 0x1C:	/* Part Panpot */
		    if (!dtb) return ME_RANDOM_PAN;
		    return ME_PAN;
	        case 0x21:		/* chorus send */
		    return ME_CHORUSDEPTH;
	        case 0x22:		/* reverb send */
		    return ME_REVERBERATION;
		case 0x30:	/* TONE MODIFY1: Vibrato Rate */
		    return ME_VIBRATO_RATE;
		case 0x31:	/* TONE MODIFY2: Vibrato Depth */
		    return ME_VIBRATO_DEPTH;
		case 0x37:	/* TONE MODIFY8: Vibrato Delay */
		    return ME_VIBRATO_DELAY;
	    }
	}


	else if ((cd & 0xf0) == 0x20) {
	    switch (dta) {
	      case 0x00:	/* MW Pitch Control 0x16 */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW pitch control %d semitones",
		       	*syschan+1, dtb-64);
		break;
	      case 0x01:	/* MW TVF Cutoff Control 0x17 */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW filter control %d cents",
		       	*syschan+1, (dtb-64)*(9600/64));
		break;
	      case 0x02:	/* MW Amplitude Control 0x18 */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW amp control %d semitones",
		       	*syschan+1, (dtb-64)*(100/64));
		return ME_TREMOLO_EFFECT;
	      case 0x03:	/* MW LFO1 Rate Control 0x19 */
		break;
	      case 0x04:	/* MW LFO1 Pitch Depth 0x1A */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW pitch depth %d (10)",
		       	*syschan+1, dtb);
		return ME_MW_PMOD;
	      case 0x05:	/* MW LFO1 TVF Depth 0x1B */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW filter depth %d (0)",
		       	*syschan+1, dtb);
		return ME_MW_FMOD;
	      case 0x06:	/* MW LFO1 TVA Depth 0x1C */
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "ch%d MW amp depth %d (0)",
		       	*syschan+1, dtb);
		return ME_MW_AMOD;
	      case 0x07:	/* MW LFO2 Rate Control 0x1D */
	      case 0x08:	/* MW LFO2 Pitch Depth 0x1E */
	      case 0x09:	/* MW LFO2 TVF Depth 0x1F */
	      case 0x0A:	/* MW LFO2 TVA Depth 0x20 */
		break;
	    }
	}

	else if (cd == 0x01)
	    switch (dta) {
	        case 0x30:	/* Reverb Macro */
		    switch (dtb) {
		        case 0: XG_System_reverb_type = ROOM1; break;
		        case 1: XG_System_reverb_type = ROOM2; break;
		        case 2: XG_System_reverb_type = ROOM3; break;
		        case 3: XG_System_reverb_type = HALL1; break;
		        case 4: XG_System_reverb_type = HALL2; break;
		        case 5: XG_System_reverb_type = PLATE; break;
		        case 6: XG_System_reverb_type = TUNNEL; break;
		        case 7: XG_System_reverb_type = CANYON; break;
		    }
		break;
#if 0
	    case 0x31:	/* Reverb Character */
	    case 0x32:	/* Reverb Pre-LPF */
	    case 0x33:	/* Reverb Level */
	    case 0x34:	/* Reverb Time */
	    case 0x35:	/* Reverb Delay Feedback */
	    case 0x37:	/* Reverb Predelay Time */
#endif
	    case 0x38:	/* Chorus Macro */
		switch (dtb) {
		    case 0: XG_System_chorus_type = CHORUS1; break;
		    case 1: XG_System_chorus_type = CHORUS2; break;
		    case 2: XG_System_chorus_type = CHORUS3; break;
		    case 3: XG_System_chorus_type = CHORUS4; break;
		    case 4: /* Feedback chorus */
		        break;
		    case 5: XG_System_chorus_type = FLANGER1; break;
		    case 6:
		        /* Short delay */
		        break;
		    case 7:
		        /* Short delay feedback */
		        break;
		}
		break;
#if 0
	    case 0x39:	/* Chorus Pre-LPF */
	    case 0x3A:	/* Chorus Level */
	    case 0x3B:	/* Chorus Feedback */
	    case 0x3C:	/* Chorus Delay */
	    case 0x3D:	/* Chorus Rate */
	    case 0x3E:	/* Chorus Depth */
	    case 0x3F:	/* Chorus Send Level to Reverb */
	    case 0x40:	/* Chorus Send Level to Delay */
	    case 0x50:	/* Delay Macro */
		...
#endif
	}

#if 0
	else if (cd == 0x02) {
	    switch (dta) {
	    case 0x00:	/* EQ LOW FREQ */
	    ...
	    }
	}
	else if (cd == 0x03) {
	    switch (dta) {  /* Insertion Effect Parameter */
	    case 0x00:
	    ...
	    }
	}
	else if ((cd & 0xf0) == 0x40) {
	//chan as above
	    switch (dta) {
	    case 0x00:	/* TONE MAP NUMBER */
	    case 0x01:	/* TONE MAP-0 NUMBER */
	    case 0x20:	/* EQ ON/OFF */
	    case 0x22:	/* EFX ON/OFF */
	    }
	}
#endif
	return 0;
    }
#if 0
    else if (id == 0x41 && model == 0x42 && adhi == 0x12 && adlo == 0x41) {
	    ...
    }
#endif
    return 0;
}


static int reading_this_track;

/* Print a string from the file, followed by a newline. Any non-ASCII
   or unprintable characters will be converted to periods. */
static int
dumpstring (uint32 len, const char *label, int type)
{
    char   *s = (char *) safe_malloc (len + 1);
    if (len != fread (s, 1, len, fp)) {
	free (s);
	return -1;
    }
    s[len] = '\0';
    if (!metatext (type, len, s)) {
	while (len--) {
	    if (s[len] < 32)
		s[len] = '.';
	}
	if (type == 3)
	    ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "T%02d: %s",
		       reading_this_track, s);
	else if (type < 2 && len > 3 && s[0] == '@') {
	    char   *karaoke;
	    switch (s[1]) {
	    case 'L':
		karaoke = "Language";
		break;
	    case 'K':
		karaoke = "";
		break;
	    case 'T':
		karaoke = "Title";
		ctl->song_title (s + 2);
		break;
	    default:
		karaoke = "type";
		break;
	    }
	    ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "Karaoke %s: %s", karaoke,
		       s + 2);
	}
	else {
	    ctl->cmsg (CMSG_TEXT, VERB_VERBOSE, "%s%s", label, s);
	    if (type == 2) ctl->author(s);
	    else if (type == 6) ctl->song_title (s);
	}
    }
    free (s);
    return 0;
}

#define MIDIEVENT(at,t,ch,pa,pb) \
  newev=(MidiEventList *)safe_malloc(sizeof(MidiEventList)); \
  newev->event.time=at; newev->event.type=t; newev->event.channel=ch; \
  newev->event.a=pa; newev->event.b=pb; newev->next=0; \
  return newev;

#define MAGIC_EOT ((MidiEventList *)(-1))

#define CBYTEI	    if ((i = tf_getc ()) == EOF) { \
			if (errno) \
			    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, \
				       "\"%s\": read_midi_event: %s", \
				       current_filename, strerror (errno)); \
			else \
			    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, \
				       "Warning: \"%s\": Short midi file.", \
				       current_filename); \
			return 0; \
		    }

/* Read a MIDI event, returning a freshly allocated element that can
   be linked to the event list */
static MidiEventList *
read_midi_event (void)
{
    static uint8 laststatus, lastchan;
    static uint8 nrpn = 0, rpn_msb[MAXCHAN], rpn_lsb[MAXCHAN];	/* one per channel */
    uint8   me, type, a, b, c;
    int32   len, i;
    MidiEventList *newev;
    uint8 rpn_count = 0, nrpn_count = 0;

    for (;;) {
#ifdef tplus
	if ((len = getvl ()) < 0)
	    return 0;
	at += len;
#else
	at += getvl ();
#endif

#ifdef tplus
	if ((i = tf_getc ()) == EOF) {
	    if (errno)
		ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			   "\"%s\": read_midi_event: %s",
			   current_filename, strerror (errno));
	    else
		ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			   "Warning: \"%s\": Short midi file.",
			   current_filename);
	    return 0;
	}
	me = (uint8) i;
#else
	if (fread (&me, 1, 1, fp) != 1) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s",
		       current_filename, strerror (errno));
	    return 0;
	}
#endif

	if (me == 0xF0 || me == 0xF7) {	/* SysEx event */
	    int32   sret;
	    uint8   sysa = 0, sysb = 0, syschan = 0;
#ifdef tplus
	    if ((len = getvl ()) < 0)
		return 0;
#else
	    len = getvl ();
#endif
	    sret = sysex ((unsigned)len, &syschan, &sysa, &sysb);
	    if (sret) {
		MIDIEVENT (at, sret, syschan, sysa, sysb);
	    }
	}
	else if (me == 0xFF) {	/* Meta event */
#ifdef tplus
	    if ((i = tf_getc ()) == EOF) {
		if (errno)
		    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			       "\"%s\": read_midi_event: %s",
			       current_filename, strerror (errno));
		else
		    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			       "Warning: \"%s\": Short midi file.",
			       current_filename);
		return 0;
	    }
	    type = (uint8) i;
#else
	    fread (&type, 1, 1, fp);
#endif
#ifdef tplus
	    if ((len = getvl ()) < 0)
		return 0;
#else
	    len = getvl ();
#endif
	    if (type > 0 && type < 16) {
		static const char *label[] = {
		    "Text: ", "Text: ", "Copyright: ", "Track: ",
		    "Instrument: ", "Lyric: ", "Marker: ", "Cue Point: "
		};
		dumpstring ((unsigned)len, label[(type > 7) ? 0 : type], type);
	    }
	    else
		switch (type) {

		/* case 0x00 sequence number */

		case 0x21:	/* MIDI port number */
		    if (len == 1) {
			fread (&midi_port_number, 1, 1, fp);
			if (midi_port_number == EOF) {
			    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
				       "Warning: \"%s\": Short midi file.",
				       current_filename);
			    return 0;
			}
			midi_port_number &= 0x0f;
			if (midi_port_number)
			    ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
				       "(MIDI port number %d)",
				       midi_port_number);
			midi_port_number &= 0x03;
		    }
		    else
			skip (fp, (unsigned)len);
		    break;

		case 0x2F:	/* End of Track */
		    return MAGIC_EOT;

		case 0x51:	/* Tempo */
#ifdef tplus
		    CBYTEI
		    a = (uint8) i;
		    CBYTEI
		    b = (uint8) i;
		    CBYTEI
		    c = (uint8) i;
#else
		    fread (&a, 1, 1, fp);
		    fread (&b, 1, 1, fp);
		    fread (&c, 1, 1, fp);
#endif
		    MIDIEVENT (at, ME_TEMPO, c, a, b);

#ifdef tplus
		/*case 0x54:*/
		    /* SMPTE Offset (hr mn se fr ff)
		     * hr: hours&type
		     *     0     1     2     3    4    5    6    7   bits
		     *     0  |<--type -->|<---- hours [0..23]---->|
		     * type: 00: 24 frames/second
		     *       01: 25 frames/second
		     *       10: 30 frames/second (drop frame)
		     *       11: 30 frames/second (non-drop frame)
		     * mn: minis [0..59]
		     * se: seconds [0..59]
		     * fr: frames [0..29]
		     * ff: fractional frames [0..99]
		     */



		  case 0x58: /* Time Signature */
		    if (len != 4) {
			skip (fp, (unsigned)len);
			break;
		    }
		    CBYTEI
		    a = i;
		    CBYTEI
		    a |= i << 4;
		    CBYTEI
		    b = i;
		    CBYTEI
		    b |= i << 4;

		    MIDIEVENT(at, ME_TIMESIG, 0, a, b);

		  case 0x59: /* Key Signature */
		    if (len != 2) {
			skip (fp, (unsigned)len);
			break;
		    }
		    CBYTEI
		    if (i-256 < -7 || i-256 > 7) { skip (fp, 1); break; }
		    a = i;
		    CBYTEI
		    if (i < 0 || i > 1) break;
		    b = i;

		    MIDIEVENT(at, ME_KEYSIG, 0, a, b);
#endif

		default:
		    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
			       "(Meta event type 0x%02x, length %ld)", type,
			       len);
		    skip (fp, (unsigned)len);
		    break;
		}
	}
	else {
	    a = me;
	    if (a & 0x80) {	/* status byte */
		lastchan = MERGE_CHANNEL_PORT (a & 0x0F);
		laststatus = (a >> 4) & 0x07;
#ifdef tplus
		CBYTEI
		a = (uint8) i;
#else
		fread (&a, 1, 1, fp);
#endif
		a &= 0x7F;
	    }
	    switch (laststatus) {
	    case 0:		/* Note off */
#ifdef tplus
		CBYTEI
		b = (uint8) i;
#else
		fread (&b, 1, 1, fp);
#endif
		b &= 0x7F;
		/*MIDIEVENT(at, ME_NOTEOFF, lastchan, a,b); */
		MIDIEVENT (at, ME_NOTEON, lastchan, a, 0);

	    case 1:		/* Note on */
#ifdef tplus
		CBYTEI
		b = (uint8) i;
#else
		fread (&b, 1, 1, fp);
#endif
		b &= 0x7F;
		MIDIEVENT (at, ME_NOTEON, lastchan, a, b);

	    case 2:		/* Key Pressure */
#ifdef tplus
		CBYTEI
		b = (uint8) i;
#else
		fread (&b, 1, 1, fp);
#endif
		b &= 0x7F;
		MIDIEVENT (at, ME_KEYPRESSURE, lastchan, a, b);

	    case 3:		/* Control change */
#ifdef tplus
		CBYTEI
		b = (uint8) i;
#else
		fread (&b, 1, 1, fp);
#endif
		b &= 0x7F;
		{
		    int     control = 255;
		    switch (a) {
#ifdef tplus
		    case 1: control = ME_MODULATION_WHEEL; break;
		    case 5: control = ME_PORTAMENTO_TIME_MSB; break;
		    case 37: control = ME_PORTAMENTO_TIME_LSB; break;
		    case 65: control = ME_PORTAMENTO; break;

		    case   2: control = ME_BREATH; break;
		    case   4: control = ME_FOOT; break;
		    case   8: control = ME_BALANCE; break;
		    case  38: control = ME_DATA_ENTRY_LSB; break;
		    case  66: control = ME_SOSTENUTO; break;
		    case  67: control = ME_SOFT_PEDAL; break;
		    case  68: control = ME_LEGATO_FOOTSWITCH; break;
		    case  69: control = ME_HOLD2; break;
		    case  84: control = ME_PORTAMENTO_CONTROL; break;
		    case  92: control = ME_TREMOLO_EFFECT; break;
		    case  94: control = ME_CELESTE_EFFECT; break;
		    case  95: control = ME_PHASER_EFFECT; break;
		    case  96: control = ME_RPN_INC; break;
		    case  97: control = ME_RPN_DEC; break;
		    case 126: control = ME_MONO; break;
		    case 127: control = ME_POLY; break;

#endif
		    case 7: control = ME_MAINVOLUME; break;
		    case 10: control = ME_PAN; break;
		    case 11: control = ME_EXPRESSION; break;
		    case 16: control = ME_AC1; break;
		    case 17: control = ME_AC2; break;
#ifdef tplus
		    case 64:
			control = ME_SUSTAIN;
			b = (b >= 64);
			break;
#else
		    case 64: control = ME_SUSTAIN; break;
#endif
		    case 71: control = ME_HARMONICCONTENT; break;
		    case 72: control = ME_RELEASETIME; break;
		    case 73: control = ME_ATTACKTIME; break;
		    case 74: control = ME_BRIGHTNESS; break;
		    case 91: control = ME_REVERBERATION; break;
		    case 93: control = ME_CHORUSDEPTH; break;
		    case 120: control = ME_ALL_SOUNDS_OFF; break;
		    case 121: control = ME_RESET_CONTROLLERS; break;
		    case 123: control = ME_ALL_NOTES_OFF; break;

			/* These should be the SCC-1 tone bank switch
			   commands. I don't know why there are two, or
			   why the latter only allows switching to bank 0.
			   Also, some MIDI files use 0 as some sort of
			   continuous controller. This will cause lots of
			   warnings about undefined tone banks. */
		    case 0:
			if (XG_System_On)
			    control = ME_TONE_KIT;
			else
			    control = ME_TONE_BANK;
			break;
		    case 32:
			if (XG_System_On)
			    control = ME_TONE_BANK;
			break;

		    case 100:
			nrpn = 0;
			rpn_msb[lastchan] = b;
			rpn_count++;
			break;
		    case 101:
			nrpn = 0;
			rpn_lsb[lastchan] = b;
			rpn_count++;
			break;
		    case 98:
			nrpn = 1;
			rpn_lsb[lastchan] = b;
			nrpn_count++;
			break;
		    case 99:
			nrpn = 1;
			rpn_msb[lastchan] = b;
			nrpn_count++;
			break;
		    case 6:
			if (nrpn && nrpn_count == 2) {
			    nrpn_count = 0;
			    if (rpn_msb[lastchan] == 1)
				switch (rpn_lsb[lastchan]) {
#ifdef tplus
				case 0x08:
				    control = ME_VIBRATO_RATE;
				    break;
				case 0x09:
				    control = ME_VIBRATO_DEPTH;
				    break;
				case 0x0a:
				    control = ME_VIBRATO_DELAY;
				    break;
#endif
				case 0x20:
				    control = ME_BRIGHTNESS;
				    break;
				case 0x21:
				    control = ME_HARMONICCONTENT;
				    break;
				case 0x63: /* envelope attack rate */
				    control = ME_ATTACKTIME;
				    break;
				case 0x64: /* envelope decay rate */
				    control = ME_DECAYTIME;
				    break;
				case 0x66: /* envelope release rate */
				    control = ME_RELEASETIME;
				    break;
				}
			    else
				switch (rpn_msb[lastchan]) {
				case 0x14: /* filter cutoff frequency */
				    drumcutoff[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x15: /* filter resonance */
				    drumresonance[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x16:
				    drumattack[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x17:
				    drumdecay[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x18: /* pitch coarse */
				    drumpitch[lastchan][0x7f & rpn_lsb[lastchan]] = b;
				    break;
				case 0x19: /* pitch fine */
				    break;
				case 0x1a:
				    drumvolume[lastchan][0x7f &
							 rpn_lsb[lastchan]] = b;
				    break;
				case 0x1c:
				    if (!b)
					b = (int) (127.0 * rand () /
						   (RAND_MAX));
				    drumpanpot[lastchan][0x7f & rpn_lsb[lastchan]] = b;
				    break;
				case 0x1d:
				    drumreverberation[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x1e:
				    drumchorusdepth[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				case 0x1f: /* variation send level */
				    drumvariationsend[lastchan][0x7f & rpn_lsb [lastchan]] = b;
				    break;
				}
			    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
				       "(Data entry (MSB) for NRPN %02x,%02x: %ld)",
				       rpn_msb[lastchan], rpn_lsb[lastchan], b);
			    break;
			}

			if (rpn_count < 2) {
				rpn_count = 0;
				break;
			}
			rpn_count = 0;

			switch ((rpn_msb[lastchan] << 8) | rpn_lsb[lastchan]) {
			case 0x0000:	/* Pitch bend sensitivity */
			    control = ME_PITCH_SENS;
			    break;
#ifdef tplus
			case 0x0001:
			    control = ME_FINE_TUNING;
			    break;
			case 0x0002:
			    control = ME_COARSE_TUNING;
			    break;
#endif

			case 0x7F7F:	/* RPN reset */
			    /* reset pitch bend sensitivity to 2 */
			    MIDIEVENT (at, ME_PITCH_SENS, lastchan, 2, 0);

			default:
			    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
				       "(Data entry (MSB) for RPN %02x,%02x: %ld)",
				       rpn_msb[lastchan], rpn_lsb[lastchan],
				       b);
			    break;
			}
			break;

		    default:
			ctl->cmsg (CMSG_INFO, VERB_DEBUG,
				   "(Control %d: %d)", a, b);
			break;
		    }
		    if (control != 255) {
			MIDIEVENT (at, control, lastchan, b, 0);
		    }
		}
		break;

	    case 4:		/* Program change */
		a &= 0x7f;
		MIDIEVENT (at, ME_PROGRAM, lastchan, a, 0);

#ifdef tplus
	    case 5:		/* Channel pressure */
		MIDIEVENT (at, ME_CHANNEL_PRESSURE, lastchan, a, 0);
#else
	    case 5:		/* Channel pressure - NOT IMPLEMENTED */
		break;
#endif

	    case 6:		/* Pitch wheel */
#ifdef tplus
		CBYTEI
		b = (uint8) i;
#else
		fread (&b, 1, 1, fp);
#endif
		b &= 0x7F;
		MIDIEVENT (at, ME_PITCHWHEEL, lastchan, a, b);

	    case 7:
		break;

	    default:
		ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			   "*** Can't happen: status 0x%02X, channel 0x%02X",
			   laststatus, lastchan);
		break;
	    }
	}
    }

    return newev;
}

#undef MIDIEVENT

/* Read a midi track into the linked list, either merging with any previous
   tracks or appending to them. */
static int
read_track (int append, int track_number)
{
    MidiEventList *meep;
    MidiEventList *next, *newev;
    int32   len;
    char    tmp[4];

    reading_this_track = track_number;

    midi_port_number = 0;
    meep = evlist;
    if (append && meep) {
	/* find the last event in the list */
	for (; meep->next; meep = (MidiEventList *) meep->next);
	at = meep->event.time;
    }
    else
	at = 0;

    /* Check the formalities */

    if ((fread (tmp, 1, 4, fp) != 4) || (fread (&len, 4, 1, fp) != 1)) {
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "\"%s\": Can't read track header.", current_filename);
	return -1;
    }
    len = BE_LONG (len);
    if (memcmp (tmp, "MTrk", 4)) {
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "\"%s\": Corrupt MIDI file.", current_filename);
	return -2;
    }

    for (;;) {
	if (!(newev = read_midi_event ()))	/* Some kind of error  */
	    return -2;

	if (newev == MAGIC_EOT) {	/* End-of-track Hack. */
	    return 0;
	}

	next = (MidiEventList *) meep->next;
	while (next && (next->event.time < newev->event.time)) {
	    meep = next;
	    next = (MidiEventList *) meep->next;
	}

	newev->next = next;
	meep->next = newev;

	event_count++;		/* Count the event. (About one?) */
	meep = newev;
    }
}

/* Free the linked event list from memory. */
static void
free_midi_list (void)
{
    MidiEventList *meep, *next;
    if (!(meep = evlist))
	return;
    while (meep) {
	next = (MidiEventList *) meep->next;
	free (meep);
	meep = next;
    }
    evlist = 0;
}

static void
xremap_percussion (int *banknumpt, int *this_notept, int this_kit)
{
    int     i, newmap;
    int     banknum = *banknumpt;
    int     this_note = *this_notept;
    int     newbank, newnote;

/* When this_kit is 125, the second rhythm sfx set is requested. */
    if (this_kit == 125) {
	    if (drumset[SFXDRUM2]) *banknumpt = SFXDRUM2;
	    else if (drumset[122]) *banknumpt = 122;
	    return;
    }

    if (this_kit != 127 && this_kit != 126)
	return;

    for (i = 0; i < XMAPMAX; i++) {
	newmap = xmap[i][0];
	if (!newmap)
	    return;
	if (this_kit == 127 && newmap != XGDRUM)
	    continue;
	if (this_kit == 126 && newmap != SFXDRUM1)
	    continue;
	if (xmap[i][1] != banknum)
	    continue;
	if (xmap[i][3] != this_note)
	    continue;
	newbank = xmap[i][2];
	newnote = xmap[i][4];
	if (newbank == banknum && newnote == this_note)
	    return;
	if (!drumset[newbank])
	    return;
	*banknumpt = newbank;
	*this_notept = newnote;
	return;
    }
}

/* Allocate an array of MidiEvents and fill it from the linked list of
   events, marking used instruments for loading. Convert event times to
   samples: handle tempo changes. Strip unnecessary events from the list.
   Free the linked list. */
static MidiEvent *
groom_list (int32 divisions, uint32 *eventsp, uint32 *samplesp)
{
    MidiEvent *groomed_list, *lp;
    MidiEventList *meep;
    int32   i, our_event_count, tempo, skip_this_event, new_value;
    int32   sample_cum, samples_to_do, st, dt, counting_time;
    //uint32  at;
    struct meta_text_type *meta = meta_text_list;

    int     current_bank[MAXCHAN], current_variation[MAXCHAN], current_banktype[MAXCHAN],
	current_set[MAXCHAN], current_kit[MAXCHAN],
       	current_program[MAXCHAN], sfx_is_valid[MAXCHAN];
    /* Or should each bank have its own current program? */
    int     dset, dnote, drumsflag, mprog;

    for (i = 0; i < MAXCHAN; i++) {
	current_bank[i] = 0;
	current_variation[i] = 0;
	current_banktype[i] = 0;
	current_set[i] = 0;
	current_kit[i] = channel[i].kit;
	current_program[i] = default_program;
	sfx_is_valid[i] = 0;
    }

    tempo = 500000;
    compute_sample_increment (tempo, divisions);

    /* This may allocate a bit more than we need */
    groomed_list = lp =
	(MidiEvent *) safe_malloc (sizeof (MidiEvent) * (event_count + 1));
    meep = evlist;

    our_event_count = 0;
    st = at = sample_cum = 0;
    counting_time = 2;		/* We strip any silence before the first NOTE ON. */


    for (i = 0; i < event_count; i++) {
	int a, b, ch;
	skip_this_event = 0;
	ch = meep->event.channel;
	a = meep->event.a;
	b = meep->event.b;
	ctl->cmsg (CMSG_INFO, VERB_DEBUG_SILLY,
		   "%6d: ch %2d: event %d (%d,%d)",
		   meep->event.time, ch + 1,
		   meep->event.type, a, b);
	while (meta && meta->time <= at) {
	    meta->time = st;
	    meta = meta->next;
	}
	if (meep->event.type == ME_TEMPO) {
#ifndef tplus
	    tempo =
		ch + b * 256 + a * 65536;
	    compute_sample_increment (tempo, divisions);
#endif
	}
	else if ((quietchannels & (1 << ch)))
	    skip_this_event = 1;
	else
	    switch (meep->event.type) {
	    case ME_PROGRAM:
		if (current_kit[ch]) {
		    if (current_kit[ch] == 126 || current_kit[ch] == 125) {
			/* note request for 2nd sfx rhythm kit */
			if (a == 1 && (drumset[SFXDRUM2]||drumset[122])) {
			    current_kit[ch] = 125;
			    current_set[ch] = SFXDRUM2;
			    new_value = a;
			}
			else if (!a && (drumset[SFXDRUM1]||drumset[121])) {
			    current_set[ch] = SFXDRUM1;
			    new_value = a;
			}
			else if (drumset[a + SFXBANK]) {
			    current_set[ch] = a + SFXBANK;
			    new_value = a;
			}
			else {
			    ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				       "XG SFX drum set %d is undefined", a);
			    skip_this_event = 1;
			}
			break;
		    }
		    if (drumset[a])	/* Is this a defined drumset? */
			new_value = a;
		    else {
			ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "Drum set %d is undefined", a);
			if (drumset[0])
			    new_value = a = 0;
			else {
			    skip_this_event = 1;
			    break;
			}
		    }
		    if (current_set[ch] != new_value)
			current_set[ch] = new_value;
		    else
			skip_this_event = 1;
		}
		else {
		    new_value = a;
		    current_program[ch] = new_value;

		    /* Have to mark the instrument to be loaded here, because
		     * there might not be any notes on a channel that receives
		     * from another channel.
		     */
		    if (!skip_this_event) {
			int banknum = current_bank[ch];

		        if (current_banktype[ch] == SFX_BANKTYPE && sfx_is_valid[ch]) {
			    if (tonebank[SFXBANK]) banknum = SFXBANK;
			    else ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "XG sfx bank on channel %d is undefined",
				   ch + 1);
			}
		        else if (current_banktype[ch] == 48) {
			    if (tonebank[banknum + MU100BANK]) banknum += MU100BANK;
			    else ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "XG mu100 bank %d on channel %d is undefined",
				   current_bank[ch], ch + 1);
		        }
		        else if (current_banktype[ch] == 33) {
			    if (tonebank[banknum + VLBANK]) banknum += VLBANK;
			    else ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "XG vl bank %d on channel %d is undefined",
				   current_bank[ch], ch + 1);
		        }
			else if (current_variation[ch]) {
				if (XG_System_On &&
				    current_variation[ch] < NUM_VARIATION_BANKS &&
				    tonebank[SFXBANK+current_variation[ch]] &&
				    tonebank[SFXBANK+current_variation[ch]]->tone[new_value].name)
					banknum = SFXBANK + current_variation[ch];
				else banknum = 0;
			}
#define WATCH_MU
			if (opt_bank && !banknum &&
				tonebank[opt_bank] &&
				tonebank[opt_bank]->tone[new_value].name)
			    banknum = opt_bank;
			if (tonebank[banknum] && !(tonebank[banknum]->tone[new_value].layer)) {
			        tonebank[banknum]->tone[new_value].layer =
				    MAGIC_LOAD_INSTRUMENT;
#ifdef WATCH_MU
			  if (banknum >= MU100BANK) ctl->cmsg (CMSG_TRACE, VERB_VERBOSE,
			   "Load xg patch [%d,%d] ch %d",
			   new_value, current_bank[ch], ch + 1);
#endif
			}
		    }
		}
		break;

	    case ME_NOTEON:

		if (counting_time)
		    counting_time = 1;

		drumsflag = current_kit[ch];

		if (drumsflag) {	/* percussion channel? */
		    dset = current_set[ch];
		    dnote = a;
		    if (XG_System_On)
			xremap_percussion (&dset, &dnote, drumsflag);

		    /*if (current_config_pc42b) pcmap(&dset, &dnote, &mprog, &drumsflag); */

		    if (drumsflag) {
			int rec_chan;
			/* Mark this instrument to be loaded */
			if (!(drumset[dset]->tone[dnote].layer)) {
			    drumset[dset]->tone[dnote].layer =
				MAGIC_LOAD_INSTRUMENT;
			}
			else
			    drumset[dset]->tone[dnote].last_used
				= current_tune_number;
			if (!channel[ch].name)
			    channel[ch].name =
				drumset[dset]->name;

			for (rec_chan = 0; rec_chan < MAXCHAN; rec_chan++) {
			    if (rec_chan == ch) continue;
			    if (channel[rec_chan].receive == ch && current_kit[rec_chan]) {
				dset = current_set[rec_chan];
				if (!channel[rec_chan].kit) {
					channel[rec_chan].kit = current_kit[rec_chan];
					channel[rec_chan].futurekit = current_kit[rec_chan];
				}
		    		if (XG_System_On)
					xremap_percussion (&dset, &dnote, current_kit[rec_chan]);
				/* Mark this instrument to be loaded */
				if (!drumset[dset]) continue;
				if (!(drumset[dset]->tone[dnote].layer)) {
			    	    drumset[dset]->tone[dnote].layer =
					MAGIC_LOAD_INSTRUMENT;
				}
				else drumset[dset]->tone[dnote].last_used = current_tune_number;
			    }
			}

		    }
		}

		if (!drumsflag) {	/* not percussion */
		    int     banknum = current_bank[ch];

		    mprog = current_program[ch];

		    if (current_banktype[ch] == SFX_BANKTYPE && sfx_is_valid[ch])
			banknum = SFXBANK;
		    else if (current_banktype[ch] == 48) {
			if (tonebank[banknum+MU100BANK] &&
			    tonebank[banknum+MU100BANK]->tone[mprog].name) {
			       	banknum += MU100BANK;
				current_variation[ch] = 0;
			}
		    }
		    else if (current_banktype[ch] == 33) {
			if (tonebank[banknum+VLBANK] &&
			    tonebank[banknum+VLBANK]->tone[mprog].name) {
			       	banknum += VLBANK;
				current_variation[ch] = 0;
			}
		    }


		    if (mprog == SPECIAL_PROGRAM)
			break;

		    if (XG_System_On && banknum == SFXBANK
			&& !tonebank[SFXBANK] && tonebank[120])
			banknum = 120;

		    /*if (current_config_pc42b) pcmap(&banknum, &dnote, &mprog, &drumsflag); */

		    if (drumsflag) {
		      if (drumset[dset] && drumset[dset]->tone[dnote].name) {
			/* Mark this instrument to be loaded */
			if (!(drumset[dset]->tone[dnote].layer)) {
			    drumset[dset]->tone[dnote].layer =
				MAGIC_LOAD_INSTRUMENT;
			}
			else
			    drumset[dset]->tone[dnote].last_used =
				current_tune_number;
			if (!channel[ch].name)
			    channel[ch].name =
				drumset[dset]->name;
		      }
		    }
		    if (!drumsflag) {
		      if (opt_bank && !banknum &&
				tonebank[opt_bank] &&
				tonebank[opt_bank]->tone[mprog].name)
			    banknum = opt_bank;
		      if (tonebank[banknum] && tonebank[banknum]->tone[mprog].name) {
			/* Mark this instrument to be loaded */
			if (!(tonebank[banknum]->tone[mprog].layer)) {
			    tonebank[banknum]->tone[mprog].layer =
				MAGIC_LOAD_INSTRUMENT;

#ifdef WATCH_MU
			  if (banknum >= MU100BANK) ctl->cmsg (CMSG_TRACE, VERB_VERBOSE,
			   "Load xg patch [%d,%d] ch %d",
			   mprog, current_bank[ch], ch + 1);
#endif
			}
			else
			    tonebank[banknum]->tone[mprog].last_used =
				current_tune_number;
			if (!channel[ch].name)
			    channel[ch].name =
				tonebank[banknum]->tone[mprog].name;
		      }
		      else if (banknum >= MU100BANK) ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
			   "No patch %d for XG mu100 or vl bank %d on channel %d",
			   mprog, current_bank[ch], ch + 1);
		    }
		}
		break;

	    case ME_TONE_KIT:
		sfx_is_valid[ch] = 0;
		if (!a || a == 127 || a == 126) {
		    current_kit[ch] = a;
		    break;
		}
		if (a == 48 || a == 33) {
			ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "XG %s bank %d on channel %d",
				   (a == 48)? "mu100" : "vl",
				   a, ch + 1);
		    current_banktype[ch] = a;
		    break;
		}
		if (a == 81 || a == 97) {
		    ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
				   "VL_XG kit %d on channel %d",
				   a, ch + 1);
		    skip_this_event = 1;
		    break;
		}
		if (a != SFX_BANKTYPE) {
		    ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
			       "XG kit %d on channel %d is impossible",
			       a, ch + 1);
		    skip_this_event = 1;
		    break;
		}

		//if (current_kit[ch]) {
		 //   skip_this_event = 1;
		 //   break;
		//}
		if (a == SFX_BANKTYPE && (tonebank[SFXBANK] || tonebank[120]))
				/* Is this a defined tone bank? */
		    new_value = SFX_BANKTYPE;
		else {
		    ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
			       "XG Sfx bank is undefined");
		    skip_this_event = 1;
		    break;
		}
		current_banktype[ch] = new_value;
		current_variation[ch] = 0;
		break;

	    case ME_TONE_BANK:
		if (current_kit[ch]) {
		    skip_this_event = 1;
		    break;
		}
		if (!a && current_banktype[ch] == SFX_BANKTYPE)
			sfx_is_valid[ch] = 1;
		else sfx_is_valid[ch] = 0;
		if (XG_System_On && !current_banktype[ch] && a < NUM_VARIATION_BANKS) {
		    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
			       "XG variation bank %d", a);
		    current_variation[ch] = new_value = a;
		    current_bank[ch] = 0;
		    if ( (new_value >= 40 && new_value <= 45) || (new_value >= 52 && new_value <= 54) )
			if (!(tonebank[0]->tone[115].layer)) {
			    tonebank[0]->tone[115].layer =
				MAGIC_LOAD_INSTRUMENT;
			}
		    break;
		}
		else {
		    int bo = 0;

		    current_variation[ch] = 0;
		    if (current_banktype[ch] == 33) bo = VLBANK;
		    else if (current_banktype[ch] == 48) bo = MU100BANK;
		    if (tonebank[a + bo])	/* Is this a defined tone bank? */
		        new_value = a;
		    else {
		        ctl->cmsg (CMSG_INFO, VERB_DEBUG,
			       "Variation bank %d", a);
		        current_variation[ch] = new_value = a;
		        current_bank[ch] = 0;
		        if ( (new_value >= 40 && new_value <= 45) || (new_value >= 52 && new_value <= 54) )
			    if (!(tonebank[0]->tone[115].layer)) {
			        tonebank[0]->tone[115].layer =
				    MAGIC_LOAD_INSTRUMENT;
			    }
		        break;
		    }
		}

		current_bank[ch] = new_value;
		break;

	    }

	/* Recompute time in samples */
	if ((dt = meep->event.time - at) && !counting_time) {
	    samples_to_do = sample_increment * dt;
	    sample_cum += sample_correction * dt;
	    if (sample_cum & 0xFFFF0000) {
		samples_to_do += ((sample_cum >> 16) & 0xFFFF);
		sample_cum &= 0x0000FFFF;
	    }
	    st += samples_to_do;
	}
	else if (counting_time == 1)
	    counting_time = 0;
#ifdef tplus
	if (meep->event.type == ME_TEMPO) {
	    tempo =
		ch + b * 256 + a * 65536;
	    compute_sample_increment (tempo, divisions);
	}
#endif
	if (!skip_this_event) {
	    /* Add the event to the list */
	    *lp = meep->event;
	    lp->time = st;
	    lp++;
	    our_event_count++;
	}
	at = meep->event.time;
	meep = (MidiEventList *) meep->next;
    }
    /* Add an End-of-Track event */
    lp->time = st;
    lp->type = ME_EOT;
    our_event_count++;
    free_midi_list ();

    *eventsp = our_event_count;
    *samplesp = st;
    return groomed_list;
}

MidiEvent *
read_midi_file (FILE * mfp, uint32 *count, uint32 *sp)
{
    uint32  len;
    int32   divisions;
    int16   format, tracks, divisions_tmp;
    int     i;
    char    tmp[4];

    fp = mfp;
    event_count = 0;
    at = 0;
    evlist = 0;
    free_metatext ();
    GM_System_On = GS_System_On = XG_System_On = 0;
    vol_table = def_vol_table;
    XG_System_reverb_type = HALL1;
    XG_System_chorus_type = CHORUS1;
    XG_System_variation_type = DELAYLCR;
    XG_insertion1_type = DISTORTION;
    XG_insertion2_type = DISTORTION;

    for (i = 0; i < MAX_PARAMETER_DEFAULT; i++)
	xg_parameter[i] = xg_parameter_default[i];
    for (i = 0; i < MAX_INSERTION_PARAMETER; i++)
	xg_insertion1_parameter[i] = xg_insertion2_parameter[i] = xg_insertion_parameter_default[i];
    for (i = 0; i < MAX_XG_DRUM_SETUP; i++)
	drum_setup_xg[i] = rhythm_part[i] = -1;

    memset (&drumvolume, -1, sizeof (drumvolume));
    memset (&drumchorusdepth, -1, sizeof (drumchorusdepth));
    memset (&drumreverberation, -1, sizeof (drumreverberation));
    memset (&drumattack, -1, sizeof (drumattack));
    memset (&drumdecay, -1, sizeof (drumdecay));
    memset (&drumpitch, -1, sizeof (drumpitch));
    memset (&drumpanpot, NO_PANNING, sizeof (drumpanpot));
    memset (&drumcutoff, -1, sizeof (drumcutoff));
    memset (&drumresonance, -1, sizeof (drumresonance));
    memset (&drumvariationsend, -1, sizeof (drumvariationsend));

    for (i = 0; i < MAXCHAN; i++) {
	channel[i].transpose = 0;
	if (ISDRUMCHANNEL (i))
	    channel[i].kit = 127;
	else
	    channel[i].kit = 0;
	channel[i].futurekit = 0;
	channel[i].brightness = 64;
	channel[i].harmoniccontent = 64;
	channel[i].variationbank = 0;
	channel[i].chorusdepth = 0;
	channel[i].reverberation = 0;
	channel[i].name = 0;
	channel[i].xg = 0;
	channel[i].receive = -1;
    }

  past_riff:

    if ((fread (tmp, 1, 4, fp) != 4) || (fread (&len, 4, 1, fp) != 1)) {
	if (ferror (fp)) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "\"%s\": %s",
		       current_filename, strerror (errno));
	}
	else
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		       "\"%s\": Not a MIDI file!", current_filename);
	return 0;
    }
    len = BE_LONG (len);

    if (!memcmp (tmp, "RIFF", 4)) {
	fread (tmp, 1, 12, fp);
	goto past_riff;
    }

    if (memcmp (tmp, "MThd", 4) || len < 6) {
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "\"%s\": Not a MIDI file!", current_filename);
	return 0;
    }

    if (fread (&format, 2, 1, fp) != 1) {
	if (ferror (fp)) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "\"%s\": %s",
		       current_filename, strerror (errno));
	}
	else
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		       "\"%s\": Not a MIDI file!", current_filename);
	return 0;
    }
    if (fread (&tracks, 2, 1, fp) != 1) {
	if (ferror (fp)) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "\"%s\": %s",
		       current_filename, strerror (errno));
	}
	else
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		       "\"%s\": Not a MIDI file!", current_filename);
	return 0;
    }
    if (fread (&divisions_tmp, 2, 1, fp) != 1) {
	if (ferror (fp)) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "\"%s\": %s",
		       current_filename, strerror (errno));
	}
	else
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		       "\"%s\": Not a MIDI file!", current_filename);
	return 0;
    }
    /* fread(&divisions_tmp, 2, 1, fp); */
    format = BE_SHORT (format);
    tracks = BE_SHORT (tracks);
    divisions_tmp = BE_SHORT (divisions_tmp);

    if (divisions_tmp < 0) {
	/* SMPTE time -- totally untested. Got a MIDI file that uses this? */
	divisions =
	    (int32) (-(divisions_tmp / 256)) * (int32) (divisions_tmp & 0xFF);
    }
    else
	divisions = (int32) (divisions_tmp);

    if (len > 6) {
	ctl->cmsg (CMSG_WARNING, VERB_NORMAL,
		   "%s: MIDI file header size %ld bytes",
		   current_filename, len);
	skip (fp, len - 6);	/* skip the excess */
    }
    if (format < 0 || format > 2) {
	ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		   "\"%s\": Unknown MIDI file format %d", current_filename,
		   format);
	return 0;
    }
    ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
	       "Format: %d  Tracks: %d  Divisions: %d", format, tracks,
	       divisions);

    /* Put a do-nothing event first in the list for easier processing */
    evlist = (MidiEventList *) safe_malloc (sizeof (MidiEventList));
    evlist->event.time = 0;
    evlist->event.type = ME_NONE;
    evlist->next = 0;
    event_count++;

    switch (format) {
    case 0:
	if (read_track (0, 0)) {
	    free_midi_list ();
	    return 0;
	}
	break;

    case 1:
	for (i = 0; i < tracks; i++)
	    if (read_track (0, i)) {
		free_midi_list ();
		return 0;
	    }
	break;

    case 2:			/* We simply play the tracks sequentially */
	for (i = 0; i < tracks; i++)
	    if (read_track (1, i)) {
		free_midi_list ();
		return 0;
	    }
	break;
    }
    return groom_list (divisions, count, sp);
}
