--- playmidi-1.2/emumidi.c	Sun Nov 20 09:46:34 1994
+++ emumidi.cc	Sat Nov 29 02:24:33 1997
@@ -4,12 +4,21 @@
  * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
  * Source code may be freely distributed in unmodified form.
  *************************************************************************/
+
+/*
+ * modified by S.Kuramochi 1996,1997
+ * $Id: emumidi.cc,v 1.3 1997-11-29 02:24:33+09 satoshi Exp $
+ */
 #include "playmidi.h"
+#include "shmem.h"
 #ifndef USE_SEQUENCER2
 
+extern CRegister* creg;
+extern volatile Register* reg;
+
 SEQ_USE_EXTBUF();
 
-extern int seqfd, play_ext, play_gus, play_sb, gus_dev, sb_dev, wantopl3;
+extern int seqfd, play_ext, play_gus, play_sb, gus_dev, sb_dev, ext_dev, wantopl3;
 extern struct synth_info card_info[MAX_CARDS];
 extern int perc, ticks;
 
@@ -36,6 +45,74 @@
 static struct chanstate channel[16];
 #define CN (ISGUS(chn) ? 0 : 1)
 
+static int recv_port[16];	// 32 ???
+
+#if defined(RSMIDI)
+static int cur_port;
+static const unsigned char MIDI_PORT_CHANGE = 0xf5;
+// Roland SC-88, Yamaha MU80, etc. accept this message.
+
+inline void change_port(int dev, int p)
+{
+  SEQ_MIDIOUT(dev, MIDI_PORT_CHANGE);
+  SEQ_MIDIOUT(dev, p);
+}
+
+inline void check_channel(int dev, int chn)
+{
+  if((chn & 0xf0) != cur_port) {
+    cur_port = chn & 0xf0;
+    change_port(dev, (cur_port>>4)+1);	// 1:A port, 2:B port
+  }
+}
+#elif defined(EXC32)
+static int invalid_block[32] = {
+  17, 18, 19, 20, 21, 22, 23, 24, 25, 16, 26, 27, 28, 29, 30, 31,
+   1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12, 13, 14, 15};
+static int valid_block[32] = {
+   1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12, 13, 14, 15,
+  17, 18, 19, 20, 21, 22, 23, 24, 25, 16, 26, 27, 28, 29, 30, 31};
+
+inline void change_recv_port(int dev, int chn)
+{
+  unsigned char sum = 128-((0x00+0x01+invalid_block[chn]+0x01)&0x7f);
+  SEQ_MIDIOUT(dev, 0xf0);
+  SEQ_MIDIOUT(dev, 0x41);
+  SEQ_MIDIOUT(dev, 0x10);
+  SEQ_MIDIOUT(dev, 0x42);
+  SEQ_MIDIOUT(dev, 0x12);
+  SEQ_MIDIOUT(dev, 0x00);
+  SEQ_MIDIOUT(dev, 0x01);
+  SEQ_MIDIOUT(dev, invalid_block[chn]); /* CHANNEL MSG RX PORT*/
+  SEQ_MIDIOUT(dev, 0x01); /* PORT B */
+  SEQ_MIDIOUT(dev, sum);
+  SEQ_MIDIOUT(dev, 0xf7);
+
+  sum = 128-((0x00+0x01+valid_block[chn]+0x00)&0x7f);
+  SEQ_MIDIOUT(dev, 0xf0);
+  SEQ_MIDIOUT(dev, 0x41);
+  SEQ_MIDIOUT(dev, 0x10);
+  SEQ_MIDIOUT(dev, 0x42);
+  SEQ_MIDIOUT(dev, 0x12);
+  SEQ_MIDIOUT(dev, 0x00);
+  SEQ_MIDIOUT(dev, 0x01);
+  SEQ_MIDIOUT(dev, valid_block[chn]); /* CHANNEL MSG RX PORT*/
+  SEQ_MIDIOUT(dev, 0x00); /* PORT A */
+  SEQ_MIDIOUT(dev, sum);
+  SEQ_MIDIOUT(dev, 0xf7);
+}
+
+inline void check_channel(int dev, int chn)
+{
+  if(recv_port[chn&0x0f] != (chn>>4)) {
+    change_recv_port(dev, chn);
+    recv_port[chn&0x0f] = (chn>>4);
+  }
+}
+#elif defined(CUT32)
+#define check_channel(dev,chn) if((chn) > 16) return;
+#endif /* CUT32 */
+
 void seq_reset()
 {
     int i;
@@ -67,24 +144,36 @@
 	    }
 		
     }
+
+    if(play_ext) {
+      for(i = 0; i < 16; i++)
+	recv_port[i] = 0;
+    }
+
+#ifdef RSMIDI
+    if(play_ext) {
+      cur_port = 0x10;	// A port
+      change_port(ext_dev, cur_port);
+    }
+#endif
 }
 
-void seq_set_patch(dev, chn, pgm)
-int dev, chn, pgm;
+void seq_set_patch(int dev, int chn, int pgm)
 {
    if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_PGM_CHANGE + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_PGM_CHANGE + (chn&0x0f));
 	SEQ_MIDIOUT(dev, pgm);
    } else
 	channel[chn].program = pgm;
 }
 
-void seq_stop_note(dev, chn, note, vel)
-int dev, chn, note, vel;
+void seq_stop_note(int dev, int chn, int note, int vel)
 {
     int i, card = CN;
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_NOTEOFF + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_NOTEOFF + (chn&0x0f));
 	SEQ_MIDIOUT(dev, note);
 	SEQ_MIDIOUT(dev, vel);
     } else
@@ -98,12 +187,12 @@
 	    }
 }
 
-void seq_key_pressure(dev, chn, note, vel)
-int dev, chn, note, vel;
+void seq_key_pressure(int dev, int chn, int note, int vel)
 {
     int i, card = CN;
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_KEY_PRESSURE + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_KEY_PRESSURE + (chn&0x0f));
 	SEQ_MIDIOUT(dev, note);
 	SEQ_MIDIOUT(dev, vel);
     } else if (vel == 0)
@@ -115,12 +204,12 @@
 		SEQ_KEY_PRESSURE(dev, i, note, vel);
 }
 
-void seq_start_note(dev, chn, note, vel)
-int dev, chn, note, vel;
+void seq_start_note(int dev, int chn, int note, int vel)
 {
     int i, oldest = 0, card = CN;
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_NOTEON + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_NOTEON + (chn&0x0f));
 	SEQ_MIDIOUT(dev, note);
 	SEQ_MIDIOUT(dev, vel);
     } else if (vel == 0)
@@ -159,12 +248,12 @@
 { 127, 127, 127, 127, 127, 127, 127, 127,
   127, 127, 127, 127, 127, 127, 127, 127};
 
-void seq_control(dev, chn, p1, p2)
-int dev, chn, p1, p2;
+void seq_control(int dev, int chn, int p1, int p2)
 {
     int i, card = CN;
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_CTL_CHANGE + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_CTL_CHANGE + (chn&0x0f));
 	SEQ_MIDIOUT(dev, p1);
 	SEQ_MIDIOUT(dev, p2);
     } else {
@@ -207,22 +296,22 @@
     }
 }
 
-void seq_chn_pressure(dev, chn, vel)
-int dev, chn, vel;
+void seq_chn_pressure(int dev, int chn, int vel)
 {
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_CHN_PRESSURE + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_CHN_PRESSURE + (chn&0x0f));
 	SEQ_MIDIOUT(dev, vel);
     } else
 	channel[chn].pressure = vel;
 }
 
