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 #include "playmidi.h" 21 #include <unistd.h> 22 23 int format, ntrks, division; 24 unsigned char *midifilebuf; 25 26 /* the following few lines are needed for dealing with CMF files */ 27 int reloadfm = 0; 28 extern void loadfm(); 29 extern int seqfd, sb_dev, wantopl3, play_fm, fmloaded[256]; 30 SEQ_USE_EXTBUF(); 31 32 extern struct miditrack seq[MAXTRKS]; 33 extern int find_header; 34 extern unsigned long int default_tempo; 35 36 unsigned short Read16() 37 { 38 register unsigned short x; 39 40 x = (*(midifilebuf) << 8) | midifilebuf[1]; 41 midifilebuf += 2; 42 return x; 43 } 44 45 unsigned long Read32() 46 { 47 register unsigned long x; 48 49 x = (*(midifilebuf) << 24) | (midifilebuf[1] << 16) | 50 (midifilebuf[2] << 8) | midifilebuf[3]; 51 midifilebuf += 4; 52 return x; 53 } 54 55 int readmidi(filebuf, filelength) 56 unsigned char *filebuf; 57 off_t filelength; 58 { 59 unsigned long int i = 0, track, tracklen; 60 61 midifilebuf = filebuf; 62 /* allow user to specify header number in from large archive */ 63 while (i != find_header && midifilebuf < (filebuf + filelength - 32)) { 64 if (strncmp(midifilebuf, "MThd", 4) == 0) { 65 i++; 66 midifilebuf += 4; 67 } else 68 midifilebuf++; 69 } 70 if (i != find_header) { /* specified header was not found */ 71 midifilebuf = filebuf; 72 return find_header = 0; 73 } 74 if (midifilebuf != filebuf) 75 midifilebuf -= 4; 76 i = Read32(); 77 if (i == RIFF) { 78 midifilebuf += 16; 79 i = Read32(); 80 } 81 if (i == MThd) { 82 tracklen = Read32(); 83 format = Read16(); 84 ntrks = Read16(); 85 division = Read16(); 86 } else if (i == CTMF) { 87 /* load a creative labs CMF file, with instruments for fm */ 88 tracklen = midifilebuf[4] | (midifilebuf[5] << 8); 89 format = 0; 90 ntrks = 1; 91 division = midifilebuf[6] | (midifilebuf[7] << 8); 92 default_tempo = 1000000 * division / 93 (midifilebuf[8] | (midifilebuf[9] << 8)); 94 seq[0].data = filebuf + tracklen; 95 seq[0].length = filelength - tracklen; 96 i = (unsigned long int) (*(short *) &midifilebuf[2]) - 4; 97 /* if fm playback is enabled, load all fm patches from file */ 98 if (play_fm) { 99 struct sbi_instrument instr; 100 int j, k; 101 reloadfm = midifilebuf[32]; /* number of custom patches */ 102 instr.device = sb_dev; 103 for (j = 0; j < 32; j++) 104 instr.operators[j] = 0x3f; 105 instr.key = FM_PATCH; 106 for (j = 0; j < reloadfm && j < 255; j++) { 107 instr.channel = j; 108 fmloaded[j] = instr.key; 109 for (k = 0; k < 16; k++) 110 instr.operators[k] = midifilebuf[i + (16 * j) + k]; 111 SEQ_WRPATCH(&instr, sizeof(instr)); 112 } 113 } 114 return ntrks; 115 } else { 116 int found = 0; 117 while (!found && midifilebuf < (filebuf + filelength - 8)) 118 if (strncmp(midifilebuf, "MThd", 4) == 0) 119 found++; 120 else 121 midifilebuf++; 122 if (found) { 123 midifilebuf += 4; 124 tracklen = Read32(); 125 format = Read16(); 126 ntrks = Read16(); 127 division = Read16(); 128 } else { 129 #ifndef DISABLE_RAW_MIDI_FILES 130 /* this allows playing ANY file, so watch out */ 131 midifilebuf -= 4; 132 format = 0; /* assume it's .mus file ? */ 133 ntrks = 1; 134 division = 40; 135 #else 136 return -1; 137 #endif 138 } 139 } 140 if (ntrks > MAXTRKS) { 141 fprintf(stderr, "\nWARNING: %d TRACKS IGNORED!\n", ntrks - MAXTRKS); 142 ntrks = MAXTRKS; 143 } 144 if (play_fm && reloadfm) { 145 loadfm(); /* if custom CMF patches loaded, replace */ 146 reloadfm = 0; 147 } 148 for (track = 0; track < ntrks; track++) { 149 if (Read32() != MTrk) { 150 /* MTrk isn't where it's supposed to be, search rest of file */ 151 int fuzz, found = 0; 152 midifilebuf -= 4; 153 if (strncmp(midifilebuf, "MThd", 4) == 0) 154 continue; 155 else { 156 if (!track) { 157 seq[0].length = filebuf + filelength - midifilebuf; 158 seq[0].data = midifilebuf; 159 continue; /* assume raw midi data file */ 160 } 161 midifilebuf -= seq[track - 1].length; 162 for (fuzz = 0; (fuzz + midifilebuf) < 163 (filebuf + filelength - 8) && !found; fuzz++) 164 if (strncmp(&midifilebuf[fuzz], "MTrk", 4) == 0) 165 found++; 166 seq[track - 1].length = fuzz; 167 midifilebuf += fuzz; 168 if (!found) 169 continue; 170 } 171 } 172 tracklen = Read32(); 173 if (midifilebuf + tracklen > filebuf + filelength) 174 tracklen = filebuf + filelength - midifilebuf; 175 seq[track].length = tracklen; 176 seq[track].data = midifilebuf; 177 midifilebuf += tracklen; 178 } 179 ntrks = track; 180 return ntrks; 181 } 182