/* mid2dsp - Convert MIDI files to raw wave output. */

/* Copyright (C) 1997-2000 by David A. Madore <david.madore@ens.fr>
 * Permission is granted to use, copy and modify under the terms of
 * the GNU General Public License (version 2 or later, at your
 * option).  This program is provided WITHOUT ANY WARRANTY: see the
 * the GNU General Public License for details. */

/* Compile with
   gcc -o mid2dsp mid2dsp.c -O6 -Wall -ansi -pedantic -W \
   -Wwrite-strings -Wcast-qual -Wpointer-arith -Wstrict-prototypes \
   -Wno-unused -lm
 */

/* Use with mid2dsp [MIDI file], piping the standard output to a
 * program that understands raw wave data, typically sox -t raw -r
 * 11025 -s -w - -t ossdsp /dev/dsp (where 11025 is actually the
 * SAMPLERATE given below). */

/* Note: the essential difference with a program like ``timidity'' is
 * that this does not use a set of patches: the patches are computed
 * on the fly from a set of numerical constants by using a few
 * oscillators.  As a result, (i) this is extremely CPU intensive, and
 * (ii) it soulds awful - really awful.  *But*, at least, you don't
 * waste some precious disk space with patches (or Internet bandwidth
 * downloading them :-).  Please note that output is monophonic, and
 * that aftertouch and pitchbend are not supported. */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>

/* The sampling rate of the output (in Hz) */
#define SAMPLERATE 11025.

#define MIDIFILESIG 0x4d546864	   /* "MThd" in big-endian format */
#define MIDITRKSIG 0x4d54726b	   /* "MTrk" in big-endian format */

/* The type and functions with which to do the computations */
typedef double real_t;
#define SIN sin
#define FABS fabs
#define PI 3.14159265358979323846

/* The structure that describes an instrument */
struct instrument_s {
  /* The envelope parameters: the volume linearly increases from 0 to
   * max_vol in time att_del, then it linearly decreases to sus_vol
   * (the sustain volume) in time dec_del.  If irel==0, it is kept at
   * sus_vol so long as the note is not released; if irel==1, the note
   * is considered to be released immediately.  After that, the volume
   * drops back linearly to 0 in time rel_del. */
  real_t max_vol, sus_vol;	   /* Maximal and sustained volumes */
  real_t att_del, dec_del, rel_del; /* Attack, decay and release delays
                                    * (in seconds) */
  char irel;			   /* Release instantly (i.e. no
                                    * sustain)? */
  /* The wave shape: 0 is sine, 1 is square, 2 is absolute value of
   * sine, 3 is sawtooth, 4 is alternate sine bump and zero. */
  char shape;			   /* Wave shape */
  /* The oscillators.  These are added to the main wave.  amp_ and
   * frq_ give their relative amplitude and frequency, while del_
   * gives the delay before oscillator comes in: its amplitude
   * increases linearly between 0 and 1 in that delay, and then stays
   * at 1.  shape_ of course is the oscillator's wave shape. */
  real_t amp2, frq2;		   /* Second oscillator amplitude
                                    * (ratio) and frequency (ratio) */
  real_t del2;			   /* Time taken for second oscillator
                                    * to reach its maximal amplitude */
  char shape2;			   /* Second oscillator wave shape */
  real_t amp3, frq3;		   /* Third oscillator amplitude
                                    * (ratio) and frequency (ratio) */
  real_t del3;			   /* Time taken for third oscillator
                                    * to reach its maximal amplitude */
  char shape3;			   /* Third oscillator wave shape */
  /* The wobulator.  It acts like an oscillator, except that it
   * perturbs time (frequency) instead of amplitude. */
  real_t ampw, frqw;		   /* Wobulator amplitude and
                                    * frequency (ratio) */
  real_t delw;			   /* Time taken for wobulator to
                                    * reach its maximal amplitude */
  char shapew;			   /* Wobulator wave shape */
};

