home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / midifile / part01 next >
Internet Message Format  |  1991-02-18  |  35KB

  1. From: arensb@alv.umd.edu (Andrew Arensburger)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i002:  midifile - A MIDI file parser, Part01/01
  4. Message-ID: <1991Feb18.225411.5540@sparky.IMD.Sterling.COM>
  5. Date: 18 Feb 91 22:54:11 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 0b871ef3 2004531f f537b92b d9dbacef
  8.  
  9. Submitted-by: Andrew Arensburger <arensb@alv.umd.edu>
  10. Posting-number: Volume 17, Issue 2
  11. Archive-name: midifile/part01
  12.  
  13. This is 'midifile()', a parser for MIDI files. This is functionally
  14. identical to the 'midifile()' written by Tim Thompson, and recently posted
  15. to the net. I wasn't quite satisfied with his implementation, so I rewrote it.
  16.  
  17. midifile() reads in a MIDI format file, and calls user-defined routines each 
  18. time it encounters an event. You can ignore any events you're not interested 
  19. in, and concentrate on the ones you want. In fact, you can even ignore the 
  20. tracks you're not interested in.
  21.  
  22. Why should you use my version? This midifile() deals less traumatically with 
  23. errors: by default, it returns an error code to the calling routine, instead 
  24. of exit()ing the program (so you can do that with the original, too. Big deal). 
  25. Also, this version allows you to return an error code if and when you do 
  26. interrupt the routine's execution.  I've added a new variable: Mf_deltatime, 
  27. which gives the time elapsed since the previous event.  A complete and (hopefully)
  28. accurate man page is also supplied.
  29.  
  30. Why should you use the original version (Classic midifile())? Because you have 
  31. system-exclusive events in your MIDI file. I haven't implemented these, but will 
  32. do so in the next version, scheduled to come out RSN.
  33.  
  34. Andrew Arensburger
  35. arensb@cvl.umd.edu
  36.  
  37. ----- CUT HERE -------------------------------------------------------
  38. : Run this shell script with "sh" not "csh"
  39. PATH=:/bin:/usr/bin:/usr/ucb
  40. export PATH
  41. all=FALSE
  42. if [ x$1 = x-a ]; then
  43.     all=TRUE
  44. fi
  45. /bin/echo 'Making directory "midifile"'
  46. mkdir midifile
  47. /bin/echo 'Extracting midifile/Makefile'
  48. sed 's/^X//' <<'//go.sysin dd *' >midifile/Makefile
  49. # Makefile for 'midifile()'. It's pretty trivial, really.
  50.  
  51. all:    midifile
  52.  
  53. midifile:    mf.c mf.h
  54.     cc -c mf.c
  55. //go.sysin dd *
  56. if [ `wc -c < midifile/Makefile` != 106 ]; then
  57.     made=FALSE
  58.     /bin/echo 'error transmitting "midifile/Makefile" --'
  59.     /bin/echo 'length should be 106, not' `wc -c < midifile/Makefile`
  60. else
  61.     made=TRUE
  62. fi
  63. if [ $made = TRUE ]; then
  64.     /bin/chmod 664 midifile/Makefile
  65.     /bin/echo -n '    '; /bin/ls -ld midifile/Makefile
  66. fi
  67. /bin/echo 'Extracting midifile/mf.c'
  68. sed 's/^X//' <<'//go.sysin dd *' >midifile/mf.c
  69. X/* MF.C v.1.2
  70.  * A MIDI file analyzer. The routine 'midifile()' reads in a MIDI file,
  71.  * calling external routines as it goes along, processing it. 'midifile()'
  72.  * returns 0 if all went well, and an error code otherwise.
  73.  *    This program is based on Tim Thompson's 'midifile()'. I rewrote
  74.  * it because I didn't like the way he did it. This one should be 100%
  75.  * compatible with his.
  76.  *    The differences between this 'midifile()' and Thompson's are as
  77.  * follows: this one does not 'exit()' from the program as soon as it finds
  78.  * an error. Instead, it causes the main routine, 'midifile()' to return
  79.  * a negative error code.
  80.  *    In addition to 'Mf_currtime', which gives the time elapsed since
  81.  * the beginning of the track, I have added another variable: 'Mf_deltatime',
  82.  * which gives the time elapsed since the last event. This is because the
  83.  * MPU-401 requires delta-times, and not absolute times.
  84.  *
  85.  * IMPLEMENTATION NOTES:
  86.  * About 'bailout()': this macro calls the user-defined error routine,
  87.  * passing it an error message.
  88.  *    a) DO NOT PUT A SEMICOLON AFTER IT, i.e.
  89.  *        bailout(MFE_EOF)
  90.  *    b) It should be called as soon as the error is detected, and
  91.  * not at lower levels, otherwise, the error routine will be called
  92.  * several times for the same error. A routine is expected to return
  93.  * a negative value in case of error, so test for that first.
  94.  */
  95.  
  96. #include <stdio.h>
  97. #include "mf.h"
  98.  
  99. extern char *malloc();
  100.  
  101. typedef unsigned char uchar;
  102. typedef unsigned long ulong;
  103. typedef unsigned short ushort;
  104.  
  105. long Mf_currtime;    /* Current time */
  106. long Mf_deltatime;    /* Time since last event */
  107. int eot_called;        /* Flag: has 'Mf_eot()' been called? */
  108.  
  109. X/* NUM_PARAMS
  110.  * Returns the number of parameters for a given status byte, or -1 for
  111.  * SysEx and meta-messages, which have a variable number of arguments.
  112.  */
  113. static int num_params(stat)
  114. uchar stat;
  115. {
  116.     if (stat >= MIDI_SYSEX)
  117.         return(-1);    /* SysEx or meta */
  118.     if (stat < MIDI_PROGRAM || stat >= MIDI_PITCHB)
  119.         return(2);
  120.     else
  121.         return(1);
  122. }
  123.  
  124. X/* READ_LONG
  125.  * Reads a 32-bit unsigned number and returns it. MSB first.
  126.  * Returns an error code upon error.
  127.  */
  128. static long read_long()
  129. {
  130.     ulong retval;
  131.     int i;
  132.     int c;
  133.  
  134.     retval = 0L;            /* Set 'retval to 0 initially */
  135.     for (i = 0; i < 4; i++)        /* Read in 4 bytes into 'retval' */
  136.     {
  137.         if ((c = (*Mf_getc)()) == -1)
  138.             bailout(MFE_EOF)
  139.         else {
  140.             retval <<= 8;
  141.             retval |= (uchar) c;
  142.         }
  143.     }
  144.  
  145.     return(retval);            /* All went well */
  146. }
  147.  
  148. X/* READ_SHORT
  149.  * Reads a 16-bit number, MSB first, and returns it.
  150.  * Returns an error code upon error.
  151.  */
  152. static short read_short()
  153. {
  154.     ushort retval;
  155.     int i;
  156.     int c;
  157.  
  158.     retval = 0x00;            /* Set 'retval to 0 initially */
  159.     for (i = 0; i < 2; i++)        /* Read in 2 bytes into 'retval' */
  160.     {
  161.         if ((c = (*Mf_getc)()) == -1)
  162.             bailout(MFE_EOF)
  163.         else {
  164.             retval <<= 8;
  165.             retval |= (uchar) c;
  166.         }
  167.     }
  168.  
  169.     return(retval);            /* All went well */
  170. }
  171.  
  172. X/* STOL
  173.  * Converts a string of 'len' bytes, MSB first, into a long int. This is
  174.  * not to be confused with 'atoi()': 'atoi()' converts "abcdef12" into
  175.  * '0xabcdef12L', whereas 'stol()' converts '0xab,0xcd,0xef,0x12' into
  176.  * '0xabcdef12L'.
  177.  */
  178. ulong stol(str,len)
  179. uchar *str;
  180. int len;
  181. {
  182.     int i;
  183.     long retval;
  184.  
  185.     retval = 0L;
  186.     for (i = 0; i < len; i++)
  187.     {
  188.         retval <<= 8;
  189.         retval |= str[i];
  190.     }
  191.  
  192.     return(retval);
  193. }
  194.  
  195. X/* READ_VARLEN
  196.  * Reads a variable-length number, and returns it.
  197.  * Returns an error code upon error.
  198.  * This routine is copied almost verbatim from the MIDI 0.6 file specs.
  199.  */
  200. static long read_varlen(toberead)
  201. long *toberead;
  202. {
  203.     long value;
  204.     int c;
  205.  
  206.     if ((value = (*Mf_getc)()) < 0)
  207.         bailout(value)        /* Return error code */
  208.     else {
  209.         if (--*toberead < 0)
  210.             bailout(MFE_EOF);    /* Error: number expected */
  211.  
  212.         if (value & 0x80)
  213.         {
  214.             value &= 0x7f;
  215.             do
  216.             {
  217.                 if ((c = (*Mf_getc)()) < 0)
  218.                     bailout(c)    /* Return error code */
  219.                 else
  220.                     if (--*toberead < 0)
  221.                         bailout(MFE_EOF);
  222.                 value = (value << 7) + (c & 0x7f);
  223.             } while (c & 0x80);
  224.         }
  225.     }
  226.  
  227.     return(value);
  228. }
  229.  
  230. X/* READ_HEADER
  231.  * Reads in the header from the input file, using the function 'Mf_getc()'.
  232.  * Returns the number of tracks in the file if all goes well, or an error
  233.  * code otherwise (including if the user disapproves).
  234.  */
  235. static int read_header()
  236. {
  237.     int i;
  238.     static char kw_buff[4];    /* Buffer for input keyword "MThd" */
  239.     long header_len;    /* Header length */
  240.     short format;        /* File format */
  241.     short ntrks;        /* Number of tracks in the file */
  242.     short division;        /* Quarter-note division */
  243.     int retval = 0;
  244.  
  245.     /* Read in the first four characters into 'kw_buff' */
  246.     for (i = 0; i < 4; i++)
  247.     {
  248.         int c;        /* Input character */
  249.  
  250.         if ((c = (*Mf_getc)()) == -1)
  251.             bailout(MFE_EOF)
  252.         else
  253.             kw_buff[i] = (char) c;
  254.     }
  255.  
  256.     /* See if 'kw_buff' contains "MThd" */
  257.     if (strncmp(kw_buff,"MThd",4) != 0)
  258.         bailout(MFE_HKWEXP)
  259.  
  260.     /* Read the number 6 (header length) from the header */
  261.     if ((header_len = read_long()) < 0)
  262.         return(header_len);        /* Return error code */
  263.     else if (header_len != 6L)
  264.         bailout(MFE_ILLHLEN)        /* Incorrect header length */
  265.  
  266.     /* Read the file format, number of tracks, and quarter-note division */
  267.     if ((format = read_short()) < 0)
  268.         bailout(format)
  269.     if (format > 2)            /* Illegal file format */
  270.         bailout(MFE_ILLFORM)
  271.     if ((ntrks = read_short()) < 0)
  272.         return(ntrks);        /* Return error code */
  273.     if ((division = read_short()) < 0)
  274.         return(division);    /* Return error code */
  275.  
  276.     /* Pass on the header info to the user */
  277.     if (Mf_header == NULL ||
  278.         (retval = (*Mf_header)(format,ntrks,division)) >= 0)
  279.         return(ntrks);
  280.     else
  281.         return(retval);        /* User already knows about error */
  282. }
  283.  
  284. X/* READ_SYSEX
  285.  * Read a system-exclusive/meta message, and pass it on to the user.
  286.  * Warning: the buffer in which the SysEx data is stored will be reclaimed,
  287.  * so the user is responsible for storing it if it is needed.
  288.  * BTW, I'm doing some funky stuff with 'Mf_deltatime', so read the
  289.  * comments at the beginning of 'read_event()'.
  290.  */
  291. static int read_sysex(stat,toberead)
  292. uchar stat;            /* Type of SysEx message */
  293. long *toberead;            /* # bytes remaining to be read in track */
  294. {
  295.     char *data;        /* Where the data is kept */
  296.     long length;        /* Length of message */
  297.     long i;
  298.  
  299.     if (stat == 0xff)    /* Meta message */
  300.     {
  301.         int msg_type;    /* Type of meta-event */
  302.  
  303.         /* Read type of meta-event */
  304.         if ((msg_type = (*Mf_getc)()) < 0 ||
  305.             --*toberead < 0)
  306.             bailout(MFE_EOF)    /* Event type expected */
  307.  
  308.         /* Read length of meta-event */
  309.         if ((length = read_varlen(toberead)) < 0)
  310.             return((int) length);
  311.  
  312.         /* Allocate memory for meta-event */
  313.         if (length != 0L &&
  314.             (data = malloc((unsigned) length)) == NULL)
  315.             bailout(MFE_MEM)
  316.         else if (length == 0L)
  317.             data = NULL;
  318.  
  319.         /* Read in the meta-event */
  320.         for (i = 0; i < length; i++)
  321.         {
  322.             int c;        /* Input character */
  323.  
  324.             if ((c = (*Mf_getc)()) < 0 ||
  325.                 --*toberead < 0)
  326.             {
  327.                 free(data);    /* Free up the memory */
  328.                 bailout(MFE_EOF)
  329.             }
  330.             data[i] = (char) c;
  331.         }
  332.  
  333.         /* Take action according to the type of meta-event.
  334.          * In particular, make sure that the length of the
  335.          * meta-event is correct (where applicable).
  336.          */
  337.         switch(msg_type) {
  338.             case META_SEQNUM:    /* Sequence number */
  339.                 {
  340.                     short seqnum;
  341.                     int retval;
  342.  
  343.                     if (length != 2)    /* Check length */
  344.                         bailout(MFE_ILLMLEN)
  345.  
  346.                     seqnum = ((short) data[0] << 8) |
  347.                           data[1];
  348.                     if (Mf_seqnum != NULL &&
  349.                         (retval = (*Mf_seqnum)(seqnum),
  350.                         Mf_deltatime = 0L,
  351.                         retval) < 0)
  352.                     {
  353.                         free(data);
  354.                         return(retval);
  355.                     }
  356.  
  357.                     break;
  358.                 }
  359.  
  360.             case META_TEXT:        /* Text event */
  361.             case META_COPYRIGHT:    /* Copyright notice */
  362.             case META_SEQNAME:    /* Sequence name */
  363.             case META_INSTNAME:    /* Instrument name */
  364.             case META_LYRIC:    /* Lyric */
  365.             case META_MARKER:    /* Marker */
  366.             case META_CUEPT:    /* Cue point */
  367.                 {
  368.                     int retval;
  369.  
  370.                     if (Mf_text != NULL &&
  371.                         (retval = (*Mf_text)((int) msg_type,
  372.                             length,data),
  373.                          Mf_deltatime = 0L,
  374.                          retval) < 0)
  375.                     {
  376.                         if (data != NULL)
  377.                             free(data);
  378.                         return(retval);
  379.                     }
  380.  
  381.                     break;
  382.                 }
  383.             case META_EOT:        /* End of track */
  384.                 {
  385.                     int retval;
  386.  
  387.                     if (length != 0L)    /* Check length */
  388.                         bailout(MFE_ILLMLEN)
  389.  
  390.                     if (Mf_eot != NULL &&
  391.                         (retval = (*Mf_eot)(),
  392.                          Mf_deltatime = 0L,
  393.                          retval) < 0)
  394.                     {
  395.                         free(data);
  396.                         return(retval);
  397.                     }
  398.                     eot_called = 1;
  399.  
  400.                     break;
  401.                 }
  402.  
  403.             case META_TEMPO:    /* Set tempo */
  404.                 {
  405.                     ulong tempo;
  406.                     int retval;
  407.  
  408.                     if (length != 3)    /* Check length */
  409.                         bailout(MFE_ILLMLEN)
  410.  
  411.                     tempo = /**(ushort *) data;*/
  412.                         stol(data,3);
  413.                     if (Mf_tempo != NULL &&
  414.                         (retval = (*Mf_tempo)(tempo),
  415.                          Mf_deltatime = 0L,
  416.                          retval) < 0)
  417.                     {
  418.                         free(data);
  419.                         return(retval);
  420.                     }
  421.  
  422.                     break;
  423.                 }
  424.             case META_SMPTE:    /* SMPTE offset */
  425.                 {
  426.                     int retval;
  427.                     int hour,min,sec,frame,fract;
  428.  
  429.                     if (length != 5)
  430.                         bailout(MFE_ILLMLEN)
  431.                     hour  = (int) data[0];
  432.                     min   = (int) data[1];
  433.                     sec   = (int) data[2];
  434.                     frame = (int) data[3];
  435.                     fract = (int) data[4];
  436.                     if (Mf_smpte != NULL &&
  437.                         (retval = (*Mf_smpte)(hour,min,
  438.                             sec,frame,fract),
  439.                          Mf_deltatime = 0L,
  440.                          retval) < 0)
  441.                     {
  442.                         free(data);
  443.                         return(retval);
  444.                     }
  445.  
  446.                     break;
  447.                 }
  448.             case META_TIMESIG:    /* Time signature */
  449.                 {
  450.                     int retval;
  451.                     int numer,denom,clocks,qnotes;
  452.  
  453.                     if (length != 4)
  454.                         bailout(MFE_ILLMLEN)
  455.                     numer  = (int) data[0];
  456.                     denom  = (int) data[1];
  457.                     clocks = (int) data[2];
  458.                     qnotes = (int) data[3];
  459.                     if (Mf_timesig != NULL &&
  460.                         (retval = (*Mf_timesig)(numer,
  461.                         denom,clocks,qnotes),
  462.                          Mf_deltatime = 0L,
  463.                          retval) < 0)
  464.                     {
  465.                         free(data);
  466.                         return(retval);
  467.                     }
  468.  
  469.                     break;
  470.                 }
  471.             case META_KEYSIG:    /* Key signature */
  472.                 {
  473.                     int retval;
  474.                     int sharpflat,minor;
  475.  
  476.                     if (length != 2)
  477.                         bailout(MFE_ILLMLEN)
  478.                     sharpflat = (int) data[0];
  479.                     minor     = (int) data[1];
  480.                     if (sharpflat > 7 ||
  481.                         sharpflat < -7 ||
  482.                         (minor != 0 && minor != 1))
  483.                         bailout(MFE_ILLMVAL)
  484.                     if (Mf_keysig != NULL &&
  485.                         (retval = (*Mf_keysig)(sharpflat,
  486.                             minor),
  487.                          Mf_deltatime = 0L,
  488.                          retval) < 0)
  489.                     {
  490.                         free(data);
  491.                         return(retval);
  492.                     }
  493.  
  494.                     break;
  495.                 }
  496.             case META_SEQSPEC:    /* Sequencer-specific */
  497.                 {
  498.                     int retval;
  499.  
  500.                     if (Mf_sqspecific != NULL &&
  501.                         (retval = (*Mf_sqspecific)(0,
  502.                             length,data),
  503.                          Mf_deltatime = 0L,
  504.                          retval) < 0)
  505.                     {
  506.                         if (data != NULL)
  507.                             free(data);
  508.                         return(retval);
  509.                     }
  510.  
  511.                     break;
  512.                 }
  513.             default:
  514.                 {
  515.                     int retval;
  516.  
  517.                     if (Mf_error != NULL &&
  518.                         (retval = (*Mf_error)
  519.                             (err_msgs[MFE_UKMETA])) < 0)
  520.                     {
  521.                         if (data != NULL)
  522.                             free(data);
  523.                         return(retval);
  524.                     }
  525.  
  526.                     break;
  527.                 }
  528.         }
  529.  
  530.         /* All went well. Free 'data' if necessary, and return */
  531.         if (data != NULL)
  532.             free(data);
  533.         return(MFE_OK);
  534.     }
  535.  
  536.     if (stat == 0xf0)    /* Syntactically complete message */
  537.     {
  538. fprintf(stderr, "Sorry, no complete SysEx messages\n");
  539.     }
  540.  
  541.     if (stat == 0xf7)    /* Part of a complete SysEx message */
  542.     {
  543. fprintf(stderr, "Sorry, no incomplete SysEx messages\n");
  544.     }
  545.  
  546.     bailout(MFE_ILLSETYPE)
  547. }
  548.  
  549. X/* READ_EVENT
  550.  * Read an event, parse it by type, and pass the data to the user's
  551.  * routines.
  552.  * Returns MFE_OK if all goes well, or an error code otherwise.
  553.  * A comment about the funky stuff I'm doing with 'Mf_deltatime':
  554.  * it turned out that if the user didn't check for _every_ event,
  555.  * then 'Mf_deltatime' got screwed up. In other words, if you didn't
  556.  * trap pitch-bends, then any pitch-bends in the file, >>> and their
  557.  * associated deltas <<< would be ignored. This is obviously a badism.
  558.  * To solve this, 'Mf_deltatime' is always incremented by the current
  559.  * delta, in 'read_event()'. Later, when the event is processed,
  560.  * 'Mf_deltatime' gets reset to 0 iff the handling routine has been
  561.  * called.
  562.  * The specific mechanism is a bit funky, so here's an example:
  563.  *    if (Mf_off != NULL &&
  564.  *        (retval = (*Mf_off)(run_stat & 0x07,
  565.  *                params[0],
  566.  *                params[1]),
  567.  *         Mf_deltatime = 0,
  568.  *         retval) < 0)
  569.  *        return(retval);
  570.  * This uses two particularities of C: lazy evaluation, and statements
  571.  * separated by commas. If 'Mf_off' is NULL, then the event is not
  572.  * important to the user, and 'Mf_deltatime' is kept intact for the next
  573.  * event. Otherwise, the following sequence of events occurs:
  574.  *    - The user's routine is called, and the return value is stored
  575.  *      in 'retval'.
  576.  *    - 'Mf_deltatime' gets reset to 0.
  577.  *    - 'retval' is called to the forefront, just in time to see
  578.  *      whether the user's routine returned an error value.
  579.  */
  580. static int read_event(toberead)
  581. long *toberead;            /* # bytes left to be read in the track */
  582. {
  583.     static uchar run_stat = 0x00;    /* Running status */
  584.     int stat;            /* Current status */
  585.     long delta_time;        /* Time since last event */
  586.     static uchar params[2];        /* Event parameters */
  587.     int cur_param;            /* Parameter being currently read */
  588.     int i;
  589.  
  590.     /* Read delta-time */
  591.     if ((delta_time = read_varlen(toberead)) < 0)
  592.         return((int) delta_time);    /* Return error code */
  593.  
  594.     /* Update 'Mf_currtime' and 'Mf_deltatime' */
  595.     Mf_currtime += Mf_deltatime += delta_time;
  596.  
  597.     /* Read event type */
  598.     if ((stat = (*Mf_getc)()) < 0 ||
  599.         --*toberead < 0)
  600.         bailout(MFE_EOF)    /* Error: event type expected */
  601.     if (stat & 0x80)        /* Is it a new event type? */
  602.     {
  603.         run_stat = (uchar) stat;    /* Set new running status */
  604.         cur_param = 0;            /* Start reading at 0th param */
  605.     } else {
  606.         params[0] = (uchar) stat;    /* Record 1st parameter */
  607.         cur_param = 1;            /* Start reading at 1st param */
  608.     }
  609.  
  610.     /* Read the parameters corresponding to the status byte */
  611.     for (i = num_params(run_stat)-cur_param; i > 0; i--, cur_param++)
  612.     {
  613.         int c;        /* Input character */
  614.  
  615.         if ((c = (*Mf_getc)()) < 0 ||
  616.             --*toberead < 0)
  617.             bailout(MFE_EOF);    /* Premature end of file */
  618.         params[cur_param] = (uchar) c;    /* Record parameter */
  619.     }
  620.  
  621.     /* Report event and parameters to user, depending on type of
  622.      * event.
  623.      */
  624.     switch(run_stat & 0xf0) {
  625.         int retval;
  626.  
  627.         case MIDI_NOTEOFF:    /* Note off */
  628.             if (Mf_off != NULL &&
  629.                 (retval = (*Mf_off)(run_stat & 0x07,
  630.                         params[0],
  631.                         params[1]),
  632.                  Mf_deltatime = 0,
  633.                  retval) < 0)
  634.                 return(retval);    /* Return error code */
  635.             return(MFE_OK);
  636.  
  637.         case MIDI_NOTEON:    /* Note on */
  638.             if (Mf_on != NULL &&
  639.                 (retval = (*Mf_on)(run_stat & 0x07,
  640.                         params[0],
  641.                         params[1]),
  642.                  Mf_deltatime = 0L,
  643.                  retval) < 0)
  644.                 return(retval);    /* Return error code */
  645.             return(MFE_OK);
  646.  
  647.         case MIDI_PRESSURE:    /* Polyphonic key pressure */
  648.             if (Mf_pressure != NULL &&
  649.                 (retval = (*Mf_pressure)(run_stat & 0x07,
  650.                         params[0],
  651.                         params[1]),
  652.                  Mf_deltatime = 0L,
  653.                  retval) < 0)
  654.                 return(retval);    /* Return error code */
  655.             return(MFE_OK);
  656.  
  657.         case MIDI_CONTROL:    /* Control change */
  658.             if (Mf_controller != NULL &&
  659.                 (retval = (*Mf_controller)(run_stat & 0x07,
  660.                         params[0],
  661.                         params[1]),
  662.                  Mf_deltatime = 0L,
  663.                  retval) < 0)
  664.                 return(retval);    /* Return error code */
  665.             return(MFE_OK);
  666.  
  667.         case MIDI_PROGRAM:    /* Program change */
  668.             if (Mf_program != NULL &&
  669.                 (retval = (*Mf_program)(run_stat & 0x07,
  670.                         params[0]),
  671.                  Mf_deltatime = 0L,
  672.                  retval) < 0)
  673.                 return(retval);    /* Return error code */
  674.             return(MFE_OK);
  675.  
  676.         case MIDI_CHANPRES:    /* Channel pressure */
  677.             if (Mf_chanpressure != NULL &&
  678.                 (retval = (*Mf_chanpressure)(run_stat & 0x07,
  679.                         params[0]),
  680.                  Mf_deltatime = 0L,
  681.                  retval) < 0)
  682.                 return(retval);    /* Return error code */
  683.             return(MFE_OK);
  684.  
  685.         case MIDI_PITCHB:    /* Pitch wheel change */
  686.             if (Mf_pitchbend != NULL &&
  687.                 (retval = (*Mf_pitchbend)(run_stat & 0x07,
  688.                         params[0],
  689.                         params[1]),
  690.                  Mf_deltatime = 0L,
  691.                  retval) < 0)
  692.                 return(retval);    /* Return error code */
  693.             return(MFE_OK);
  694.  
  695.         case MIDI_SYSEX:    /* System-exclusive/meta */
  696.             return(read_sysex(run_stat,toberead));
  697.         default:
  698.             bailout(MFE_ILLSTAT)
  699.     }
  700. }
  701.  
  702. X/* READ_TRACK
  703.  * Reads in a track, parses it, and passes the various parts on to the
  704.  * user's routines.
  705.  * Returns MFE_OK if all goes well, or an error code if anything goes wrong.
  706.  */
  707. static int read_track()
  708. {
  709.     int i;
  710.     static char kw_buff[4];    /* Buffer for input keyword "MTrk" */
  711.     int error;
  712.     long tklen;        /* Track length */
  713.  
  714.     /* Reset 'Mf_currtime'. If the file format is 2, then it probably
  715.      * doesn't matter anyway, but for the other types (single and
  716.      * multiple tracks), 'Mf_currtime' should measure the time elapsed
  717.      * since the beginning of the track.
  718.      */
  719.     Mf_currtime = 0L;
  720.  
  721.     eot_called = 0;    /* Indicate that 'Mf_eot()' hasn't been called yet */
  722.  
  723.     /* Read in the first four characters into 'kw_buff' */
  724.     for (i = 0; i < 4; i++)
  725.     {
  726.         int c;        /* Input character */
  727.  
  728.         if ((c = (*Mf_getc)()) == -1)
  729.             bailout(MFE_EOF)
  730.         else
  731.             kw_buff[i] = (char) c;
  732.     }
  733.  
  734.     /* See if 'kw_buff' contains "MTrk". In some future version,
  735.      * if the chunk type is unknown, then this section of code
  736.      * should just ignore it.
  737.      */
  738.     if (strncmp(kw_buff,"MTrk",4) != 0)
  739.         bailout(MFE_TKWEXP)
  740.  
  741.     /* Tell the user that we're starting a new track */
  742.     if (Mf_starttrack != NULL &&
  743.         (error = (*Mf_starttrack)()) < 0)
  744.         return(error);        /* User already knows about error */
  745.  
  746.     /* Read the length of the track */
  747.     if ((tklen = read_long()) < 0)
  748.         return(tklen);        /* Return error code */
  749.  
  750.     /* Read the data in the track */
  751.     error = MFE_OK;
  752.     while (tklen > 0 && error == MFE_OK)
  753.         error = read_event(&tklen);
  754.     if (error != MFE_OK)
  755.         return(error);
  756.  
  757.     if (!eot_called)    /* Has 'Mf_eot()' been called? */
  758.         bailout(MFE_NOEOT)
  759.  
  760.     return(MFE_OK);        /* All went well */
  761. }
  762.  
  763. X/* MIDIFILE
  764.  * This is the main routine of the whole thing, and the only one which
  765.  * should be accessible to the user. It reads in a MIDI format file,
  766.  * parses it, and passes the various parts on to user-supplied routines.
  767.  * Although it is very similar to Tim Thompson's 'midifile()', and performs
  768.  * the same function, it does _not_ cravenly exit the program as soon as
  769.  * an error occurs, and therefore can safely be used inside another
  770.  * application.
  771.  * Since 'midifile()' does not care where the input file is coming from,
  772.  * the user is expected to do all of the grunt work of opening files and
  773.  * all that.
  774.  * Returns MFE_OK if all goes well, or an error code if anything goes wrong,
  775.  * including user disapproval.
  776.  */
  777. int midifile()
  778. {
  779.     int i;
  780.     int ntrks;
  781.  
  782.     /* Initialize 'Mf_currtime' and 'Mf_deltatime' */
  783.     Mf_currtime =
  784.     Mf_deltatime = 0L;
  785.  
  786.     if (Mf_getc == NULL)
  787.         bailout(MFE_NOGETC)
  788.  
  789.     /* Read the file header, and return an error code if
  790.      * anything wrong occurs.
  791.      */
  792.     if ((ntrks = read_header()) < 0)
  793.         return(ntrks);        /* Return error value */
  794.  
  795.     /* Read the tracks, and return an error code if anything
  796.      * wrong occurs.
  797.      */
  798.     for (i = 0; i < ntrks; i++)
  799.     {
  800.         int error;
  801.  
  802.         if ((error = read_track()) != MFE_OK)
  803.             return(error);
  804.     }
  805.  
  806.     return(MFE_OK);        /* No errors */
  807. }
  808. //go.sysin dd *
  809. if [ `wc -c < midifile/mf.c` != 19018 ]; then
  810.     made=FALSE
  811.     /bin/echo 'error transmitting "midifile/mf.c" --'
  812.     /bin/echo 'length should be 19018, not' `wc -c < midifile/mf.c`
  813. else
  814.     made=TRUE
  815. fi
  816. if [ $made = TRUE ]; then
  817.     /bin/chmod 664 midifile/mf.c
  818.     /bin/echo -n '    '; /bin/ls -ld midifile/mf.c
  819. fi
  820. /bin/echo 'Extracting midifile/mf.h'
  821. sed 's/^X//' <<'//go.sysin dd *' >midifile/mf.h
  822. X/* MF.H
  823.  * Definitions etc. for MIDI file analyzer.
  824.  */
  825.  
  826. int (*Mf_getc)();        /* Returns -1 on EOF */
  827. int (*Mf_error)();
  828. int (*Mf_header)();
  829. int (*Mf_starttrack)();
  830. int (*Mf_endtrack)();
  831. int (*Mf_on)();
  832. int (*Mf_off)();
  833. int (*Mf_pressure)();
  834. int (*Mf_controller)();
  835. int (*Mf_pitchbend)();
  836. int (*Mf_program)();
  837. int (*Mf_chanpressure)();
  838. int (*Mf_sysex)();
  839. int (*Mf_metamisc)();
  840. int (*Mf_sqspecific)();
  841. int (*Mf_seqnum)();
  842. int (*Mf_text)();
  843. int (*Mf_eot)();
  844. int (*Mf_timesig)();
  845. int (*Mf_smpte)();
  846. int (*Mf_tempo)();
  847. int (*Mf_keysig)();
  848. int (*Mf_arbitrary)();
  849.  
  850. X/* ERROR CODES
  851.  * These are the error codes returned by the various routines.
  852.  */
  853. #define MFE_OK          0    /* No error */
  854. #define MFE_EOF         -1    /* Premature end of file */
  855. #define MFE_HKWEXP     -2    /* Header keyword expected */
  856. #define MFE_NOGETC     -3    /* 'Mf_getc' is not defined */
  857. #define MFE_ILLHLEN     -4    /* Illegal header length */
  858. #define MFE_USER     -5    /* User disapproves of something */
  859. #define MFE_ILLFORM     -6    /* Illegal file format */
  860. #define MFE_TKWEXP     -7    /* Track keyword expected */
  861. #define MFE_ILLSETYPE     -8    /* Illegal SysEx message type */
  862. #define MFE_MEM         -9    /* Insufficient memory */
  863. #define MFE_ILLSTAT    -10    /* Illegal status byte */
  864. #define MFE_ILLMLEN    -11    /* Illegal meta-event length */
  865. #define MFE_ILLMVAL    -12    /* Illegal value in meta-event */
  866. #define MFE_UKMETA    -13    /* Unknown meta-event */
  867. #define MFE_NOEOT    -14    /* No end-of-track meta-event */
  868.  
  869. X/* ERR_MSGS
  870.  * Error messages corresponding to the various errors that might occur.
  871.  */
  872. char *err_msgs[] = {
  873.     "No error",
  874.     "Premature end of file",
  875.     "'MThd' expected",
  876.     "'Mf_getc' undefined",
  877.     "Illegal header length",
  878.     "User disapproval",
  879.     "Illegal file format",
  880.     "'MTrk' expected",
  881.     "Illegal system-exclusive message type",
  882.     "Insufficient memory",
  883.     "Illegal status byte",
  884.     "Illegal meta-event length",
  885.     "Illegal value in meta-event",
  886.     "Unknown meta-event",
  887.     "Missing end-of-track meta-event",
  888.     NULL
  889. };
  890.  
  891. X/* BAILOUT
  892.  * Call 'Mf_error()' with the error code 'code', then return that code.
  893.  */
  894. #define bailout(code)    {if(Mf_error!=NULL)(*Mf_error)(err_msgs[-(code)]);\
  895.             return(code);}
  896.  
  897. X/* MIDI COMMANDS */
  898. #define MIDI_NOTEOFF    0x80    /* Note off */
  899. #define MIDI_NOTEON    0x90    /* Note on */
  900. #define MIDI_PRESSURE    0xa0    /* Polyphonic key pressure */
  901. #define MIDI_CONTROL    0xb0    /* Control change */
  902. #define MIDI_PROGRAM    0xc0    /* Program change */
  903. #define MIDI_CHANPRES    0xd0    /* Channel pressure */
  904. #define MIDI_PITCHB    0xe0    /* Pitch wheel change */
  905. #define MIDI_SYSEX    0xf0    /* System exclusive data */
  906.  
  907. X/* META-EVENT MESSAGE TYPES */
  908. #define META_SEQNUM        0x00    /* Sequence number */
  909. #define META_TEXT        0x01    /* Text event */
  910. #define META_COPYRIGHT        0x02    /* Copyright notice */
  911. #define META_SEQNAME        0x03    /* Sequence/track name */
  912. #define META_INSTNAME        0x04    /* Instrument name */
  913. #define META_LYRIC        0x05    /* Lyric */
  914. #define META_MARKER        0x06    /* Marker */
  915. #define META_CUEPT        0x07    /* Cue point */
  916. #define META_EOT        0x2f    /* End of track */
  917. #define META_TEMPO        0x51    /* Set tempo */
  918. #define META_SMPTE        0x54    /* SMPTE offset */
  919. #define META_TIMESIG        0x58    /* Time signature */
  920. #define META_KEYSIG        0x59    /* Key signature */
  921. #define META_SEQSPEC        0x7f    /* Sequencer-specific event */
  922. //go.sysin dd *
  923. if [ `wc -c < midifile/mf.h` != 3174 ]; then
  924.     made=FALSE
  925.     /bin/echo 'error transmitting "midifile/mf.h" --'
  926.     /bin/echo 'length should be 3174, not' `wc -c < midifile/mf.h`
  927. else
  928.     made=TRUE
  929. fi
  930. if [ $made = TRUE ]; then
  931.     /bin/chmod 664 midifile/mf.h
  932.     /bin/echo -n '    '; /bin/ls -ld midifile/mf.h
  933. fi
  934. /bin/echo 'Extracting midifile/midifile.3'
  935. sed 's/^X//' <<'//go.sysin dd *' >midifile/midifile.3
  936. X.TH MIDIFILE.3 "May 12, 1990"
  937. X.AT 3
  938. X.SH NAME
  939. midifile \- a MIDI file parser
  940. X.SH SYNOPSIS
  941. X.B #include 
  942. "midifile.h"
  943. X.PP
  944. X.B int midifile()
  945. X.PP
  946. X.B int (*Mf_getc)()
  947. X.PP
  948. X.B int (*Mf_error)(str)
  949. X.br
  950. X.B char *str;
  951. X.PP
  952. X.B int (*Mf_header)(format,ntrks,division)
  953. X.br
  954. X.B short format, ntrks, division;
  955. X.PP
  956. X.B int (*Mf_starttrack)()
  957. X.PP
  958. X.B int (*Mf_on)(chan,note,vol)
  959. X.br
  960. X.B unsigned char chan, note, vol;
  961. X.PP
  962. X.B int (*Mf_off)(chan,note,vol)
  963. X.br
  964. X.B unsigned char chan, note, vol;
  965. X.PP
  966. X.B int (*Mf_pressure)(chan,note,pressure)
  967. X.br
  968. X.B unsigned char chan, note, pressure;
  969. X.PP
  970. X.B int (*Mf_controller)(chan,control,value)
  971. X.br
  972. X.B unsigned char chan, control, value;
  973. X.PP
  974. X.B int (*Mf_pitchbend)(chan,lsb,msb)
  975. X.br
  976. X.B unsigned char chan, lsb, msb;
  977. X.PP
  978. X.B int (*Mf_program)(chan,prog)
  979. X.br
  980. X.B unsigned char chan, prog;
  981. X.PP
  982. X.B int (*Mf_chanpressure)(chan,pressure)
  983. X.br
  984. X.B unsigned char chan, pressure;
  985. X.PP
  986. X.B int (*Mf_sysex)()
  987. X.PP
  988. X.B int (*Mf_metamisc)()
  989. X.PP
  990. X.B int (*Mf_sqspecific)(chan,length,data)
  991. X.br
  992. X.B unsigned char chan;
  993. X.br
  994. X.B long length;
  995. X.br
  996. X.B char *data;
  997. X.PP
  998. X.B int (*Mf_seqnum)(seqnum)
  999. X.br
  1000. X.B short seqnum
  1001. X.PP
  1002. X.B int (*Mf_text)(msg_type,length,data)
  1003. X.br
  1004. X.B int msg_type;
  1005. X.br
  1006. X.B long length;
  1007. X.br
  1008. X.B char *data;
  1009. X.PP
  1010. X.B int (*Mf_eot)()
  1011. X.PP
  1012. X.B int (*Mf_timesig)(numer,denom,clocks,qnotes)
  1013. X.br
  1014. X.B int numer, denom, clocks, qnotes;
  1015. X.PP
  1016. X.B int (*Mf_smpte)(hour,min,sec,frame,fract)
  1017. X.br
  1018. X.B int hour, min, sec, frame, fract;
  1019. X.PP
  1020. X.B int (*Mf_tempo)(tempo)
  1021. X.br
  1022. X.B unsigned long tempo;
  1023. X.PP
  1024. X.B int (*Mf_keysig)(sharpflat,minor)
  1025. X.br
  1026. X.B int sharpflat, minor;
  1027. X.PP
  1028. X.B int (*Mf_arbitrary)()
  1029. X.PP
  1030. X.B long Mf_currtime
  1031. X.PP
  1032. X.B long Mf_deltatime
  1033. X.SH DESCRIPTION
  1034. X.I midifile
  1035. is a routine that parses an arbitrary MIDI format file.
  1036. It contains hooks for every type of event, for the user
  1037. to add his own event-handling functions. Each time
  1038. X.I midifile
  1039. reads an event, it calls a user function (if one is
  1040. defined, i.e., if it is non-NULL) with a description of the event.
  1041. X.PP
  1042. Not all functions must be supplied at all times:
  1043. X.I midifile
  1044. always checks for the existence of a user function
  1045. before calling it. Thus, if you're only interested in the
  1046. third track, you can have
  1047. X.B Mf_starttrack
  1048. assign values to the appropriate functions at the beginning of the
  1049. third track, and
  1050. X.B Mf_eot
  1051. reset them to NULL.
  1052. X.PP
  1053. The only function which must be supplied is
  1054. X.I Mf_getc,
  1055. which should read a byte from the MIDI file and return it; it
  1056. should return -1 in case of end of file, and a negative error
  1057. code in case of error.
  1058. X.PP
  1059. X.I Mf_error
  1060. is called in case of error. It is passed a string describing
  1061. the error. If
  1062. X.I Mf_error
  1063. returns a negative value, then
  1064. X.I midifile
  1065. aborts and returns that value.
  1066. X.PP
  1067. Actually, any user function can abort the execution of
  1068. X.I midifile:
  1069. anytime a function returns a negative value,
  1070. X.I midifile
  1071. returns that value to the calling routine.
  1072. X.PP
  1073. X.I Mf_header
  1074. is called whene the file header has been read. Its parameters are
  1075. the file format (0, 1 or 2), the number of tracks in the file,
  1076. and the division of quarter-notes, as described by the deltas in
  1077. the file.
  1078. X.PP
  1079. X.I Mf_starttrack
  1080. is called at the beginning of each track.
  1081. X.PP
  1082. X.I Mf_on
  1083. and
  1084. X.I Mf_off
  1085. are called each time
  1086. X.I midifile
  1087. reads a MIDI ON and MIDI OFF event, respectively. The parameters
  1088. are the MIDI channel, the note number, and the note-on (or off)
  1089. velocity.
  1090. X.PP
  1091. X.I Mf_pressure
  1092. is called for polyphonic key pressure (after-touch) events. It
  1093. gives the channel, the note number, and the pressure value.
  1094. Similarly,
  1095. X.I Mf_chanpressure
  1096. is called for channel pressure events.
  1097. X.PP
  1098. X.I Mf_controller
  1099. is called for controller changes. It gives the MIDI channel, the
  1100. controller number, and the controller value.
  1101. X.PP
  1102. X.I Mf_pitchbend
  1103. is called for pitch wheel events. It gives the MIDI channel, the
  1104. least-significant and most-significant bytes of the pitch-bend
  1105. value.
  1106. X.PP
  1107. X.I Mf_program
  1108. is called for program (patch) changes. It gives the MIDI channel
  1109. and the program number.
  1110. X.PP
  1111. X.I Mf_sysex
  1112. is called for system-exclusive messages. This function is not yet
  1113. implemented.
  1114. X.PP
  1115. X.I midifile
  1116. includes a series of functions designed to deal with the various
  1117. meta-events described by the MIDI 1.0 file spec. In each case,
  1118. the
  1119. X.I length
  1120. parameter, when given, includes the end-of-system-exclusive marker.
  1121. X.PP
  1122. X.I Mf_metamisc
  1123. is called for miscellaneous meta-events, as described in the
  1124. MIDI 1.0 file spec. This function is not yet implemented.
  1125. X.PP
  1126. X.I Mf_sqspecific
  1127. is called for sequencer-specific meta-events. It gives the MIDI
  1128. channel number, the length of the event, and a data string
  1129. containing the data.
  1130. X.PP
  1131. X.I Mf_seqnum
  1132. specifies the number of a sequence.
  1133. X.PP
  1134. X.I Mf_text
  1135. covers the entire class of text meta-events. It gives the
  1136. message type (miscellaneous, copyright notice, track name, etc.),
  1137. the text length, and a string containing the text.
  1138. X.PP
  1139. X.I Mf_eot
  1140. is called for the end-of-track meta-event.
  1141. X.PP
  1142. X.I Mf_timesig
  1143. gives the time signature of a piece. The time signature, as given
  1144. at the beginning of a piece is given by
  1145. X.B numer/(2^-denom).
  1146. X.B clocks
  1147. represents the number of MIDI clocks per metronome click.
  1148. X.B qnotes
  1149. gives the number of notated 32nd-notes in a MIDI quarter-note.
  1150. X.PP
  1151. X.I Mf_smpte
  1152. specifies a SMPTE offset for a track. It gives the number of
  1153. hours, minutes, seconds, frames and 100ths of a frame.
  1154. X.PP
  1155. X.I Mf_tempo
  1156. sets the tempo, in microseconds per MIDI quarter-note.
  1157. X.PP
  1158. X.I Mf_keysig
  1159. gives the key signature of the piece.
  1160. X.B sharpflat
  1161. gives the number of sharps or flats in the signature: 0 means
  1162. the piece is in the key of C, -1 means there is one flat in
  1163. the signature, 1 means there is one sharp, and so forth.
  1164. X.I minor
  1165. is set to 0 if the piece is in a major key, and 1 if it is in
  1166. a minor key.
  1167. X.PP
  1168. There are two user-accessible variables used by
  1169. X.I midifile:
  1170. X.I Mf_currtime
  1171. and
  1172. X.I Mf_deltatime
  1173. X.I Mf_currtime
  1174. measures the time elapsed between the beginning of the track
  1175. and the current event.
  1176. X.I Mf_deltatime
  1177. is the event's delta, i.e., it measures the time elapsed between
  1178. the previous event and the current event (or the beginning of
  1179. the track, if the current event is the first one).
  1180. X.SH FILES
  1181. X.B midifile.h
  1182. X.SH BUGS
  1183. X.I midifile
  1184. does not handle system-exclusive messages, except for the
  1185. meta-events described in the
  1186. X.I MIDI 1.0 File Specification.
  1187. X.SH AUTHOR
  1188. Original author: Tim Thompson. This version was rewritten and
  1189. enhanced by Andrew Arensburger.
  1190. X.SH "SEE ALSO"
  1191. X.IR "MIDI 1.0 specification"
  1192. X.br
  1193. X.I "MIDI 1.0 file specification"
  1194. //go.sysin dd *
  1195. if [ `wc -c < midifile/midifile.3` != 6394 ]; then
  1196.     made=FALSE
  1197.     /bin/echo 'error transmitting "midifile/midifile.3" --'
  1198.     /bin/echo 'length should be 6394, not' `wc -c < midifile/midifile.3`
  1199. else
  1200.     made=TRUE
  1201. fi
  1202. if [ $made = TRUE ]; then
  1203.     /bin/chmod 664 midifile/midifile.3
  1204.     /bin/echo -n '    '; /bin/ls -ld midifile/midifile.3
  1205. fi
  1206. /bin/echo 'Extracting midifile/midifile.h'
  1207. sed 's/^X//' <<'//go.sysin dd *' >midifile/midifile.h
  1208. X/* MIDI.H
  1209.  * Definitions etc. for MIDI file analyzer.
  1210.  */
  1211.  
  1212. extern int (*Mf_getc)();
  1213. extern int (*Mf_error)();
  1214. extern int (*Mf_header)();
  1215. extern int (*Mf_starttrack)();
  1216. extern int (*Mf_endtrack)();
  1217. extern int (*Mf_on)();
  1218. extern int (*Mf_off)();
  1219. extern int (*Mf_pressure)();
  1220. extern int (*Mf_controller)();
  1221. extern int (*Mf_pitchbend)();
  1222. extern int (*Mf_program)();
  1223. extern int (*Mf_chanpressure)();
  1224. extern int (*Mf_sysex)();
  1225. extern int (*Mf_metamisc)();
  1226. extern int (*Mf_sqspecific)();
  1227. extern int (*Mf_seqnum)();
  1228. extern int (*Mf_text)();
  1229. extern int (*Mf_eot)();
  1230. extern int (*Mf_timesig)();
  1231. extern int (*Mf_smpte)();
  1232. extern int (*Mf_tempo)();
  1233. extern int (*Mf_keysig)();
  1234. extern int (*Mf_arbitrary)();
  1235.  
  1236. extern int midifile();
  1237.  
  1238. extern long Mf_currtime;
  1239. extern long Mf_deltatime;
  1240.  
  1241. X/* ERROR CODES
  1242.  * These are the error codes returned by 'midifile()'.
  1243.  */
  1244. #define MFE_OK          0    /* No error */
  1245. #define MFE_EOF         -1    /* Premature end of file */
  1246. #define MFE_HKWEXP     -2    /* Header keyword expected */
  1247. #define MFE_NOGETC     -3    /* 'Mf_getc' is not defined */
  1248. #define MFE_ILLHLEN     -4    /* Illegal header length */
  1249. #define MFE_USER     -5    /* User disapproves of something */
  1250. #define MFE_ILLFORM     -6    /* Illegal file format */
  1251. #define MFE_TKWEXP     -7    /* Track keyword expected */
  1252. #define MFE_ILLSETYPE     -8    /* Illegal SysEx message type */
  1253. #define MFE_MEM         -9    /* Insufficient memory */
  1254. #define MFE_ILLSTAT    -10    /* Illegal status byte */
  1255. #define MFE_ILLMLEN    -11    /* Illegal meta-event length */
  1256. #define MFE_ILLMVAL    -12    /* Illegal value in meta-event */
  1257. #define MFE_UKMETA    -13    /* Unknown meta-event */
  1258. #define MFE_NOEOT    -14    /* No end-of-track meta-event */
  1259.  
  1260. //go.sysin dd *
  1261. if [ `wc -c < midifile/midifile.h` != 1621 ]; then
  1262.     made=FALSE
  1263.     /bin/echo 'error transmitting "midifile/midifile.h" --'
  1264.     /bin/echo 'length should be 1621, not' `wc -c < midifile/midifile.h`
  1265. else
  1266.     made=TRUE
  1267. fi
  1268. if [ $made = TRUE ]; then
  1269.     /bin/chmod 664 midifile/midifile.h
  1270.     /bin/echo -n '    '; /bin/ls -ld midifile/midifile.h
  1271. fi
  1272. made=TRUE
  1273. if [ $made = TRUE ]; then
  1274.     /bin/chmod 775 midifile
  1275.     /bin/echo -n '    '; /bin/ls -ld midifile
  1276. fi
  1277.  
  1278. exit 0 # Just in case...
  1279. -- 
  1280. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1281. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1282. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1283. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1284.