blob: 7161818421ec87506cdaa71010108320068b8065 [file] [log] [blame]
Stepan Moskovchenko215e4922005-04-15 06:08:55 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 Stepan Moskovchenko
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19
20
21extern struct plugin_api * rb;
22
23struct Track * readTrack(int file);
24int readID(int file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000025
26struct MIDIfile * loadFile(char * filename)
27{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000028 struct MIDIfile * mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000029 int file = rb->open (filename, O_RDONLY);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000030
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000031 if(file==-1)
32 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000033 printf("Could not open file");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000034 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000035 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000036
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000037 mfload = (struct MIDIfile*)malloc(sizeof(struct MIDIfile));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000038
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000039 if(mfload==NULL)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000040 {
41 rb->close(file);
Jens Arnoldb1f00492007-04-21 05:35:17 +000042 printf("Could not allocate memory for MIDIfile struct");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000043 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000044 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000045
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000046 rb->memset(mfload, 0, sizeof(struct MIDIfile));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000047
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000048 int fileID = readID(file);
49 if(fileID != ID_MTHD)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000050 {
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000051 if(fileID == ID_RIFF)
52 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000053 printf("Detected RMID file");
54 printf("Looking for MThd header");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000055 char dummy[17];
56 rb->read(file, &dummy, 16);
57 if(readID(file) != ID_MTHD)
58 {
59 rb->close(file);
60 printf("Invalid MIDI header within RIFF.");
61 return NULL;
62 }
63
64 } else
65 {
66 rb->close(file);
67 printf("Invalid file header chunk.");
68 return NULL;
69 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000070 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000071
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000072 if(readFourBytes(file)!=6)
73 {
74 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000075 printf("Header chunk size invalid.");
76 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000077 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000078
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000079 if(readTwoBytes(file)==2)
80 {
81 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000082 printf("MIDI file type 2 not supported");
83 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000084 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000085
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000086 mfload->numTracks = readTwoBytes(file);
87 mfload->div = readTwoBytes(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000088
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000089 int track=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000090
Jens Arnoldb1f00492007-04-21 05:35:17 +000091 printf("File has %d tracks.", mfload->numTracks);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000092
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000093 while(! eof(file) && track < mfload->numTracks)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000094 {
95 unsigned char id = readID(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000096
97
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000098 if(id == ID_EOF)
99 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000100 if(mfload->numTracks != track)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000101 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000102 printf("Error: file claims to have %d tracks. I only see %d here.", mfload->numTracks, track);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000103 mfload->numTracks = track;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000104 }
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000105 return mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000106 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000107
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000108 if(id == ID_MTRK)
109 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000110 mfload->tracks[track] = readTrack(file);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000111 track++;
112 } else
113 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000114 printf("SKIPPING TRACK");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000115 int len = readFourBytes(file);
116 while(--len)
117 readChar(file);
118 }
119 }
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000120
121 rb->close(file);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000122 return mfload;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000123
124}
125
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000126/* Global again. Not static. What if track 1 ends on a running status event
127 * and then track 2 starts loading */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000128
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000129int rStatus = 0;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000130/* Returns 0 if done, 1 if keep going */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000131int readEvent(int file, void * dest)
132{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000133 struct Event dummy;
134 struct Event * ev = (struct Event *) dest;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000135
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000136 if(ev == NULL)
137 ev = &dummy; /* If we are just counting events instead of loading them */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000138
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000139 ev->delta = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000140
141
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000142 int t=readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000143
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000144 if((t&0x80) == 0x80) /* if not a running status event */
145 {
146 ev->status = t;
147 if(t == 0xFF)
148 {
149 ev->d1 = readChar(file);
150 ev->len = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000151
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000152 /* Allocate and read in the data block */
153 if(dest != NULL)
154 {
155 ev->evData = readData(file, ev->len);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000156/* printf("\nDATA: <%s>", ev->evData); */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000157 }
158 else
159 {
160 /*
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000161 * Don't allocate anything, just see how much it would take
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000162 * To make memory usage efficient
163 */
164 unsigned int a=0;
165 for(a=0; a<ev->len; a++)
166 readChar(file); //Skip skip
167 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000168
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000169 if(ev->d1 == 0x2F)
170 {
171 return 0; /* Termination meta-event */
172 }
173 } else /* If part of a running status event */
174 {
175 rStatus = t;
176 ev->status = t;
177 ev->d1 = readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000178
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000179 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
180 {
181 ev->d2 = readChar(file);
182 } else
183 ev->d2 = 127;
184 }
185 } else /* Running Status */
186 {
187 ev->status = rStatus;
188 ev->d1 = t;
189 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
190 {
191 ev->d2 = readChar(file);
192 } else
193 ev->d2 = 127;
194 }
195 return 1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000196}
197
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000198struct Track * readTrack(int file)
199{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000200 struct Track * trk = (struct Track *)malloc(sizeof(struct Track));
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000201 rb->memset(trk, 0, sizeof(struct Track));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000202
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000203 trk->size = readFourBytes(file);
204 trk->pos = 0;
205 trk->delta = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000206
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000207 int numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000208
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000209 int pos = rb->lseek(file, 0, SEEK_CUR);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000210
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000211 while(readEvent(file, NULL)) /* Memory saving technique */
212 numEvents++; /* Attempt to read in events, count how many */
213 /* THEN allocate memory and read them in */
214 rb->lseek(file, pos, SEEK_SET);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000215
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000216 int trackSize = (numEvents+1) * sizeof(struct Event);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000217 void * dataPtr = malloc(trackSize);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000218 trk->dataBlock = dataPtr;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000219
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000220 numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000221
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000222 while(readEvent(file, dataPtr))
223 {
224 if(trackSize < dataPtr-trk->dataBlock)
225 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000226 printf("Track parser memory out of bounds");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000227 exit(1);
228 }
229 dataPtr+=sizeof(struct Event);
230 numEvents++;
231 }
232 trk->numEvents = numEvents;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000233
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000234 return trk;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000235}
236
237
238int readID(int file)
239{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000240 char id[5];
241 id[4]=0;
242 BYTE a;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000243
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000244 for(a=0; a<4; a++)
245 id[a]=readChar(file);
246 if(eof(file))
247 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000248 printf("End of file reached.");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000249 return ID_EOF;
250 }
251 if(rb->strcmp(id, "MThd")==0)
252 return ID_MTHD;
253 if(rb->strcmp(id, "MTrk")==0)
254 return ID_MTRK;
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +0000255 if(rb->strcmp(id, "RIFF")==0)
256 return ID_RIFF;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000257 return ID_UNKNOWN;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000258}
259
260
261int readFourBytes(int file)
262{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000263 int data=0;
264 BYTE a=0;
265 for(a=0; a<4; a++)
266 data=(data<<8)+readChar(file);
267 return data;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000268}
269
270int readTwoBytes(int file)
271{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000272 int data=(readChar(file)<<8)+readChar(file);
273 return data;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000274}
275
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000276/* This came from the MIDI file format guide */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000277int readVarData(int file)
278{
279 unsigned int value;
280 char c;
281 if ( (value = readChar(file)) & 0x80 )
282 {
283 value &= 0x7F;
284 do
285 {
286 value = (value << 7) + ((c = readChar(file)) & 0x7F);
287 } while (c & 0x80);
288 }
289 return(value);
290}
291
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000292
293/*
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000294void unloadFile(struct MIDIfile * mf)
295{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000296 if(mf == NULL)
297 return;
298 int a=0;
299 //Unload each track
300 for(a=0; a<mf->numTracks; a++)
301 {
302 int b=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000303
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000304 if(mf->tracks[a] != NULL)
305 for(b=0; b<mf->tracks[a]->numEvents; b++)
306 {
307 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
308 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
309 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000310
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000311 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
312 free(mf->tracks[a]->dataBlock); //Unload the event block
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000313
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000314 if(mf->tracks[a]!=NULL)
315 free(mf->tracks[a]); //Unload the track structure itself
316 }
317 free(mf); //Unload the main struct
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000318}
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000319*/
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +0000320
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000321