/* We now define some instruments.  I'm quite bad at that exercice so
 * these really sound awful.  Far more awful than they might.  But I
 * think even with considerable skill in defining the instruments,
 * this program will never give a decent sound. */

#define MAKEINSTR(name,max_vol,sus_vol,att_del,dec_del,rel_del,irel,\
  shape,amp2,frq2,del2,shape2,amp3,frq3,del3,shape3,ampw,frqw,delw,shapew) \
struct instrument_s name##_I = { max_vol,sus_vol,att_del,dec_del,rel_del,irel,\
  shape,amp2,frq2,del2,shape2,amp3,frq3,del3,shape3,ampw,frqw,delw,shapew }

/* A generic instrument that sounds very much like nothing and a
 * little bit like anything. */
MAKEINSTR(gener, 1.0,0.2,0.01,0.03,0.09,0,
  0, 0.3,2.0,0.0,0, 0.1,3.0,0.05,0, 0.0,1.0,0.0,0);

/* Highly symbolic brass instrument - I mean it */
MAKEINSTR(brass, 1.2,0.8,0.09,0.07,0.06,0,
  0, 0.4,2.0,0.0,0, 0.15,3.0,0.0,0, 0.03,0.5,0.08,1);

/* This sounds exactly like a recorder... having spent a couple of
 * years in a very damp place. */
MAKEINSTR(recorder, 1.1,0.9,0.01,0.01,0.05,0,
  0, 0.1,1.5,0.05,0, 0.15,2.0,0.0,0, 0.0,1.0,0.0,0);

/* This makes an almost tolerable whistle - unfortunately, nobody uses
 * that particular instrument :-( */
MAKEINSTR(whistle, 1.0,0.9,0.11,0.06,0.03,0,
  0, 0.0,1.0,0.0,0, 0.0,1.0,0.0,0, 0.01,0.01,0.0,0);

/* This is a horrible pizzicato string - it sounds more like a
 * pizzicato string than like an elephant sneezing, but I would hardly
 * dare say more.  Note, however, the ingenious (?) use of one
 * oscillator to compensate another. */
MAKEINSTR(pizzs, 1.0,0.05,0.01,0.45,0.06,1,
  3, -0.7,1.0,0.1,3, 0.7,1.0,0.1,0, 0.08,0.01,0.18,0);

/* Some extremely imaginative persons might recognize the following
 * instrument as a stylized clarinet. */
MAKEINSTR(clarinet, 1.0,0.9,0.015,0.015,0.015,0,
  0, 0.35,3.0,0.0,0, 0.2,5.0,0.03,0, 0.0,1.0,0.0,0);

/* This has some very vague similarity with what might be considered
 * as a piano. */
MAKEINSTR(piano, 1.0,0.2,0.01,0.03,0.09,0,
  0, 0.3,2.0,0.0,0, 0.1,3.0,0.05,0, 0.0,1.0,0.0,0);

/* This sounds (very) slightly like a violin. */
MAKEINSTR(violin, 1.0,0.8,0.09,0.09,0.09,0,
  3, 0.0,1.0,0.0,0, 0.0,1.0,0.0,0, 0.08,0.01,0.18,0);

/* A rather satisfactory fantasia instrument */
MAKEINSTR(fantas, 1.0,0.5,0.01,0.03,0.09,0,
  1, -0.8,1.0,0.1,1, 0.8,1.0,0.1,0, 0.0,1.0,0.0,0);

/* For lack of a better place to put this... */
MAKEINSTR(crystal, 1.0,0.2,0.01,0.45,0.06,0,
  1, -0.7,1.0,0.1,1, 0.7,1.0,0.1,0, 0.0,1.0,0.0,0);

/* The MIDI instrument mapping table.  This maps MIDI program numbers
 * to instrument structures.  I just put in gener_I whenever I didn't
 * have anything better to suggest. */
