blob: d4dcab47ef5372e2b737e3163328d1bbe821fc50 [file] [log] [blame]
Stepan Moskovchenko215e4922005-04-15 06:08:55 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Nils Wallménius0e496052007-09-24 15:57:32 +00008 * $Id$
Stepan Moskovchenko215e4922005-04-15 06:08:55 +00009 *
10 * Copyright (C) 2005 Stepan Moskovchenko
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Nils Wallménius0e496052007-09-24 15:57:32 +000019#include "plugin.h"
20#include "midiutil.h"
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000021
22extern struct plugin_api * rb;
23
24struct Track * readTrack(int file);
25int readID(int file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000026
Nils Wallménius4ebe6922007-10-03 20:38:04 +000027struct MIDIfile midi_file IBSS_ATTR;
28
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000029struct MIDIfile * loadFile(char * filename)
30{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000031 struct MIDIfile * mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000032 int file = rb->open (filename, O_RDONLY);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000033
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000034 if(file==-1)
35 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000036 printf("Could not open file");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000037 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000038 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000039
Nils Wallménius4ebe6922007-10-03 20:38:04 +000040 mfload = &midi_file;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000041
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000042 rb->memset(mfload, 0, sizeof(struct MIDIfile));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000043
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000044 int fileID = readID(file);
45 if(fileID != ID_MTHD)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000046 {
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000047 if(fileID == ID_RIFF)
48 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000049 printf("Detected RMID file");
50 printf("Looking for MThd header");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000051 char dummy[17];
52 rb->read(file, &dummy, 16);
53 if(readID(file) != ID_MTHD)
54 {
55 rb->close(file);
56 printf("Invalid MIDI header within RIFF.");
57 return NULL;
58 }
59
60 } else
61 {
62 rb->close(file);
63 printf("Invalid file header chunk.");
64 return NULL;
65 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000066 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000067
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000068 if(readFourBytes(file)!=6)
69 {
70 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000071 printf("Header chunk size invalid.");
72 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000073 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000074
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000075 if(readTwoBytes(file)==2)
76 {
77 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000078 printf("MIDI file type 2 not supported");
79 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000080 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000081
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000082 mfload->numTracks = readTwoBytes(file);
83 mfload->div = readTwoBytes(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000084
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000085 int track=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000086
Jens Arnoldb1f00492007-04-21 05:35:17 +000087 printf("File has %d tracks.", mfload->numTracks);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000088
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000089 while(! eof(file) && track < mfload->numTracks)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000090 {
91 unsigned char id = readID(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000092
93
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000094 if(id == ID_EOF)
95 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000096 if(mfload->numTracks != track)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000097 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000098 printf("Error: file claims to have %d tracks. I only see %d here.", mfload->numTracks, track);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000099 mfload->numTracks = track;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000100 }
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000101 return mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000102 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000103
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000104 if(id == ID_MTRK)
105 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000106 mfload->tracks[track] = readTrack(file);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000107 track++;
108 } else
109 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000110 printf("SKIPPING TRACK");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000111 int len = readFourBytes(file);
112 while(--len)
113 readChar(file);
114 }
115 }
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000116
117 rb->close(file);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000118 return mfload;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000119
120}
121
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000122/* Global again. Not static. What if track 1 ends on a running status event
123 * and then track 2 starts loading */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000124
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000125int rStatus = 0;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000126/* Returns 0 if done, 1 if keep going */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000127int readEvent(int file, void * dest)
128{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000129 struct Event dummy;
130 struct Event * ev = (struct Event *) dest;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000131
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000132 if(ev == NULL)
133 ev = &dummy; /* If we are just counting events instead of loading them */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000134
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000135 ev->delta = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000136
137
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000138 int t=readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000139
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000140 if((t&0x80) == 0x80) /* if not a running status event */
141 {
142 ev->status = t;
143 if(t == 0xFF)
144 {
145 ev->d1 = readChar(file);
146 ev->len = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000147
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000148 /* Allocate and read in the data block */
149 if(dest != NULL)
150 {
151 ev->evData = readData(file, ev->len);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000152/* printf("\nDATA: <%s>", ev->evData); */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000153 }
154 else
155 {
156 /*
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000157 * Don't allocate anything, just see how much it would take
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000158 * To make memory usage efficient
159 */
160 unsigned int a=0;
161 for(a=0; a<ev->len; a++)
162 readChar(file); //Skip skip
163 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000164
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000165 if(ev->d1 == 0x2F)
166 {
167 return 0; /* Termination meta-event */
168 }
169 } else /* If part of a running status event */
170 {
171 rStatus = t;
172 ev->status = t;
173 ev->d1 = readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000174
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000175 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
176 {
177 ev->d2 = readChar(file);
178 } else
179 ev->d2 = 127;
180 }
181 } else /* Running Status */
182 {
183 ev->status = rStatus;
184 ev->d1 = t;
185 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
186 {
187 ev->d2 = readChar(file);
188 } else
189 ev->d2 = 127;
190 }
191 return 1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000192}
193
Nils Wallméniusca46a3d2007-10-04 21:01:40 +0000194int curr_track = 0;
195struct Track tracks[48] IBSS_ATTR;
196
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000197struct Track * readTrack(int file)
198{
Nils Wallméniusca46a3d2007-10-04 21:01:40 +0000199 struct Track * trk = &tracks[curr_track++];
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000200 rb->memset(trk, 0, sizeof(struct Track));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000201
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000202 trk->size = readFourBytes(file);
203 trk->pos = 0;
204 trk->delta = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000205
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000206 int numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000207
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000208 int pos = rb->lseek(file, 0, SEEK_CUR);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000209
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000210 while(readEvent(file, NULL)) /* Memory saving technique */
211 numEvents++; /* Attempt to read in events, count how many */
212 /* THEN allocate memory and read them in */
213 rb->lseek(file, pos, SEEK_SET);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000214
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000215 int trackSize = (numEvents+1) * sizeof(struct Event);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000216 void * dataPtr = malloc(trackSize);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000217 trk->dataBlock = dataPtr;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000218
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000219 numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000220
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000221 while(readEvent(file, dataPtr))
222 {
223 if(trackSize < dataPtr-trk->dataBlock)
224 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000225 printf("Track parser memory out of bounds");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000226 exit(1);
227 }
228 dataPtr+=sizeof(struct Event);
229 numEvents++;
230 }
231 trk->numEvents = numEvents;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000232
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000233 return trk;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000234}
235
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000236int readID(int file)
237{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000238 char id[5];
239 id[4]=0;
240 BYTE a;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000241
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000242 for(a=0; a<4; a++)
243 id[a]=readChar(file);
244 if(eof(file))
245 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000246 printf("End of file reached.");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000247 return ID_EOF;
248 }
249 if(rb->strcmp(id, "MThd")==0)
250 return ID_MTHD;
251 if(rb->strcmp(id, "MTrk")==0)
252 return ID_MTRK;
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +0000253 if(rb->strcmp(id, "RIFF")==0)
254 return ID_RIFF;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000255 return ID_UNKNOWN;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000256}
257
258
259int readFourBytes(int file)
260{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000261 int data=0;
262 BYTE a=0;
263 for(a=0; a<4; a++)
264 data=(data<<8)+readChar(file);
265 return data;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000266}
267
268int readTwoBytes(int file)
269{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000270 int data=(readChar(file)<<8)+readChar(file);
271 return data;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000272}
273
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000274/* This came from the MIDI file format guide */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000275int readVarData(int file)
276{
277 unsigned int value;
278 char c;
279 if ( (value = readChar(file)) & 0x80 )
280 {
281 value &= 0x7F;
282 do
283 {
284 value = (value << 7) + ((c = readChar(file)) & 0x7F);
285 } while (c & 0x80);
286 }
287 return(value);
288}
289
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000290
291/*
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000292void unloadFile(struct MIDIfile * mf)
293{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000294 if(mf == NULL)
295 return;
296 int a=0;
297 //Unload each track
298 for(a=0; a<mf->numTracks; a++)
299 {
300 int b=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000301
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000302 if(mf->tracks[a] != NULL)
303 for(b=0; b<mf->tracks[a]->numEvents; b++)
304 {
305 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
306 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
307 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000308
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000309 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
310 free(mf->tracks[a]->dataBlock); //Unload the event block
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000311
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000312 if(mf->tracks[a]!=NULL)
313 free(mf->tracks[a]); //Unload the track structure itself
314 }
315 free(mf); //Unload the main struct
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000316}
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000317*/
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +0000318