summaryrefslogtreecommitdiff
path: root/apps/plugins/midi/midifile.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/midi/midifile.c')
-rw-r--r--apps/plugins/midi/midifile.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/apps/plugins/midi/midifile.c b/apps/plugins/midi/midifile.c
new file mode 100644
index 0000000000..08efb73529
--- /dev/null
+++ b/apps/plugins/midi/midifile.c
@@ -0,0 +1,305 @@
1/***************************************************************************
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);
25void bail(const char *);
26
27struct MIDIfile * loadFile(char * filename)
28{
29 struct MIDIfile * mf;
30 int file = rb->open (filename, O_RDONLY);
31
32 if(file==0)
33 {
34 bail("Could not open file\n");
35 }
36
37 mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile));
38
39 if(mf==NULL)
40 {
41 rb->close(file);
42 bail("Could not allocate memory for MIDIfile struct\n");
43 }
44
45 rb->memset(mf, 0, sizeof(struct MIDIfile));
46
47 if(readID(file) != ID_MTHD)
48 {
49 rb->close(file);
50 bail("Invalid file header chunk.");
51 }
52
53 if(readFourBytes(file)!=6)
54 {
55 rb->close(file);
56 bail("Header chunk size invalid.");
57 }
58
59 if(readTwoBytes(file)==2)
60 {
61 rb->close(file);
62 bail("MIDI file type not supported");
63 }
64
65 mf->numTracks = readTwoBytes(file);
66 mf->div = readTwoBytes(file);
67
68 int track=0;
69
70 printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div);
71
72// return;
73
74
75 while(! eof(file) && track < mf->numTracks)
76 {
77 unsigned char id = readID(file);
78
79
80 if(id == ID_EOF)
81 {
82 if(mf->numTracks != track)
83 {
84 printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track);
85 mf->numTracks = track;
86 }
87 return mf;
88 }
89
90 if(id == ID_MTRK)
91 {
92 mf->tracks[track] = readTrack(file);
93 //exit(0);
94 track++;
95 } else
96 {
97 printf("\n SKIPPING TRACK");
98 int len = readFourBytes(file);
99 while(--len)
100 readChar(file);
101 }
102 }
103 return mf;
104
105}
106
107
108int rStatus = 0;
109
110//Returns 0 if done, 1 if keep going
111int readEvent(int file, void * dest)
112{
113 struct Event dummy;
114 struct Event * ev = (struct Event *) dest;
115
116 if(ev == NULL)
117 ev = &dummy; //If we are just counting events instead of loading them
118
119 ev->delta = readVarData(file);
120
121
122 int t=readChar(file);
123
124 if((t&0x80) == 0x80) //if not a running status event
125 {
126 ev->status = t;
127 if(t == 0xFF)
128 {
129 ev->d1 = readChar(file);
130 ev->len = readVarData(file);
131
132 //Allocate and read in the data block
133 if(dest != NULL)
134 {
135 ev->evData = readData(file, ev->len);
136 printf("\nDATA: <%s>", ev->evData);
137 }
138 else
139 {
140 //Don't allocate anything, just see how much it would tale
141 //To make memory usage efficient
142
143 int a=0;
144 for(a=0; a<ev->len; a++)
145 readChar(file); //Skip skip
146 }
147
148 if(ev->d1 == 0x2F)
149 {
150 return 0; //Termination meta-event
151 }
152 } else //If part of a running status event
153 {
154 rStatus = t;
155 ev->status = t;
156 ev->d1 = readChar(file);
157
158 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
159 {
160 ev->d2 = readChar(file);
161 } else
162 ev->d2 = 127;
163 }
164 } else //Running Status
165 {
166 ev->status = rStatus;
167 ev->d1 = t;
168 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
169 {
170 ev->d2 = readChar(file);
171 } else
172 ev->d2 = 127;
173 }
174 return 1;
175}
176
177
178
179struct Track * readTrack(int file)
180{
181 struct Track * trk = (struct Track *)allocate(sizeof(struct Track));
182 rb->memset(trk, 0, sizeof(struct Track));
183
184 trk->size = readFourBytes(file);
185 trk->pos = 0;
186 trk->delta = 0;
187
188 int len=0;
189 int numEvents=0;
190
191 int pos = rb->lseek(file, 0, SEEK_CUR);
192
193 while(readEvent(file, NULL)) //Memory saving technique
194 numEvents++; //Attempt to read in events, count how many
195 //THEN allocate memory and read them in
196 rb->lseek(file, pos, SEEK_SET);
197
198 int trackSize = (numEvents+1) * sizeof(struct Event);
199 void * dataPtr = allocate(trackSize);
200 trk->dataBlock = dataPtr;
201
202 numEvents=0;
203
204 while(readEvent(file, dataPtr))
205 {
206 if(trackSize < dataPtr-trk->dataBlock)
207 {
208 printf("\nTrack parser memory out of bounds");
209 exit(1);
210 }
211 dataPtr+=sizeof(struct Event);
212 numEvents++;
213 }
214 trk->numEvents = numEvents;
215
216 return trk;
217}
218
219
220int readID(int file)
221{
222 char id[5];
223 id[4]=0;
224 BYTE a;
225
226 for(a=0; a<4; a++)
227 id[a]=readChar(file);
228 if(eof(file))
229 {
230 printf("\End of file reached.");
231 return ID_EOF;
232 }
233 if(rb->strcmp(id, "MThd")==0)
234 return ID_MTHD;
235 if(rb->strcmp(id, "MTrk")==0)
236 return ID_MTRK;
237 return ID_UNKNOWN;
238}
239
240
241int readFourBytes(int file)
242{
243 int data=0;
244 BYTE a=0;
245 for(a=0; a<4; a++)
246 data=(data<<8)+readChar(file);
247 return data;
248}
249
250int readTwoBytes(int file)
251{
252 int data=(readChar(file)<<8)+readChar(file);
253 return data;
254}
255
256//This came from the MIDI file format guide
257int readVarData(int file)
258{
259 unsigned int value;
260 char c;
261 if ( (value = readChar(file)) & 0x80 )
262 {
263 value &= 0x7F;
264 do
265 {
266 value = (value << 7) + ((c = readChar(file)) & 0x7F);
267 } while (c & 0x80);
268 }
269 return(value);
270}
271
272//This function should not be needed because we
273//can just release the whole memory buffer at once
274void unloadFile(struct MIDIfile * mf)
275{
276 if(mf == NULL)
277 return;
278 int a=0;
279 //Unload each track
280 for(a=0; a<mf->numTracks; a++)
281 {
282 int b=0;
283
284 if(mf->tracks[a] != NULL)
285 for(b=0; b<mf->tracks[a]->numEvents; b++)
286 {
287 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
288 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
289 }
290
291 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
292 free(mf->tracks[a]->dataBlock); //Unload the event block
293
294 if(mf->tracks[a]!=NULL)
295 free(mf->tracks[a]); //Unload the track structure itself
296 }
297 free(mf); //Unload the main struct
298}
299
300void bail(const char * err)
301{
302 printf("\nERROR: %s\n", err);
303 exit(0);
304}
305