struct instrument_s *instrtab[128] = {
  &piano_I,&piano_I,&piano_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &pizzs_I,&pizzs_I,&pizzs_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &pizzs_I,&pizzs_I,&pizzs_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &violin_I,&violin_I,&violin_I,&violin_I,&violin_I,&pizzs_I,&pizzs_I,&gener_I,
  &violin_I,&violin_I,&violin_I,&violin_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &brass_I,&brass_I,&brass_I,&brass_I,&brass_I,&brass_I,&brass_I,&brass_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&clarinet_I,
  &gener_I,&gener_I,&recorder_I,&gener_I,&gener_I,&gener_I,&whistle_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &fantas_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&crystal_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,
  &gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I,&gener_I
};

/* The type for delta times.  You might want to use long long if you
 * want to bicker. */
typedef unsigned long int dtime_t;

int midif;			   /* MIDI file descriptor */
off_t midi_off;			   /* Offset relative to file start */

/* The MIDI file header */
unsigned long int header_len, header_end;
struct {
  unsigned short int format;
  unsigned short int nbtrk;
  unsigned short int subd;
} header_data;

/* The MIDI tracks */
#define MAXNBTRK 65		   /* Maximal supported number of
				    * tracks */
struct {
  char active;			   /* Is the track active
                                    * (i.e. playing)? */
  unsigned long int trk_data_start, trk_data_len, trk_data_end, trk_cur;
				   /* Offsets for: start of track
				    * data, length of track data (not
				    * an offset), end of track data,
				    * current position within
				    * track. */
  dtime_t pending;		   /* Pending delay: the number of
				    * MIDI subdivisions before the
				    * track's next event is
				    * performed. */
  unsigned char rstatus;	   /* Running status */
} trktab[MAXNBTRK];

int nb_active;

real_t dtime_unit;		   /* Delta time unit (in seconds) */
real_t midi_time;		   /* Midi time (in seconds) */
real_t dsp_time_unit;		   /* Inverse of sample rate */
real_t dsp_time;		   /* DSP time (time of last byte
                                    * output, in seconds) */

/* The MIDI channels */
struct {
  unsigned char patch;		   /* Current patch on channel */
  unsigned char main_vol;	   /* Main volume (controller number
                                    * 7) */
  real_t chan_volume;		   /* Channel volume (as a real) */
} channels[16];

/* The notes */
#define MAXNOTES 50		   /* Maximal number of simultaneous
                                    * notes supported */
struct {
  char playing;			   /* Is note being heard?  (Or is the
				    * entry available for use?) */
  char sustained;		   /* Is note being sustained?  (Or is
				    * it in the release phase?) */
  unsigned char chan;		   /* Channel note is running on */
  unsigned char pitch;		   /* Note MIDI pitch */
  unsigned char speed;		   /* Note MIDI speed */
  struct instrument_s *instr;	   /* Patch used */
  real_t freq;			   /* Frequency (as a real, in Hz) */
  real_t volume;		   /* Volume (as a real), relative to
				    * channel volume. */
  real_t zero_time, cut_time;	   /* When the note started playing
				    * and when the note started
				    * releasing (unfortunate
				    * names). */
} notes[MAXNOTES];

/* The frequency in Hz of the twelve notes in the lowest octave. */
real_t freqtab[12] =
{
  16.352, 17.324, 18.354, 19.445, 20.602, 21.827,
  23.125, 24.500, 25.957, 27.500, 29.135, 30.868
};

void
midi_read (void *buf, size_t count)
     /* Read some data from the MIDI file. */
{
  char *ptr;
  ssize_t res;

  for ( ptr=buf ; count>0 ; ptr+=res, count-=res, midi_off+=res )
    {
      res = read (midif, ptr, count);
      if ( res == -1 )
	{
	  perror ("read()");
	  exit (EXIT_FAILURE);
	}
    }
}

