1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
24 struct Track
* readTrack(int file
);
27 struct MIDIfile midi_file IBSS_ATTR
;
29 struct MIDIfile
* loadFile(const char * filename
)
31 struct MIDIfile
* mfload
;
32 int file
= rb
->open (filename
, O_RDONLY
);
36 printf("Could not open file");
42 rb
->memset(mfload
, 0, sizeof(struct MIDIfile
));
44 int fileID
= readID(file
);
49 printf("Detected RMID file");
50 printf("Looking for MThd header");
52 rb
->read(file
, &dummy
, 16);
53 if(readID(file
) != ID_MTHD
)
56 printf("Invalid MIDI header within RIFF.");
63 printf("Invalid file header chunk.");
68 if(readFourBytes(file
)!=6)
71 printf("Header chunk size invalid.");
75 if(readTwoBytes(file
)==2)
78 printf("MIDI file type 2 not supported");
82 mfload
->numTracks
= readTwoBytes(file
);
83 mfload
->div
= readTwoBytes(file
);
87 printf("File has %d tracks.", mfload
->numTracks
);
89 while(! eof(file
) && track
< mfload
->numTracks
)
91 unsigned char id
= readID(file
);
96 if(mfload
->numTracks
!= track
)
98 printf("Warning: file claims to have %d tracks. I only see %d here.", mfload
->numTracks
, track
);
99 mfload
->numTracks
= track
;
107 mfload
->tracks
[track
] = readTrack(file
);
111 printf("SKIPPING TRACK");
112 int len
= readFourBytes(file
);
123 /* Global again. Not static. What if track 1 ends on a running status event
124 * and then track 2 starts loading */
127 /* Returns 0 if done, 1 if keep going */
128 int readEvent(int file
, void * dest
)
131 struct Event
* ev
= (struct Event
*) dest
;
134 ev
= &dummy
; /* If we are just counting events instead of loading them */
136 ev
->delta
= readVarData(file
);
139 int t
=readChar(file
);
141 if((t
&0x80) == 0x80) /* if not a running status event */
146 ev
->d1
= readChar(file
);
147 ev
->len
= readVarData(file
);
149 /* Allocate and read in the data block */
152 /* Null-terminate for text events */
153 ev
->evData
= malloc(ev
->len
+1); /* Extra byte for the null termination */
155 rb
->read(file
, ev
->evData
, ev
->len
);
156 ev
->evData
[ev
->len
] = 0;
160 case 0x01: /* Generic text */
162 printf("Text: %s", ev
->evData
);
166 case 0x02: /* A copyright string within the file */
168 printf("Copyright: %s", ev
->evData
);
172 case 0x03: /* Sequence of track name */
174 printf("Name: %s", ev
->evData
);
178 case 0x04: /* Instrument (synth) name */
180 printf("Instrument: %s", ev
->evData
);
184 case 0x05: /* Lyrics. These appear on the tracks at the right times */
185 { /* Usually only a small 'piece' of the lyrics. */
186 /* Maybe the sequencer should print these at play time? */
187 printf("Lyric: %s", ev
->evData
);
191 case 0x06: /* Text marker */
193 printf("Marker: %s", ev
->evData
);
198 case 0x07: /* Cue point */
200 printf("Cue point: %s", ev
->evData
);
204 case 0x08: /* Program name */
206 printf("Patch: %s", ev
->evData
);
211 case 0x09: /* Device name. Very much irrelevant here, though. */
213 printf("Port: %s", ev
->evData
);
221 * Don't allocate anything, just see how much it would take
222 * To make memory usage efficient
225 for(a
=0; a
<ev
->len
; a
++)
226 readChar(file
); //Skip skip
231 return 0; /* Termination meta-event */
233 } else /* If part of a running status event */
237 ev
->d1
= readChar(file
);
239 if ( ((t
& 0xF0) != 0xD0) && ((t
& 0xF0) != 0xC0) && ((t
& 0xF0) > 0x40) )
241 ev
->d2
= readChar(file
);
245 } else /* Running Status */
247 ev
->status
= rStatus
;
249 if ( ((rStatus
& 0xF0) != 0xD0) && ((rStatus
& 0xF0) != 0xC0) && ((rStatus
& 0xF0) > 0x40) )
251 ev
->d2
= readChar(file
);
259 struct Track tracks
[48] IBSS_ATTR
;
261 struct Track
* readTrack(int file
)
263 struct Track
* trk
= &tracks
[curr_track
++];
264 rb
->memset(trk
, 0, sizeof(struct Track
));
266 trk
->size
= readFourBytes(file
);
272 int pos
= rb
->lseek(file
, 0, SEEK_CUR
);
274 while(readEvent(file
, NULL
)) /* Memory saving technique */
275 numEvents
++; /* Attempt to read in events, count how many */
276 /* THEN allocate memory and read them in */
277 rb
->lseek(file
, pos
, SEEK_SET
);
279 int trackSize
= (numEvents
+1) * sizeof(struct Event
);
280 void * dataPtr
= malloc(trackSize
);
281 trk
->dataBlock
= dataPtr
;
285 while(readEvent(file
, dataPtr
))
287 if(trackSize
< dataPtr
-trk
->dataBlock
)
289 printf("Track parser memory out of bounds");
292 dataPtr
+=sizeof(struct Event
);
295 trk
->numEvents
= numEvents
;
307 id
[a
]=readChar(file
);
310 printf("End of file reached.");
313 if(rb
->strcmp(id
, "MThd")==0)
315 if(rb
->strcmp(id
, "MTrk")==0)
317 if(rb
->strcmp(id
, "RIFF")==0)
323 int readFourBytes(int file
)
328 data
=(data
<<8)+readChar(file
);
332 int readTwoBytes(int file
)
334 int data
=(readChar(file
)<<8)+readChar(file
);
338 /* This came from the MIDI file format guide */
339 int readVarData(int file
)
343 if ( (value
= readChar(file
)) & 0x80 )
348 value
= (value
<< 7) + ((c
= readChar(file
)) & 0x7F);
356 void unloadFile(struct MIDIfile * mf)
362 for(a=0; a<mf->numTracks; a++)
366 if(mf->tracks[a] != NULL)
367 for(b=0; b<mf->tracks[a]->numEvents; b++)
369 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
370 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
373 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
374 free(mf->tracks[a]->dataBlock); //Unload the event block
376 if(mf->tracks[a]!=NULL)
377 free(mf->tracks[a]); //Unload the track structure itself
379 free(mf); //Unload the main struct