Blame test/midifile.c

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