unsigned long int
midi_read_32 (void)
     /* Architecture-independent read a 32-bit quantity in big-endian
      * format */
{
  unsigned char c[4];
  midi_read (c, 4);
  return ((((long int)c[0])<<24)
	  | (((long int)c[1])<<16)
	  | (((long int)c[2])<<8)
	  | ((long int)c[3]));
}

unsigned short int
midi_read_16 (void)
     /* Architecture-independent read a 16-bit quantity in big-endian
      * format */
{
  unsigned char c[2];
  midi_read (c, 2);
  return ((((long int)c[0])<<8)
	  | ((long int)c[1]));
}

unsigned long int
midi_read_24 (void)
     /* Architecture-independent read a 24-bit quantity in big-endian
      * format */
{
  unsigned char c[3];
  midi_read (c, 3);
  return ((((long int)c[0])<<16)
	  | (((long int)c[1])<<8)
	  | ((long int)c[2]));
}

dtime_t
read_dtime (void)
     /* Read a delta time from MIDI file. */
{
  unsigned char c;
  dtime_t d;

  d = 0;
  do
    {
      midi_read (&c, 1);
      d = (d<<7) | (c&0x7f);
    }
  while ( c&0x80 );
  return d;
}

void
midi_seek (off_t offset)
     /* Seek the MIDI file */
{
  if ( lseek (midif, offset, SEEK_SET ) == -1 )
    {
      perror ("lseek()");
      exit (EXIT_FAILURE);
    }
  midi_off = offset;
}

void
midi_seekfwd (long int offset)
     /* Advance (or more back) in the MIDI file */
{
  if ( lseek (midif, offset, SEEK_CUR ) == -1 )
    {
      perror ("lseek()");
      exit (EXIT_FAILURE);
    }
  midi_off += offset;
}

real_t
pitch_to_freq (unsigned char pitch)
     /* Return the frequency (in Hz) for a certain pitch */
{
  int i;
  real_t t;

  t = freqtab[pitch%12];
  for ( i=0 ; i<pitch/12 ; i++)
    {
      t *= 2.0;  /* XXX - Use a table rather */
    }
  return t;
}

void
note_off (unsigned char chan, unsigned char pitch, unsigned char speed)
     /* MIDI note off */
{
  int i;

  for ( i=0 ; i<MAXNOTES ; i++ )
    {
      if ( notes[i].playing && notes[i].sustained
	   && ( notes[i].chan == chan ) && ( notes[i].pitch == pitch ) )
	{
	  notes[i].sustained = 0;
	  notes[i].cut_time = midi_time;
	  return;
	}
    }
#if 0 /* Do not produce this warning because instant-release notes
       * end up being cut twice */
  fprintf (stderr, "Warning: unknown note was cut!\n");
#endif
}

void
note_on (unsigned char chan, unsigned char pitch, unsigned char speed)
     /* MIDI note on */
{
  int i;

  if ( ! speed )
    {
      note_off (chan, pitch, 64);
      return;
    }
  for ( i=0 ; i<MAXNOTES ; i++ )
    {
      if ( ! notes[i].playing )
	{
	  notes[i].playing = 1;
	  notes[i].sustained = 1;
	  notes[i].chan = chan;
	  notes[i].pitch = pitch;
	  notes[i].speed = speed;
	  notes[i].instr = instrtab[channels[notes[i].chan].patch];
	  notes[i].freq = pitch_to_freq (pitch);
	  notes[i].volume = 0.125*((real_t)speed/100.0);
	  notes[i].zero_time = midi_time;
	  notes[i].cut_time = midi_time;
	  return;
	}
    }
  fprintf (stderr, "Warning: out of notes!\n");
}

void
aftertouch (unsigned char chan, unsigned char pitch, unsigned char touch)
     /* MIDI aftertouch */
{
  fprintf (stderr, "Warning: aftertouch is not supported.\n");
}

