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