-void seq_bender(dev, chn, val)
-int dev, chn, val;
+void seq_bender(int dev, int chn, int val)
 {
     int card = CN, i;
     if (ISMIDI(chn)) {
-	SEQ_MIDIOUT(dev, MIDI_PITCH_BEND + chn);
+	check_channel(dev, chn);
+	SEQ_MIDIOUT(dev, MIDI_PITCH_BEND + (chn&0x0f));
 	SEQ_MIDIOUT(dev, val >> 7);
 	SEQ_MIDIOUT(dev, val & 0x7f);
     } else {
--- playmidi-1.2/midifile.c	Wed Jul 12 12:19:00 1995
+++ midifile.cc	Sat Jan  3 05:21:59 1998
@@ -49,6 +49,11 @@
  *	(12) readmt returns EOF when it encounters a 0 or 0x1a byte instead of an expected
  *		header string (some midi files have padding at end).
  */
+
+/*
+ * modified by Satoshi KURAMOCHI 1996-1998
+ * $Id: midifile.cc,v 1.5 1998-01-03 05:21:59+09 satoshi Exp $
+ */
 #define NO_LC_DEFINES
 #include "midifile.h"
 #ifdef NO_LC_DEFINES
@@ -59,8 +64,20 @@
 #define upperbyte(x) ((unsigned char)((x & 0xff00)>>8))
 #endif
 
+#include "kconv.h"
+#include "shmem.h"
+extern volatile Register* reg;
+
+extern void check_sysex(const unsigned char* ex, int length);	// rcpfile.cc
+
+extern const char* inst_sc88_pro[128][128];
+extern const char* inst_sc88_88[128][128];
+extern const char* inst_sc88_55[128][128];
+
+extern void init_inst_name(void);
+
 #define NULLFUNC 0
-#define NULL 0
+/*#define NULL 0*/
 
 #define THINK
 
@@ -70,41 +87,44 @@
 
 #include <stdio.h>
 #include <values.h>
+#include <string.h>
 
-char *strcpy (), *strcat ();
-/*void exit(), free();*/
+void write16bit (int data);
+void write32bit (unsigned long data);
+void mf_write_header_chunk (int format, int ntracks, int division);
+void mf_write_track_chunk (int which_track, FILE* fp);
 
 /* public stuff */
 
 /* Functions to be called while processing the MIDI file. */
-int (*Mf_getc) () = NULLFUNC;
-void (*Mf_error) () = NULLFUNC;
-void (*Mf_header) () = NULLFUNC;
-void (*Mf_trackstart) () = NULLFUNC;
-void (*Mf_trackend) () = NULLFUNC;
-void (*Mf_noteon) () = NULLFUNC;
-void (*Mf_noteoff) () = NULLFUNC;
-void (*Mf_pressure) () = NULLFUNC;
-void (*Mf_parameter) () = NULLFUNC;
-void (*Mf_pitchbend) () = NULLFUNC;
-void (*Mf_program) () = NULLFUNC;
-void (*Mf_chanpressure) () = NULLFUNC;
-void (*Mf_sysex) () = NULLFUNC;
-void (*Mf_arbitrary) () = NULLFUNC;
-void (*Mf_metamisc) () = NULLFUNC;
-void (*Mf_seqnum) () = NULLFUNC;
-void (*Mf_eot) () = NULLFUNC;
-void (*Mf_smpte) () = NULLFUNC;
-void (*Mf_tempo) () = NULLFUNC;
-void (*Mf_timesig) () = NULLFUNC;
-void (*Mf_keysig) () = NULLFUNC;
-void (*Mf_seqspecific) () = NULLFUNC;
-void (*Mf_text) () = NULLFUNC;
+int (*Mf_getc) (void) = NULLFUNC;
+void (*Mf_error) (char *msg) = NULLFUNC;
+void (*Mf_header) (int format, int ntrks, int division) = NULLFUNC;
+void (*Mf_trackstart) (void) = NULLFUNC;
+void (*Mf_trackend) (void) = NULLFUNC;
+void (*Mf_noteon) (int chan, int pitch, int vol) = NULLFUNC;
+void (*Mf_noteoff) (int chan, int pitch, int vol) = NULLFUNC;
+void (*Mf_pressure) (int chan, int pitch, int pressure) = NULLFUNC;
+void (*Mf_parameter) (int chan, int control, int value) = NULLFUNC;
+void (*Mf_pitchbend) (int chan, int msb, int lsb) = NULLFUNC;
+void (*Mf_program) (int chan, int program) = NULLFUNC;
+void (*Mf_chanpressure) (int chan, int pressure) = NULLFUNC;
+void (*Mf_sysex) (int leng, char *msg) = NULLFUNC;
+void (*Mf_arbitrary) (int leng, char *msg) = NULLFUNC;
+void (*Mf_metamisc) (int type, int leng, char *msg) = NULLFUNC;
+void (*Mf_seqnum) (int num) = NULLFUNC;
+void (*Mf_eot) (void) = NULLFUNC;
+void (*Mf_smpte) (int hour, int min, int sec, int frame, int fract) = NULLFUNC;
+void (*Mf_tempo) (int microsecs) = NULLFUNC;
+void (*Mf_timesig) (int numer, int denom, int clocks, int qnotes) = NULLFUNC;
+void (*Mf_keysig) (int sharpflat, int minor) = NULLFUNC;
+void (*Mf_seqspecific) (int type, int leng, char *msg) = NULLFUNC;
+void (*Mf_text) (int type, int leng, char *msg) = NULLFUNC;
 
 /* Functions to implement in order to write a MIDI file */
-int (*Mf_putc) () = NULLFUNC;
-int (*Mf_writetrack) () = NULLFUNC;
-int (*Mf_writetempotrack) () = NULLFUNC;
+int (*Mf_putc) (int c) = NULLFUNC;
+int (*Mf_writetrack) (int track) = NULLFUNC;
+int (*Mf_writetempotrack) (void) = NULLFUNC;
 
 int Mf_nomerge = 0;		/* 1 => continue'ed system exclusives are */
  /* not collapsed. */
@@ -130,64 +150,95 @@
 static long Mf_toberead = 0L;
 static long Mf_numbyteswritten = 0L;
 
-static long readvarinum ();
-static long read32bit ();
-static long to32bit ();
-static int read16bit ();
-static int to16bit ();
-static char *msg ();
-static void readheader ();
-static int readtrack ();
-static void badbyte ();
-static void metaevent ();
-static void sysex ();
-static void chanmessage ();
-static void msginit ();
-static int msgleng ();
-static void msgadd ();
-static void biggermsg ();
+extern bool is_xg;	// data for XG
+extern bool is_sc88;	// data for SC-88
+extern bool is_sc88pro;	// data for SC-88Pro
+
+static long readvarinum (void);
+static long read32bit (void);
+static long to32bit (int c1, int c2, int c3, int c4);
+static int read16bit (void);
+static int to16bit (int c1, int c2);
+static char *msg (void);
+static void readheader (void);
+static int readtrack (void);
+static void badbyte (int c);
+static void metaevent (int type);
+static void sysex (void);
+static void chanmessage (int status, int c1, int c2);
+static void msginit (void);
+static int msgleng (void);
+static void msgadd (int c);
+static void biggermsg (void);
 static int eputc (unsigned char c);
 
 double mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo);
-int mf_write_meta_event ();
-void mf_write_tempo ();
-void mf_write_seqnum ();
-void WriteVarLen ();
+int mf_write_meta_event (unsigned long delta_time, unsigned char type,
+		     unsigned char* data, unsigned long size);
+void mf_write_tempo (unsigned long delta_time, unsigned long tempo);
+void mf_write_seqnum (unsigned long delta_time, unsigned seqnum);
+void WriteVarLen (unsigned long value);
 
 #ifdef READ_MODS
 #include "mp_mod.c"
 static int mod_file_flag = 0;
 #endif /* READ_MODS */
 static int force_exit;
+static bool title_flag = false;
 
 void
-mfread ()
+mfread (void)
 {
+  is_sc88 = false;
+  is_sc88pro = false;
+  is_xg = false;
+  title_flag = false;
+
   force_exit = 0;
   if (Mf_getc == NULLFUNC)
     mferror ("mfread() called without setting Mf_getc");
 
+  init_inst_name();
+
   readheader ();
 #ifdef READ_MODS
   if (mod_file_flag)
     do_module();
   else
 #endif
-    while (readtrack () && !force_exit)
-      ;
+    {
+      unsigned long total_st = 0;
+      while (readtrack () && !force_exit)
+	if (total_st < Mf_currtime)
+	  total_st = Mf_currtime;
+      fprintf(stderr, "Total ST: %lu\n", total_st);
+      for(Mf_currtime = 0; Mf_currtime <= total_st;
+	  Mf_currtime += 4*Mf_division/48)
+	Mf_seqspecific(0, 0, NULL);
+    }
+
+  reg->timebase = Mf_division;
+
+  fprintf(stderr, "Data for %s\n",
+	  (is_xg ? "XG" :
+	   is_sc88pro ? "SC-88Pro" :
+	   is_sc88 ? "SC-88" : "SC-55"));
+  reg->xg = is_xg;
+  reg->sc88pro = is_sc88pro;
+  reg->sc88 = is_sc88;
+  reg->sc55 = !(is_sc88pro || is_sc88 || is_xg);
 }
 
 /* for backward compatibility with the original lib */
 void
-midifile ()
+midifile (void)
 {
   mfread ();
 }
 
 static
 int 
-readmt (s)			/* read through the "MThd" or "MTrk" header string */
-     char *s;
+readmt (char* s)	/* read through the "MThd" or "MTrk" header string */
 {
   int n = 0;
   char *p = s;
@@ -229,7 +280,7 @@
 
 static
 void 
-readheader ()			/* read a header chunk */
+readheader (void)			/* read a header chunk */
 {
   int format, ntrks, division;
 
@@ -311,7 +362,7 @@
 
 static
 int 
-readtrack ()			/* read a track chunk */
+readtrack (void)			/* read a track chunk */
 {
   /* This array is indexed by the high half of a status byte.  It's */
   /* value is either the number of bytes needed (1 or 2) for a channel */
@@ -503,8 +554,7 @@
 
 static
 void 
-badbyte (c)
-     int c;
+badbyte (int c)
 {
   char buff[32];
 
@@ -540,9 +590,22 @@
     case 0x0d:
     case 0x0e:
     case 0x0f:
-      /* These are all text events */
-      if (Mf_text)
-	(*Mf_text) (type, leng, m);
+      {
+	/* These are all text events */
+	char title[255+1];
+	char title_[255*2+1];
+
+	strncpy(title, m, leng);
+	title[leng] = '\0';
+	kconv((unsigned char*)title, (unsigned char*)title_);
+	if (Mf_text)
+	  (*Mf_text) (type, leng, title_);
+	if(type == 0x03 && !title_flag) {	// Sequence name
+	  strncpy(reg->title, title_, leng);
+	  fprintf(stderr, "Title: %s\n", title_);
+	  title_flag = true;
+	}
+      }
       break;
     case 0x2f:			/* End of Track */
       if (Mf_eot)
@@ -581,18 +644,19 @@
 
 static
 void 
-sysex ()
+sysex (void)
 {
   if (Mf_sysex)
     (*Mf_sysex) (msgleng (), msg ());
+  check_sysex(msg(), msgleng());
 }
 
 static
 void 
-chanmessage (status, c1, c2)
-     int status;
-     int c1, c2;
+chanmessage (int status, int c1, int c2)
 {
+  static prg[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
   int chan = status & 0xf;
 
   /* I found a midi file with Mod Wheel values 128. --gl */
@@ -617,6 +681,41 @@
     case 0xb0:
       if (Mf_parameter)
 	(*Mf_parameter) (chan, c1, c2);
+      if(c1 == 0x00) {	// Bank Number MSB
+	// $B%P%s%/$N2;?'$NB8:_$NM-L5$K$h$kH=Dj!J$$$$2C8:!K(B ???
+	if(!is_sc88pro) {
+	  if(inst_sc88_55[prg[chan]][c2] == NULL) {
+	    if(inst_sc88_88[prg[chan]][c2] == NULL) {
+	      if(inst_sc88_pro[prg[chan]][c2] == NULL) {
+		fprintf(stderr, "No Instrument: prg:%3d, bnk:%3d\n",
+			prg[chan]+1, c2);
+	      } else {
+		is_sc88pro = true;
+		fprintf(stderr, "Matches: prg:%3d, bnk:%3d (SC-88Pro)\n",
+			prg[chan]+1, c2);
+	      }
+	    } else {
+	      if(!is_sc88) {
+		is_sc88 = true;
+		fprintf(stderr, "Matches: prg:%3d, bnk:%3d (SC-88)\n",
+			prg[chan]+1, c2);
+	      }
+	    }
+	  }
+	}
+      }
+      if(c1 == 0x20) {	// Bank Number LSB
+//	if(c2 > 0x03)
+//	  fprintf(stderr, "Invalid bank no. (LSB): %d\n", c2);
+	if(c2 == 0x02)	// SC-88 MAP
+	  if(!is_sc88pro)
+	    is_sc88 = true;
+	if(c2 == 0x03)	// SC-88Pro MAP
+	  is_sc88pro = true;
+      }
+      if(c1 == 0x5e)	// Effect 4 (Delay Send Level)
+	if(!is_sc88pro)
+	  is_sc88 = true;
       break;
     case 0xe0:
       if (Mf_pitchbend)
@@ -625,6 +724,7 @@
     case 0xc0:
       if (Mf_program)
 	(*Mf_program) (chan, c1);
+      prg[chan] = c1;
       break;
     case 0xd0:
       if (Mf_chanpressure)
@@ -637,7 +737,7 @@
 /* number of characters it took. */
 
 static long
-readvarinum ()
+readvarinum (void)
 {
   long value;
   int c;
@@ -670,14 +770,13 @@
 }
 
 static int
-to16bit (c1, c2)
-     int c1, c2;
+to16bit (int c1, int c2)
 {
   return ((c1 & 0xff) << 8) + (c2 & 0xff);
 }
 
 static long
-read32bit ()
+read32bit (void)
 {
   int c1, c2, c3, c4;
 
@@ -689,7 +788,7 @@
 }
 
 static int
-read16bit ()
+read16bit (void)
 {
   int c1, c2;
   c1 = egetc ();
@@ -699,8 +798,7 @@
 
 /* static */
 void
-mferror (s)
-     char *s;
+mferror (char* s)
 {
   if (Mf_error)
     (*Mf_error) (s);
@@ -718,28 +816,27 @@
 
 static
 void 
-msginit ()
+msginit (void)
 {
   Msgindex = 0;
 }
 
 static char *
-msg ()
+msg (void)
 {
   return (Msgbuff);
 }
 
 static
 int 
-msgleng ()
+msgleng (void)
 {
   return (Msgindex);
 }
 
 static
 void 
-msgadd (c)
-     int c;
+msgadd (int c)
 {
   /* If necessary, allocate larger message buffer. */
   if (Msgindex >= Msgsize)
@@ -749,7 +846,7 @@
 
 static
 void 
-biggermsg ()
+biggermsg (void)
 {
 /* 	char *malloc(); */
   char *newmess;
@@ -807,12 +904,10 @@
  *             to work with Mf_putc.
  */
 void
-mfwrite (format, ntracks, division, fp)
-     int format, ntracks, division;
-     FILE *fp;
+mfwrite (int format, int ntracks, int division, FILE* fp)
 {
   int i;
-  void mf_write_track_chunk (), mf_write_header_chunk ();
+
 
   if (Mf_putc == NULLFUNC)
     mferror ("mfmf_write() called without setting Mf_putc");
@@ -839,13 +934,11 @@
 }
 
 void
-mf_write_track_chunk (which_track, fp)
-     int which_track;
-     FILE *fp;
+mf_write_track_chunk (int which_track, FILE* fp)
 {
   unsigned long trkhdr, trklength;
   long offset, place_marker;
-  void write16bit (), write32bit ();
+
 
 
   laststatus = 0;
@@ -912,11 +1005,10 @@
 
 
 void
-mf_write_header_chunk (format, ntracks, division)
-     int format, ntracks, division;
+mf_write_header_chunk (int format, int ntracks, int division)
 {
   unsigned long ident, length;
-  void write16bit (), write32bit ();
+
 
   ident = MThd;			/* Head chunk identifier                    */
   length = 6;			/* Chunk length                             */
@@ -950,11 +1042,8 @@
  * size - The length of the meta-event data.
  */
 int
-mf_write_midi_event (delta_time, type, chan, data, size)
-     unsigned long delta_time;
-     int chan, type;
-     unsigned long size;
-     char *data;
+mf_write_midi_event (unsigned long delta_time, int type, int chan,
+		     char* data, unsigned long size)
 {
   int i;
   unsigned char c;
@@ -1002,10 +1091,8 @@
  * size - The length of the meta-event data.
  */
 int 
-mf_write_meta_event (delta_time, type, data, size)
-     unsigned long delta_time;
-     unsigned char *data, type;
-     unsigned long size;
+mf_write_meta_event (unsigned long delta_time, unsigned char type,
+		     unsigned char* data, unsigned long size)
 {
   int i;
 
@@ -1029,9 +1116,7 @@
 }				/* end mf_write_meta_event */
 
 void
-mf_write_tempo (delta_time, tempo)
-     unsigned long delta_time;
-     unsigned long tempo;
+mf_write_tempo (unsigned long delta_time, unsigned long tempo)
 {
   /* Write tempo */
   /* all tempos are written as 120 beats/minute, */
@@ -1048,9 +1133,7 @@
 }
 
 void
-mf_write_seqnum (delta_time, seqnum)
-     unsigned long delta_time;
-     unsigned seqnum;
+mf_write_seqnum (unsigned long delta_time, unsigned seqnum)
 {
 
   WriteVarLen (delta_time);
@@ -1062,10 +1145,7 @@
 }
 
 unsigned long
-mf_sec2ticks (secs, division, tempo)
-     int division;
-     unsigned long tempo;
-     double secs;
+mf_sec2ticks (double secs, int division, unsigned long tempo)
 {
   return (unsigned long) (((secs * 1000.0) / 4.0 * division) / tempo);
 }
@@ -1074,8 +1154,7 @@
  * Write multi-length bytes to MIDI format files
  */
 void
-WriteVarLen (value)
-     unsigned long value;
+WriteVarLen (unsigned long value)
 {
   unsigned long buffer;
 
@@ -1104,10 +1183,7 @@
  *
  */
 double
-mf_ticks2sec (ticks, division, tempo)
-     int division;
-     unsigned long tempo;
-     unsigned long ticks;
+mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo)
 {
   double smpte_format, smpte_resolution;
 
@@ -1135,8 +1211,7 @@
  *
  */
 void
-write32bit (data)
-     unsigned long data;
+write32bit (unsigned long data)
 {
   eputc ((unsigned) ((data >> 24) & 0xff));
   eputc ((unsigned) ((data >> 16) & 0xff));
@@ -1145,8 +1220,7 @@
 }
 
 void
-write16bit (data)
-     int data;
+write16bit (int data)
 {
   eputc ((unsigned) ((data & 0xff00) >> 8));
   eputc ((unsigned) (data & 0xff));
@@ -1154,8 +1228,7 @@
 
 /* write a single character and abort on error */
 static int
-eputc (c)
-     unsigned char c;
+eputc (unsigned char c)
 {
   int return_val;
 
--- playmidi-1.2/midifile.h	Sun Nov 20 09:46:34 1994
+++ midifile.h	Wed Dec 31 21:57:40 1997
@@ -1,27 +1,34 @@
 /* definitions for MIDI file parsing code */
-extern int (*Mf_getc)();
-extern void (*Mf_header)();
-extern void (*Mf_trackstart)();
-extern void (*Mf_trackend)();
-extern void (*Mf_noteon)();
-extern void (*Mf_noteoff)();
-extern void (*Mf_pressure)();
-extern void (*Mf_parameter)();
-extern void (*Mf_pitchbend)();
-extern void (*Mf_program)();
-extern void (*Mf_chanpressure)();
-extern void (*Mf_sysex)();
-extern void (*Mf_metamisc)();
-extern void (*Mf_seqspecific)();
-extern void (*Mf_seqnum)();
-extern void (*Mf_text)();
-extern void (*Mf_eot)();
-extern void (*Mf_timesig)();
-extern void (*Mf_smpte)();
-extern void (*Mf_tempo)();
-extern void (*Mf_keysig)();
-extern void (*Mf_arbitrary)();
-extern void (*Mf_error)();
+
+/*
+ * modified by Satoshi KURAMOCHI 1996,1997
+ * $Id: midifile.h,v 1.2 1997-07-27 04:07:04+09 satoshi Exp $
+ */
+#include <stdio.h>
+
+extern int (*Mf_getc)(void);
+extern void (*Mf_header)(int format, int ntrks, int division);
+extern void (*Mf_trackstart)(void);
+extern void (*Mf_trackend)(void);
+extern void (*Mf_noteon)(int chan, int pitch, int vol);
+extern void (*Mf_noteoff)(int chan, int pitch, int vol);
+extern void (*Mf_pressure)(int chan, int pitch, int pressure);
+extern void (*Mf_parameter)(int chan, int control, int value);
+extern void (*Mf_pitchbend)(int chan, int msb, int lsb);
+extern void (*Mf_program)(int chan, int program);
+extern void (*Mf_chanpressure)(int chan, int pressure);
+extern void (*Mf_sysex)(int leng, char *msg);
+extern void (*Mf_metamisc)(int type, int leng, char* msg);
+extern void (*Mf_seqspecific)(int type, int leng, char* msg);
+extern void (*Mf_seqnum)(int num);
+extern void (*Mf_text)(int type, int leng, char* msg);
+extern void (*Mf_eot)(void);
+extern void (*Mf_timesig)(int numer, int denom, int clocks, int qnotes);
+extern void (*Mf_smpte)(int hour, int min, int sec, int frame, int fract);
+extern void (*Mf_tempo)(int microsecs);
+extern void (*Mf_keysig)(int sharpflat, int minor);
+extern void (*Mf_arbitrary)(int leng, char* msg);
+extern void (*Mf_error)(char *msg);
 extern unsigned long Mf_currtime;
 extern unsigned long Mf_realtime;
 extern unsigned long Mf_currtempo;
@@ -33,20 +40,21 @@
 #endif
 
 /* definitions for MIDI file writing code */
-extern int (*Mf_putc)();
-extern int (*Mf_writetrack)();
-extern int (*Mf_writetempotrack)();
+extern int (*Mf_putc)(int c);
+extern int (*Mf_writetrack)(int track);
+extern int (*Mf_writetempotrack)(void);
 
-extern void midifile();
-extern unsigned long mf_sec2ticks();
-extern void mfwrite();
-extern int mf_write_meta_event();
+extern void midifile(void);
+extern unsigned long mf_sec2ticks(float seconds, int division, int tempo);
+extern void mfwrite(int format, int ntracks, int division, FILE *fp);
+extern int mf_write_meta_event(unsigned long delta_time, int type,
+	int chan, char *data, unsigned long size);
 extern int mf_write_midi_event(unsigned long delta_time, int type,
 	int chan, char *data, unsigned long size);
 extern double mf_ticks2sec(unsigned long ticks,int division,unsigned long tempo);
-extern void mf_write_tempo();
-extern void mf_write_seqnum();
-extern void mfread();
+extern void mf_write_tempo(unsigned long tempo);
+extern void mf_write_seqnum(unsigned long delta_time, unsigned seqnum);
+extern void mfread(void);
 extern void mferror(char *s);
 
 #ifndef NO_LC_DEFINES
--- playmidi-1.2/multisig.c	Sun May  7 18:56:35 1995
+++ multisig.cc	Wed Mar 25 08:09:12 1998
@@ -1,13 +1,25 @@
+/*
+ * modified by Satoshi KURAMOCHI 1996,1997
+ * $Id: multisig.cc,v 1.4 1998-03-25 08:09:11+09 satoshi Exp $
+ */
+#include <stdlib.h>
 #include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
 
 void multisig( int sig, void (*handler)(int) )
 {
   struct sigaction sig_act;
   
-  sig_act.sa_handler = handler;
-  sig_act.sa_mask = 0;
+  sigemptyset(&sig_act.sa_mask);
+#if defined(linux)
+  sig_act.sa_handler = (void(*)(int))handler;
   sig_act.sa_flags = SA_NOMASK;
   sig_act.sa_restorer = NULL;
-  
+#elif defined(__FreeBSD__)
+  sig_act.sa_handler = (void(*)(int))handler;
+  sig_act.sa_flags = 0;		// ???
+//  sig_act.sa_restorer = NULL;	// ???
+#endif
   sigaction( sig, &sig_act, NULL );
 }
--- playmidi-1.2/patchload.c	Sun Nov 20 09:46:34 1994
+++ patchload.cc	Wed Mar 25 08:05:57 1998
@@ -6,12 +6,21 @@
  * Some of this code was adapted from code written by Hannu Solovainen
  *************************************************************************/
 
+/*
+ * modified by Satoshi KURAMOCHI 1996-1998
+ * $Id: patchload.cc,v 1.5 1998-03-25 08:05:57+09 satoshi Exp $
+ */
 #include "playmidi.h"
+#if defined(linux)
 #include <sys/ultrasound.h>
+#elif defined(__FreeBSD__)
+#include <machine/ultrasound.h>
+#endif
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include "gmvoices.h"
+#include "shmem.h"
 
 SEQ_USE_EXTBUF();
 extern int play_gus, play_sb, play_ext, playing, verbose, force8bit, reverb;
@@ -19,36 +28,210 @@
 
 static int use8bit = 0;
 
-void load_sysex(length, data)
-int length;
-char *data;
+extern volatile Register* reg;
+
+int chn2part[32*(32+1)];	// channel to part
+int rx_chn[32];			// receive channel
+
+static int block2part[32] = {
+   9,  0,  1,  2,  3,  4,  5,  6,  7,  8, 10, 11, 12, 13, 14, 15,
+  25, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31};
+
+inline void print_chn2part(int chn)
 {
-    struct sysex_info *sysex;
+  int i = 0, part;
+  fprintf(stderr, "channel %2d: ", chn);
+  while((part = chn2part[chn*32+(i++)]) != 0xff)
+    fprintf(stderr, "%2d ", part);
+  fprintf(stderr, "\n");
+}
 
-    if (!play_ext)
-	return;
-    sysex = (struct sysex_info *) malloc(length + sizeof(*sysex));
-    if (sysex == NULL) {
-	fprintf(stderr, "No more memory for sysex, ignoring\n");
-	return;
-    }
-    sysex->key = SYSEX_PATCH;
-    sysex->device_no = ext_dev;
-    sysex->len = length;
-    memcpy(sysex->data, data, length);
+inline void set_chn2part(int old_chn, int new_chn, int part)
+{
+  if(old_chn == 0xff) {
+    fprintf(stderr, "set_chn2part: end marker appearred\n");
+    exit(-1);
+  }
+//print_chn2part(old_chn);
+  // delete part
+  int i = 0;
+  while(chn2part[old_chn*32+(i++)] != part);
+  if(chn2part[old_chn*32+i] == 0xff) {
+    chn2part[old_chn*32+(i-1)] = 0xff;
+  } else {
+    int j = i+1;
+    while(chn2part[old_chn*32+(j++)] != 0xff);
+    chn2part[old_chn*32+(i-1)] = chn2part[old_chn*32+(j-2)];
+    chn2part[old_chn*32+(j-2)] = 0xff;
+  }
+//print_chn2part(old_chn);
+//print_chn2part(new_chn);
+  // add part
+  i = 0;
+  while(chn2part[new_chn*32+(i++)] != 0xff);
+  chn2part[new_chn*32+(i-1)] = part;
+  chn2part[new_chn*32+i] = 0xff;
+  if(verbose)
+    print_chn2part(new_chn);
+}
+
+
+void load_sysex(int length, char* data)
+{
+  struct sysex_info *sysex;
+
+  sysex = (struct sysex_info *) malloc(length + sizeof(*sysex));
+  if(sysex == NULL) {
+    fprintf(stderr, "No more memory for sysex, ignoring\n");
+    return;
+  }
+  sysex->key = SYSEX_PATCH;
+  sysex->device_no = ext_dev;
+  sysex->len = length;
+  memcpy(sysex->data, data, length);
+  if(play_ext) {
 #ifdef USE_SEQUENCER2
     SEQ_WRPATCH(sysex, sizeof(*sysex) + sysex->len);
 #else
-    for (length = 0; length < sysex->len; length++)
-	SEQ_MIDIOUT(ext_dev, sysex->data[length]);
+    for(length = 0; length < sysex->len; length++)
+      SEQ_MIDIOUT(ext_dev, sysex->data[length]);
+#endif
+  }
+  if(sysex->data[1] == 0x7f &&		// Universal Realtime Message
+     sysex->data[2] == 0x7f &&		// Broadcast
+     sysex->data[3] == 0x04 &&		// Device Control Messages
+     sysex->data[4] == 0x01)		// Master Volume
+    reg->mvol = sysex->data[6];
+  if(sysex->data[1] == 0x7e &&		// Universal Non-Realtime Message
+     sysex->data[2] == 0x7f &&		// Broadcast
+     sysex->data[3] == 0x09 &&		// General MIDI Message
+     sysex->data[4] == 0x01)		// General MIDI On
+    reg->gm = true;
+  if(sysex->data[1] == 0x41 &&		// Roland
+     sysex->data[2] == 0x10) {		// Device ID: 17
+    if(sysex->data[3] == 0x42 &&	// GS
+       sysex->data[4] == 0x12) {	// DT1
+      if(sysex->data[5] == 0x00 &&
+	 sysex->data[6] == 0x01 &&
+	  sysex->data[7] <= 0x1f) {	// 00 01 xx: CHANNEL MSG RX PORT
+	int part = block2part[sysex->data[7]];
+	if(sysex->data[8] <= 1) {
+	  int old_chn = rx_chn[part];
+	  rx_chn[part] = (old_chn&0x0f)+(sysex->data[8]<<4);
+	  if(verbose)
+	    fprintf(stderr, "Rx.PORT: part:%2d, chan:%2d=>%2d\n",
+		    part, old_chn, rx_chn[part]);
+	  if(old_chn != rx_chn[part])
+	    set_chn2part(old_chn, rx_chn[part], part);
+	}
+      }
+      // How about processing 0x50 ???
+      if(sysex->data[5] == 0x40 ||
+	 sysex->data[5] == 0x50) {
+	if(sysex->data[6] == 0x00) {
+	  if(sysex->data[7] == 0x04)	// 40 00 04: MASTER VOLUME
+	    reg->mvol = sysex->data[8];
+	  if(sysex->data[7] == 0x06)	// 40 00 06: MASTER PAN
+	    reg->mpan = sysex->data[8];
+	  if(sysex->data[7] == 0x7f &&	// 40 00 7F: MODE SET
+	     sysex->data[8] == 0x00)	// GS Reset
+	    reg->gs = true;
+	}
+	if(sysex->data[6] == 0x01 &&
+	   sysex->data[7] == 0x00) {	// 40 01 00: PATCH NAME
+	  memcpy((void*)&reg->patch[0], &sysex->data[8], 16);
+	}
+	if(sysex->data[6] == 0x03 &&
+	   sysex->data[7] == 0x00) {	// 40 03 00: EFX TYPE (SC-88Pro)
+	  reg->efx_type[0] = sysex->data[8];
+	  reg->efx_type[1] = sysex->data[9];
+	}
+	if((0x10 <= sysex->data[6] &&
+	    sysex->data[6] <= 0x1f)) {
+	  if(sysex->data[7] == 0x02) {	// 40 1x 02: Rx. CHANNEL
+//	    int ch = sysex->data[6]-0x10;
+//	    ch = (ch == 0) ? 9 : (ch <= 9) ? ch-1 : ch;
+	    int part = (block2part[sysex->data[6]-0x10] +
+			(sysex->data[5] == 0x40) ? 0 : 0x10);
+	    int old_chn = rx_chn[part];
+	    rx_chn[part] = (rx_chn[part]&0xf0)+(sysex->data[8]&0x0f);	// ???
+	    if(verbose)
+	      fprintf(stderr, "Rx.CHAN: part:%2d, chan:%2d=>%2d\n",
+		      part, old_chn, rx_chn[part]);
+	    set_chn2part(old_chn, rx_chn[part], part);
+	  }
+	  if(sysex->data[7] == 0x15) {	// 40 1x 15: USE FOR RHYTHM PART
+	    int ch = sysex->data[6]-0x10;
+	    ch = (ch == 0) ? 9 : (ch <= 9) ? ch-1 : ch;
+	    reg->rhythm[ch] = sysex->data[8];
+	  }
+	}
+      }
+      if(sysex->data[5] == 0x21) {
+	if((sysex->data[6] == 0x00 ||
+	    sysex->data[6] == 0x10) &&
+	   sysex->data[7] == 0x00) {	// 21 d0 00: USER DRUM SET NAME
+	  memcpy((void*)&reg->userdrum[sysex->data[6] ? 1 : 0][0],
+		 &sysex->data[8], 12);
+	  reg->userdrum[sysex->data[6] ? 1 : 0][12] = '\0';
+	}
+      }
+#if 0
+      if(sysex->data[5] == 0x23) {
+	if((0x00 <= sysex->data[6] &&
+	    sysex->data[6] <= 0x0f) &&
+	   sysex->data[7] == 0x08) {	// 23 pp 08: PATCH NAME
+	  memcpy((void*)&reg->patch[sysex->data[6]][0], &sysex->data[8], 16);
+	  reg->patch[sysex->data[6]][16] = '\0';
+	}
+      }
 #endif
-    if (verbose > 3) {
-	printf("Sent SysEx: ");
-	for (length = 0; length < sysex->len; length++)
-	    printf("%02x", sysex->data[length]);
-	putchar('\n');
     }
-    free(sysex);
+    if(sysex->data[3] == 0x45 &&	// SC-55
+       sysex->data[4] == 0x12) {	// DT1
+      if(sysex->data[5] == 0x10) {
+	if(sysex->data[6] == 0x00 &&
+	   sysex->data[7] == 0x00) {	// Displayed Letter
+	  int len = length-10;
+	  memcpy((void*)reg->lcd, &sysex->data[8], len > 32 ? 32 : len);
+	  if(len < 32)
+	    reg->lcd[len] = '\0';
+	}
+	if(0x01 <= sysex->data[6] && sysex->data[6] <= 0x05 &&
+	   (sysex->data[7] == 0x00 || sysex->data[7] == 0x40)) {
+					// Displayed Dot Data
+	  unsigned char page = ((sysex->data[6]-1)*2 +
+				((sysex->data[7] == 0x40) ? 1 : 0));
+	  reg->page = page;
+	  int len = (length-10 <= 16*16) ? length-10 : 16*16;
+	  memcpy((void*)&reg->lcd_dd[page*16*16], &sysex->data[8], len);
+	}
+	if(sysex->data[6] == 0x20) {
+	  if(sysex->data[7] == 0x00)	// Display Page
+	    reg->page = sysex->data[8];
+	  if(sysex->data[7] == 0x01)	// Display Time
+	    reg->lcd_time = sysex->data[8];
+	}
+      }
+    }
+  }
+  if(sysex->data[1] == 0x43 &&		// Yamaha
+     sysex->data[2] == 0x10) {		// Device ID: 17
+    if(sysex->data[3] == 0x4c) {	// XG
+      if(sysex->data[4] == 0x00 &&
+	 sysex->data[5] == 0x00) {
+	if(sysex->data[6] == 0x7e)	// XG System ON
+	  reg->xg = true;
+      }
+    }
+  }
+  if(verbose) {
+    printf("SysEx: ");
+    for(length = 0; length < sysex->len; length++)
+      printf("%02x ", sysex->data[length]);
+    putchar('\n');
+  }
+  free(sysex);
 }
 
 struct pat_header {
@@ -98,8 +281,7 @@
 
 void gus_reload_8_bit();
 
-int gus_load(pgm)
-int pgm;
+int gus_load(int pgm)
 {
     int i, j, patfd, offset;
     struct pat_header header;
@@ -296,7 +478,7 @@
     return 0;
 }
 
-void gus_reload_8_bit()
+void gus_reload_8_bit(void)
 {
     int i;
 
@@ -347,7 +529,7 @@
     return( (volbyte & 0xc0) | (n & 0x3f) );
 }
 
-void loadfm()
+void loadfm(void)
 {
     int sbfd, i, n, voice_size, data_size;
     char buf[60];
--- playmidi-1.2/playevents.c	Mon Nov 21 04:17:43 1994
+++ playevents.cc	Wed Apr  8 17:23:02 1998
@@ -4,11 +4,27 @@
  * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
  * Source code may be freely distributed in unmodified form.
  *************************************************************************/
+
+/*
+ * modified by Satoshi KURAMOCHI 1996-1998
+ * $Id: playevents.cc,v 1.9 1998-04-08 17:23:02+09 satoshi Exp $
+ */
+#include <unistd.h>
 #include "playmidi.h"
+#include "shmem.h"
+#include "server_impl.h"
+#include "filelist.h"
 
 /* sustain gus/fm percussion to prevent driver dropoff... */
 #define P_SUSTAIN
 
+extern Server* server;
+extern volatile Register* reg;
+extern FileList* filelist;
+extern const char* prgname;
+
+extern void preprocess(void);
+
 #ifdef USE_SEQUENCER2
 #define seq_set_patch(a, b, c) (SEQ_SET_PATCH(a, b, c))
 #define seq_key_pressure(a, b, c, d) (SEQ_KEY_PRESSURE(a, b, c, d))
@@ -26,209 +42,346 @@
 extern void seq_control(int, int, int, int);
 extern void seq_chn_pressure(int, int, int);
 extern void seq_bender(int, int, int);
-extern void seq_reset();
+extern void seq_reset(void);
+extern void load_sysex(int, char *);
 #endif
 
 SEQ_USE_EXTBUF();
-extern int playing, newevent, graphics, verbose;
-extern int dochan, gus_dev, ext_dev, sb_dev, perc, seqfd;
+extern int playing, newevent, verbose;
+extern int dochan, gus_dev, ext_dev, sb_dev, seqfd;
 extern int play_gus, play_fm, play_ext;
 extern struct mididata *event;
-extern float skew;
-extern char *gmvoice[256];
-int ticks;
+unsigned long ticks = 0;
 
-extern void cleanup();
+extern void cleanup(int sig);
 extern void load_sysex(int, char *);
 
-char *metatype[7] =
-{"Text event", "Copyright Notice", "Sequence/Track name",
- "Instrument Name", "Lyric", "Marker", "Cue Point"};
+extern int chn2part[32*(32+1)];
+extern int rx_chn[32];
 
-char *notes[12] =	/* my personal preference on notes */
-{"C", "Db", "D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B"};
-char *sharps[12] =	/* for a sharp key */
-{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "B#", "B"};
-char *flats[12] =	/* for a flat key */
-{"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Gb", "A", "Bb", "B"};
-char *kflat[15] = 	/* name of key with 'x' flats */
-{"C", "F", "Bb", "Eb", "Ab", "Db", "Gb", "Cb", "Fb", "Bbb", "Ebb",
-"Abb", "Gbb", "Cbb", "Fbb" };	/* anyone using more flats is SICK */
-char *ksharp[15] =	/* name of key with 'x' sharps */
-{"C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "A#",
-"E#","B#", "F##", "C##"};	/* anyone using more sharps is SICK */
+#define set_register(para,chn,val) { \
+  int __i = 0, __part; \
+  while((__part = chn2part[(chn)*32+(__i++)]) != 0xff) \
+    (para)[__part] = (val); \
+}
+
+#define set_register_vel(para,chn,val) { \
+  int __i = 0, __part; \
+  while((__part = chn2part[(chn)*32+(__i++)]) != 0xff) { \
+    reg->vel[__part] = (val); \
+    reg->_vel[__part]++; \
+  } \
+}
+
+#define set_register_kb(chn,note,val) { \
+  int __i = 0, __part; \
+  while((__part = chn2part[(chn)*32+(__i++)]) != 0xff) \
+    reg->kb[__part][note] = (val); \
+}
 
 /* these are to make my life a little easier */
-#define BUF		&buf[strlen(buf)]
 #define CMD		event[i].cmd
-#define CHN		(event[i].cmd & 0xf)
+#define CHN		event[i].chn
 #define NOTE		event[i].arg1
 #define VEL		event[i].arg2
 #define TIME		event[i].etime
 #define ARG1		event[i].arg1
 #define ARG2		event[i].arg2
 #define DATA		event[i].data
-#define OCTAVE		(NOTE / 12)
-#define OCHAR		(dochan ? 0x30 + OCTAVE : 0)
-#define XPOS		(1 + 4 * (dochan ? CHN : OCTAVE))
-#define YPOS		(dochan ? 25 - NOTE % 24 : 13 - NOTE % 12)
-#define NNAME		nn[NOTE % 12]
-void playevents()
+
+void playevents(const char* filename)
 {
-    unsigned int i, lasttime = 0;
-    unsigned int tempo = 500000;
-    float current = 0.0, dtime = 0.0;
-    int division = -1, use_dev;
-    char **nn;
-    char buf[2048];
+  unsigned long i;
+  unsigned long lasttime = 0;
+  unsigned long tempo = 500000;
+  double current = 0.0, dtime = 0.0;
+  int division = -1, use_dev;
+  unsigned paused_time = 0;	// elapsed time when pausing
+  ticks = 0;
 
-    seq_reset();
-    SEQ_START_TIMER();
-    *buf = 0;
-    nn = notes;		/* this can be changed by midi keysig */
-    playing = 1;
-    for (i = 0; playing && i < newevent; i++) {
-	if (ISMIDI(CHN))
-	   use_dev = ext_dev;
-	else if (ISGUS(CHN))
-	   use_dev = gus_dev;
-	else
-	   use_dev = sb_dev;
-	if (CMD == meta_event && ARG1 == set_tempo) {
-	    tempo = ARG2;
-	    if (verbose > 3)
-		printf("Tempo: %d bpm\n", tempo * 3 / 12500);
+  for(i = 0; i < 32; i++) {
+    rx_chn[i] = i;
+    chn2part[i*32+0] = i;
+    int j;
+    for(j = 1; j <= 32; j++)
+      chn2part[i*32+j] = 0xff;	// end marker
+  }
+
+  // calculate play time
+  for(i = 0; i < newevent; i++) {
+    if(CMD == meta_event && ARG1 == set_tempo)
+      tempo = ARG2;
+    else if(CMD == MThd)
+      division = ARG2;
+    if(TIME > lasttime) {
+      if(division > 0) {
+	current += (((double)(TIME-lasttime)*(double)tempo) /
+		    ((double)division*1000000.0)) * 100.0;
+	lasttime = TIME;
+      } else {
+	if(division < 0)
+	  current =
+	    ((double)TIME / (double)((division & 0xff00 >> 8) *
+				     (division & 0xff)*1000000.0)) * 100.0;
+      }
+    }
+  }
+  reg->playtime = (unsigned)current;
+  fprintf(stderr, "Play time: %2d\'%2d\"\n",
+	  reg->playtime/6000%60, reg->playtime/100%60);
+  fprintf(stderr, "** Now Playing \"%s\": %d events\n", filename, newevent);
+
+  tempo = 500000;
+  lasttime = 0;
+  division = -1;
+  current = 0.0;
+
+  seq_reset();
+  SEQ_START_TIMER();
+  preprocess();
+  SEQ_DUMPBUF();
+  playing = 1;
+  reg->status = STATUS_PLAY;
+  reg->time = 0;
+
+  for (i = 0; playing && i < newevent; i++) {
+    if(reg->status == STATUS_PAUSE) {
+      ((Server_Impl*)server)->select(false);
+      current += 10.24;		// 0.1 sec.
+      paused_time += (unsigned long)current-ticks;
+      ticks = (unsigned long)current;
+      SEQ_WAIT_TIME(ticks);
+      SEQ_DUMPBUF();
+      ioctl(seqfd, SNDCTL_SEQ_SYNC);
+      continue;
+    }
+    if(reg->status == STATUS_FADE) {
+      // ???
+    }
+    use_dev = (ISMIDI(CHN) ? ext_dev : (ISGUS(CHN) ? gus_dev : sb_dev));
+    if (CMD == meta_event && ARG1 == set_tempo) {
+      tempo = ARG2;
+      reg->tempo = tempo*3/12500;
+    }
+    if (TIME > lasttime) {
+      if (division > 0) {
+	dtime = (((double)(TIME-lasttime)*(double)tempo) /
+		 ((double)division*1000000.0)) * reg->skew;
+	current += dtime;
+	lasttime = TIME;
+      } else {
+	if (division < 0)
+	  current = ((double)TIME /
+		     (double)((division & 0xff00 >> 8) *
+			      (division & 0xff)*1000000.0)) * reg->skew;
+      }
+      /* stop if there's more than 40 seconds of nothing *//* ??? */
+      if (dtime > 4096.0 && playing) {
+//	cleanup(0);
+	return;
+      } else {
+	if ((unsigned long)current > ticks) {
+	  ((Server_Impl*)server)->select(false);
+	  if(!playing)
+	    continue;
+	  reg->time = (unsigned long)current-paused_time;
+	  SEQ_WAIT_TIME((ticks = (unsigned long)current));
+	  SEQ_DUMPBUF();
 	}
-	if (TIME > lasttime) {
-	    if (division > 0) {
-		dtime = mf_ticks2sec(TIME - lasttime, division, tempo) * skew;
-		current += dtime;
-	    } else if (division < 0)
-		current = mf_ticks2sec(TIME, division, tempo) * skew;
-	    /* interrupt if we have to wait 81.92 seconds or more */
-	    if (dtime > 8192 && playing)
-		cleanup();
-	    else if (dtime > 0.75)
-		SEQ_WAIT_TIME((ticks = ((int) current)));
-	    /* keep output synchronized with music */
-	    if (verbose || graphics) {
-		if (playing)
-		    SEQ_DUMPBUF();
-		if (graphics)	/* show picture we've stored in buf */
-		    printf("%s\033[1;73H\033[37m%0.1f\n", buf, current / 100);
-	    }
-	    *buf = 0;
-	    lasttime = TIME;
+      }
+    }
+    /* keep output synchronized with music */
+    switch(CMD) {
+    case MThd:
+      division = ARG2;
+      fprintf(stderr, "format=%d, tracks=%d, division=%d\n",
+	      ARG1 >> 8, ARG1 & 0xff, division);
+      break;
+    case MIDI_SYSTEM_PREFIX:
+      {
+	const unsigned char MIDI_PORT_CHANGE = 0xf5;
+	if(ISMIDI(CHN)) {
+	  SEQ_MIDIOUT(ext_dev, MIDI_PORT_CHANGE);	// ???
+	  SEQ_MIDIOUT(ext_dev, 0);		//
 	}
-	if (CMD == MThd) {
-	    division = ARG2;
-	    if (verbose)
-		printf("format=%d, tracks=%d, division=%d\n",
-		       ARG1 >> 8, ARG1 & 0xff, division);
-	} else if (CMD == MIDI_SYSTEM_PREFIX)
-	    load_sysex(ARG1, DATA);
-	else if (CMD == meta_event) {
-	    if (ARG1 < 8 && ARG1 > 0 && verbose)
-		printf("%s: %s\n", metatype[ARG1 - 1], DATA);
-	    else if (ARG1 == key_signature) {
-		int value = (int) (ARG2) / 2;
-		if (graphics)
-		    nn = (!value ? notes : value < 0 ? flats : sharps);
-		else if (verbose > 1)
-		    printf("Key Signature: %s\n",
-			   (value >= 0 ? ksharp[value] : kflat[-value]));
+	load_sysex(ARG1, DATA);
+      }
+      break;
+    case meta_event:
+      switch(ARG1) {
+      case 1:	// Text event
+      case 6:	// Marker
+	strncpy((char*)reg->text, DATA, 20);
+	break;
+      case 3:	// Sequence/Track name
+	{
+	  static ch = 0;
+	  if(ch < 32)
+	    strncpy((char*)reg->name[ch++], DATA, 20);	// ??????????
+	}
+	break;
+      case key_signature:
+	{
+	  const char *kflat[15] = {	/* name of key with 'x' flats */
+	    "C", "F", "Bb", "Eb", "Ab", "Db", "Gb", "Cb",
+	    "Fb", "Bbb", "Ebb", "Abb", "Gbb", "Cbb", "Fbb" };
+	  /* anyone using more flats is SICK */
+	  const char *ksharp[15] = { /* name of key with 'x' sharps */
+	    "C", "G", "D", "A", "E", "B", "F#", "C#",
+	    "G#", "D#", "A#", "E#","B#", "F##", "C##"};
+	  /* anyone using more sharps is SICK */
+	  int value = (int) (ARG2) / 2;
+	  if (verbose > 1)
+	    fprintf(stderr, "Key Signature: %s\n",
+		    (value >= 0 ? ksharp[value] : kflat[-value]));
+	  strncpy((char*)reg->keysig, 
+		  (value >= 0 ? ksharp[value] : kflat[-value]), 10);
+	}
+	break;
+      case 2: case 4: case 5: case 7:
+	{
+	  const char *metatype[7] = {
+	    "Text event",
+	    "Copyright Notice",
+	    "Sequence/Track name",
+	    "Instrument Name",
+	    "Lyric",
+	    "Marker",
+	    "Cue Point"
+	  };
+	  fprintf(stderr, "%s: %s\n", metatype[ARG1-1], DATA);
+	}
+	break;
+      default:
+	if((ARG1 & 0xff) == sequencer_specific) {
+	  switch(ARG1 >> 16) {
+	  case 0: // step
+//	    if(reg->step % reg->timebase == 0)
+//	      fprintf(stderr, ".");
+	    reg->step += 4*reg->timebase/48;
+	    if(reg->step > 4*reg->timebase) {	// for the data without bar
+//	      fprintf(stderr, "Bar: %d\n", reg->bar);
+	      reg->bar++;
+	      reg->step -= 4*reg->timebase;
 	    }
-	} else if (playing)
-	    switch (CMD & 0xf0) {
-	    case MIDI_KEY_PRESSURE:
-		if (ISPERC(CHN) && VEL && !ISMIDI(CHN)) {
-		    seq_set_patch(use_dev, CHN, NOTE + 128);
-		}
+	    break;
+	  case 1: // measure
+//	    fprintf(stderr, "Bar: %d\n", reg->bar);
+	    reg->bar++;
+	    reg->step = 0;
+	    break;
+	  }
+	}
+	break;
+      }
+      break;
+    default:
+      switch (CMD & 0xf0) {
+      case MIDI_KEY_PRESSURE:
+	if (ISPERC(CHN) && VEL && !ISMIDI(CHN)) {
+	  seq_set_patch(use_dev, CHN, NOTE + 128);
+	}
 #ifdef P_SUSTAIN
-		if (!ISPERC(CHN) || VEL || ISMIDI(CHN))
+	if (!ISPERC(CHN) || VEL || ISMIDI(CHN))
 #endif
-		    { seq_key_pressure(use_dev, CHN, NOTE, VEL); }
-		if (graphics)
-		    if (VEL) {
-			sprintf(BUF, "\033[%d;%dH\033[%dm%s%c",
-				YPOS, XPOS, NOTE % 7 + 31, NNAME, OCHAR);
-		    } else
-			sprintf(BUF, "\033[%d;%dH   ", YPOS, XPOS);
-		break;
-	    case MIDI_NOTEON:
-		if (ISPERC(CHN) && VEL && !ISMIDI(CHN)) {
-		    seq_set_patch(use_dev, CHN, NOTE + 128);
-		}
+	  { seq_key_pressure(use_dev, CHN, NOTE, VEL); }
+	if(VEL) {
+	  set_register_vel(reg->vel, CHN, VEL);
+	} else {
+	  set_register_vel(reg->vel, CHN, 0);
+//	  reg->vel[CHN] = 0;		// ???????
+	}
+	break;
+      case MIDI_NOTEON:
+	if (ISPERC(CHN) && VEL && !ISMIDI(CHN)) {
+	  seq_set_patch(use_dev, CHN, NOTE + 128);
+	}
 #ifdef P_SUSTAIN
-		if (!ISPERC(CHN) || VEL || ISMIDI(CHN))
+	if (!ISPERC(CHN) || VEL || ISMIDI(CHN))
 #endif
-		    { seq_start_note(use_dev, CHN, NOTE, VEL); }
-		if (graphics)
-		    if (VEL) {
-			sprintf(BUF, "\033[%d;%dH\033[%dm%s%c",
-				YPOS, XPOS, NOTE % 7 + 31, NNAME, OCHAR);
-		    } else
-			sprintf(BUF, "\033[%d;%dH   ", YPOS, XPOS);
-		break;
-	    case MIDI_NOTEOFF:
+	  { seq_start_note(use_dev, CHN, NOTE, VEL); }
+	set_register_vel(reg->vel, CHN, VEL);
+	set_register_kb(CHN, NOTE, VEL ? 1 : 0);
+	break;
+      case MIDI_NOTEOFF:
 #ifdef P_SUSTAIN
-		if (!ISPERC(CHN) || ISMIDI(CHN))
+	if (!ISPERC(CHN) || ISMIDI(CHN))
 #endif
-		    { seq_stop_note(use_dev, CHN, NOTE, VEL); }
-		if (graphics)
-		    sprintf(BUF, "\033[%d;%dH   ", YPOS, XPOS);
-		break;
-	    case MIDI_CTL_CHANGE:
-		seq_control(use_dev, CHN, ARG1, ARG2);
-		break;
-	    case MIDI_CHN_PRESSURE:
-		seq_chn_pressure(use_dev, CHN, ARG1);
-		break;
-	    case MIDI_PITCH_BEND:
-		seq_bender(use_dev, CHN, ARG1);
-		if (graphics)
-		    sprintf(BUF, "\033[37m\033[%d;%dH%c", 2, 3 + 4 * CHN,
-			 ARG1 == 0x40 ? ' ' : ARG1 > 0x2000 ? '^' : 'v');
-		break;
-	    case MIDI_PGM_CHANGE:
-		if (ISMIDI(CHN) || !ISPERC(CHN)) {
-		    seq_set_patch(use_dev, CHN, ARG1);
-		}
-		if (graphics) {
-		    sprintf(BUF, "\033[37m");
-		    if (!ISPERC(CHN) && dochan)
-			sprintf(BUF, "\033[1;%dH%c%c%c", 1 + 4 * CHN,
-				gmvoice[ARG1][0], gmvoice[ARG1][1],
-				gmvoice[ARG1][2]);
-		    else if (dochan)
-			sprintf(BUF, "\033[1;%dH%03d", 1 + 4 * CHN,
-				ARG1);
-		    else
-			sprintf(BUF, "\033[1;50H%8s %3d", (ISPERC(CHN) ?
-				"drumset" : gmvoice[ARG1]), ARG1);
-		}
-		break;
-	    default:
-		break;
-	    }
-    }
-    if (playing) {
-	SEQ_DUMPBUF();
-	if (verbose)
-	    printf("** Ended at %0.1f sec\n", current / 100);
-	if (graphics)
-	    printf("\033[1;73H*Ended\033[K\n");
-    } else {
-	if (verbose)
-	    printf("** Interrupted at %0.1f sec\n", current / 100);
-	else if (graphics)
-	    printf("\033[1;73H*Abort\033[K\n");
-	seq_reset();
+	  { seq_stop_note(use_dev, CHN, NOTE, VEL); }
+	if(!ISPERC(CHN))
+	  set_register_vel(reg->vel, CHN, 0);
+	set_register_kb(CHN, NOTE, 0);
+	break;
+      case MIDI_CHN_PRESSURE:
+	seq_chn_pressure(use_dev, CHN, ARG1);
+	break;
+      case MIDI_PITCH_BEND:
+	seq_bender(use_dev, CHN, ARG1);
+	set_register(reg->bend, CHN, ARG1);
+	break;
+      case MIDI_PGM_CHANGE:
+	if (ISMIDI(CHN) || !ISPERC(CHN))
+	  seq_set_patch(use_dev, CHN, ARG1);
+	set_register(reg->prg, CHN, ARG1);
+	break;
+      case MIDI_CTL_CHANGE:
+	seq_control(use_dev, CHN, ARG1, ARG2);
+	switch(ARG1) {
+	case CTL_MAIN_VOLUME:
+	  set_register(reg->vol, CHN, ARG2);
+	  break;
+	case CTL_EXPRESSION:
+	  set_register(reg->expr, CHN, ARG2);
+	  break;
+	case CTL_PAN:
+	  set_register(reg->pan, CHN, ARG2);
+	  break;
+	case CTL_MODWHEEL:
+	  set_register(reg->mod, CHN, ARG2);
+	  break;
+	case CTL_BANK_SELECT:
+	  set_register(reg->bnk, CHN, ARG2);
+	  break;
+	case 0x20: // Bank Select LSB (Roland SC-88)
+	  set_register(reg->map, CHN, ARG2);
+	  break;
+	case CTL_HOLD:
+	case CTL_SOFT_PEDAL:
+	case CTL_HOLD2:
+	  break;
+	case CTL_EXT_EFF_DEPTH:	// Reverb Send Level
+	  set_register(reg->rev, CHN, ARG2);
+	  break;
+	case CTL_CHORUS_DEPTH:	// Chorus Send Level
+	  set_register(reg->cho, CHN, ARG2);
+	  break;
+	case CTL_DETUNE_DEPTH:	// Delay Send Level
+	  set_register(reg->delay, CHN, ARG2);
+	  break;
+	case 0x7b: // All Note Off
+	  {
+	    int j;
+	    for(j = 0; j < 128; j++)
+	      set_register_kb(CHN, j, 0);
+	    set_register_vel(reg->vel, CHN, 0);
+	  }
+	  break;
+	}
+	break;
+      default:
+	break;
+      }
+      break;
     }
-    for (i = 0; i < newevent; i++)
-	if (DATA)
-	    free(DATA);
-    if (graphics)
-	printf("\033[22;1H\033[J\033[m\n");
-    playing = newevent = 0;
+    ioctl(seqfd, SNDCTL_SEQ_SYNC);
+  }
+  if (playing)
+    SEQ_DUMPBUF();
+  else
+    seq_reset();
+  for (i = 0; i < newevent; i++)
+    if (DATA)
+      free(DATA);
+  playing = newevent = 0;
+//filelist->next();
 }
--- playmidi-1.2/playmidi.c	Thu May 11 13:30:04 1995
+++ playmidi.cc	Wed Apr  8 17:23:46 1998
@@ -8,34 +8,89 @@
  * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
  * Source code may be freely distributed in unmodified form.
  *************************************************************************/
-#include "playmidi.h"
-#include "multisig.h"
+
+/*
+ * modified by Satoshi KURAMOCHI 1996-1998
+ * $Id: playmidi.cc,v 1.11 1998-04-08 17:23:46+09 satoshi Exp $
+ */
+
+#define getopt getopt__
+#include <stdlib.h>
+#undef getopt
+#include <stdio.h>
 #include <signal.h>
-#include <getopt.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <unistd.h>
 
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "getopt.h"
+#endif
+
+#include "playmidi.h"
+#include "multisig.h"
+#include "shmem.h"
+#include "server_impl.h"
+#include "filelist.h"
+
+static const char* version = VERSION;
+
+//static const char* WRDPLAYER = "xwrdplay";
+#define MAX_PATH 80	/* maximum length of path */
+char path[MAX_PATH+1];	/* directory search path */
+
+Server* server = NULL;
+volatile Register* reg = NULL;
+FileList* filelist = NULL;
+
 SEQ_DEFINEBUF(SEQUENCERBLOCKSIZE);
 
 struct mididata *event;		/* allocated/resized at runtime */
 
 /* SET YOUR DEFAULT PLAYBACK DEVICE BY SETTING MASK OF CHANNELS TO PLAY */
-int play_sb = 0, play_gus = 0xffff, play_ext = 0;
+/*int play_sb = 0, play_gus = 0, play_ext = 0xffffffff;*/
+#ifdef PLAY_FM
+int play_sb = 0xffffffff, play_gus = 0, play_ext = 0;
+#endif
+#ifdef PLAY_GUS
+int play_sb = 0, play_gus = 0xffffffff, play_ext = 0;
+#endif
+#ifdef PLAY_EXT
+int play_sb = 0, play_gus = 0, play_ext = 0xffffffff;
+#endif
+#ifdef PLAY_AWE32
+int play_sb = 0, play_gus = 0xffffffff, play_ext = 0;
+#endif
 
-#define EVENTBLOCK	 4096
+#define EVENTBLOCK	 (1024*256)
 unsigned int maxevents = EVENTBLOCK;
-int verbose = 0, chanmask = 0xffff, perc = PERCUSSION;
+int verbose = 0, chanmask = 0xffffffff;
 int newevent = 0, dochan = 1, force8bit = 0, wantopl3 = FM_DEFAULT_MODE;
-int patchloaded[256], useprog[16], c_loaded[16], c_noteon[16];
-int playing = 0, graphics = 0, reverb = 0, nrsynths, nrmidis;
+int patchloaded[256], useprog[32], c_loaded[32], c_noteon[32];	// 32 ???
+int playing = 0, reverb = 0, nrsynths, nrmidis;
 int sb_dev = -1, gus_dev = -1, ext_dev = -1;
-int seqfd, mfd;
-float skew = 100.0;
+int seqfd;
+FILE* mfd;
+const char* prgname = NULL;
+static bool parseonly = false;
+static Options options0;	// initializer
+
+static void print_version(void);
+static void print_usage(void);
+static void print_status(void);
+static void server_main(int argc, char* argv[], int optind, Options options);
+static bool parse_dev_opts(char c, Options* options, int& error);
+bool addFile(const char* args);
+
 extern char *gmvoice[256];
-extern void playevents();
+extern void playevents(const char* filename);
 extern int gus_load(int);
 extern void loadfm();
+extern void control(bool wait);
+extern void rcpread(void);
+
 #define CHANNEL (dochan ? chan : 0)
 
 #ifdef USE_SEQUENCER2
@@ -45,53 +100,56 @@
 #endif
 
 struct synth_info card_info[MAX_CARDS];
-void synth_setup()
+bool synth_setup(void)
 {
-    int i;
-
-    if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nrsynths) == -1) {
-	fprintf(stderr, "there is no soundcard\n");
-	exit(1);
+  if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nrsynths) == -1) {
+    fprintf(stderr, "there is no soundcard\n");
+    return false;
+  }
+  int i;
+  for (i = 0; i < nrsynths; i++) {
+    card_info[i].device = i;
+    if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info[i]) == -1) {
+      fprintf(stderr, "cannot get info on soundcard\n");
+      perror(SEQUENCER_DEV);
+      return false;
     }
-    for (i = 0; i < nrsynths; i++) {
-	card_info[i].device = i;
-	if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info[i]) == -1) {
-	    fprintf(stderr, "cannot get info on soundcard\n");
-	    perror(SEQUENCER_DEV);
-	    exit(-1);
-	}
-	card_info[i].device = i;
-	if (card_info[i].synth_type == SYNTH_TYPE_SAMPLE
-	    && card_info[i].synth_subtype == SAMPLE_TYPE_GUS)
-	    gus_dev = i;
-	else if (card_info[i].synth_type == SYNTH_TYPE_FM)
-	    sb_dev = i;
+    card_info[i].device = i;
+    if (card_info[i].synth_type == SYNTH_TYPE_SAMPLE
+	&& (card_info[i].synth_subtype == SAMPLE_TYPE_GUS
+#ifdef PLAY_AWE32
+	    || card_info[i].synth_subtype == SAMPLE_TYPE_AWE32
+#endif
+	    ))
+      gus_dev = i;
+    else if (card_info[i].synth_type == SYNTH_TYPE_FM)
+      sb_dev = i;
 #ifdef USE_SEQUENCER2
-	else if (card_info[i].synth_type == SYNTH_TYPE_MIDI)
-	    if (ext_dev < 0)
-		ext_dev = i;
+    else if (card_info[i].synth_type == SYNTH_TYPE_MIDI)
+      if (ext_dev < 0)
+	ext_dev = i;
 #endif
-    }
+  }
 
-    if (gus_dev >= 0) {
-	if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1) {
-	    perror("Sample reset");
-	    exit(1);
-	}
+  if (gus_dev >= 0) {
+    if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1) {
+      perror("Sample reset");
+      return false;
     }
+  }
 
 #ifndef USE_SEQUENCER2
-    if (ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &nrmidis) == -1) {
-	fprintf(stderr, "can't get info about midi ports\n");
-	exit(1);
-    }
-    if (nrmidis > 0) {
+  if (ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &nrmidis) == -1) {
+    fprintf(stderr, "can't get info about midi ports\n");
+    return false;
+  }
+  if (nrmidis > 0) {
 #ifdef FORCE_EXT_DEV
-	ext_dev = FORCE_EXT_DEV;
+    ext_dev = FORCE_EXT_DEV;
 #else
-	ext_dev = nrmidis - 1;
+    ext_dev = nrmidis - 1;
 #endif
-    }
+  }
 #endif
 
     if (!play_gus)
@@ -106,83 +164,70 @@
 	play_sb = 0;
     if (gus_dev < 0)
 	play_gus = 0;
+    return true;
 }
 
-void seqbuf_dump()
+
+void seqbuf_dump(void)
 {
-    if (_seqbufptr)
-	if (write(seqfd, _seqbuf, _seqbufptr) == -1) {
-	    perror("write " SEQUENCER_DEV );
-	    exit(-1);
-	}
-    _seqbufptr = 0;
-    ioctl(seqfd, SNDCTL_SEQ_SYNC);
+  if(_seqbufptr)
+    if(write(seqfd, _seqbuf, _seqbufptr) == -1) {
+      perror("write " SEQUENCER_DEV);
+      exit(-1);
+    }
+  _seqbufptr = 0;
+//  ioctl(seqfd, SNDCTL_SEQ_SYNC);
 }
 
-void record(dotime, cmd, arg1, arg2, data)
-unsigned int dotime;
-unsigned int cmd;
-unsigned int arg1;
-unsigned int arg2;
-unsigned char *data;
+
+void record(unsigned int dotime, unsigned int cmd, unsigned int chn,
+	    unsigned int arg1, unsigned int arg2, unsigned char* data)
 {
-    event[newevent].etime = dotime;
-    if (!dochan && cmd < 0xf0)	/* stripping channel data? */
-	event[newevent].cmd = cmd & 0xf0;
-    else
-	event[newevent].cmd = cmd;
-    event[newevent].arg1 = arg1;
-    event[newevent].arg2 = arg2;
-    event[newevent++].data = data;
-    if (newevent == maxevents) {
-	maxevents += EVENTBLOCK;
-	event = (struct mididata *)
-	    realloc(event, maxevents * sizeof(struct mididata));
-	if (event == NULL) {
-	    fprintf(stderr, "No more memory for events, aborting\n");
-	    exit(-1);
-	}
+  event[newevent].etime = dotime;
+  event[newevent].cmd = cmd;
+  event[newevent].chn = chn;
+  event[newevent].arg1 = arg1;
+  event[newevent].arg2 = arg2;
+  event[newevent++].data = data;
+  if (newevent == maxevents) {
+    maxevents += EVENTBLOCK;
+    event = (struct mididata *)
+      realloc(event, maxevents * sizeof(struct mididata));
+    if (event == NULL) {
+      fprintf(stderr, "No more memory for events, aborting\n");
+      exit(-1);
     }
+  }
 }
 
 static int lastsignal = 0;
 
 void do_nothing(int sig)
 {
-    signal((lastsignal = sig), do_nothing);
+  signal((lastsignal = sig), do_nothing);
 }
 
 /* Catch falling children */
 void fireman(int sig)
 {
+  (void) sig;
   while (waitpid(-1, NULL, WNOHANG) > 0)
     ;
 }
 
-void cleanup()
+void cleanup(int sig)
 {
-    /* this is probably over-protective */
-    signal(SIGINT, do_nothing);
-    if (!playing) {
-	/* if not playing, we can trash everything */
-	fprintf(stderr, "%s Program Killed\n",
-		(graphics ? "\033[22;1H\033[m\033[J\n**" : "**"));
-	exit(130);
-    }
-    playing = 0;
-    signal(SIGINT, cleanup);
+  delete server;
+  delete filelist;
+  exit(sig ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
-int do_getc()
+int do_getc(void)
 {
-    int c = 0;
-    if (read(mfd, &c, 1) < 1)
-	return EOF;
-    return c;
+  return fgetc(mfd);
 }
 
-int hextoi(s)
-char *s;
+int hextoi(char* s)
 {
     int i, j, k, l;
 
@@ -199,44 +244,41 @@
 	    exit(-1);
 	}
     }
-    if (j < 0 || j > 0xffff) {
-	fprintf(stderr, "mask must be between 0 and ffff hexidecimal\n");
+    if (j < 0 || j > 0xffffffff) {	// ???
+	fprintf(stderr, "mask must be between 0 and ffffffff hexidecimal\n");
 	exit(-1);
     }
     return j;
 
 }
 
-void do_error(s)
-char *s;
+void do_error(char* s)
 {
-    fprintf(stderr, "Error: %s\n", s);
+  fprintf(stderr, "Error: %s\n", s);
 }
 
-void do_header(format, ntrks, ldivision)
-int format, ntrks, ldivision;
+void do_header(int format, int ntrks, int ldivision)
 {
-    /* force time = 0: assume no more than 1 header per file */
-    record(0, MThd, (format << 8) + ntrks, ldivision, 0);
+  /* force time = 0: assume no more than 1 header per file */
+  record(0, MThd, 0, (format << 8) + ntrks, ldivision, 0);
 }
 
 void do_trackstart()
 {
-    record(Mf_currtime, MTrk, 1, 0, 0);
+  record(Mf_currtime, MTrk, 0, 1, 0, 0);
 }
 
 void do_trackend()
 {
-    record(Mf_currtime, MTrk, 0, 0, 0);
+  record(Mf_currtime, MTrk, 0, 0, 0, 0);
 }
 
 void do_eot()
 {
-    record(Mf_currtime, meta_event, MTrk, 0, 0);
+  record(Mf_currtime, meta_event, 0, MTrk, 0, 0);
 }
 
-void do_program(chan, pgm)
-int chan, pgm;
+void do_program(int chan, int pgm)
 {
     unsigned int i, now = Mf_currtime;
     if (chanmask & (1 << chan)) {
@@ -259,14 +301,13 @@
 		    exit(-1);
 		}
 	    }
-	record(now, MIDI_PGM_CHANGE + chan, pgm, 0, 0);
+	record(now, MIDI_PGM_CHANGE + (chan&0x0f), chan, pgm, 0, 0);
 	if (now < c_loaded[CHANNEL] || c_loaded[CHANNEL] == -1)
 	    c_loaded[CHANNEL] = now;	/* mark when channel loaded */
     }
 }
 
-void do_noteon(chan, pitch, vol)
-int chan, pitch, vol;
+void do_noteon(int chan, int pitch, int vol)
 {
     if (chanmask & (1 << chan)) {
 	if (ISPERC(chan) && !ISMIDI(chan)) {
@@ -274,14 +315,13 @@
 		(ISGUS(chan) && gus_load(pitch + 128)))
 		return;
 	}
-	record(Mf_currtime, MIDI_NOTEON + chan, pitch, vol, 0);
+	record(Mf_currtime, MIDI_NOTEON + (chan&0x0f), chan, pitch, vol, 0);
 	if (Mf_currtime < c_noteon[CHANNEL] || c_noteon[CHANNEL] == -1)
 	    c_noteon[CHANNEL] = Mf_currtime;	/* mark when channel used */
     }
 }
 
-void do_pressure(chan, pitch, press)
-int chan, pitch, press;
+void do_pressure(int chan, int pitch, int press)
 {
     if (chanmask & (1 << chan)) {
 	if (ISPERC(chan) && !ISMIDI(chan)) {
@@ -291,588 +331,905 @@
 	    if (ISFM(chan))
 		pitch -= 27;
 	}
-	record(Mf_currtime, MIDI_KEY_PRESSURE + chan, pitch, press, 0);
+	record(Mf_currtime, MIDI_KEY_PRESSURE + (chan&0x0f), chan, pitch, press, 0);
 	if (Mf_currtime < c_noteon[CHANNEL] || c_noteon[CHANNEL] == -1)
 	    c_noteon[CHANNEL] = Mf_currtime;	/* mark when channel used */
     }
 }
 
-void do_noteoff(chan, pitch, vol)
-int chan, pitch, vol;
+void do_noteoff(int chan, int pitch, int vol)
 {
-
-    if (chanmask & (1 << chan))
-	record(Mf_currtime, MIDI_NOTEOFF + chan, pitch, vol, 0);
+  if (chanmask & (1 << chan))
+    record(Mf_currtime, MIDI_NOTEOFF + (chan&0x0f), chan, pitch, vol, 0);
 }
 
-void do_parameter(chan, control, value)
-int chan, control, value;
+void do_parameter(int chan, int control, int value)
 {
-    if (chanmask & (1 << chan))
-	record(Mf_currtime, MIDI_CTL_CHANGE + chan, control, value, 0);
+  if (chanmask & (1 << chan))
+    record(Mf_currtime, MIDI_CTL_CHANGE + (chan&0x0f), chan, control, value, 0);
 }
 
-void do_pitchbend(chan, msb, lsb)
-int chan, msb, lsb;
+void do_pitchbend(int chan, int msb, int lsb)
 {
-    if (chanmask & (1 << chan))
-	record(Mf_currtime,
-		    MIDI_PITCH_BEND + chan, lsb + (msb << 7), 0, 0);
+  if (chanmask & (1 << chan))
+    record(Mf_currtime, MIDI_PITCH_BEND + (chan&0x0f), chan, lsb + (msb << 7), 0, 0);
 }
 
-void do_chanpressure(chan, press)
-int chan, press;
+void do_chanpressure(int chan, int press)
 {
-    if (chanmask & (1 << chan))
-	record(Mf_currtime, MIDI_CHN_PRESSURE + chan, press, 0, 0);
+  if (chanmask & (1 << chan))
+    record(Mf_currtime, MIDI_CHN_PRESSURE + (chan&0x0f), chan, press, 0, 0);
 }
 
-void do_sysex(leng, mess)
-int leng;
-char *mess;
+void do_sysex(int leng, char* mess)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(leng);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for sysex, ignoring\n");
-	return;
-    }
-    memcpy(data, mess, leng);
-    record(Mf_currtime, MIDI_SYSTEM_PREFIX, leng, 0, data);
+  data = (unsigned char*) malloc(leng);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for sysex, ignoring\n");
+    return;
+  }
+  memcpy(data, mess, leng);
+  record(Mf_currtime, MIDI_SYSTEM_PREFIX, 0, leng, 0, data);
 }
 
-void do_metamisc(type, leng, mess)
-int type, leng;
-char *mess;
+void do_metamisc(int type, int leng, char* mess)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(leng);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for meta misc, ignoring\n");
-	return;
-    }
-    memcpy(data, mess, leng);
-    record(Mf_currtime, meta_event, meta_event + (type << 16), leng, data);
+  data = (unsigned char*) malloc(leng);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for meta misc, ignoring\n");
+    return;
+  }
+  memcpy(data, mess, leng);
+  record(Mf_currtime, meta_event, 0, meta_event + (type << 16), leng, data);
 }
 
-void do_seqspecific(type, leng, mess)
-int type, leng;
-char *mess;
+void do_seqspecific(int type, int leng, char* mess)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(leng);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for meta special, ignoring\n");
-	return;
-    }
-    memcpy(data, mess, leng);
-    record
-	(Mf_currtime, meta_event, sequencer_specific + (type << 16), leng, data);
+  data = (unsigned char*) malloc(leng);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for meta special, ignoring\n");
+    return;
+  }
+  memcpy(data, mess, leng);
+  record(Mf_currtime, meta_event, 0,
+	 sequencer_specific + (type << 16), leng, data);
 }
 
-void do_text(type, leng, mess)
-int type, leng;
-char *mess;
+void do_text(int type, int leng, char* mess)
 {
-    int i;
-    unsigned char *data;
+  int i;
+  unsigned char *data;
 
-    if (!strncmp(mess, "WinJammer", 9))		/* this is done in spite */
-	return;
+  if (!strncmp(mess, "WinJammer", 9))		/* this is done in spite */
+    return;
 
-    data = malloc(leng + 1);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for meta text, ignoring\n");
-	return;
-    }
-    for (i = 0; i < leng; i++)
-	data[i] = isprint(mess[i]) ? mess[i] : mess[i] ? 254 : 0;
-    data[leng] = 0;
-    record(Mf_currtime, meta_event, type, leng, data);
+  data = (unsigned char*) malloc(leng + 1);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for meta text, ignoring\n");
+    return;
+  }
+  for (i = 0; i < leng; i++)
+    data[i] = mess[i];
+/*  data[i] = isprint(mess[i]) ? mess[i] : mess[i] ? 254 : 0;*/
+  data[leng] = 0;
+  record(Mf_currtime, meta_event, 0, type, leng, data);
 }
 