void
controller (unsigned char chan, unsigned char ctrl, unsigned char val)
     /* MIDI controller change */
{
  if ( ctrl == 7 )
    {
      channels[chan].main_vol = val;
      channels[chan].chan_volume = ((real_t)val)/100.0;
      /* XXX - This is wrong, it should be logarithmic */
    }
}

void
program_change (unsigned char chan, unsigned char patch)
     /* MIDI program change */
{
  fprintf (stderr, "Channel %d: patch %d.\n", chan, patch);
  channels[chan].patch = patch;
}

void
channel_pressure (unsigned char chan, unsigned char press)
     /* MIDI channel pressure */
{
  fprintf (stderr, "Warning: channel pressure is not supported.\n");
}

void
pitchbend (unsigned char chan, signed short int bend)
     /* MIDI pitchbend */
{
  /* XXX - This *really* should be written */
  /* Beware: bend is tricky.  I _think_ 8192 is the base value (no
   * bend, exact frequency) and 0 means lower by 2 (well tempered)
   * semitones, 16384 means raise by 2 (well tempered) semitones. */
  fprintf (stderr, "Warning: pitch bend is not supported.\n");
}

void
set_tempo (long int tempo)
     /* Set tempo - in microsecond per beat */
{
  dtime_unit = ((real_t)tempo*1.0E-6)/((real_t)header_data.subd);
}

unsigned char
process_event (unsigned char rs, int tk)
     /* Process one event on track tk (at the current position), with
      * running status rs, and return the new running status. */
{
  unsigned char data, data2;
  long int len, end;

  midi_read (&data, 1);
  if ( data & 0x80 )
    /* Running status change */
    {
      rs = data;
      midi_read (&data, 1);
    }
  switch ( rs>>4 )
    {
    case 0x8:
      midi_read (&data2, 1);
      note_off (rs&0x0f, data, data2);
      break;
    case 0x9:
      midi_read (&data2, 1);
      note_on (rs&0x0f, data, data2);
      break;
    case 0xa:
      midi_read (&data2, 1);
      aftertouch (rs&0x0f, data, data2);
      break;
    case 0xb:
      midi_read (&data2, 1);
      controller (rs&0x0f, data, data2);
      break;
    case 0xc:
      program_change (rs&0x0f, data);
      break;
    case 0xd:
      channel_pressure (rs&0x0f, data);
      break;
    case 0xe:
      midi_read (&data2, 1);
      pitchbend (rs&0x0f, ((short int)data) | (((short int)data2)<<7));
      /* For some obscure reason, pitch bend data is in little-endian
       * format (everything else in MIDI is big-endian). */
      break;
    case 0xf:
      /* A Meta or Sysex event */
      switch ( rs & 0x0f )
	{
	case 0x0:
	case 0x7:
	  /* Sysex event.  First comes the length, in delta time
	   * format. */
	  midi_seekfwd (-1);	   /* Unread data byte */
	  len = read_dtime ();	   /* This is stored like a dtime */
	  midi_seekfwd (len);
	  break;
	case 0xf:
	  /* Meta event.  We only honor track end (compulsory) and
	   * tempo change. */
	  len = read_dtime ();	   /* Event length in delta time
                                    * format */
	  end = midi_off + len;
	  switch (data)
	    {
	    case 0x2f:
	      /* Track end */
	      trktab[tk].active = 0;
	      nb_active--;
	      break;
	    case 0x51:
	      /* Tempo change */
	      set_tempo (midi_read_24 ());
	      break;
	    }
	  midi_seek (end);
	  break;
	default:
	  fprintf (stderr, "Unknown event encountered!\n");
	  exit (EXIT_FAILURE);
	}
      break;
    }
  return rs;
}

