native_midi_gpl/readmidi.c
changeset 160 c62666b42573
equal deleted inserted replaced
159:01490534f9fe 160:c62666b42573
       
     1 /************************************************************************
       
     2    readmidi.c -- last change: 1 Jan 96
       
     3 
       
     4    Creates a linked list of each chunk in a midi file.
       
     5    ENTIRE MIDI FILE IS RETAINED IN MEMORY so that no additional malloc
       
     6    calls need be made to store the data of the events in the midi file.
       
     7 
       
     8    Copyright (C) 1995-1996 Nathan I. Laredo
       
     9 
       
    10    This program is modifiable/redistributable under the terms
       
    11    of the GNU General Public Licence.
       
    12 
       
    13    You should have received a copy of the GNU General Public License
       
    14    along with this program; if not, write to the Free Software
       
    15    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       
    16    Send your comments and all your spare pocket change to
       
    17    laredo@gnu.ai.mit.edu (Nathan Laredo) or to PSC 1, BOX 709, 2401
       
    18    Kelly Drive, Lackland AFB, TX 78236-5128, USA.
       
    19  *************************************************************************/
       
    20 /*    edited by Peter Kutak           */
       
    21 /*    email : kutak@stonline.sk       */
       
    22 
       
    23 #if defined(linux) || defined(__FreeBSD__)
       
    24 
       
    25 #include "playmidi.h"
       
    26 #include <unistd.h>
       
    27 
       
    28 int format, ntrks, division;
       
    29 unsigned char *midifilebuf;
       
    30 
       
    31 /* the following few lines are needed for dealing with CMF files */
       
    32 int reloadfm = 0;
       
    33 extern void loadfm();
       
    34 extern int seqfd, sb_dev, wantopl3, play_fm, fmloaded[256];
       
    35 SEQ_USE_EXTBUF();
       
    36 
       
    37 extern struct miditrack seq[MAXTRKS];
       
    38 extern unsigned long int default_tempo;
       
    39 
       
    40 unsigned short Read16()
       
    41 {
       
    42     register unsigned short x;
       
    43 
       
    44     x = (*(midifilebuf) << 8) | midifilebuf[1];
       
    45     midifilebuf += 2;
       
    46     return x;
       
    47 }
       
    48 
       
    49 unsigned long Read32()
       
    50 {
       
    51     register unsigned long x;
       
    52 
       
    53     x = (*(midifilebuf) << 24) | (midifilebuf[1] << 16) |
       
    54 	(midifilebuf[2] << 8) | midifilebuf[3];
       
    55     midifilebuf += 4;
       
    56     return x;
       
    57 }
       
    58 
       
    59 int readmidi(filebuf, filelength)
       
    60 unsigned char *filebuf;
       
    61 off_t filelength;
       
    62 {
       
    63     unsigned long int i = 0, track, tracklen;
       
    64 
       
    65     midifilebuf = filebuf;
       
    66     /* allow user to specify header number in from large archive */
       
    67 #if 0
       
    68     while (i != find_header && midifilebuf < (filebuf + filelength - 32)) {
       
    69 	if (strncmp(midifilebuf, "MThd", 4) == 0) {
       
    70 	    i++;
       
    71 	    midifilebuf += 4;
       
    72 	} else
       
    73 	    midifilebuf++;
       
    74     }
       
    75     if (i != find_header) {	/* specified header was not found */
       
    76 	midifilebuf = filebuf;
       
    77 	return find_header = 0;
       
    78     }
       
    79 #endif
       
    80     if (midifilebuf != filebuf)
       
    81 	midifilebuf -= 4;
       
    82     i = Read32();
       
    83     if (i == RIFF) {
       
    84 	midifilebuf += 16;
       
    85 	i = Read32();
       
    86     }
       
    87     if (i == MThd) {
       
    88 	tracklen = Read32();
       
    89 	format = Read16();
       
    90 	ntrks = Read16();
       
    91 	division = Read16();
       
    92     } else if (i == CTMF) {
       
    93 	/* load a creative labs CMF file, with instruments for fm */
       
    94 	tracklen = midifilebuf[4] | (midifilebuf[5] << 8);
       
    95 	format = 0;
       
    96 	ntrks = 1;
       
    97 	division = midifilebuf[6] | (midifilebuf[7] << 8);
       
    98 	default_tempo = 1000000 * division /
       
    99 		(midifilebuf[8] | (midifilebuf[9] << 8));
       
   100 	seq[0].data = filebuf + tracklen;
       
   101 	seq[0].length = filelength - tracklen;
       
   102 	i = (unsigned long int) (*(short *) &midifilebuf[2]) - 4;
       
   103 	/* if fm playback is enabled, load all fm patches from file */
       
   104 	if (play_fm) {
       
   105 	    struct sbi_instrument instr;
       
   106 	    int j, k;
       
   107 	    reloadfm = midifilebuf[32]; /* number of custom patches */
       
   108             instr.device = sb_dev;
       
   109 	    for (j = 0; j < 32; j++)
       
   110 		instr.operators[j] = 0x3f;
       
   111 	    instr.key = FM_PATCH;
       
   112 	    for (j = 0; j < reloadfm && j < 255; j++) {
       
   113                 instr.channel = j;
       
   114 		fmloaded[j] = instr.key;
       
   115                 for (k = 0; k < 16; k++)
       
   116 		    instr.operators[k] = midifilebuf[i + (16 * j) + k];
       
   117 		SEQ_WRPATCH(&instr, sizeof(instr));
       
   118 	    }
       
   119 	}
       
   120 	return ntrks;
       
   121     } else {
       
   122 	int found = 0;
       
   123 	while (!found && midifilebuf < (filebuf + filelength - 8))
       
   124 	    if (strncmp(midifilebuf, "MThd", 4) == 0)
       
   125 		found++;
       
   126 	    else
       
   127 		midifilebuf++;
       
   128 	if (found) {
       
   129 	    midifilebuf += 4;
       
   130 	    tracklen = Read32();
       
   131 	    format = Read16();
       
   132 	    ntrks = Read16();
       
   133 	    division = Read16();
       
   134 	} else {
       
   135 #ifndef DISABLE_RAW_MIDI_FILES
       
   136 	    /* this allows playing ANY file, so watch out */
       
   137 	    midifilebuf -= 4;
       
   138 	    format = 0;		/* assume it's .mus file ? */
       
   139 	    ntrks = 1;
       
   140 	    division = 40;
       
   141 #else
       
   142 	    return -1;
       
   143 #endif
       
   144 	}
       
   145     }
       
   146     if (ntrks > MAXTRKS) {
       
   147 	fprintf(stderr, "\nWARNING: %d TRACKS IGNORED!\n", ntrks - MAXTRKS);
       
   148 	ntrks = MAXTRKS;
       
   149     }
       
   150     if (play_fm && reloadfm) {
       
   151 	loadfm();	/* if custom CMF patches loaded, replace */
       
   152 	reloadfm = 0;
       
   153     }
       
   154     for (track = 0; track < ntrks; track++) {
       
   155 	if (Read32() != MTrk) {
       
   156 	    /* MTrk isn't where it's supposed to be, search rest of file */
       
   157 	    int fuzz, found = 0;
       
   158 	    midifilebuf -= 4;
       
   159 	    if (strncmp(midifilebuf, "MThd", 4) == 0)
       
   160 		continue;
       
   161 	    else {
       
   162 		if (!track) {
       
   163 		    seq[0].length = filebuf + filelength - midifilebuf;
       
   164 		    seq[0].data = midifilebuf;
       
   165 		    continue;	/* assume raw midi data file */
       
   166 		}
       
   167 		midifilebuf -= seq[track - 1].length;
       
   168 		for (fuzz = 0; (fuzz + midifilebuf) <
       
   169 		     (filebuf + filelength - 8) && !found; fuzz++)
       
   170 		    if (strncmp(&midifilebuf[fuzz], "MTrk", 4) == 0)
       
   171 			found++;
       
   172 		seq[track - 1].length = fuzz;
       
   173 		midifilebuf += fuzz;
       
   174 		if (!found)
       
   175 		    continue;
       
   176 	    }
       
   177 	}
       
   178 	tracklen = Read32();
       
   179 	if (midifilebuf + tracklen > filebuf + filelength)
       
   180 	    tracklen = filebuf + filelength - midifilebuf;
       
   181 	seq[track].length = tracklen;
       
   182 	seq[track].data = midifilebuf;
       
   183 	midifilebuf += tracklen;
       
   184     }
       
   185     ntrks = track;
       
   186     return ntrks;
       
   187 }
       
   188 #endif /* linux || FreeBSD */