-void do_seqnum(num)
-int num;
+void do_seqnum(int num)
 {
-    record(Mf_currtime, meta_event, sequence_number, num, 0);
+  record(Mf_currtime, meta_event, 0, sequence_number, num, 0);
 }
 
-void do_keysig(sf, mi)
-int sf, mi;
+void do_keysig(int sf, int mi)
 {
-    record(Mf_currtime, meta_event, key_signature, (sf * 2) | (mi & 1), 0);
+  record(Mf_currtime, meta_event, 0, key_signature, (sf * 2) | (mi & 1), 0);
 }
 
-void do_tempo(ltempo)
-int ltempo;
+void do_tempo(int ltempo)
 {
-    record(Mf_currtime, meta_event, set_tempo, ltempo, 0);
+  record(Mf_currtime, meta_event, 0, set_tempo, ltempo, 0);
 }
 
-void do_timesig(nn, dd, cc, bb)
-int nn, dd, cc, bb;
+void do_timesig(int nn, int dd, int cc, int bb)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(16);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for time sig, ignoring\n");
-	return;
-    }
-    *(int *) &data[0] = nn;
-    *(int *) &data[4] = dd;
-    *(int *) &data[8] = cc;
-    *(int *) &data[12] = bb;
-    record(Mf_currtime, meta_event, time_signature, 0, data);
+  data = (unsigned char*) malloc(16);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for time sig, ignoring\n");
+    return;
+  }
+  *(int *) &data[0] = nn;
+  *(int *) &data[4] = dd;
+  *(int *) &data[8] = cc;
+  *(int *) &data[12] = bb;
+  record(Mf_currtime, meta_event, 0, time_signature, 0, data);
 }
 