real_t
envelope (int not)
     /* Calculate note envelope. */
{
  real_t t;
  struct instrument_s *ins;

  t = dsp_time - notes[not].zero_time;
  ins = notes[not].instr;
  if ( t < ins->att_del )
    /* Note is in attack phase. */
    return ins->max_vol * t / ins->att_del;
  t -= ins->att_del;
  if ( t < ins->dec_del )
    /* Note is in decay phase. */
    return ( ins->max_vol
	     - (ins->max_vol-ins->sus_vol) * t / ins->dec_del );
  if ( notes[not].sustained && ! ins->irel )
    return ins->sus_vol;
  if ( ins->irel || ( notes[not].cut_time - notes[not].zero_time
		      < ins->att_del + ins->dec_del ) )
    /* Release cannot start before decay ends; in instant release
     * instruments, that's exactly when it starts. */
    notes[not].cut_time = notes[not].zero_time + ins->att_del + ins->dec_del;
  t = dsp_time - notes[not].cut_time;
  if ( t < ins->rel_del )
    /* Note is in release phase. */
    return ins->sus_vol * (1.0-t/ins->rel_del);
  /* Note has finished playing.  It is dead.  It should not be heard
   * (of) any more. */
  notes[not].playing = 0;
  return 0.0;
}

real_t
simpenv (real_t del, real_t x)
     /* Simple envelope, for oscillators and wobulator */
{
  if ( x < del )
    return x/del;
  return 1.0;
}

real_t
wave (char shape, real_t x)
     /* Calculate wave value of a certain shape */
{
  if ( shape == 0 )
    return SIN (x*2.*PI);
  if ( shape == 2 )
    return FABS (SIN (x*PI));
  if ( shape == 4 )
    {
      real_t tmp;

      tmp = SIN (x*2.0*PI);
      if ( tmp > 0. )
	return tmp;
      else
	return 0.;
    }
  x -= floor (x);
  if ( shape == 1 )
    {
      if ( x < 0.02 )
	return x*50.0;
      if ( x < 0.48 )
	return 1.0;
      if ( x < 0.52 )
	return (0.52-x)*50.0-1.0;
      if ( x < 0.98 )
	return -1.0;
      return (x-1.0)*50.0;
    }
  if ( shape == 3 )
    {
      if ( x < 0.48 )
	return x/0.48;
      if ( x < 0.52 )
	return (0.52-x)*50.0-1.0;
      return (x-1.0)/0.48;
    }
  return 0.0;  /* Does not occur. */
}

short int
calculate_output (void)
     /* The actual output calculation function */
{
  int i;
  real_t t, x, a, u;
  struct instrument_s *ins;

  a = 0.0;
  for ( i=0 ; i<MAXNOTES ; i++ )
    if ( notes[i].playing )
      {
	ins = notes[i].instr;
	t = dsp_time - notes[i].zero_time;
	x = t * notes[i].freq;
	if ( ins->ampw != 0.0 ) /* Wobulate */
	  x += ( ins->ampw * wave (ins->shapew, x*ins->frqw)
		 * simpenv (ins->delw, t) );
	u = wave (ins->shape, x);
	if ( ins->amp2 != 0.0 ) /* Oscillator 2 */
	  u += ( ins->amp2 * wave (ins->shape2, x*ins->frq2)
		 * simpenv (ins->del2, t) );
	if ( ins->amp3 != 0.0 ) /* Oscillator 3 */
	  u += ( ins->amp3 * wave (ins->shape3, x*ins->frq3)
		 * simpenv (ins->del3, t) );
	a += ( channels[notes[i].chan].chan_volume * notes[i].volume
	       * u * envelope (i) );
      }
  /* Now correct for saturation (we prefer using a differentiable
   * function rather than one which saturates to rapidly: it
   * introduces more deformation, but at least it doesn't saturate to
   * violently. */
  /* XXX - Is this a good choice? */
  a = a / ( 1.0 + FABS (a) );
  /* Return the result as a short int. */
  return (short int)(a*32766.0);
}

void
produce_output (void)
     /* Calculate the output, output it, and make the time advance. */
{
  short int w;

  w = calculate_output ();
  fwrite (&w, sizeof(w), 1, stdout);
  dsp_time += dsp_time_unit;
}

