diff options
Diffstat (limited to 'apps/plugins/midi/midifile.c')
-rw-r--r-- | apps/plugins/midi/midifile.c | 305 |
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 | |||
21 | extern struct plugin_api * rb; | ||
22 | |||
23 | struct Track * readTrack(int file); | ||
24 | int readID(int file); | ||
25 | void bail(const char *); | ||
26 | |||
27 | struct 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 | |||
108 | int rStatus = 0; | ||
109 | |||
110 | //Returns 0 if done, 1 if keep going | ||
111 | int 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 | |||
179 | struct 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 | |||
220 | int 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 | |||
241 | int 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 | |||
250 | int 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 | ||
257 | int 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 | ||
274 | void 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 | |||
300 | void bail(const char * err) | ||
301 | { | ||
302 | printf("\nERROR: %s\n", err); | ||
303 | exit(0); | ||
304 | } | ||
305 | |||