Blame test/midifile.c

Packit 4a16fb
/*
Packit 4a16fb
 * midifile 1.11
Packit 4a16fb
 *
Packit 4a16fb
 * Read and write a MIDI file.  Externally-assigned function pointers are
Packit 4a16fb
 * called upon recognizing things in the file.
Packit 4a16fb
 *
Packit 4a16fb
 * Original release ?
Packit 4a16fb
 * June 1989 - Added writing capability, M. Czeiszperger.
Packit 4a16fb
 *
Packit 4a16fb
 *          The file format implemented here is called
Packit 4a16fb
 *          Standard MIDI Files, and is part of the Musical
Packit 4a16fb
 *          instrument Digital Interface specification.
Packit 4a16fb
 *          The spec is available from:
Packit 4a16fb
 *
Packit 4a16fb
 *               International MIDI Association
Packit 4a16fb
 *               5316 West 57th Street
Packit 4a16fb
 *               Los Angeles, CA 90056
Packit 4a16fb
 *
Packit 4a16fb
 *          An in-depth description of the spec can also be found
Packit 4a16fb
 *          in the article "Introducing Standard MIDI Files", published
Packit 4a16fb
 *          in Electronic Musician magazine, April, 1989.
Packit 4a16fb
 *
Packit 4a16fb
 * February 1993 - Minor adjustments, Greg Lee:
Packit 4a16fb
 *	(1) can now set the global variable Mf_interactive to 1 to prevent the
Packit 4a16fb
 *	    reading functions from looking for file and track headers
Packit 4a16fb
 *	(2) can now write system exclusive data with
Packit 4a16fb
 *		mf_write_midi_event(delta_time, system_exclusive, 0, data, size)
Packit 4a16fb
 *	(3) changed definition of 'sequencer_specific' in midifile.h to 0x7f
Packit 4a16fb
 *	(4) changed mf_write_tempo to take additional delta_time as first argument
Packit 4a16fb
 *	    (since delta need not be zero)
Packit 4a16fb
 *	(5) added function mf_write_seqnum(unsigned long delta_time, unsigned seqnum)
Packit 4a16fb
 *	(6) changed mf_write_midi_event to use running status
Packit 4a16fb
 *	(7) removed the code to write an end of track meta event automatically
Packit 4a16fb
 *		-- this must now be done by the user of the library (I changed
Packit 4a16fb
 *		it because I need to be able to control the time delta of this
Packit 4a16fb
 *		 meta event)
Packit 4a16fb
 *	(8) added global variables Mf_division, Mf_currtempo, Mf_realtime, which
Packit 4a16fb
 *		are updated by the reading functions.  Mf_realtime is useful,
Packit 4a16fb
 *		because Mf_currtime does not really measure time at all, since
Packit 4a16fb
 *		its units change value at every tempo change.  Mf_realtime is
Packit 4a16fb
 *		the midi-time elapsed in units of 1/16 of a centisecond (but it
Packit 4a16fb
 *		does not handle SMPTE times)
Packit 4a16fb
 *	(9) maintains a history of tempo settings to update Mf_currtempo,
Packit 4a16fb
 *		to handle tempo tracks.
Packit 4a16fb
 *	(10) if there is an Mf_error function, the error routine no longer
Packit 4a16fb
 *		exits, leaving it to the application to do this.
Packit 4a16fb
 *	(11) chanmessage skips over invalid c1 command bytes > 127 and
Packit 4a16fb
 *		adjusts invalid c2 argument byte > 127 to 127.
Packit 4a16fb
 *	(12) readmt returns EOF when it encounters a 0 or 0x1a byte instead of an expected
Packit 4a16fb
 *		header string (some midi files have padding at end).
Packit 4a16fb
 */
Packit 4a16fb
#define NO_LC_DEFINES
Packit 4a16fb
#include "midifile.h"
Packit 4a16fb
#ifdef NO_LC_DEFINES
Packit 4a16fb
#define system_exclusive      	0xf0
Packit 4a16fb
#define	meta_event		0xFF
Packit 4a16fb
#define	set_tempo		0x51
Packit 4a16fb
#define lowerbyte(x) ((unsigned char)(x & 0xff))
Packit 4a16fb
#define upperbyte(x) ((unsigned char)((x & 0xff00)>>8))
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#define NULLFUNC 0
Packit 4a16fb
#if 0
Packit 4a16fb
#define NULL 0
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#define THINK
Packit 4a16fb
Packit 4a16fb
#ifdef THINK
Packit 4a16fb
#include <stdlib.h>
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#include <stdio.h>
Packit 4a16fb
#include <values.h>
Packit 4a16fb
Packit 4a16fb
#include <string.h>
Packit 4a16fb
/*void exit(), free();*/
Packit 4a16fb
Packit 4a16fb
/* public stuff */
Packit 4a16fb
Packit 4a16fb
/* Functions to be called while processing the MIDI file. */
Packit 4a16fb
int (*Mf_getc) () = NULLFUNC;
Packit 4a16fb
void (*Mf_error) () = NULLFUNC;
Packit 4a16fb
void (*Mf_header) () = NULLFUNC;
Packit 4a16fb
void (*Mf_trackstart) () = NULLFUNC;
Packit 4a16fb
void (*Mf_trackend) () = NULLFUNC;
Packit 4a16fb
void (*Mf_noteon) () = NULLFUNC;
Packit 4a16fb
void (*Mf_noteoff) () = NULLFUNC;
Packit 4a16fb
void (*Mf_pressure) () = NULLFUNC;
Packit 4a16fb
void (*Mf_parameter) () = NULLFUNC;
Packit 4a16fb
void (*Mf_pitchbend) () = NULLFUNC;
Packit 4a16fb
void (*Mf_program) () = NULLFUNC;
Packit 4a16fb
void (*Mf_chanpressure) () = NULLFUNC;
Packit 4a16fb
void (*Mf_sysex) () = NULLFUNC;
Packit 4a16fb
void (*Mf_arbitrary) () = NULLFUNC;
Packit 4a16fb
void (*Mf_metamisc) () = NULLFUNC;
Packit 4a16fb
void (*Mf_seqnum) () = NULLFUNC;
Packit 4a16fb
void (*Mf_eot) () = NULLFUNC;
Packit 4a16fb
void (*Mf_smpte) () = NULLFUNC;
Packit 4a16fb
void (*Mf_tempo) () = NULLFUNC;
Packit 4a16fb
void (*Mf_timesig) () = NULLFUNC;
Packit 4a16fb
void (*Mf_keysig) () = NULLFUNC;
Packit 4a16fb
void (*Mf_seqspecific) () = NULLFUNC;
Packit 4a16fb
void (*Mf_text) () = NULLFUNC;
Packit 4a16fb
Packit 4a16fb
/* Functions to implement in order to write a MIDI file */
Packit 4a16fb
int (*Mf_putc) () = NULLFUNC;
Packit 4a16fb
int (*Mf_writetrack) () = NULLFUNC;
Packit 4a16fb
int (*Mf_writetempotrack) () = NULLFUNC;
Packit 4a16fb
Packit 4a16fb
int Mf_nomerge = 0;		/* 1 => continue'ed system exclusives are */
Packit 4a16fb
 /* not collapsed. */