void
delay_action (void)
     /* Make a MIDI division delay pass. */
{
  midi_time += dtime_unit;
  while ( dsp_time < midi_time )
    produce_output ();
}

int
main (int argc, char *argv[])
{
  int number;
  int i;

  if ( argc < 2 )
    {
      fprintf (stderr, "Usage is:\n  %s FILENAME...\n", argv[0]);
      exit (EXIT_FAILURE);
    }
  number = 1;
 another:
  /* Open the MIDI file. */
  fprintf (stderr, "Playing %s\n", argv[number]);
  if ( ( midif = open (argv[number], O_RDONLY ) ) == -1 )
    {
      perror ("open()");
      exit (EXIT_FAILURE);
    }
  midi_off = 0;
  /* Read the MIDI file header. */
  if ( midi_read_32 () != MIDIFILESIG )
    {
      fprintf (stderr, "This is not a MIDI file!\n");
      exit (EXIT_FAILURE);
    }
  header_len = midi_read_32 ();
  if ( header_len < 6 )
    {
      fprintf (stderr, "Oops!  Header is too small for me.\n");
      exit (EXIT_FAILURE);
    }
  header_end = midi_off + header_len;
  header_data.format = midi_read_16 ();
  /* XXX - Check this */
  header_data.nbtrk = midi_read_16 ();
  if ( header_data.nbtrk > MAXNBTRK )
    {
      fprintf (stderr, "Too many tracks - truncating.\n");
      header_data.nbtrk = MAXNBTRK;
    }
  header_data.subd = midi_read_16 ();
  midi_time = 0.0;
  dsp_time = 0.0;
  set_tempo (500000L);
  dsp_time_unit = 1.0/SAMPLERATE;
  midi_seek (header_end);
  /* Initialize tracks and determine their positions. */
  for ( i=0 ; i<header_data.nbtrk ; i++ )
    {
      if ( midi_read_32 () != MIDITRKSIG )
	{
	  fprintf (stderr, "Ouch! Track %d has wrong signature.\n", i);
	  exit (EXIT_FAILURE);
	}
      trktab[i].active = 1;
      trktab[i].trk_data_len = midi_read_32();
      trktab[i].trk_data_start = midi_off;
      trktab[i].trk_data_end = ( trktab[i].trk_data_start
				 + trktab[i].trk_data_len );
      trktab[i].pending = read_dtime ();
      trktab[i].rstatus = 0x90; /* This ought not be useful... */
      trktab[i].trk_cur = midi_off;
      midi_seek (trktab[i].trk_data_end);
    }
  nb_active = header_data.nbtrk;
  /* Initialize channels. */
  for ( i=0 ; i<16 ; i++ )
    {
      channels[i].patch = 0;
      channels[i].main_vol = 100;
      channels[i].chan_volume = 1.0;
    }
  /* Initialize notes. */
  for ( i=0 ; i<MAXNOTES ; i++ )
    {
      notes[i].playing = 0;
    }
  /* Main loop */
  while ( nb_active )
    {
      for ( i=0 ; i<header_data.nbtrk ; i++ )
	if ( trktab[i].active && ! trktab[i].pending )
	  {
	    midi_seek (trktab[i].trk_cur);
	    while ( trktab[i].active && ! trktab[i].pending )
	      {
		trktab[i].rstatus = process_event (trktab[i].rstatus, i);
		if ( trktab[i].active )
		  trktab[i].pending = read_dtime ();
	      }
	    trktab[i].trk_cur = midi_off;
	  }
      delay_action ();
      for ( i=0 ; i<header_data.nbtrk ; i++ )
	if ( trktab[i].active )
	  trktab[i].pending--;
    }
  close (midif);
  if ( ++number < argc )
    goto another; /* Yuck, but I didn't want to add another loop */
  return 0;
}