-void do_smpte(hr, mn, se, fr, ff)
-int hr, mn, se, fr, ff;
+void do_smpte(int hr, int mn, int se, int fr, int ff)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(20);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for smpte time, ignoring\n");
-	return;
-    }
-    *(int *) &data[0] = hr;
-    *(int *) &data[4] = mn;
-    *(int *) &data[8] = se;
-    *(int *) &data[12] = fr;
-    *(int *) &data[16] = ff;
-    record(Mf_currtime, meta_event, smpte_offset, 0, data);
+  data = (unsigned char*) malloc(20);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for smpte time, ignoring\n");
+    return;
+  }
+  *(int *) &data[0] = hr;
+  *(int *) &data[4] = mn;
+  *(int *) &data[8] = se;
+  *(int *) &data[12] = fr;
+  *(int *) &data[16] = ff;
+  record(Mf_currtime, meta_event, 0, smpte_offset, 0, data);
 }
 
-void do_arbitrary(leng, mess)
-int leng;
-char *mess;
+void do_arbitrary(int leng, char* mess)
 {
-    unsigned char *data;
+  unsigned char *data;
 
-    data = malloc(leng);
-    if (data == NULL) {
-	fprintf(stderr, "no memory for midi arbitrary, ignoring\n");
-	return;
-    }
-    memcpy(data, mess, leng);
-    record(Mf_currtime, meta_event, sequencer_specific, leng, data);
+  data = (unsigned char*) malloc(leng);
+  if (data == NULL) {
+    fprintf(stderr, "no memory for midi arbitrary, ignoring\n");
+    return;
+  }
+  memcpy(data, mess, leng);
+  record(Mf_currtime, meta_event, 0, sequencer_specific, leng, data);
 }
 
 void initfuncs()
 {
-    Mf_error = (void *) do_error;
-    Mf_header = (void *) do_header;
-    Mf_trackstart = (void *) do_trackstart;
-    Mf_trackend = (void *) do_trackend;
-    Mf_noteon = (void *) do_noteon;
-    Mf_noteoff = (void *) do_noteoff;
-    Mf_pressure = (void *) do_pressure;
-    Mf_parameter = (void *) do_parameter;
-    Mf_pitchbend = (void *) do_pitchbend;
-    Mf_program = (void *) do_program;
-    Mf_chanpressure = (void *) do_chanpressure;
-    Mf_sysex = (void *) do_sysex;
-    Mf_metamisc = (void *) do_metamisc;
-    Mf_seqnum = (void *) do_seqnum;
-    Mf_timesig = (void *) do_timesig;
-    Mf_smpte = (void *) do_smpte;
-    Mf_tempo = (void *) do_tempo;
-    Mf_eot = (void *) do_eot;
-    Mf_keysig = (void *) do_keysig;
-    Mf_seqspecific = (void *) do_seqspecific;
-    Mf_text = (void *) do_text;
-    Mf_arbitrary = (void *) do_arbitrary;
-    Mf_getc = do_getc;
+  Mf_error = do_error;
+  Mf_header = do_header;
+  Mf_trackstart = do_trackstart;
+  Mf_trackend = do_trackend;
+  Mf_noteon = do_noteon;
+  Mf_noteoff = do_noteoff;
+  Mf_pressure = do_pressure;
+  Mf_parameter = do_parameter;
+  Mf_pitchbend = do_pitchbend;
+  Mf_program = do_program;
+  Mf_chanpressure = do_chanpressure;
+  Mf_sysex = do_sysex;
+  Mf_metamisc = do_metamisc;
+  Mf_seqnum = do_seqnum;
+  Mf_timesig = do_timesig;
+  Mf_smpte = do_smpte;
+  Mf_tempo = do_tempo;
+  Mf_eot = do_eot;
+  Mf_keysig = do_keysig;
+  Mf_seqspecific = do_seqspecific;
+  Mf_text = do_text;
+  Mf_arbitrary = do_arbitrary;
+  Mf_getc = do_getc;
 }
 
