blob: 1fa648ff507c020b4bd10ee2bf284dba6a31e7a5 [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
27struct MIDIfile * loadFile(char * filename)
28{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000029 struct MIDIfile * mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000030 int file = rb->open (filename, O_RDONLY);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000031
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000032 if(file==-1)
33 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000034 printf("Could not open file");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000035 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000036 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000037
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000038 mfload = (struct MIDIfile*)malloc(sizeof(struct MIDIfile));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000039
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000040 if(mfload==NULL)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000041 {
42 rb->close(file);
Jens Arnoldb1f00492007-04-21 05:35:17 +000043 printf("Could not allocate memory for MIDIfile struct");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000044 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000045 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000046
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000047 rb->memset(mfload, 0, sizeof(struct MIDIfile));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000048
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000049 int fileID = readID(file);
50 if(fileID != ID_MTHD)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000051 {
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000052 if(fileID == ID_RIFF)
53 {
Jens Arnoldb1f00492007-04-21 05:35:17 +000054 printf("Detected RMID file");
55 printf("Looking for MThd header");
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000056 char dummy[17];
57 rb->read(file, &dummy, 16);
58 if(readID(file) != ID_MTHD)
59 {
60 rb->close(file);
61 printf("Invalid MIDI header within RIFF.");
62 return NULL;
63 }
64
65 } else
66 {
67 rb->close(file);
68 printf("Invalid file header chunk.");
69 return NULL;
70 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000071 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000072
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000073 if(readFourBytes(file)!=6)
74 {
75 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000076 printf("Header chunk size invalid.");
77 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000078 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000079
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000080 if(readTwoBytes(file)==2)
81 {
82 rb->close(file);
Stepan Moskovchenkob9b2bcd2006-05-08 02:43:29 +000083 printf("MIDI file type 2 not supported");
84 return NULL;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000085 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000086
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000087 mfload->numTracks = readTwoBytes(file);
88 mfload->div = readTwoBytes(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000089
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000090 int track=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000091
Jens Arnoldb1f00492007-04-21 05:35:17 +000092 printf("File has %d tracks.", mfload->numTracks);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000093
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +000094 while(! eof(file) && track < mfload->numTracks)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000095 {
96 unsigned char id = readID(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000097
98
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000099 if(id == ID_EOF)
100 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000101 if(mfload->numTracks != track)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000102 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000103 printf("Error: file claims to have %d tracks. I only see %d here.", mfload->numTracks, track);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000104 mfload->numTracks = track;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000105 }
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000106 return mfload;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000107 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000108
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000109 if(id == ID_MTRK)
110 {
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000111 mfload->tracks[track] = readTrack(file);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000112 track++;
113 } else
114 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000115 printf("SKIPPING TRACK");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000116 int len = readFourBytes(file);
117 while(--len)
118 readChar(file);
119 }
120 }
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000121
122 rb->close(file);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000123 return mfload;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000124
125}
126
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000127/* Global again. Not static. What if track 1 ends on a running status event
128 * and then track 2 starts loading */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000129
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000130int rStatus = 0;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000131/* Returns 0 if done, 1 if keep going */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000132int readEvent(int file, void * dest)
133{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000134 struct Event dummy;
135 struct Event * ev = (struct Event *) dest;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000136
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000137 if(ev == NULL)
138 ev = &dummy; /* If we are just counting events instead of loading them */
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000139
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000140 ev->delta = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000141
142
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000143 int t=readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000144
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000145 if((t&0x80) == 0x80) /* if not a running status event */
146 {
147 ev->status = t;
148 if(t == 0xFF)
149 {
150 ev->d1 = readChar(file);
151 ev->len = readVarData(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000152
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000153 /* Allocate and read in the data block */
154 if(dest != NULL)
155 {
156 ev->evData = readData(file, ev->len);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000157/* printf("\nDATA: <%s>", ev->evData); */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000158 }
159 else
160 {
161 /*
Stepan Moskovchenko47efba82006-05-03 05:18:18 +0000162 * Don't allocate anything, just see how much it would take
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000163 * To make memory usage efficient
164 */
165 unsigned int a=0;
166 for(a=0; a<ev->len; a++)
167 readChar(file); //Skip skip
168 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000169
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000170 if(ev->d1 == 0x2F)
171 {
172 return 0; /* Termination meta-event */
173 }
174 } else /* If part of a running status event */
175 {
176 rStatus = t;
177 ev->status = t;
178 ev->d1 = readChar(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000179
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000180 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
181 {
182 ev->d2 = readChar(file);
183 } else
184 ev->d2 = 127;
185 }
186 } else /* Running Status */
187 {
188 ev->status = rStatus;
189 ev->d1 = t;
190 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
191 {
192 ev->d2 = readChar(file);
193 } else
194 ev->d2 = 127;
195 }
196 return 1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000197}
198
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000199struct Track * readTrack(int file)
200{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000201 struct Track * trk = (struct Track *)malloc(sizeof(struct Track));
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000202 rb->memset(trk, 0, sizeof(struct Track));
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000203
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000204 trk->size = readFourBytes(file);
205 trk->pos = 0;
206 trk->delta = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000207
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000208 int numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000209
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000210 int pos = rb->lseek(file, 0, SEEK_CUR);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000211
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000212 while(readEvent(file, NULL)) /* Memory saving technique */
213 numEvents++; /* Attempt to read in events, count how many */
214 /* THEN allocate memory and read them in */
215 rb->lseek(file, pos, SEEK_SET);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000216
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000217 int trackSize = (numEvents+1) * sizeof(struct Event);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000218 void * dataPtr = malloc(trackSize);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000219 trk->dataBlock = dataPtr;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000220
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000221 numEvents=0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000222
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000223 while(readEvent(file, dataPtr))
224 {
225 if(trackSize < dataPtr-trk->dataBlock)
226 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000227 printf("Track parser memory out of bounds");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000228 exit(1);
229 }
230 dataPtr+=sizeof(struct Event);
231 numEvents++;
232 }
233 trk->numEvents = numEvents;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000234
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000235 return trk;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000236}
237
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000238int 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