Packit 4a16fb
int Mf_interactive = 0;		/* 1 => file and track headers are not required */
Packit 4a16fb
unsigned long Mf_currtime = 0L;	/* current time in delta-time units */
Packit 4a16fb
unsigned long Mf_realtime = 0L;	/* current time in 1/16 centisecond-time units */
Packit 4a16fb
static double Mf_f_realtime = 0;/* as above, floating */
Packit 4a16fb
static double old_f_realtime = 0;
Packit 4a16fb
int Mf_division = 96;
Packit 4a16fb
unsigned long Mf_currtempo = 500000;
Packit 4a16fb
static unsigned long old_currtempo = 500000;
Packit 4a16fb
static unsigned long old_realtime = 0;
Packit 4a16fb
static unsigned long old_currtime = 0;
Packit 4a16fb
static unsigned long revised_time = 0;
Packit 4a16fb
static unsigned long tempo_change_time = 0;
Packit 4a16fb
Packit 4a16fb
#define MAX_HISTORY 512
Packit 4a16fb
static unsigned long tempo_history[MAX_HISTORY];
Packit 4a16fb
static unsigned long tempo_history_time[MAX_HISTORY];
Packit 4a16fb
static int tempo_history_count = 0;
Packit 4a16fb
Packit 4a16fb
/* private stuff */
Packit 4a16fb
static long Mf_toberead = 0L;
Packit 4a16fb
static long Mf_numbyteswritten = 0L;
Packit 4a16fb
Packit 4a16fb
static long readvarinum ();
Packit 4a16fb
static long read32bit ();
Packit 4a16fb
static long to32bit ();
Packit 4a16fb
static int read16bit ();
Packit 4a16fb
static int to16bit ();
Packit 4a16fb
static char *msg ();
Packit 4a16fb
static void readheader ();
Packit 4a16fb
static int readtrack ();
Packit 4a16fb
static void badbyte ();
Packit 4a16fb
static void metaevent ();
Packit 4a16fb
static void sysex ();
Packit 4a16fb
static void chanmessage ();
Packit 4a16fb
static void msginit ();
Packit 4a16fb
static int msgleng ();
Packit 4a16fb
static void msgadd ();
Packit 4a16fb
static void biggermsg ();
Packit 4a16fb
static int eputc (unsigned char c);
Packit 4a16fb
Packit 4a16fb
double mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo);
Packit 4a16fb
int mf_write_meta_event ();
Packit 4a16fb
void mf_write_tempo ();
Packit 4a16fb
void mf_write_seqnum ();
Packit 4a16fb
void WriteVarLen ();
Packit 4a16fb
Packit 4a16fb
#ifdef READ_MODS
Packit 4a16fb
#include "mp_mod.c"
Packit 4a16fb
static int mod_file_flag = 0;
Packit 4a16fb
#endif /* READ_MODS */
Packit 4a16fb
static int force_exit;
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
mfread ()
Packit 4a16fb
{
Packit 4a16fb
  force_exit = 0;
Packit 4a16fb
  if (Mf_getc == NULLFUNC)
Packit 4a16fb
    mferror ("mfread() called without setting Mf_getc");
Packit 4a16fb
Packit 4a16fb
  readheader ();
Packit 4a16fb
#ifdef READ_MODS
Packit 4a16fb
  if (mod_file_flag)
Packit 4a16fb
    do_module();
Packit 4a16fb
  else
Packit 4a16fb
#endif
Packit 4a16fb
    while (readtrack () && !force_exit)
Packit 4a16fb
      ;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* for backward compatibility with the original lib */
Packit 4a16fb
void
Packit 4a16fb
midifile ()
Packit 4a16fb
{
Packit 4a16fb
  mfread ();
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
int 
Packit 4a16fb
readmt (s)			/* read through the "MThd" or "MTrk" header string */
Packit 4a16fb
     char *s;
Packit 4a16fb
{
Packit 4a16fb
  int n = 0;
Packit 4a16fb
  char *p = s;
Packit 4a16fb
  int c;
Packit 4a16fb
Packit 4a16fb
  while (n++ < 4 && (c = (*Mf_getc) ()) != EOF)
Packit 4a16fb
    {
Packit 4a16fb
      if (c != *p++)
Packit 4a16fb
	{
Packit 4a16fb
	  char buff[32];
Packit 4a16fb
	  if (!c) return(EOF);
Packit 4a16fb
	  if (c == 0x1a) return(EOF);
Packit 4a16fb
	  (void) strcpy (buff, "expecting ");
Packit 4a16fb
	  (void) strcat (buff, s);
Packit 4a16fb
	  mferror (buff);
Packit 4a16fb
	  break;
Packit 4a16fb
	}
Packit 4a16fb
    }
Packit 4a16fb
  return (c);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
int
Packit 4a16fb
egetc ()			/* read a single character and abort on EOF */
Packit 4a16fb
{
Packit 4a16fb
  int c = (*Mf_getc) ();
Packit 4a16fb
Packit 4a16fb
  if (c == EOF) {
Packit 4a16fb
    mferror ("premature EOF");
Packit 4a16fb
    force_exit = 1;
Packit 4a16fb
  }
Packit 4a16fb
  Mf_toberead--;
Packit 4a16fb
  return (c);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
readheader ()			/* read a header chunk */
Packit 4a16fb
{
Packit 4a16fb
  int format, ntrks, division;
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
  Mf_division = 96;
Packit 4a16fb
  Mf_currtempo = 500000;
Packit 4a16fb
  old_currtempo = 500000;
Packit 4a16fb
  tempo_history_count = 0;
Packit 4a16fb
  tempo_history[tempo_history_count] = Mf_currtempo;
Packit 4a16fb
  tempo_history_time[tempo_history_count] = 0;
Packit 4a16fb
Packit 4a16fb
  if (Mf_interactive)
Packit 4a16fb
    {
Packit 4a16fb
      Mf_toberead = 0;
Packit 4a16fb
      format = 0;
Packit 4a16fb
      ntrks = 1;
Packit 4a16fb
      division = 96;
Packit 4a16fb
    }
Packit 4a16fb
  else
Packit 4a16fb
#ifdef READ_MODS
Packit 4a16fb
    if (!strncmp(Mf_file_contents, "MThd", 4))
Packit 4a16fb
#endif
Packit 4a16fb
    {
Packit 4a16fb
      if (readmt ("MThd") == EOF)
Packit 4a16fb
	return;
Packit 4a16fb
Packit 4a16fb
      Mf_toberead = read32bit ();
Packit 4a16fb
      format = read16bit ();
Packit 4a16fb
      ntrks = read16bit ();
Packit 4a16fb
      Mf_division = division = read16bit ();
Packit 4a16fb
    }
Packit 4a16fb
#ifdef READ_MODS
Packit 4a16fb
  else
Packit 4a16fb
    {
Packit 4a16fb
      format = 0;
Packit 4a16fb
      ntrks = 1;
Packit 4a16fb
      division = Mf_division;
Packit 4a16fb
      Mf_toberead = 0;
Packit 4a16fb
      mod_file_flag = 1;
Packit 4a16fb
    }
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
  if (Mf_header)
Packit 4a16fb
    (*Mf_header) (format, ntrks, division);
Packit 4a16fb
Packit 4a16fb
  /* flush any extra stuff, in case the length of header is not 6 */
Packit 4a16fb
  while (Mf_toberead > 0 && !force_exit)
Packit 4a16fb
    (void) egetc ();
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/*#define DEBUG_TIMES*/
Packit 4a16fb
static
Packit 4a16fb
unsigned long
Packit 4a16fb
find_tempo()
Packit 4a16fb
{
Packit 4a16fb
  int i;
Packit 4a16fb
  unsigned long old_tempo = Mf_currtempo;
Packit 4a16fb
  unsigned long new_tempo = Mf_currtempo;
Packit 4a16fb
Packit 4a16fb
  for (i = 0; i <= tempo_history_count; i++) {
Packit 4a16fb
    if (tempo_history_time[i] <= Mf_currtime) old_tempo = tempo_history[i];
Packit 4a16fb
    new_tempo = tempo_history[i];
Packit 4a16fb
    if (tempo_history_time[i] > revised_time) break;
Packit 4a16fb
  }
Packit 4a16fb
  if (i > tempo_history_count || tempo_history_time[i] > Mf_currtime) {
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("[past %lu, old_tempo %lu]\n", tempo_history_time[i], old_tempo);
Packit 4a16fb
#endif
Packit 4a16fb
    revised_time = Mf_currtime;
Packit 4a16fb
    return(old_tempo);
Packit 4a16fb
  }
Packit 4a16fb
  tempo_change_time = revised_time = tempo_history_time[i];
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("[revised_time %lu, new_tempo %lu]\n", revised_time, new_tempo);
Packit 4a16fb
#endif
Packit 4a16fb
  return(new_tempo);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
int 
Packit 4a16fb
readtrack ()			/* read a track chunk */
Packit 4a16fb
{
Packit 4a16fb
  /* This array is indexed by the high half of a status byte.  It's */
Packit 4a16fb
  /* value is either the number of bytes needed (1 or 2) for a channel */
Packit 4a16fb
  /* message, or 0 (meaning it's not  a channel message). */
Packit 4a16fb
  static int chantype[] =
Packit 4a16fb
  {
Packit 4a16fb
    0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 through 0x70 */
Packit 4a16fb
    2, 2, 2, 2, 1, 1, 2, 0	/* 0x80 through 0xf0 */
Packit 4a16fb
  };
Packit 4a16fb
  long lookfor;
Packit 4a16fb
  int c, c1, type;
Packit 4a16fb
  int sysexcontinue = 0;	/* 1 if last message was an unfinished sysex */
Packit 4a16fb
  int running = 0;		/* 1 when running status used */
Packit 4a16fb
  int status = 0;		/* status value (e.g. 0x90==note-on) */
Packit 4a16fb
  int needed;
Packit 4a16fb
Packit 4a16fb
  if (Mf_interactive)
Packit 4a16fb
    {
Packit 4a16fb
      Mf_toberead = MAXINT;
Packit 4a16fb
    }
Packit 4a16fb
  else
Packit 4a16fb
    {
Packit 4a16fb
      if (readmt ("MTrk") == EOF)
Packit 4a16fb
	return (0);
Packit 4a16fb
Packit 4a16fb
      Mf_toberead = read32bit ();
Packit 4a16fb
    }
Packit 4a16fb
  Mf_currtime = Mf_realtime = 0;
Packit 4a16fb
  Mf_f_realtime = old_f_realtime = 0;
Packit 4a16fb
  old_currtime = old_realtime = 0;
Packit 4a16fb
  Mf_currtempo = find_tempo();
Packit 4a16fb
Packit 4a16fb
  if (Mf_trackstart)
Packit 4a16fb
    (*Mf_trackstart) ();
Packit 4a16fb
Packit 4a16fb
  while (!force_exit && (Mf_interactive || Mf_toberead > 0))
Packit 4a16fb
    {
Packit 4a16fb
Packit 4a16fb
      if (Mf_interactive)
Packit 4a16fb
	Mf_currtime += 1;
Packit 4a16fb
      else
Packit 4a16fb
	{
Packit 4a16fb
	  double delta_secs;
Packit 4a16fb
	  unsigned long delta_ticks = readvarinum ();
Packit 4a16fb
	  revised_time = Mf_currtime;
Packit 4a16fb
	  Mf_currtime += delta_ticks;	/* delta time */
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Step through each tempo change from old_currtime up to now,
Packit 4a16fb
 * revising Mf_realtime after each change.
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
	  while (revised_time < Mf_currtime) {
Packit 4a16fb
	    unsigned long save_time = revised_time;
Packit 4a16fb
	    unsigned long save_tempo = Mf_currtempo;
Packit 4a16fb
	    Mf_currtempo = find_tempo();
Packit 4a16fb
Packit 4a16fb
	    if (Mf_currtempo != old_currtempo) {
Packit 4a16fb
	      old_currtempo = Mf_currtempo;
Packit 4a16fb
	      old_realtime = Mf_realtime;
Packit 4a16fb
	      if (revised_time != tempo_change_time) {
Packit 4a16fb
	        old_f_realtime = Mf_f_realtime;
Packit 4a16fb
	        old_currtime = save_time;
Packit 4a16fb
	      }
Packit 4a16fb
	    delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, save_tempo);
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("d(rev %lu - old %lu, div %d, tempo %lu) = %.3f\n",
Packit 4a16fb
revised_time, old_currtime, Mf_division, save_tempo, delta_secs * 1600.0);
Packit 4a16fb
#endif
Packit 4a16fb
	    Mf_f_realtime = old_f_realtime + delta_secs * 1600.0;
Packit 4a16fb
	    Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime);
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("\tt=%lu ticks ( = %lu csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime,
Packit 4a16fb
old_f_realtime, delta_secs * 1600.0);
Packit 4a16fb
#endif
Packit 4a16fb
	      if (revised_time == tempo_change_time) {
Packit 4a16fb
		old_currtime = revised_time;
Packit 4a16fb
	      old_f_realtime = Mf_f_realtime;
Packit 4a16fb
	      }
Packit 4a16fb
	    }
Packit 4a16fb
	    else {
Packit 4a16fb
	    delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, Mf_currtempo);
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("d(rev %lu - old %lu, div %d, tempo %lu) = %.3f\n",
Packit 4a16fb
revised_time, old_currtime, Mf_division, Mf_currtempo, delta_secs * 1600.0);
Packit 4a16fb
#endif
Packit 4a16fb
	    Mf_f_realtime = old_f_realtime + delta_secs * 1600.0;
Packit 4a16fb
	    Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime);
Packit 4a16fb
#ifdef DEBUG_TIMES
Packit 4a16fb
printf("\tt=%lu ticks ( = %lu csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime,
Packit 4a16fb
old_f_realtime, delta_secs * 1600.0);
Packit 4a16fb
#endif
Packit 4a16fb
	    }
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
	  }
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
      c = egetc ();
Packit 4a16fb
Packit 4a16fb
      if (sysexcontinue && c != 0xf7)
Packit 4a16fb
	mferror ("didn't find expected continuation of a sysex");
Packit 4a16fb
Packit 4a16fb
      if ((c & 0x80) == 0)
Packit 4a16fb
	{			/* running status? */
Packit 4a16fb
	  if (status == 0)
Packit 4a16fb
	    mferror ("unexpected running status");
Packit 4a16fb
	  running = 1;
Packit 4a16fb
	}
Packit 4a16fb
      else
Packit 4a16fb
	{
Packit 4a16fb
	  status = c;
Packit 4a16fb
	  running = 0;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
      needed = chantype[(status >> 4) & 0xf];
Packit 4a16fb
Packit 4a16fb
      if (needed)
Packit 4a16fb
	{			/* ie. is it a channel message? */
Packit 4a16fb
Packit 4a16fb
	  if (running)
Packit 4a16fb
	    c1 = c;
Packit 4a16fb
	  else
Packit 4a16fb
	    c1 = egetc ();
Packit 4a16fb
	  chanmessage (status, c1, (needed > 1) ? egetc () : 0);
Packit 4a16fb
	  continue;;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
      switch (c)
Packit 4a16fb
	{
Packit 4a16fb
Packit 4a16fb
	case 0xff:		/* meta event */
Packit 4a16fb
Packit 4a16fb
	  type = egetc ();
Packit 4a16fb
	  lookfor = Mf_toberead - readvarinum ();
Packit 4a16fb
	  msginit ();
Packit 4a16fb
Packit 4a16fb
	  while (Mf_toberead > lookfor)
Packit 4a16fb
	    msgadd (egetc ());
Packit 4a16fb
Packit 4a16fb
	  metaevent (type);
Packit 4a16fb
	  break;
Packit 4a16fb
Packit 4a16fb
	case 0xf0:		/* start of system exclusive */
Packit 4a16fb
Packit 4a16fb
	  lookfor = Mf_toberead - readvarinum ();
Packit 4a16fb
	  msginit ();
Packit 4a16fb
	  msgadd (0xf0);
Packit 4a16fb
Packit 4a16fb
	  while (Mf_toberead > lookfor)
Packit 4a16fb
	    msgadd (c = egetc ());
Packit 4a16fb
Packit 4a16fb
	  if (c == 0xf7 || Mf_nomerge == 0)
Packit 4a16fb
	    sysex ();
Packit 4a16fb
	  else
Packit 4a16fb
	    sysexcontinue = 1;	/* merge into next msg */
Packit 4a16fb
	  break;
Packit 4a16fb
Packit 4a16fb
	case 0xf7:		/* sysex continuation or arbitrary stuff */
Packit 4a16fb
Packit 4a16fb
	  lookfor = Mf_toberead - readvarinum ();
Packit 4a16fb
Packit 4a16fb
	  if (!sysexcontinue)
Packit 4a16fb
	    msginit ();
Packit 4a16fb
Packit 4a16fb
	  while (Mf_toberead > lookfor)
Packit 4a16fb
	    msgadd (c = egetc ());
Packit 4a16fb
Packit 4a16fb
	  if (!sysexcontinue)
Packit 4a16fb
	    {
Packit 4a16fb
	      if (Mf_arbitrary)
Packit 4a16fb
		(*Mf_arbitrary) (msgleng (), msg ());
Packit 4a16fb
	    }
Packit 4a16fb
	  else if (c == 0xf7)
Packit 4a16fb
	    {
Packit 4a16fb
	      sysex ();
Packit 4a16fb
	      sysexcontinue = 0;
Packit 4a16fb
	    }
Packit 4a16fb
	  break;
Packit 4a16fb
	default:
Packit 4a16fb
	  badbyte (c);
Packit 4a16fb
	  break;
Packit 4a16fb
	}
Packit 4a16fb
    }
Packit 4a16fb
  if (Mf_trackend)
Packit 4a16fb
    (*Mf_trackend) ();
Packit 4a16fb
  return (1);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
badbyte (c)
Packit 4a16fb
     int c;
Packit 4a16fb
{
Packit 4a16fb
  char buff[32];
Packit 4a16fb
Packit 4a16fb
  (void) sprintf (buff, "unexpected byte: 0x%02x", c);
Packit 4a16fb
  mferror (buff);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
metaevent (int type)
Packit 4a16fb
{
Packit 4a16fb
  int leng = msgleng ();
Packit 4a16fb
  char *m = msg ();
Packit 4a16fb
Packit 4a16fb
  switch (type)
Packit 4a16fb
    {
Packit 4a16fb
    case 0x00:
Packit 4a16fb
      if (Mf_seqnum)
Packit 4a16fb
	(*Mf_seqnum) (to16bit (m[0], m[1]));
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x01:			/* Text event */
Packit 4a16fb
    case 0x02:			/* Copyright notice */
Packit 4a16fb
    case 0x03:			/* Sequence/Track name */
Packit 4a16fb
    case 0x04:			/* Instrument name */
Packit 4a16fb
    case 0x05:			/* Lyric */
Packit 4a16fb
    case 0x06:			/* Marker */
Packit 4a16fb
    case 0x07:			/* Cue point */
Packit 4a16fb
    case 0x08:
Packit 4a16fb
    case 0x09:
Packit 4a16fb
    case 0x0a:
Packit 4a16fb
    case 0x0b:
Packit 4a16fb
    case 0x0c:
Packit 4a16fb
    case 0x0d:
Packit 4a16fb
    case 0x0e:
Packit 4a16fb
    case 0x0f:
Packit 4a16fb
      /* These are all text events */
Packit 4a16fb
      if (Mf_text)
Packit 4a16fb
	(*Mf_text) (type, leng, m);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x2f:			/* End of Track */
Packit 4a16fb
      if (Mf_eot)
Packit 4a16fb
	(*Mf_eot) ();
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x51:			/* Set tempo */
Packit 4a16fb
      if (Mf_tempo)
Packit 4a16fb
	(*Mf_tempo) (Mf_currtempo = to32bit (0, m[0], m[1], m[2]));
Packit 4a16fb
      if (tempo_history[tempo_history_count] == Mf_currtempo) break;
Packit 4a16fb
      if (tempo_history_time[tempo_history_count] > Mf_currtime) break;
Packit 4a16fb
      if (tempo_history_count < MAX_HISTORY - 1) tempo_history_count++;
Packit 4a16fb
      tempo_history[tempo_history_count] = Mf_currtempo;
Packit 4a16fb
      tempo_history_time[tempo_history_count] = Mf_currtime;
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x54:
Packit 4a16fb
      if (Mf_smpte)
Packit 4a16fb
	(*Mf_smpte) (m[0], m[1], m[2], m[3], m[4]);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x58:
Packit 4a16fb
      if (Mf_timesig)
Packit 4a16fb
	(*Mf_timesig) (m[0], m[1], m[2], m[3]);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x59:
Packit 4a16fb
      if (Mf_keysig)
Packit 4a16fb
	(*Mf_keysig) (m[0], m[1]);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x7f:
Packit 4a16fb
      if (Mf_seqspecific)
Packit 4a16fb
	(*Mf_seqspecific) (leng, m);
Packit 4a16fb
      break;
Packit 4a16fb
    default:
Packit 4a16fb
      if (Mf_metamisc)
Packit 4a16fb
	(*Mf_metamisc) (type, leng, m);
Packit 4a16fb
    }
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
sysex ()
Packit 4a16fb
{
Packit 4a16fb
  if (Mf_sysex)
Packit 4a16fb
    (*Mf_sysex) (msgleng (), msg ());
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
chanmessage (status, c1, c2)
Packit 4a16fb
     int status;
Packit 4a16fb
     int c1, c2;
Packit 4a16fb
{
Packit 4a16fb
  int chan = status & 0xf;
Packit 4a16fb
Packit 4a16fb
  /* I found a midi file with Mod Wheel values 128. --gl */
Packit 4a16fb
Packit 4a16fb
  if (c1 > 127) /*mferror("chanmessage: bad c1") ??*/ return;
Packit 4a16fb
  if (c2 > 127) c2 = 127;
Packit 4a16fb
Packit 4a16fb
  switch (status & 0xf0)
Packit 4a16fb
    {
Packit 4a16fb
    case 0x80:
Packit 4a16fb
      if (Mf_noteoff)
Packit 4a16fb
	(*Mf_noteoff) (chan, c1, c2);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0x90:
Packit 4a16fb
      if (Mf_noteon)
Packit 4a16fb
	(*Mf_noteon) (chan, c1, c2);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0xa0:
Packit 4a16fb
      if (Mf_pressure)
Packit 4a16fb
	(*Mf_pressure) (chan, c1, c2);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0xb0:
Packit 4a16fb
      if (Mf_parameter)
Packit 4a16fb
	(*Mf_parameter) (chan, c1, c2);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0xe0:
Packit 4a16fb
      if (Mf_pitchbend)
Packit 4a16fb
	(*Mf_pitchbend) (chan, c1, c2);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0xc0:
Packit 4a16fb
      if (Mf_program)
Packit 4a16fb
	(*Mf_program) (chan, c1);
Packit 4a16fb
      break;
Packit 4a16fb
    case 0xd0:
Packit 4a16fb
      if (Mf_chanpressure)
Packit 4a16fb
	(*Mf_chanpressure) (chan, c1);
Packit 4a16fb
      break;
Packit 4a16fb
    }
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* readvarinum - read a varying-length number, and return the */
Packit 4a16fb
/* number of characters it took. */
Packit 4a16fb
Packit 4a16fb
static long
Packit 4a16fb
readvarinum ()
Packit 4a16fb
{
Packit 4a16fb
  long value;
Packit 4a16fb
  int c;
Packit 4a16fb
Packit 4a16fb
  c = egetc ();
Packit 4a16fb
  value = c;
Packit 4a16fb
  if (c & 0x80)
Packit 4a16fb
    {
Packit 4a16fb
      value &= 0x7f;
Packit 4a16fb
      do
Packit 4a16fb
	{
Packit 4a16fb
	  c = egetc ();
Packit 4a16fb
	  value = (value << 7) + (c & 0x7f);
Packit 4a16fb
	}
Packit 4a16fb
      while (c & 0x80);
Packit 4a16fb
    }
Packit 4a16fb
  return (value);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static long
Packit 4a16fb
to32bit (int c1, int c2, int c3, int c4)
Packit 4a16fb
{
Packit 4a16fb
  long value = 0L;
Packit 4a16fb
Packit 4a16fb
  value = (c1 & 0xff);
Packit 4a16fb
  value = (value << 8) + (c2 & 0xff);
Packit 4a16fb
  value = (value << 8) + (c3 & 0xff);
Packit 4a16fb
  value = (value << 8) + (c4 & 0xff);
Packit 4a16fb
  return (value);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int
Packit 4a16fb
to16bit (c1, c2)
Packit 4a16fb
     int c1, c2;
Packit 4a16fb
{
Packit 4a16fb
  return ((c1 & 0xff) << 8) + (c2 & 0xff);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static long
Packit 4a16fb
read32bit ()
Packit 4a16fb
{
Packit 4a16fb
  int c1, c2, c3, c4;
Packit 4a16fb
Packit 4a16fb
  c1 = egetc ();
Packit 4a16fb
  c2 = egetc ();
Packit 4a16fb
  c3 = egetc ();
Packit 4a16fb
  c4 = egetc ();
Packit 4a16fb
  return to32bit (c1, c2, c3, c4);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int
Packit 4a16fb
read16bit ()
Packit 4a16fb
{
Packit 4a16fb
  int c1, c2;
Packit 4a16fb
  c1 = egetc ();
Packit 4a16fb
  c2 = egetc ();
Packit 4a16fb
  return to16bit (c1, c2);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* static */
Packit 4a16fb
void
Packit 4a16fb
mferror (s)
Packit 4a16fb
     char *s;
Packit 4a16fb
{
Packit 4a16fb
  if (Mf_error)
Packit 4a16fb
    (*Mf_error) (s);
Packit 4a16fb
  else exit (1);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* The code below allows collection of a system exclusive message of */
Packit 4a16fb
/* arbitrary length.  The Msgbuff is expanded as necessary.  The only */
Packit 4a16fb
/* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */
Packit 4a16fb
Packit 4a16fb
#define MSGINCREMENT 128
Packit 4a16fb
static char *Msgbuff = NULL;	/* message buffer */
Packit 4a16fb
static int Msgsize = 0;		/* Size of currently allocated Msg */
Packit 4a16fb
static int Msgindex = 0;	/* index of next available location in Msg */
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
msginit ()
Packit 4a16fb
{
Packit 4a16fb
  Msgindex = 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static char *
Packit 4a16fb
msg ()
Packit 4a16fb
{
Packit 4a16fb
  return (Msgbuff);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
int 
Packit 4a16fb
msgleng ()
Packit 4a16fb
{
Packit 4a16fb
  return (Msgindex);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
msgadd (c)
Packit 4a16fb
     int c;
Packit 4a16fb
{
Packit 4a16fb
  /* If necessary, allocate larger message buffer. */
Packit 4a16fb
  if (Msgindex >= Msgsize)
Packit 4a16fb
    biggermsg ();
Packit 4a16fb
  Msgbuff[Msgindex++] = c;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static
Packit 4a16fb
void 
Packit 4a16fb
biggermsg ()
Packit 4a16fb
{
Packit 4a16fb
/* 	char *malloc(); */
Packit 4a16fb
  char *newmess;
Packit 4a16fb
  char *oldmess = Msgbuff;
Packit 4a16fb
  int oldleng = Msgsize;
Packit 4a16fb
Packit 4a16fb
  Msgsize += MSGINCREMENT;
Packit 4a16fb
  newmess = (char *) malloc ((unsigned) (sizeof (char) * Msgsize));
Packit 4a16fb
Packit 4a16fb
  if (newmess == NULL)
Packit 4a16fb
    mferror ("malloc error!");
Packit 4a16fb
Packit 4a16fb
  /* copy old message into larger new one */
Packit 4a16fb
  if (oldmess != NULL)
Packit 4a16fb
    {
Packit 4a16fb
      register char *p = newmess;
Packit 4a16fb
      register char *q = oldmess;
Packit 4a16fb
      register char *endq = &oldmess[oldleng];
Packit 4a16fb
Packit 4a16fb
      for (; q != endq; p++, q++)
Packit 4a16fb
	*p = *q;
Packit 4a16fb
      free (oldmess);
Packit 4a16fb
    }
Packit 4a16fb
  Msgbuff = newmess;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int laststatus = 0;
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * mfwrite() - The only function you'll need to call to write out
Packit 4a16fb
 *             a midi file.
Packit 4a16fb
 *
Packit 4a16fb
 * format      0 - Single multi-channel track
Packit 4a16fb
 *             1 - Multiple simultaneous tracks
Packit 4a16fb
 *             2 - One or more sequentially independent
Packit 4a16fb
 *                 single track patterns
Packit 4a16fb
 * ntracks     The number of tracks in the file.
Packit 4a16fb
 * division    This is kind of tricky, it can represent two
Packit 4a16fb
 *             things, depending on whether it is positive or negative
Packit 4a16fb
 *             (bit 15 set or not).  If  bit  15  of division  is zero,
Packit 4a16fb
 *             bits 14 through 0 represent the number of delta-time
Packit 4a16fb
 *             "ticks" which make up a quarter note.  If bit  15 of
Packit 4a16fb
 *             division  is  a one, delta-times in a file correspond to
Packit 4a16fb
 *             subdivisions of a second similar to  SMPTE  and  MIDI
Packit 4a16fb
 *             time code.  In  this format bits 14 through 8 contain
Packit 4a16fb
 *             one of four values - 24, -25, -29, or -30,
Packit 4a16fb
 *             corresponding  to  the  four standard  SMPTE and MIDI
Packit 4a16fb
 *             time code frame per second formats, where  -29
Packit 4a16fb
 *             represents  30  drop  frame.   The  second  byte
Packit 4a16fb
 *             consisting  of  bits 7 through 0 corresponds the the
Packit 4a16fb
 *             resolution within a frame.  Refer the Standard MIDI
Packit 4a16fb
 *             Files 1.0 spec for more details.
Packit 4a16fb
 * fp          This should be the open file pointer to the file you
Packit 4a16fb
 *             want to write.  It will have be a global in order
Packit 4a16fb
 *             to work with Mf_putc.
Packit 4a16fb
 */
Packit 4a16fb
void
Packit 4a16fb
mfwrite (format, ntracks, division, fp)
Packit 4a16fb
     int format, ntracks, division;
Packit 4a16fb
     FILE *fp;
Packit 4a16fb
{
Packit 4a16fb
  int i;
Packit 4a16fb
  void mf_write_track_chunk (), mf_write_header_chunk ();
Packit 4a16fb
Packit 4a16fb
  if (Mf_putc == NULLFUNC)
Packit 4a16fb
    mferror ("mfmf_write() called without setting Mf_putc");
Packit 4a16fb
Packit 4a16fb
  if (Mf_writetrack == NULLFUNC)
Packit 4a16fb
    mferror ("mfmf_write() called without setting Mf_mf_writetrack");
Packit 4a16fb
Packit 4a16fb
  laststatus = 0;
Packit 4a16fb
Packit 4a16fb
  /* every MIDI file starts with a header */
Packit 4a16fb
  mf_write_header_chunk (format, ntracks, division);
Packit 4a16fb
Packit 4a16fb
  laststatus = 0;
Packit 4a16fb
Packit 4a16fb
  /* In format 1 files, the first track is a tempo map */
Packit 4a16fb
  if (format == 1 && (Mf_writetempotrack))
Packit 4a16fb
    {
Packit 4a16fb
      (*Mf_writetempotrack) ();
Packit 4a16fb
    }
Packit 4a16fb
Packit 4a16fb
  /* The rest of the file is a series of tracks */
Packit 4a16fb
  for (i = 0; i < ntracks; i++)
Packit 4a16fb
    mf_write_track_chunk (i, fp);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
mf_write_track_chunk (which_track, fp)
Packit 4a16fb
     int which_track;
Packit 4a16fb
     FILE *fp;
Packit 4a16fb
{
Packit 4a16fb
  unsigned long trkhdr, trklength;
Packit 4a16fb
  long offset, place_marker;
Packit 4a16fb
  void write16bit (), write32bit ();
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
  laststatus = 0;
Packit 4a16fb
Packit 4a16fb
  trkhdr = MTrk;
Packit 4a16fb
  trklength = 0;
Packit 4a16fb
Packit 4a16fb
  /* Remember where the length was written, because we don't
Packit 4a16fb
	   know how long it will be until we've finished writing */
Packit 4a16fb
  offset = ftell (fp);
Packit 4a16fb
Packit 4a16fb
#ifdef DEBUG
Packit 4a16fb
  printf ("offset = %d\n", (int) offset);
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
  /* Write the track chunk header */
Packit 4a16fb
  write32bit (trkhdr);
Packit 4a16fb
  write32bit (trklength);
Packit 4a16fb
Packit 4a16fb
  Mf_numbyteswritten = 0L;	/* the header's length doesn't count */
Packit 4a16fb
Packit 4a16fb
  if (Mf_writetrack)
Packit 4a16fb
    {
Packit 4a16fb
      (*Mf_writetrack) (which_track);
Packit 4a16fb
    }
Packit 4a16fb
Packit 4a16fb
  /* mf_write End of track meta event */
Packit 4a16fb
/* but this does not necessarily have a delta of 0, so
Packit 4a16fb
 * I don't want to do it -- leave it up to the user of the
Packit 4a16fb
 * library functions to do
Packit 4a16fb
 *	--gl
Packit 4a16fb
	eputc(0);
Packit 4a16fb
	eputc(laststatus = meta_event);
Packit 4a16fb
	eputc(end_of_track);
Packit 4a16fb
Packit 4a16fb
 	eputc(0);
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
  /* It's impossible to know how long the track chunk will be beforehand,
Packit 4a16fb
           so the position of the track length data is kept so that it can
Packit 4a16fb
           be written after the chunk has been generated */
Packit 4a16fb
  place_marker = ftell (fp);
Packit 4a16fb
Packit 4a16fb
  /* This method turned out not to be portable because the
Packit 4a16fb
           parameter returned from ftell is not guaranteed to be
Packit 4a16fb
           in bytes on every machine */
Packit 4a16fb
  /* track.length = place_marker - offset - (long) sizeof(track); */
Packit 4a16fb
Packit 4a16fb
#ifdef DEBUG
Packit 4a16fb
  printf ("length = %d\n", (int) trklength);
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
  if (fseek (fp, offset, 0) < 0)
Packit 4a16fb
    mferror ("error seeking during final stage of write");
Packit 4a16fb
Packit 4a16fb
  trklength = Mf_numbyteswritten;
Packit 4a16fb
Packit 4a16fb
  /* Re-mf_write the track chunk header with right length */
Packit 4a16fb
  write32bit (trkhdr);
Packit 4a16fb
  write32bit (trklength);
Packit 4a16fb
Packit 4a16fb
  fseek (fp, place_marker, 0);
Packit 4a16fb
}				/* End gen_track_chunk() */
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
mf_write_header_chunk (format, ntracks, division)
Packit 4a16fb
     int format, ntracks, division;
Packit 4a16fb
{
Packit 4a16fb
  unsigned long ident, length;
Packit 4a16fb
  void write16bit (), write32bit ();
Packit 4a16fb
Packit 4a16fb
  ident = MThd;			/* Head chunk identifier                    */
Packit 4a16fb
  length = 6;			/* Chunk length                             */
Packit 4a16fb
Packit 4a16fb
  /* individual bytes of the header must be written separately
Packit 4a16fb
       to preserve byte order across cpu types :-( */
Packit 4a16fb
  write32bit (ident);
Packit 4a16fb
  write32bit (length);
Packit 4a16fb
  write16bit (format);
Packit 4a16fb
  write16bit (ntracks);
Packit 4a16fb
  write16bit (division);
Packit 4a16fb
}				/* end gen_header_chunk() */
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * mf_write_midi_event()
Packit 4a16fb
 *
Packit 4a16fb
 * Library routine to mf_write a single MIDI track event in the standard MIDI
Packit 4a16fb
 * file format. The format is:
Packit 4a16fb
 *
Packit 4a16fb
 *                    <delta-time><event>
Packit 4a16fb
 *
Packit 4a16fb
 * In this case, event can be any multi-byte midi message, such as
Packit 4a16fb
 * "note on", "note off", etc.
Packit 4a16fb
 *
Packit 4a16fb
 * delta_time - the time in ticks since the last event.
Packit 4a16fb
 * type - the type of meta event.
Packit 4a16fb
 * chan - The midi channel.
Packit 4a16fb
 * data - A pointer to a block of chars containing the META EVENT,
Packit 4a16fb
 *        data.
Packit 4a16fb
 * size - The length of the meta-event data.
Packit 4a16fb
 */
Packit 4a16fb
int
Packit 4a16fb
mf_write_midi_event (delta_time, type, chan, data, size)
Packit 4a16fb
     unsigned long delta_time;
Packit 4a16fb
     int chan, type;
Packit 4a16fb
     unsigned long size;
Packit 4a16fb
     char *data;
Packit 4a16fb
{
Packit 4a16fb
  int i;
Packit 4a16fb
  unsigned char c;
Packit 4a16fb
Packit 4a16fb
  WriteVarLen (delta_time);
Packit 4a16fb
Packit 4a16fb
  /* all MIDI events start with the type in the first four bits,
Packit 4a16fb
       and the channel in the lower four bits */
Packit 4a16fb
  if (type == system_exclusive || type == 0xf7)
Packit 4a16fb
    {
Packit 4a16fb
      c = type;
Packit 4a16fb
      laststatus = 0;
Packit 4a16fb
    }
Packit 4a16fb
  else
Packit 4a16fb
    c = type | chan;
Packit 4a16fb
Packit 4a16fb
  if (chan > 15)
Packit 4a16fb
    perror ("error: MIDI channel greater than 16\n");
Packit 4a16fb
Packit 4a16fb
  if (laststatus != c)
Packit 4a16fb
    eputc (laststatus = c);
Packit 4a16fb
Packit 4a16fb
  if (type == system_exclusive || type == 0xf7)
Packit 4a16fb
    WriteVarLen (size);
Packit 4a16fb
Packit 4a16fb
  /* write out the data bytes */
Packit 4a16fb
  for (i = 0; i < (int)size; i++)
Packit 4a16fb
    eputc (data[i]);
Packit 4a16fb
Packit 4a16fb
  return (size);
Packit 4a16fb
}				/* end mf_write MIDI event */
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * mf_write_meta_event()
Packit 4a16fb
 *
Packit 4a16fb
 * Library routine to mf_write a single meta event in the standard MIDI
Packit 4a16fb
 * file format. The format of a meta event is:
Packit 4a16fb
 *
Packit 4a16fb
 *          <delta-time><FF><type><length><bytes>
Packit 4a16fb
 *
Packit 4a16fb
 * delta_time - the time in ticks since the last event.
Packit 4a16fb
 * type - the type of meta event.
Packit 4a16fb
 * data - A pointer to a block of chars containing the META EVENT,
Packit 4a16fb
 *        data.
Packit 4a16fb
 * size - The length of the meta-event data.
Packit 4a16fb
 */
Packit 4a16fb
int 
Packit 4a16fb
mf_write_meta_event (delta_time, type, data, size)
Packit 4a16fb
     unsigned long delta_time;
Packit 4a16fb
     unsigned char *data, type;
Packit 4a16fb
     unsigned long size;
Packit 4a16fb
{
Packit 4a16fb
  int i;
Packit 4a16fb
Packit 4a16fb
  WriteVarLen (delta_time);
Packit 4a16fb
Packit 4a16fb
  /* This marks the fact we're writing a meta-event */
Packit 4a16fb
  eputc (laststatus = meta_event);
Packit 4a16fb
Packit 4a16fb
  /* The type of meta event */
Packit 4a16fb
  eputc (type);
Packit 4a16fb
Packit 4a16fb
  /* The length of the data bytes to follow */
Packit 4a16fb
  WriteVarLen (size);
Packit 4a16fb
Packit 4a16fb
  for (i = 0; i < (int)size; i++)
Packit 4a16fb
    {
Packit 4a16fb
      if (eputc (data[i]) != data[i])
Packit 4a16fb
	return (-1);
Packit 4a16fb
    }
Packit 4a16fb
  return (size);
Packit 4a16fb
}				/* end mf_write_meta_event */
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
mf_write_tempo (delta_time, tempo)
Packit 4a16fb
     unsigned long delta_time;
Packit 4a16fb
     unsigned long tempo;
Packit 4a16fb
{
Packit 4a16fb
  /* Write tempo */
Packit 4a16fb
  /* all tempos are written as 120 beats/minute, */
Packit 4a16fb
  /* expressed in microseconds/quarter note     */
Packit 4a16fb
Packit 4a16fb
  WriteVarLen (delta_time);
Packit 4a16fb
  eputc (laststatus = meta_event);
Packit 4a16fb
  eputc (set_tempo);
Packit 4a16fb
Packit 4a16fb
  eputc (3);
Packit 4a16fb
  eputc ((unsigned) (0xff & (tempo >> 16)));
Packit 4a16fb
  eputc ((unsigned) (0xff & (tempo >> 8)));
Packit 4a16fb
  eputc ((unsigned) (0xff & tempo));
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
mf_write_seqnum (delta_time, seqnum)
Packit 4a16fb
     unsigned long delta_time;
Packit 4a16fb
     unsigned seqnum;
Packit 4a16fb
{
Packit 4a16fb
Packit 4a16fb
  WriteVarLen (delta_time);
Packit 4a16fb
  eputc (laststatus = meta_event);
Packit 4a16fb
  eputc (0);
Packit 4a16fb
Packit 4a16fb
  eputc ((unsigned) (0xff & (seqnum >> 8)));
Packit 4a16fb
  eputc ((unsigned) (0xff & seqnum));
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
unsigned long
Packit 4a16fb
mf_sec2ticks (secs, division, tempo)
Packit 4a16fb
     int division;
Packit 4a16fb
     unsigned long tempo;
Packit 4a16fb
     double secs;
Packit 4a16fb
{
Packit 4a16fb
  return (unsigned long) (((secs * 1000.0) / 4.0 * division) / tempo);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Write multi-length bytes to MIDI format files
Packit 4a16fb
 */
Packit 4a16fb
void
Packit 4a16fb
WriteVarLen (value)
Packit 4a16fb
     unsigned long value;
Packit 4a16fb
{
Packit 4a16fb
  unsigned long buffer;
Packit 4a16fb
Packit 4a16fb
  buffer = value & 0x7f;
Packit 4a16fb
  while ((value >>= 7) > 0)
Packit 4a16fb
    {
Packit 4a16fb
      buffer <<= 8;
Packit 4a16fb
      buffer |= 0x80;
Packit 4a16fb
      buffer += (value & 0x7f);
Packit 4a16fb
    }
Packit 4a16fb
  while (1)
Packit 4a16fb
    {
Packit 4a16fb
      eputc ((unsigned) (buffer & 0xff));
Packit 4a16fb
Packit 4a16fb
      if (buffer & 0x80)
Packit 4a16fb
	buffer >>= 8;
Packit 4a16fb
      else
Packit 4a16fb
	return;
Packit 4a16fb
    }
Packit 4a16fb
}				/* end of WriteVarLen */
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * This routine converts delta times in ticks into seconds. The
Packit 4a16fb
 * else statement is needed because the formula is different for tracks
Packit 4a16fb
 * based on notes and tracks based on SMPTE times.
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
double
Packit 4a16fb
mf_ticks2sec (ticks, division, tempo)
Packit 4a16fb
     int division;
Packit 4a16fb
     unsigned long tempo;
Packit 4a16fb
     unsigned long ticks;
Packit 4a16fb
{
Packit 4a16fb
  double smpte_format, smpte_resolution;
Packit 4a16fb
Packit 4a16fb
  if (division > 0)
Packit 4a16fb
    return ((double) (((double) (ticks) * (double) (tempo)) / ((double) (division) * 1000000.0)));
Packit 4a16fb
  else
Packit 4a16fb
    {
Packit 4a16fb
      smpte_format = upperbyte (division);
Packit 4a16fb
      smpte_resolution = lowerbyte (division);
Packit 4a16fb
      return (double) ((double) ticks / (smpte_format * smpte_resolution * 1000000.0));
Packit 4a16fb
    }
Packit 4a16fb
}				/* end of ticks2sec() */
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * write32bit()
Packit 4a16fb
 * write16bit()
Packit 4a16fb
 *
Packit 4a16fb
 * These routines are used to make sure that the byte order of
Packit 4a16fb
 * the various data types remains constant between machines. This
Packit 4a16fb
 * helps make sure that the code will be portable from one system
Packit 4a16fb
 * to the next.  It is slightly dangerous that it assumes that longs
Packit 4a16fb
 * have at least 32 bits and ints have at least 16 bits, but this
Packit 4a16fb
 * has been true at least on PCs, UNIX machines, and Macintosh's.
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
void
Packit 4a16fb
write32bit (data)
Packit 4a16fb
     unsigned long data;
Packit 4a16fb
{
Packit 4a16fb
  eputc ((unsigned) ((data >> 24) & 0xff));
Packit 4a16fb
  eputc ((unsigned) ((data >> 16) & 0xff));
Packit 4a16fb
  eputc ((unsigned) ((data >> 8) & 0xff));
Packit 4a16fb
  eputc ((unsigned) (data & 0xff));
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void
Packit 4a16fb
write16bit (data)
Packit 4a16fb
     int data;
Packit 4a16fb
{
Packit 4a16fb
  eputc ((unsigned) ((data & 0xff00) >> 8));
Packit 4a16fb
  eputc ((unsigned) (data & 0xff));
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* write a single character and abort on error */
Packit 4a16fb
static int
Packit 4a16fb
eputc (c)
Packit 4a16fb
     unsigned char c;
Packit 4a16fb
{
Packit 4a16fb
  int return_val;
Packit 4a16fb
Packit 4a16fb
  if ((Mf_putc) == NULLFUNC)
Packit 4a16fb
    {
Packit 4a16fb
      mferror ("Mf_putc undefined");
Packit 4a16fb
      return (-1);
Packit 4a16fb
    }
Packit 4a16fb
Packit 4a16fb
  return_val = (*Mf_putc) (c);
Packit 4a16fb
Packit 4a16fb
  if (return_val == EOF)
Packit 4a16fb
    mferror ("error writing");
Packit 4a16fb
Packit 4a16fb
  Mf_numbyteswritten++;
Packit 4a16fb
  return (return_val);
Packit 4a16fb
}