-int do_compare(e1, e2)
-struct mididata *e1, *e2;
+int do_compare(const mididata* e1, const mididata* e2)
 {
-    if (e1->etime > e2->etime)
-	return 1;
-    if (e1->etime < e2->etime)
-	return -1;
-    if (e1->cmd & 0xf0 == MIDI_PITCH_BEND)
-	return -1;
-    if (e2->cmd & 0xf0 == MIDI_PITCH_BEND)
-	return 1;
-    if (e1->cmd == meta_event && e1->arg1 == set_tempo)
-	return 1;
-    if (e2->cmd == meta_event && e2->arg1 == set_tempo)
-	return -1;
-    return 0;
+  if (e1->etime > e2->etime)
+    return 1;
+  if (e1->etime < e2->etime)
+    return -1;
+
+  if (e1->chn > e2->chn)
+    return 1;
+  if (e1->chn < e2->chn)
+    return -1;
+
+  if (e1->cmd & 0xf0 == MIDI_PITCH_BEND)
+    return -1;
+  if (e2->cmd & 0xf0 == MIDI_PITCH_BEND)
+    return 1;
+  if (e1->cmd == meta_event && e1->arg1 == set_tempo)
+    return 1;
+  if (e2->cmd == meta_event && e2->arg1 == set_tempo)
+    return -1;
+  return 0;
 }
 
