FS#12756 by Marek Salaba - update Czech translation
[maemo-rb.git] / apps / plugins / midi / midifile.c
blob86544fd9443c11aeb0a2d62856811a0e0222137d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Stepan Moskovchenko
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "midiutil.h"
23 #include "midifile.h"
25 struct Track * readTrack(int file);
26 int readID(int file);
28 struct MIDIfile midi_file IBSS_ATTR;
30 struct MIDIfile * loadFile(const char * filename)
32 struct MIDIfile * mfload;
33 int file = rb->open (filename, O_RDONLY);
35 if(file < 0)
37 midi_debug("Could not open file");
38 return NULL;
41 mfload = &midi_file;
43 rb->memset(mfload, 0, sizeof(struct MIDIfile));
45 int fileID = readID(file);
46 if(fileID != ID_MTHD)
48 if(fileID == ID_RIFF)
50 midi_debug("Detected RMID file");
51 midi_debug("Looking for MThd header");
52 char dummy[17];
53 rb->read(file, &dummy, 16);
54 if(readID(file) != ID_MTHD)
56 rb->close(file);
57 midi_debug("Invalid MIDI header within RIFF.");
58 return NULL;
61 } else
63 rb->close(file);
64 midi_debug("Invalid file header chunk.");
65 return NULL;
69 if(readFourBytes(file)!=6)
71 rb->close(file);
72 midi_debug("Header chunk size invalid.");
73 return NULL;
76 if(readTwoBytes(file)==2)
78 rb->close(file);
79 midi_debug("MIDI file type 2 not supported");
80 return NULL;
83 mfload->numTracks = readTwoBytes(file);
84 mfload->div = readTwoBytes(file);
86 int track=0;
88 midi_debug("File has %d tracks.", mfload->numTracks);
90 while(! eof(file) && track < mfload->numTracks)
92 unsigned char id = readID(file);
95 if(id == ID_EOF)
97 if(mfload->numTracks != track)
99 midi_debug("Warning: file claims to have %d tracks. I only see %d here.", mfload->numTracks, track);
100 mfload->numTracks = track;
102 rb->close(file);
103 return mfload;
106 if(id == ID_MTRK)
108 mfload->tracks[track] = readTrack(file);
109 track++;
110 } else
112 midi_debug("SKIPPING TRACK");
113 int len = readFourBytes(file);
114 while(--len)
115 readChar(file);
119 rb->close(file);
120 return mfload;
124 /* Global again. Not static. What if track 1 ends on a running status event
125 * and then track 2 starts loading */
127 int rStatus = 0;
128 /* Returns 0 if done, 1 if keep going */
129 static int readEvent(int file, void * dest)
131 struct Event dummy;
132 struct Event * ev = (struct Event *) dest;
134 if(ev == NULL)
135 ev = &dummy; /* If we are just counting events instead of loading them */
137 ev->delta = readVarData(file);
140 int t=readChar(file);
142 if((t&0x80) == 0x80) /* if not a running status event */
144 ev->status = t;
145 if(t == 0xFF)
147 ev->d1 = readChar(file);
148 ev->len = readVarData(file);
150 /* Allocate and read in the data block */
151 if(dest != NULL)
153 /* Null-terminate for text events */
154 ev->evData = malloc(ev->len+1); /* Extra byte for the null termination */
156 rb->read(file, ev->evData, ev->len);
157 ev->evData[ev->len] = 0;
159 switch(ev->d1)
161 case 0x01: /* Generic text */
163 midi_debug("Text: %s", ev->evData);
164 break;
167 case 0x02: /* A copyright string within the file */
169 midi_debug("Copyright: %s", ev->evData);
170 break;
173 case 0x03: /* Sequence of track name */
175 midi_debug("Name: %s", ev->evData);
176 break;
179 case 0x04: /* Instrument (synth) name */
181 midi_debug("Instrument: %s", ev->evData);
182 break;
185 case 0x05: /* Lyrics. These appear on the tracks at the right times */
186 { /* Usually only a small 'piece' of the lyrics. */
187 /* Maybe the sequencer should print these at play time? */
188 midi_debug("Lyric: %s", ev->evData);
189 break;
192 case 0x06: /* Text marker */
194 midi_debug("Marker: %s", ev->evData);
195 break;
199 case 0x07: /* Cue point */
201 midi_debug("Cue point: %s", ev->evData);
202 break;
205 case 0x08: /* Program name */
207 midi_debug("Patch: %s", ev->evData);
208 break;
212 case 0x09: /* Device name. Very much irrelevant here, though. */
214 midi_debug("Port: %s", ev->evData);
215 break;
219 else
222 * Don't allocate anything, just see how much it would take
223 * To make memory usage efficient
225 unsigned int a=0;
226 for(a=0; a<ev->len; a++)
227 readChar(file); //Skip skip
230 if(ev->d1 == 0x2F)
232 return 0; /* Termination meta-event */
234 } else /* If part of a running status event */
236 rStatus = t;
237 ev->status = t;
238 ev->d1 = readChar(file);
240 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
242 ev->d2 = readChar(file);
243 } else
244 ev->d2 = 127;
246 } else /* Running Status */
248 ev->status = rStatus;
249 ev->d1 = t;
250 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
252 ev->d2 = readChar(file);
253 } else
254 ev->d2 = 127;
256 return 1;
259 int curr_track = 0;
260 struct Track tracks[48] IBSS_ATTR;
262 struct Track * readTrack(int file)
264 struct Track * trk = &tracks[curr_track++];
265 rb->memset(trk, 0, sizeof(struct Track));
267 trk->size = readFourBytes(file);
268 trk->pos = 0;
269 trk->delta = 0;
271 int numEvents=0;
273 int pos = rb->lseek(file, 0, SEEK_CUR);
275 while(readEvent(file, NULL)) /* Memory saving technique */
276 numEvents++; /* Attempt to read in events, count how many */
277 /* THEN allocate memory and read them in */
278 rb->lseek(file, pos, SEEK_SET);
280 int trackSize = (numEvents+1) * sizeof(struct Event);
281 void * dataPtr = malloc(trackSize);
282 trk->dataBlock = dataPtr;
284 numEvents=0;
286 while(readEvent(file, dataPtr))
288 if(trackSize < dataPtr-trk->dataBlock)
290 midi_debug("Track parser memory out of bounds");
291 exit(1);
293 dataPtr+=sizeof(struct Event);
294 numEvents++;
296 trk->numEvents = numEvents;
298 return trk;
301 int readID(int file)
303 char id[5];
304 id[4]=0;
305 BYTE a;
307 for(a=0; a<4; a++)
308 id[a]=readChar(file);
309 if(eof(file))
311 midi_debug("End of file reached.");
312 return ID_EOF;
314 if(rb->strcmp(id, "MThd")==0)
315 return ID_MTHD;
316 if(rb->strcmp(id, "MTrk")==0)
317 return ID_MTRK;
318 if(rb->strcmp(id, "RIFF")==0)
319 return ID_RIFF;
320 return ID_UNKNOWN;
324 int readFourBytes(int file)
326 int data=0;
327 BYTE a=0;
328 for(a=0; a<4; a++)
329 data=(data<<8)+readChar(file);
330 return data;
333 int readTwoBytes(int file)
335 int data=(readChar(file)<<8)+readChar(file);
336 return data;
339 /* This came from the MIDI file format guide */
340 int readVarData(int file)
342 unsigned int value;
343 char c;
344 if ( (value = readChar(file)) & 0x80 )
346 value &= 0x7F;
349 value = (value << 7) + ((c = readChar(file)) & 0x7F);
350 } while (c & 0x80);
352 return(value);
357 void unloadFile(struct MIDIfile * mf)
359 if(mf == NULL)
360 return;
361 int a=0;
362 //Unload each track
363 for(a=0; a<mf->numTracks; a++)
365 int b=0;
367 if(mf->tracks[a] != NULL)
368 for(b=0; b<mf->tracks[a]->numEvents; b++)
370 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
371 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
374 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
375 free(mf->tracks[a]->dataBlock); //Unload the event block
377 if(mf->tracks[a]!=NULL)
378 free(mf->tracks[a]); //Unload the track structure itself
380 free(mf); //Unload the main struct