-#define GUNZIP "gunzip -c"
-int copen(name)
-char *name;
+
+/*
+ * print version number
+ */
+static void print_version(void)
 {
+  fprintf(stderr,
+	  "Eplaymidi %s Copyright (C) 1995-1998 S.Kuramochi\n"
+	  "based on Playmidi 1.2 Copyright (C) 1994 Nathan I. Laredo\n",
+	  version);
+}
 
-    int compressed = 0, namelen = strlen(name);
-    char *command = NULL;
-    FILE *myfile;
 
-    if (namelen >= 2)
-	if (!strncmp(name + namelen - 2, ".Z", 2) ||
-	    !strncmp(name + namelen - 2, ".z", 2))
-	    compressed++;
-	else if (namelen >= 3)
-	    if (!strncmp(name + namelen - 3, ".gz", 3))
-		compressed++;
+/*
+ * print usage
+ */
+static void print_usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-device options] midifile ...\n"
+	  "       %s [-control options]\n"
+	  "Options:\n"
+	  "  -h, --help       show this help\n"
+	  "  -V, --version    display version number\n"
+	  "Device options:\n"
+	  "  -i x             set channels to ignore to bitmask x (hex)\n"
+	  "  -c x             set channels to play to bitmask x (hex)\n"
+	  "  -a x             add channel x to channel mask to play\n"
+	  "  -x x             exclude channel x from channel mask\n"
+	  "  -p [c,]x         play program x on channel c (all if no c)\n"
+//	  "  -V [c,]x         play channel c with volume x (all if no c)\n"
+//	  "  -d               don't play any percussion\n"
+//	  "  -P x             play percussion on channel x\n"
+	  "  -e               output to external midi\n"
+//	  "  -D x             output to midi device x\n"
+	  "  -f               output to fm (sb patches)\n"
+	  "  -4               output to 4-op fm (opl/3 patches)\n"
+//	  "  -a               output to awe32 wave synth\n"
+	  "  -g               output to gravis ultrasound\n"
+	  "  -E x             play channels in bitmask x external\n"
+	  "  -F x             play channels in bitmask x on fm\n"
+	  "  -G x             play channels in bitmask x on gus\n"
+//	  "  -A x             play channels in bitmask x on awe32\n"
+	  "  -z               zero all midi channel data\n"
+	  "  -8               force 8-bit samples on ultrasound\n"
+//	  "  -M               enable MT-32 to GM translation mode\n"
+	  "  -R x             set reverb to x (for fm or ultrasound)\n"
+//	  "  -C x             set initial chorus to x (0-127)\n"
+	  "  -v, --verbose    verbose mode\n"
+	  "  --parseonly      parse the files without playing\n"
+	  "Control options:\n"
+	  "  -S, --status     display sequencer status\n"
+	  "  -l, --list       show the program\n"
+	  "  --play           play\n"
+	  "  --pause          pause\n"
+	  "  --continue       continue\n"
+	  "  --stop           stop playing\n"
+	  "  --prev           play the previous song\n"
+	  "  --next           play the next song\n"
+	  "  --clear          clear the program\n"
+	  "  -I               show list of all GUS programs and numbers\n"
+	  "  -t x, --skew=x   skew tempo by x (float)\n"
+	  "  -q, --quit       stop the server\n"
+#if 0
+	  "  --fade           fade out\n"
+	  "  --jump x         jump to bar no. x\n"
+#endif
+	  ,
+	  prgname, prgname);
+}
 
-    if (!compressed) {
-	if ((myfile = fopen(name, "rb")) == NULL) {
-	    perror(name);
-	    return -1;
+
+static const struct option long_options[] = {
+  {"clear",     no_argument,       NULL, '!'},
+  {"continue",  no_argument,       NULL, 'C'},
+//{"fade",      no_argument,       NULL, ''},
+  {"help",      no_argument,       NULL, 'h'},
+//{"jump",      required_argument, NULL, ''},
+  {"list",      no_argument,       NULL, 'l'},
+  {"next",      no_argument,       NULL, 'X'},
+  {"parseonly", no_argument,       NULL, 'n'},
+  {"pause",     no_argument,       NULL, 'P'},
+  {"play",      no_argument,       NULL, 'y'},
+  {"prev",      no_argument,       NULL, 'r'},
+  {"quit",      no_argument,       NULL, 'q'},
+  {"skew",      required_argument, NULL, 't'},
+  {"status",    no_argument,       NULL, 'S'},
+  {"stop",      no_argument,       NULL, 's'},
+  {"verbose",   no_argument,       NULL, 'v'},
+  {"version",   no_argument,       NULL, 'V'},
+  {NULL,        no_argument,       NULL,  0 }
+};
+static const char* optstring = "hlqSV" "48a:c:eE:fF:gG:i:Ip:R:t:vx:z";
+//		   "!nrsyCPSX" "hlqSV" "48acdefgiptvxzACDEFGIMPRV"
+//                  long        short   original
+
+/*
+ * main routine
+ */
+int main(int argc, char* argv[])
+{
+  int i, j;
+  int error = 0;
+  char *extra;
+  bool help_opt = false;
+  bool dev_opts = false;
+  bool seq_opts = false;
+
+  prgname = argv[0];
+
+  options0.play_sb = play_sb;
+  options0.play_gus = play_gus;
+  options0.play_ext = play_ext;
+  options0.verbose = verbose;
+  options0.chanmask = chanmask;
+  options0.dochan = dochan;
+  options0.force8bit = force8bit;
+  options0.wantopl3 = wantopl3;
+  options0.reverb = reverb;
+  for(i = 0; i < 32; i++)
+    options0.useprog[i] = 0;
+  Options options = options0;
+
+  if(argc == 2 && !strcmp(argv[1], "--daemon" )) {
+    // fork a server process
+    server = new Server_Impl(NULL);
+    reg = server->creg->reg;
+//  strcpy(argv[0], "(eplaymidi)");
+  } else {
+    bool server_exists = server_exist();
+    optind = 0;
+    opterr = 1;
+    int c;
+    // parse options
+    for(;;) {
+      if((c = getopt_long_only(argc, argv,
+			       optstring, long_options, NULL)) == EOF)
+	break;
+      switch (c) {
+      case 'h': // show help
+	help_opt = true;
+	break;
+      case 'n': // parse file (don't play)
+	dev_opts = true;
+	parseonly = true;
+	break;
+      case 'V': // display display number
+	print_version();
+	break;
+      case 'I':
+	seq_opts = true;
+	break;
+      case 't': // set skew
+	{
+	  seq_opts = true;
+	  if(!help_opt && !server_exists) {
+	    fprintf(stderr, "%s: server does not exist.\n", prgname);
+	    exit(EXIT_FAILURE);
+	  }
+	  float skew;
+	  if((skew = 100.0 * atof(optarg)) < 25.0) {
+	    fprintf(stderr, "option -t skew under 0.25 unplayable\n");
+	    error++;
+	  }
 	}
+	break;
+      case 'q': // stop the server
+      case 'S': // display sequencer status
+      case 'l': // show the program
+      case 'C': // continue
+      case 'r': // play the previous song
+      case 'X': // play the next song
+      case '!': // clear the program
+      case 'y': // play
+      case 'P': // pause
+      case 's': // stop playing
+	seq_opts = true;
+	if(!help_opt && !server_exists) {
+	  fprintf(stderr, "%s: server does not exist.\n", prgname);
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      default:
+	if(parse_dev_opts(c, &options, error))
+	  dev_opts = true;
+	break;
+      }
+    }
+    if(!help_opt && dev_opts && optind == argc) {
+      fprintf(stderr,
+	      "%s: device option specified without a filename.\n",
+	      prgname);
+      error++;
+    }
+    if(!help_opt && seq_opts && optind < argc) {
+      fprintf(stderr,
+	      "%s: control option specified with a filename.\n",
+	      prgname);
+      error++;
+    }
+    if(!help_opt && dev_opts && seq_opts) {
+      fprintf(stderr,
+	      "%s: cannot specify device option and control option at once.\n",
+	      prgname);
+      error++;
+    }
+    if(help_opt || error > 0 || argc == 1) {
+      print_version();
+      print_usage();
+      exit(EXIT_FAILURE);
+    }
+    if(parseonly) {
+      reg = new Register;
     } else {
-	command = (char *) malloc(strlen(name) + strlen(GUNZIP) + 1);
-	sprintf(command, "%s '%s'", GUNZIP, name);
-	if ((myfile = popen(command, "rb")) == NULL) {
-	    perror(name);
-	    free(command);
-	    return -1;
+      // connect to the server process
+      server = new Server(prgname);
+      reg = server->creg->reg;
+    }
+    if(seq_opts) {
+      // processing control options
+      optind = 0;
+      opterr = 1;
+      for(;;) {
+	if((c = getopt_long_only(argc, argv, optstring,
+				 long_options, NULL)) == EOF)
+	  break;
+	switch ((i = c)) {
+	case 'I':
+	  {
+	    int k;
+	    printf("Gravis Ultrasound Program information:");
+	    for (j = 0; j < 128; j++) {
+	      extra = gmvoice[j];
+	      printf("%c%3d %s", j % 6 ? ' ' : '\n', j + 1, extra);
+	      for (k = strlen(extra); k < 8; k++)
+		putchar(' ');
+	    }
+	    putchar('\n');
+	  }
+	  break;
+	case 'q': // stop the server
+	  server->quit();
+	  break;
+	case 'S': // display sequencer status
+	  print_status();
+	  break;
+	case 'l': // show the program
+	  {
+	    char** list = server->getList();
+	    if(list != NULL) {
+	      int i;
+	      for(i = 0; list[i] != NULL; i++) {
+		fprintf(stderr, "%s\n", list[i]);
+		delete[] list[i];
+	      }
+	      delete[] list;
+	    } else
+	      fprintf(stderr, "no entries\n");
+	  }
+	  break;
+	case 't': // set skew
+	  reg->skew = 100.0 * atof(optarg);
+	  break;
+	case 'V': // display display number
+	  print_version();
+	  break;
+	case 'C': // continue
+	  server->unpause();
+	  break;
+	case 'r': // play the previous song
+	  server->prev();
+	  break;
+	case 'X': // play the next song
+	  server->next();
+	  break;
+	case '!': // clear the program
+	  server->clear();
+	  break;
+	case 'y': // play
+	  server->play();
+	  break;
+	case 'P': // pause
+	  server->pause();
+	  break;
+	case 's': // stop playing
+	  server->stop();
+	  break;
+	default:
+	  fprintf(stderr, "%s: internal error\n", prgname);
+	  if(parseonly)
+	    delete reg;
+	  else
+	    delete server;
+	  exit(EXIT_FAILURE);
+	  break;
 	}
-	free(command);
+      }
     }
-    return fileno(myfile);
+  }
+  if(parseonly || server->is_server) {
+    initfuncs();
+    server_main(argc, argv, optind, options);
+  } else {
+    // play all filenames listed on command line
+    const char** options = new const char*[optind];
+    for(i = 1; i < optind; i++)
+      options[i-1] =  argv[i];
+    options[optind-1] = NULL;
+    for(i = optind; i < argc; i++) {
+      const char* filename = argv[i];
+      if(filename[0] != '/') {
+	getcwd(path, MAX_PATH);
+	strcat(path, "/");
+	strcat(path, filename);
+	filename = path;
+      }
+      FILE* fp;
+      if((fp = fopen(filename, "r")) == NULL) {
+	fprintf(stderr, "cannot open \"%s\".\n", filename);
+	break;
+      }
+      fclose(fp);
+      server->add(filename, options);
+    }
+  }
+  if(parseonly)
+    delete reg;
+  else
+    delete server;
+  exit(EXIT_SUCCESS);
 }
 
-#define LOCKFILE "/tmp/LCK..playmidi"
-#define TMPLOCK "/tmp/playmidi..%d"
-static char templock[32];
 
-int locked(char *name)
+/*
+ * main loop
+ */
+void server_main(int argc, char* argv[], int optind, Options options)
 {
-    int f, p = 0;
+  int i;
+  if(!parseonly) {
+    multisig(SIGCHLD, fireman);
+    signal(SIGINT, cleanup);
+    signal(SIGHUP, cleanup);
+    signal(SIGTERM, cleanup);
+    signal(SIGABRT, cleanup);
+    signal(SIGQUIT, cleanup);
+    signal(SIGSEGV, cleanup);
+  }
 
-    if ((f = open (name, O_RDONLY, 0)) != -1) {
-	if (read(f, &p, sizeof(int)) < sizeof(int) || p == getpid())
-	    p = 0;
-	close(f);
+  filelist = new FileList();
+  if(parseonly) {
+    for(i = optind; i < argc; i++)
+      filelist->add(argv[i], options);
+  }
+
+  for(;;) {
+    // process control commands on the queue ???
+    const char* filename;
+    Options options;
+    while((filename = filelist->get(&options)) == NULL) {
+      if(parseonly)
+	return;
+      else
+	((Server_Impl*)server)->select(true);	// wait a control command
     }
-    if (!p || kill (p, lastsignal)) {
-	unlink(name);
-	p = 0;
+    play_sb = options.play_sb;
+    play_gus = options.play_gus;
+    play_ext = options.play_ext;
+    verbose = options.verbose;
+    chanmask = options.chanmask;
+    dochan = options.dochan;
+    force8bit = options.force8bit;
+    wantopl3 = options.wantopl3;
+    reverb = options.reverb;
+    for(i = 0; i < 32; i++)
+      useprog[i] = options.useprog[i];
+
+    if(!parseonly) {
+      // opening sequencer device
+      const int retry = 3;
+      int k;
+      for(k = 0; k < retry; k++) {
+	errno = 0;
+	if ((seqfd = open(SEQUENCER_DEV, O_WRONLY, 0)) < 0) {
+	  if(errno == EBUSY && k < retry-1) {
+	    sleep(1);
+	  } else {
+	    perror("open " SEQUENCER_DEV);
+	    fprintf(stderr, "Abort playing \"%s\"\n", filename);
+	    return;
+	  }
+	} else
+	  break;
+      }
+      fcntl(seqfd, F_SETFD, FD_CLOEXEC);	// ???
+
+      // synthesizer setup
+      if(!synth_setup())
+	return;
+      if (!(play_gus || play_sb || play_ext)) {
+	fprintf(stderr, "%s: No playback device set.  Aborting.\n", prgname);
+	return;
+      }
+      if (play_sb)
+	loadfm();
+      if (play_gus) {
+	gus_load(-1);
+	card_info[gus_dev].nr_voices = 32;
+      }
+      for (i = 0; i < 16; i++)
+	c_loaded[i] = c_noteon[i] = -1;
     }
-    lastsignal = 0;
-    return p;
-}
 
-void removelock()
-{
-    unlink(templock);
-    unlink(LOCKFILE);
-}
+    const char* p;
+    if((p = strrchr(filename, '/')) != NULL) {
+      strncpy(path, filename, p-filename+1);
+      path[p-filename+1] = '\0';
+    } else
+      path[0] = '\0';
 
-int main(argc, argv)
-int argc;
-char **argv;
-{
-    extern char *optarg;
-    extern int optind;
-    int i, error = 0, j, newprog, silly_playback = 0;
-    char *extra;
+#if 0
+    // check for WRD file
+    if((p = strrchr(argv[i], '.')) != NULL) {
+      char* wrdfile = new char[p-argv[i]+1+4];
+      strncpy(wrdfile, argv[i], p-argv[i]);
+      wrdfile[p-argv[i]] = '\0';
+      strcat(wrdfile, ".wrd");
 
-    while ((i = getopt(argc, argv, "48a:c:deE:fF:gG:i:Im:p:rE:R:St:vx:z"))
-	    != -1)
-	switch (i) {
-	case '8':
-	    force8bit++;
-	    break;
-	case 'a':
-	case 'x':
-	    j = atoi(optarg);
-	    if (j < 1 || j > 16) {
-		fprintf(stderr, "option -%c channel must be 1 - 16\n", i);
-		exit(-1);
-	    }
-	    j = 1 << (j - 1);
-	    if (i == 'a')
-		chanmask |= j;
-	    else
-		chanmask &= ~j;
-	    break;
-	case 'c':
-	    if (chanmask == 0xffff)
-		chanmask = hextoi(optarg);
-	    else
-		chanmask |= hextoi(optarg);
-	    break;
-	case 'd':
-	    chanmask = ~perc;
-	    break;
-	case 'e':
-	    play_ext = 0xffff;
-	    play_gus = play_sb = 0;
-	    break;
-	case 'g':
-	    play_gus = 0xffff;
-	    play_ext = play_sb = 0;
-	    break;
-	case 'f':
-	case '4':
-	    play_sb = 0xffff;
-	    play_ext = play_gus = 0;
-	    wantopl3 = (i == '4');
-	    break;
-	case 'I':
-	    {
-		int k;
-		printf("Gravis Ultrasound Program information:");
-		for (j = 0; j < 128; j++) {
-		    extra = gmvoice[j];
-		    printf("%c%3d %s", j % 6 ? ' ' : '\n', j + 1, extra);
-		    for (k = strlen(extra); k < 8; k++)
-			putchar(' ');
-		}
-		putchar('\n');
-		exit(-1);
-	    }
-	    break;
-	case 'i':
-	    chanmask &= ~hextoi(optarg);
-	    break;
-	case 'm':
-	    perc = hextoi(optarg);
-	    break;
-	case 'p':
-	    if (strchr(optarg, ',') == NULL) {	/* set all channels */
-		newprog = atoi(optarg);
-		if (newprog < 1 || newprog > 129) {
-		    fprintf(stderr, "option -p prog must be 1 - 129\n");
-		    exit(-1);
-		}
-		for (j = 0; j < 16; j++)
-		    useprog[j] = newprog;
-	    } else {		/* set channels individually */
-		extra = optarg;
-		while (extra != NULL) {
-		    j = atoi(extra);
-		    if (j < 1 || j > 16) {
-			fprintf(stderr, "opton -p chan must be 1 - 16\n");
-			exit(-1);
-		    }
-		    extra = strchr(extra, ',');
-		    if (extra == NULL) {
-			fprintf(stderr, "option -p prog needed for chan %d\n",
-				j);
-			exit(-1);
-		    } else
-			extra++;
-		    newprog = atoi(extra);
-		    if (newprog < 1 || newprog > 129) {
-			fprintf(stderr, "option -p prog must be 1 - 129\n");
-			exit(-1);
-		    }
-		    useprog[j - 1] = newprog;
-		    extra = strchr(extra, ',');
-		    if (extra != NULL)
-			extra++;
-		}
-	    }
-	    break;
-	case 'r':
-	    graphics++;
-	    break;
-	case 't':
-	    if ((skew = 100.0 * atof(optarg)) < 25.0) {
-		fprintf(stderr, "option -t skew under 0.25 unplayable\n");
-		exit(-1);
-	    }
-	    break;
-	case 'E':
-	    play_ext = hextoi(optarg);
-	    play_sb &= ~play_ext;
-	    play_gus &= ~play_ext;
-	    break;
-	case 'F':
-	    play_sb = hextoi(optarg);
-	    play_ext &= ~play_sb;
-	    play_gus &= ~play_sb;
-	    break;
-	case 'G':
-	    play_gus = hextoi(optarg);
-	    play_sb &= ~play_gus;
-	    play_ext &= ~play_gus;
-	    break;
-	case 'R':
-	    reverb = atoi(optarg);
-	    if (reverb < 0 || reverb > 127) {
-		fprintf(stderr, "option -R reverb must be 0 - 127\n");
-		exit(-1);
-	    }
-	    break;
-	case 'S':
-	    silly_playback++;
-	    break;
-	case 'v':
-	    verbose++;
-	    break;
-	case 'z':
-	    dochan = 0;
-	    break;
-	default:
-	    error++;
-	    break;
+      // spawn xwrdplay
+      pid_t pid;
+      switch((pid = fork())) {
+      case 0: // child process
+	close(seqfd);
+	if(execlp(WRDPLAYER, WRDPLAYER, wrdfile, NULL) == -1) {
+	  perror("exec");
+	  exit(EXIT_FAILURE);
 	}
-
-    if (error || optind >= argc) {
-	fprintf(stderr, "usage: %s [-options] midifilename\n", argv[0]);
-	fprintf(stderr, "  -v       verbosity (additive)\n"
-		"  -i x     set channels to ignore to bitmask x (hex)\n"
-		"  -c x     set channels to play to bitmask x (hex)\n"
-		"  -a x     add channel x to channel mask to play\n"
-		"  -x x     exclude channel x from channel mask\n"
-		"  -p [c,]x play program x on channel c (all if no c)\n"
-		"  -t x     skew tempo by x (float)\n"
-		"  -m x     override percussion mask (%04x) with x\n"
-		"  -d       don't play any drum tracks (see above)\n"
-		"  -e       output to external midi\n"
-		"  -f       output to fm (sb patches)\n"
-		"  -4       output to 4-op fm (opl/3 patches)\n"
-		"  -g       output to gravis ultrasound\n"
-		"  -E x     play channels in bitmask x external\n"
-		"  -F x     play channels in bitmask x on fm\n"
-		"  -G x     play channels in bitmask x on gus\n"
-		"  -z       zero all midi channel data\n"
-		"  -8       force 8-bit samples on ultrasound\n"
-		"  -S       play files concurrently, conflicts ignored\n"
-		"  -I       show list of all GUS programs and numbers\n"
-		"  -R x     set reverb to x (for fm or ultrasound)\n"
-		"  -r       real-time playback graphics\n",
-		PERCUSSION);
-	exit(-1);
+	break;
+      case -1: // error
+	perror("fork");
+	break;
+      default: // parent process
+	break;
+      }
+      delete[] wrdfile;
     }
+#endif
 
-    multisig(SIGCHLD, fireman);
-    signal(SIGINT, do_nothing);
-    sprintf(templock, TMPLOCK, j = getpid());
-    if ((i = creat (templock, 0644)) < 0) {
-	perror("creat (templock, 0644)");
-	exit(-1);
-    } else {
-	atexit(removelock);
-	write(i, &j, sizeof(int));
-	close(i);
-	i = access(LOCKFILE, F_OK);
-        if (i != -1)
-	    fprintf(stderr,"Waiting on lock in \"remote control\" mode...");
-	while (link(templock, LOCKFILE) < 0)
-	    if (errno != EEXIST) {
-		perror("link(templock, LOCKFILE)");
-		unlink (templock);
-		exit(-1);
-	    } else if (locked(LOCKFILE))
-		sleep(6);
-	unlink(templock);
-	if (i != -1)
-	    fprintf(stderr,"Done!  Now playing!\n");
+    // opening midi file
+    if ((mfd = fopen(filename, "r")) == NULL) {
+      fprintf(stderr, "cannot open \"%s\".\n", filename);
+      close(seqfd);
+      continue;
     }
+    strncpy((char*)reg->file, filename, MAX_PATH+MAX_NAME);
+//  reg->seqid++;
+    reg->status = STATUS_COMP;
+
+    char* extra = new char[strlen(filename)+4];
+    strcpy(extra, filename);
+    bool play_rcp;
+    if(!strcasecmp(&extra[strlen(extra)-4], ".rcp") ||
+       !strcasecmp(&extra[strlen(extra)-4], ".r36") ||
+       !strcasecmp(&extra[strlen(extra)-4], ".g18") ||
+       !strcasecmp(&extra[strlen(extra)-4], ".g36"))
+      play_rcp = true;
+    else
+      play_rcp = false;
+    delete[] extra;
 
-    if (graphics)
-	verbose = 0;
-    if ((seqfd = open(SEQUENCER_DEV, O_WRONLY, 0)) < 0) {
-	perror("open " SEQUENCER_DEV);
-	exit(-1);
-    }
-    synth_setup();
-    if (!(play_gus || play_sb || play_ext)) {
-	fprintf(stderr, "%s: No playback device set.  Aborting.\n", argv[0]);
-	exit(-1);
-    }
-    initfuncs();
     event = (struct mididata *) malloc(maxevents * sizeof(struct mididata));
     if (event == NULL) {
-	fprintf(stderr, "no free memory for events, aborting\n");
-	exit(-1);
+      fprintf(stderr, "no free memory for events, aborting\n");
+      fclose(mfd);
+      close(seqfd);
+      continue;
     }
-    signal(SIGINT, cleanup);
-    if (play_sb) {
-	loadfm();
+
+    if(play_rcp) {
+      rcpread();
+      reg->format = 1;
+    } else {
+      mfread();
+      reg->format = 0;
     }
-    if (play_gus) {
-	gus_load(-1);
-	card_info[gus_dev].nr_voices = 32;
+    fclose(mfd);
+
+    // wait for WRD player's setup ???
+
+    if(!parseonly) {
+      /* sort list of events by time */
+      qsort(event, newevent, sizeof(*event),
+	    (int(*)(const void*, const void*))do_compare);
+      playevents(filename);
+      sleep(1);	/* allow for notes to decay before closing */
+      server->creg->initialize();
+      reg->status = STATUS_IDLE;
+      if (close(seqfd) < 0) {
+	perror("close " SEQUENCER_DEV);
+	return;
+      }
+    } else {
+      printf("%d events\n", newevent);
+      printf("\n");
+      delete reg;
+      reg = new Register;
     }
-    for (i = 0; i < 16; i++)
-	c_loaded[i] = c_noteon[i] = -1;
-    /* play all filenames listed on command line */
-    for (i = optind; i < argc; i++) {
-	if ((mfd = copen(argv[i])) == -1) {
-	    if ((extra = malloc(strlen(argv[i]) + 4)) == NULL) {
-		fprintf(stderr, "unable to allocate %d bytes!\n",
-			strlen(argv[i]) + 4);
-		exit(-1);
-	    }
-	    sprintf(extra, "%s.mid", argv[i]);
-	    if ((mfd = open(extra, O_RDONLY, 0)) == -1) {
-		perror(argv[i]);
-		exit(-1);
-	    }
-	    free(extra);
-	}
-	if (!silly_playback)
-	    for (j = 0; j < 16; j++)
-		c_loaded[j] = c_noteon[j] = -1;
-	if (!silly_playback && play_gus)
-	    gus_load(-1);
-	mfread();
-	close(mfd);
-	if (!silly_playback) {
-	    for (j = 0; j < 16; j++)
-		if (c_noteon[j] != -1 &&
-		    ( c_loaded[j] == -1 || c_loaded[j] > c_noteon[j]))
-		    do_program(j, -1);
-	    /* sort list of events by time */
-	    qsort(event, newevent, sizeof(*event), do_compare);
-	    if (graphics) {
-		if (dochan)	/* plot notes by channel */
-		    printf("\033[H\033[2Jch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch9 "
-			   "c10 c11 c12 c13 c14 c15 c16");
-		else		/* with no channel data plot by octave */
-		    printf("\033[H\033[2JO0  O1  O2  O3  O4  O5  O6  O7  O8  "
-			   "O9  O10");
-		printf("\033[1;66HClock:\n\n%78s\n\n%78s\n%78s\n\n%78s\n"
-		     "\033[65C%6d events\033[1m\n", "Playmidi 1.1", "by",
-		       "Nathan Laredo", argv[i], newevent);
-	    }
-	    if (verbose)
-		printf("** Now Playing \"%s\": %d events\n", argv[i], newevent);
-	    playevents();
-	}
+    free(event);
+  }
+}
+
+
+/*
+ * add a file to play list
+ */
+bool addFile(const char* args)
+{
+  char args0[4096];
+  char* argv[256];
+  argv[0] = prgname;
+  strcpy(args0, args);
+  int i = 0, argc = 1;
+  for(;;) {
+    while(args0[i++] == ' ');
+    argv[argc++] = &args0[i-1];
+    if(argc > 255) {
+      fprintf(stderr, "%s: too many arguments\n", prgname);
+      break;
     }
-    if (silly_playback) {
+    while(args0[i] != ' ' && args0[i] != '\0') i++;
+    if(args0[i] == '\0') {
+      argv[argc] = NULL;
+      break;
+    } else
+      args0[i++] = '\0';
+  }
+  Options options = options0;
+  optind = 0;
+  opterr = 0;
+  int c;
+  int error = 0;
+  // parse options
+  for(;;) {
+    if((c = getopt_long_only(argc, argv,
+			     optstring, long_options, NULL)) == EOF)
+      break;
+    parse_dev_opts(c, &options, error);
+  }
+  if(optind < argc) {
+    filelist->add(argv[optind], options);
+    return true;
+  } else
+    return false;
+}
+
+
+/*
+ * parese device options
+ */
+bool parse_dev_opts(char c, Options* options, int& error)
+{
+  int i, j;
+  char* extra;
+  switch((i = c)) {
+  case '8':
+    options->force8bit = 1;
+    break;
+  case 'a':
+  case 'x':
+    j = atoi(optarg);
+    if (j < 1 || j > 16) {
+      if(opterr)
+	fprintf(stderr, "option -%c channel must be 1 - 16\n", i);
+      error++;
+    }
+    j = 1 << (j - 1);
+    if (i == 'a')
+      options->chanmask |= j;
+    else
+      options->chanmask &= ~j;
+    break;
+  case 'c':
+    if (options->chanmask == 0xffffffff)	// ???
+      options->chanmask = hextoi(optarg);
+    else
+      options->chanmask |= hextoi(optarg);
+    break;
+  case 'e':
+    options->play_ext = 0xffffffff;
+    options->play_gus = options->play_sb = 0;
+    break;
+  case 'g':
+    options->play_gus = 0xffffffff;
+    options->play_ext = options->play_sb = 0;
+    break;
+  case 'f':
+  case '4':
+    options->play_sb = 0xffffffff;
+    options->play_ext = options->play_gus = 0;
+    options->wantopl3 = (i == '4');
+    break;
+  case 'i':
+    options->chanmask &= ~hextoi(optarg);
+    break;
+  case 'p':
+    {
+      int newprog;
+      if (strchr(optarg, ',') == NULL) {	/* set all channels */
+	newprog = atoi(optarg);
+	if (newprog < 1 || newprog > 129) {
+	  if(opterr)
+	    fprintf(stderr, "option -p prog must be 1 - 129\n");
+	  error++;
+	  break;
+	}
 	for (j = 0; j < 16; j++)
-	    if (c_noteon[j] != -1 &&
-		    ( c_loaded[j] == -1 || c_loaded[j] > c_noteon[j]))
-		do_program(j, -1);
-	/* sort list of events by time */
-	qsort(event, newevent, sizeof(*event), do_compare);
-	if (graphics) {
-	    if (dochan)		/* plot notes by channel */
-		printf("\033[H\033[2Jch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch9 "
-		       "c10 c11 c12 c13 c14 c15 c16");
-	    else		/* with no channel data plot by octave */
-		printf("\033[H\033[2JO0  O1  O2  O3  O4  O5  O6  O7  O8  "
-		       "O9  O10");
-	    printf("\033[1;66HClock:\n\n%78s\n\n%78s\n%78s\n\n%78s\n"
-		   "\033[65C%6d events\033[1m\n", "Playmidi 1.1", "by",
-		   "Nathan Laredo", "All Files", newevent);
+	  options->useprog[j] = newprog;
+      } else {		/* set channels individually */
+	extra = optarg;
+	while (error == 0 && extra != NULL) {
+	  j = atoi(extra);
+	  if (j < 1 || j > 16) {
+	    if(opterr)
+	      fprintf(stderr, "opton -p chan must be 1 - 16\n");
+	    error++;
+	    break;
+	  }
+	  extra = strchr(extra, ',');
+	  if (extra == NULL) {
+	    if(opterr)
+	      fprintf(stderr, "option -p prog needed for chan %d\n", j);
+	    error++;
+	    break;
+	  } else
+	    extra++;
+	  newprog = atoi(extra);
+	  if (newprog < 1 || newprog > 129) {
+	    if(opterr)
+	      fprintf(stderr, "option -p prog must be 1 - 129\n");
+	    error++;
+	    break;
+	  }
+	  options->useprog[j - 1] = newprog;
+	  extra = strchr(extra, ',');
+	  if (extra != NULL)
+	    extra++;
 	}
-	if (verbose)
-	    printf("** Now Playing \"All Files\": %d events\n", newevent);
-	playevents();
+      }
     }
-    sleep(2);	/* allow for notes to decay before closing */
-    if (close(seqfd) < 0) {
-	perror("close " SEQUENCER_DEV);
-	exit(-1);
+    break;
+  case 'E':
+    options->play_ext = hextoi(optarg);
+    options->play_sb &= ~options->play_ext;
+    options->play_gus &= ~options->play_ext;
+    break;
+  case 'F':
+    options->play_sb = hextoi(optarg);
+    options->play_ext &= ~options->play_sb;
+    options->play_gus &= ~options->play_sb;
+    break;
+  case 'G':
+    options->play_gus = hextoi(optarg);
+    options->play_sb &= ~options->play_gus;
+    options->play_ext &= ~options->play_gus;
+    break;
+  case 'R':
+    j = atoi(optarg);
+    if (j < 0 || j > 127) {
+      if(opterr)
+	fprintf(stderr, "option -R reverb must be 0 - 127\n");
+      error++;
     }
-    exit(0);
+    options->reverb = j;
+    break;
+  case 'z':
+    options->dochan = 0;
+    break;
+  case 'v': // verbose mode
+    options->verbose = 1;
+    break;
+  default:
+    error++;
+    return false;
+  }
+  return true;
+}
+
+
+/*
+ * display sequencer status
+ */
+static void print_status(void)
+{
+  char* status_str[] =
+    {"idle", "play", "pause", "fade out", "search", "compute"};
+  fprintf(stderr, "Status: %s\n", status_str[reg->status]);
+  if(reg->status != STATUS_IDLE) {
+    fprintf(stderr, "File: %s\n", reg->file);
+    fprintf(stderr, "Title: %s\n", reg->title);
+  }
 }
-/* end of file */
--- playmidi-1.2/playmidi.h	Sun May  7 19:01:34 1995
+++ playmidi.h	Sun Mar 22 04:40:08 1998
@@ -3,13 +3,18 @@
  *
  * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
  * Source code may be freely distributed in unmodified form.
- *************************************************************************
- * If you have more than one midi device, this forces the first */
+ *************************************************************************/
+
+/*
+ * modified by Satoshi KURAMOCHI 1996,1997
+ * $Id: playmidi.h,v 1.4 1998-03-22 04:40:08+09 satoshi Exp $
+ */
+
+/* If you have more than one midi device, this forces the first */
 #define FORCE_EXT_DEV	0
 /* change this if you notice performance problems,  128 bytes by default */
-#define SEQUENCERBLOCKSIZE 128
-/* Default mask for percussion instruments.  Channels 16 and 10 = 0x8200 */
-#define PERCUSSION	0x8200
+#define SEQUENCERBLOCKSIZE 38400
+//#define SEQUENCERBLOCKSIZE 128
 /* IF YOU WANT TO TRY OUT THE SEQUENCER2 CODE, DEFINE THIS */
 #undef USE_SEQUENCER2
 #define MAX_CARDS	5
@@ -20,11 +25,11 @@
 /* if not found above, the following path will be searched */
 #define PATCH_PATH2	"/dos/ultrasnd/midi"
 /* where to find fm patch libraries */
-#define O3MELODIC	"/etc/std.o3"
-#define O3DRUMS		"/etc/drums.o3"
-#define SBMELODIC	"/etc/std.sb"
-#define SBDRUMS		"/etc/drums.sb"
-#define ISPERC(x)	(perc & (1 << x))
+#define O3MELODIC	FMPATCHPATH "/std.o3"
+#define O3DRUMS		FMPATCHPATH "/drums.o3"
+#define SBMELODIC	FMPATCHPATH "/std.sb"
+#define SBDRUMS		FMPATCHPATH "/drums.sb"
+#define ISPERC(x)	(reg->rhythm[x])
 #define ISGUS(x)	(play_gus & (1 << x))
 #define ISFM(x)		(play_sb & (1 << x))
 #define ISMIDI(x)	(play_ext & (1 << x))
@@ -32,7 +37,18 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <sys/soundcard.h>
+#if defined(linux)
+#  include <sys/soundcard.h>
+#elif defined(__FreeBSD__)
+#  include <machine/soundcard.h>
+#endif
+#if defined(PLAY_AWE32)
+#  if defined(linux)
+#    include <linux/awe_voice.h>
+#  else
+#    include <awe_voice.h>
+#  endif
+#endif
 #include <sys/ioctl.h>
 #define PLAYMIDI
 #include "midifile.h"
@@ -40,6 +56,7 @@
 struct mididata {
     unsigned int etime;		/* event time */
     unsigned int cmd;		/* midi command */
+    unsigned int chn;		/* midi channel */
     unsigned int arg1;		/* argument 1 */
     unsigned int arg2;		/* argument 2 */
     unsigned char *data;	/* data */
--- playmidi-1.2/etc.magic.add	Sun Nov 20 09:46:34 1994
+++ etc.magic.add	Sun Jul 27 03:46:33 1997
@@ -1,4 +1,38 @@
-# midi files
-0	string		MThd		MIDI
+# Standard MIDI Format file
+0	string		MThd		Standard MIDI
 >9	byte		x		format %d file with
 >11	byte		x		%d tracks
+
+# Recomposer (RCM v2) song data
+0	string	RCM-PC98				Recomposer
+>8	string	V2.0					V2.0
+>12	string	(C)COME\040ON\040MUSIC\015\012\0\0	song data,
+#>32	string	>\040					title: %s
+
+# Recomposer (RCM v2) song data
+0	string	COME\040ON\040MUSIC\040RECOMPOSER\040\RCP Recomposer song data,
+>28	string	3.0\0						V%s
+#>32	string	>\040					title: %s
+
+# Recomposer CM6 file
+0	string	COME\040ON\040MUSIC\0\0\0	Recomposer CM6 file,
+>16	string	>\0				%s
+#>16	string	R\040MT-32\040\040\040\0\0	MT-32
+
+# Recomposer GSD file
+0	string	COME\040ON\040MUSIC\0GS\040CONTROL\040	Recomposer GSD file
+>25	string	>\0					V%s
+
+# Ballade song data
+0	string	BALLADE\040SONG\040Ver.\0404.00\040\015\012	Ballade song data,
+>25	string	>\015	title: %s
+
+# Micro Musician song data
+0	string	MicroMusicianVer	Micro Musician
+>16	string	2.00			Ver.2.00
+>20	string	SNG\040			song data,
+>24	string	>\0			title: %s
+
+# Z-MUSIC song data
+0	string	\020ZmuSiC\040\177	Z-MUSIC song data,
+>9	string	>\0			title: %s
