rev |
line source |
nuclear@0
|
1 /*-
|
nuclear@0
|
2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraĆa <trasz@FreeBSD.org>
|
nuclear@0
|
3 * All rights reserved.
|
nuclear@0
|
4 *
|
nuclear@0
|
5 * Redistribution and use in source and binary forms, with or without
|
nuclear@0
|
6 * modification, are permitted provided that the following conditions
|
nuclear@0
|
7 * are met:
|
nuclear@0
|
8 * 1. Redistributions of source code must retain the above copyright
|
nuclear@0
|
9 * notice, this list of conditions and the following disclaimer.
|
nuclear@0
|
10 * 2. Redistributions in binary form must reproduce the above copyright
|
nuclear@0
|
11 * notice, this list of conditions and the following disclaimer in the
|
nuclear@0
|
12 * documentation and/or other materials provided with the distribution.
|
nuclear@0
|
13 *
|
nuclear@0
|
14 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
|
nuclear@0
|
15 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
nuclear@0
|
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
nuclear@0
|
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
nuclear@0
|
18 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
nuclear@0
|
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
nuclear@0
|
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
nuclear@0
|
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
nuclear@0
|
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
nuclear@0
|
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
25 *
|
nuclear@0
|
26 */
|
nuclear@0
|
27
|
nuclear@0
|
28 /**
|
nuclear@0
|
29 * \file
|
nuclear@0
|
30 *
|
nuclear@0
|
31 * Standard MIDI File format loader.
|
nuclear@0
|
32 *
|
nuclear@0
|
33 */
|
nuclear@0
|
34
|
nuclear@0
|
35 /* Reference: http://www.borg.com/~jglatt/tech/midifile.htm */
|
nuclear@0
|
36
|
nuclear@0
|
37 #include <stdlib.h>
|
nuclear@0
|
38 #include <string.h>
|
nuclear@0
|
39 #include <assert.h>
|
nuclear@0
|
40 #include <math.h>
|
nuclear@0
|
41 #include <errno.h>
|
nuclear@0
|
42 #include <ctype.h>
|
nuclear@0
|
43 #ifdef __MINGW32__
|
nuclear@0
|
44 #include <windows.h>
|
nuclear@0
|
45 #else /* ! __MINGW32__ */
|
nuclear@0
|
46 #include <arpa/inet.h>
|
nuclear@0
|
47 #endif /* ! __MINGW32__ */
|
nuclear@0
|
48 #include "smf.h"
|
nuclear@0
|
49 #include "smf_private.h"
|
nuclear@0
|
50
|
nuclear@0
|
51 /**
|
nuclear@0
|
52 * Returns pointer to the next SMF chunk in smf->buffer, based on length of the previous one.
|
nuclear@0
|
53 * Returns NULL in case of error.
|
nuclear@0
|
54 */
|
nuclear@0
|
55 static struct chunk_header_struct *
|
nuclear@0
|
56 next_chunk(smf_t *smf)
|
nuclear@0
|
57 {
|
nuclear@0
|
58 struct chunk_header_struct *chunk;
|
nuclear@0
|
59 void *next_chunk_ptr;
|
nuclear@0
|
60
|
nuclear@0
|
61 assert(smf->file_buffer != NULL);
|
nuclear@0
|
62 assert(smf->file_buffer_length > 0);
|
nuclear@0
|
63 assert(smf->next_chunk_offset >= 0);
|
nuclear@0
|
64
|
nuclear@0
|
65 if (smf->next_chunk_offset + sizeof(struct chunk_header_struct) >= smf->file_buffer_length) {
|
nuclear@0
|
66 fg_critical("SMF warning: no more chunks left.");
|
nuclear@0
|
67 return (NULL);
|
nuclear@0
|
68 }
|
nuclear@0
|
69
|
nuclear@0
|
70 next_chunk_ptr = (unsigned char *)smf->file_buffer + smf->next_chunk_offset;
|
nuclear@0
|
71
|
nuclear@0
|
72 chunk = (struct chunk_header_struct *)next_chunk_ptr;
|
nuclear@0
|
73
|
nuclear@0
|
74 if (!isalpha(chunk->id[0]) || !isalpha(chunk->id[1]) || !isalpha(chunk->id[2]) || !isalpha(chunk->id[3])) {
|
nuclear@0
|
75 fg_critical("SMF error: chunk signature contains at least one non-alphanumeric byte.");
|
nuclear@0
|
76 return (NULL);
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 /*
|
nuclear@0
|
80 * XXX: On SPARC, after compiling with "-fast" option there will be SIGBUS here.
|
nuclear@0
|
81 * Please compile with -xmemalign=8i".
|
nuclear@0
|
82 */
|
nuclear@0
|
83 smf->next_chunk_offset += sizeof(struct chunk_header_struct) + ntohl(chunk->length);
|
nuclear@0
|
84
|
nuclear@0
|
85 if (smf->next_chunk_offset > smf->file_buffer_length) {
|
nuclear@0
|
86 fg_critical("SMF warning: malformed chunk; truncated file?");
|
nuclear@0
|
87 smf->next_chunk_offset = smf->file_buffer_length;
|
nuclear@0
|
88 }
|
nuclear@0
|
89
|
nuclear@0
|
90 return (chunk);
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 /**
|
nuclear@0
|
94 * Returns 1, iff signature of the "chunk" is the same as string passed as "signature".
|
nuclear@0
|
95 */
|
nuclear@0
|
96 static int
|
nuclear@0
|
97 chunk_signature_matches(const struct chunk_header_struct *chunk, const char *signature)
|
nuclear@0
|
98 {
|
nuclear@0
|
99 if (!memcmp(chunk->id, signature, 4))
|
nuclear@0
|
100 return (1);
|
nuclear@0
|
101
|
nuclear@0
|
102 return (0);
|
nuclear@0
|
103 }
|
nuclear@0
|
104
|
nuclear@0
|
105 /**
|
nuclear@0
|
106 * Verifies if MThd header looks OK. Returns 0 iff it does.
|
nuclear@0
|
107 */
|
nuclear@0
|
108 static int
|
nuclear@0
|
109 parse_mthd_header(smf_t *smf)
|
nuclear@0
|
110 {
|
nuclear@0
|
111 int len;
|
nuclear@0
|
112 struct chunk_header_struct *mthd, *tmp_mthd;
|
nuclear@0
|
113
|
nuclear@0
|
114 /* Make sure compiler didn't do anything stupid. */
|
nuclear@0
|
115 assert(sizeof(struct chunk_header_struct) == 8);
|
nuclear@0
|
116
|
nuclear@0
|
117 /*
|
nuclear@0
|
118 * We could just do "mthd = smf->file_buffer;" here, but this way we wouldn't
|
nuclear@0
|
119 * get useful error messages.
|
nuclear@0
|
120 */
|
nuclear@0
|
121 if (smf->file_buffer_length < 6) {
|
nuclear@0
|
122 fg_critical("SMF error: file is too short, it cannot be a MIDI file.");
|
nuclear@0
|
123
|
nuclear@0
|
124 return (-1);
|
nuclear@0
|
125 }
|
nuclear@0
|
126
|
nuclear@0
|
127 tmp_mthd = smf->file_buffer;
|
nuclear@0
|
128
|
nuclear@0
|
129 if (!chunk_signature_matches(tmp_mthd, "MThd")) {
|
nuclear@0
|
130 fg_critical("SMF error: MThd signature not found, is that a MIDI file?");
|
nuclear@0
|
131
|
nuclear@0
|
132 return (-2);
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 /* Ok, now use next_chunk(). */
|
nuclear@0
|
136 mthd = next_chunk(smf);
|
nuclear@0
|
137 if (mthd == NULL)
|
nuclear@0
|
138 return (-3);
|
nuclear@0
|
139
|
nuclear@0
|
140 assert(mthd == tmp_mthd);
|
nuclear@0
|
141
|
nuclear@0
|
142 len = ntohl(mthd->length);
|
nuclear@0
|
143 if (len != 6) {
|
nuclear@0
|
144 fg_critical("SMF error: MThd chunk length %d, must be 6.", len);
|
nuclear@0
|
145
|
nuclear@0
|
146 return (-4);
|
nuclear@0
|
147 }
|
nuclear@0
|
148
|
nuclear@0
|
149 return (0);
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 /**
|
nuclear@0
|
153 * Parses MThd chunk, filling "smf" structure with values extracted from it. Returns 0 iff everything went OK.
|
nuclear@0
|
154 */
|
nuclear@0
|
155 static int
|
nuclear@0
|
156 parse_mthd_chunk(smf_t *smf)
|
nuclear@0
|
157 {
|
nuclear@0
|
158 signed char first_byte_of_division, second_byte_of_division;
|
nuclear@0
|
159
|
nuclear@0
|
160 struct mthd_chunk_struct *mthd;
|
nuclear@0
|
161
|
nuclear@0
|
162 assert(sizeof(struct mthd_chunk_struct) == 14);
|
nuclear@0
|
163
|
nuclear@0
|
164 if (parse_mthd_header(smf))
|
nuclear@0
|
165 return (1);
|
nuclear@0
|
166
|
nuclear@0
|
167 mthd = (struct mthd_chunk_struct *)smf->file_buffer;
|
nuclear@0
|
168
|
nuclear@0
|
169 smf->format = ntohs(mthd->format);
|
nuclear@0
|
170 if (smf->format < 0 || smf->format > 2) {
|
nuclear@0
|
171 fg_critical("SMF error: bad MThd format field value: %d, valid values are 0-2, inclusive.", smf->format);
|
nuclear@0
|
172 return (-1);
|
nuclear@0
|
173 }
|
nuclear@0
|
174
|
nuclear@0
|
175 if (smf->format == 2) {
|
nuclear@0
|
176 fg_critical("SMF file uses format #2, no support for that yet.");
|
nuclear@0
|
177 return (-2);
|
nuclear@0
|
178 }
|
nuclear@0
|
179
|
nuclear@0
|
180 smf->expected_number_of_tracks = ntohs(mthd->number_of_tracks);
|
nuclear@0
|
181 if (smf->expected_number_of_tracks <= 0) {
|
nuclear@0
|
182 fg_critical("SMF error: bad number of tracks: %d, must be greater than zero.", smf->expected_number_of_tracks);
|
nuclear@0
|
183 return (-3);
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 /* XXX: endianess? */
|
nuclear@0
|
187 first_byte_of_division = *((signed char *)&(mthd->division));
|
nuclear@0
|
188 second_byte_of_division = *((signed char *)&(mthd->division) + 1);
|
nuclear@0
|
189
|
nuclear@0
|
190 if (first_byte_of_division >= 0) {
|
nuclear@0
|
191 smf->ppqn = ntohs(mthd->division);
|
nuclear@0
|
192 smf->frames_per_second = 0;
|
nuclear@0
|
193 smf->resolution = 0;
|
nuclear@0
|
194 } else {
|
nuclear@0
|
195 smf->ppqn = 0;
|
nuclear@0
|
196 smf->frames_per_second = - first_byte_of_division;
|
nuclear@0
|
197 smf->resolution = second_byte_of_division;
|
nuclear@0
|
198 }
|
nuclear@0
|
199
|
nuclear@0
|
200 if (smf->ppqn == 0) {
|
nuclear@0
|
201 fg_critical("SMF file uses FPS timing instead of PPQN, no support for that yet.");
|
nuclear@0
|
202 return (-4);
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 return (0);
|
nuclear@0
|
206 }
|
nuclear@0
|
207
|
nuclear@0
|
208 /**
|
nuclear@0
|
209 * Interprets Variable Length Quantity pointed at by "buf" and puts its value into "value" and number
|
nuclear@0
|
210 * of bytes consumed into "len", making sure it does not read past "buf" + "buffer_length".
|
nuclear@0
|
211 * Explanation of Variable Length Quantities is here: http://www.borg.com/~jglatt/tech/midifile/vari.htm
|
nuclear@0
|
212 * Returns 0 iff everything went OK, different value in case of error.
|
nuclear@0
|
213 */
|
nuclear@0
|
214 static int
|
nuclear@0
|
215 extract_vlq(const unsigned char *buf, const int buffer_length, int *value, int *len)
|
nuclear@0
|
216 {
|
nuclear@0
|
217 int val = 0;
|
nuclear@0
|
218 const unsigned char *c = buf;
|
nuclear@0
|
219
|
nuclear@0
|
220 assert(buffer_length > 0);
|
nuclear@0
|
221
|
nuclear@0
|
222 for (;;) {
|
nuclear@0
|
223 if (c >= buf + buffer_length) {
|
nuclear@0
|
224 fg_critical("End of buffer in extract_vlq().");
|
nuclear@0
|
225 return (-1);
|
nuclear@0
|
226 }
|
nuclear@0
|
227
|
nuclear@0
|
228 val = (val << 7) + (*c & 0x7F);
|
nuclear@0
|
229
|
nuclear@0
|
230 if (*c & 0x80)
|
nuclear@0
|
231 c++;
|
nuclear@0
|
232 else
|
nuclear@0
|
233 break;
|
nuclear@0
|
234 };
|
nuclear@0
|
235
|
nuclear@0
|
236 *value = val;
|
nuclear@0
|
237 *len = c - buf + 1;
|
nuclear@0
|
238
|
nuclear@0
|
239 if (*len > 4) {
|
nuclear@0
|
240 fg_critical("SMF error: Variable Length Quantities longer than four bytes are not supported yet.");
|
nuclear@0
|
241 return (-2);
|
nuclear@0
|
242 }
|
nuclear@0
|
243
|
nuclear@0
|
244 return (0);
|
nuclear@0
|
245 }
|
nuclear@0
|
246
|
nuclear@0
|
247 /**
|
nuclear@0
|
248 * Returns 1 if the given byte is a valid status byte, 0 otherwise.
|
nuclear@0
|
249 */
|
nuclear@0
|
250 int
|
nuclear@0
|
251 is_status_byte(const unsigned char status)
|
nuclear@0
|
252 {
|
nuclear@0
|
253 return (status & 0x80);
|
nuclear@0
|
254 }
|
nuclear@0
|
255
|
nuclear@0
|
256 static int
|
nuclear@0
|
257 is_sysex_byte(const unsigned char status)
|
nuclear@0
|
258 {
|
nuclear@0
|
259 if (status == 0xF0)
|
nuclear@0
|
260 return (1);
|
nuclear@0
|
261
|
nuclear@0
|
262 return (0);
|
nuclear@0
|
263 }
|
nuclear@0
|
264
|
nuclear@0
|
265 static int
|
nuclear@0
|
266 is_escape_byte(const unsigned char status)
|
nuclear@0
|
267 {
|
nuclear@0
|
268 if (status == 0xF7)
|
nuclear@0
|
269 return (1);
|
nuclear@0
|
270
|
nuclear@0
|
271 return (0);
|
nuclear@0
|
272 }
|
nuclear@0
|
273
|
nuclear@0
|
274 /**
|
nuclear@0
|
275 * Just like expected_message_length(), but only for System Exclusive messages.
|
nuclear@0
|
276 * Note that value returned by this thing here is the length of SysEx "on the wire",
|
nuclear@0
|
277 * not the number of bytes that this sysex takes in the file - in SMF format sysex
|
nuclear@0
|
278 * contains VLQ telling how many bytes it takes, "on the wire" format does not have
|
nuclear@0
|
279 * this.
|
nuclear@0
|
280 */
|
nuclear@0
|
281 static int
|
nuclear@0
|
282 expected_sysex_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes)
|
nuclear@0
|
283 {
|
nuclear@0
|
284 int sysex_length, len;
|
nuclear@0
|
285
|
nuclear@0
|
286 assert(status == 0xF0);
|
nuclear@0
|
287
|
nuclear@0
|
288 if (buffer_length < 3) {
|
nuclear@0
|
289 fg_critical("SMF error: end of buffer in expected_sysex_length().");
|
nuclear@0
|
290 return (-1);
|
nuclear@0
|
291 }
|
nuclear@0
|
292
|
nuclear@0
|
293 if (extract_vlq(second_byte, buffer_length, &sysex_length, &len))
|
nuclear@0
|
294 return (-1);
|
nuclear@0
|
295
|
nuclear@0
|
296 if (consumed_bytes != NULL)
|
nuclear@0
|
297 *consumed_bytes = len;
|
nuclear@0
|
298
|
nuclear@0
|
299 /* +1, because the length does not include status byte. */
|
nuclear@0
|
300 return (sysex_length + 1);
|
nuclear@0
|
301 }
|
nuclear@0
|
302
|
nuclear@0
|
303 static int
|
nuclear@0
|
304 expected_escaped_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes)
|
nuclear@0
|
305 {
|
nuclear@0
|
306 /* -1, because we do not want to account for 0x7F status. */
|
nuclear@0
|
307 return (expected_sysex_length(status, second_byte, buffer_length, consumed_bytes) - 1);
|
nuclear@0
|
308 }
|
nuclear@0
|
309
|
nuclear@0
|
310 /**
|
nuclear@0
|
311 * Returns expected length of the midi message (including the status byte), in bytes, for the given status byte.
|
nuclear@0
|
312 * The "second_byte" points to the expected second byte of the MIDI message. "buffer_length" is the buffer
|
nuclear@0
|
313 * length limit, counting from "second_byte". Returns value < 0 iff there was an error.
|
nuclear@0
|
314 */
|
nuclear@0
|
315 static int
|
nuclear@0
|
316 expected_message_length(unsigned char status, const unsigned char *second_byte, const int buffer_length)
|
nuclear@0
|
317 {
|
nuclear@0
|
318 /* Make sure this really is a valid status byte. */
|
nuclear@0
|
319 assert(is_status_byte(status));
|
nuclear@0
|
320
|
nuclear@0
|
321 /* We cannot use this routine for sysexes. */
|
nuclear@0
|
322 assert(!is_sysex_byte(status));
|
nuclear@0
|
323
|
nuclear@0
|
324 /* We cannot use this routine for escaped events. */
|
nuclear@0
|
325 assert(!is_escape_byte(status));
|
nuclear@0
|
326
|
nuclear@0
|
327 /* Buffer length may be zero, for e.g. realtime messages. */
|
nuclear@0
|
328 assert(buffer_length >= 0);
|
nuclear@0
|
329
|
nuclear@0
|
330 /* Is this a metamessage? */
|
nuclear@0
|
331 if (status == 0xFF) {
|
nuclear@0
|
332 if (buffer_length < 2) {
|
nuclear@0
|
333 fg_critical("SMF error: end of buffer in expected_message_length().");
|
nuclear@0
|
334 return (-1);
|
nuclear@0
|
335 }
|
nuclear@0
|
336
|
nuclear@0
|
337 /*
|
nuclear@0
|
338 * Format of this kind of messages is like this: 0xFF 0xwhatever 0xlength and then "length" bytes.
|
nuclear@0
|
339 * Second byte points to this: ^^^^^^^^^^
|
nuclear@0
|
340 */
|
nuclear@0
|
341 return (*(second_byte + 1) + 3);
|
nuclear@0
|
342 }
|
nuclear@0
|
343
|
nuclear@0
|
344 if ((status & 0xF0) == 0xF0) {
|
nuclear@0
|
345 switch (status) {
|
nuclear@0
|
346 case 0xF2: /* Song Position Pointer. */
|
nuclear@0
|
347 return (3);
|
nuclear@0
|
348
|
nuclear@0
|
349 case 0xF1: /* MTC Quarter Frame. */
|
nuclear@0
|
350 case 0xF3: /* Song Select. */
|
nuclear@0
|
351 return (2);
|
nuclear@0
|
352
|
nuclear@0
|
353 case 0xF6: /* Tune Request. */
|
nuclear@0
|
354 case 0xF8: /* MIDI Clock. */
|
nuclear@0
|
355 case 0xF9: /* Tick. */
|
nuclear@0
|
356 case 0xFA: /* MIDI Start. */
|
nuclear@0
|
357 case 0xFB: /* MIDI Continue. */
|
nuclear@0
|
358 case 0xFC: /* MIDI Stop. */
|
nuclear@0
|
359 case 0xFE: /* Active Sense. */
|
nuclear@0
|
360 return (1);
|
nuclear@0
|
361
|
nuclear@0
|
362 default:
|
nuclear@0
|
363 fg_critical("SMF error: unknown 0xFx-type status byte '0x%x'.", status);
|
nuclear@0
|
364 return (-2);
|
nuclear@0
|
365 }
|
nuclear@0
|
366 }
|
nuclear@0
|
367
|
nuclear@0
|
368 /* Filter out the channel. */
|
nuclear@0
|
369 status &= 0xF0;
|
nuclear@0
|
370
|
nuclear@0
|
371 switch (status) {
|
nuclear@0
|
372 case 0x80: /* Note Off. */
|
nuclear@0
|
373 case 0x90: /* Note On. */
|
nuclear@0
|
374 case 0xA0: /* AfterTouch. */
|
nuclear@0
|
375 case 0xB0: /* Control Change. */
|
nuclear@0
|
376 case 0xE0: /* Pitch Wheel. */
|
nuclear@0
|
377 return (3);
|
nuclear@0
|
378
|
nuclear@0
|
379 case 0xC0: /* Program Change. */
|
nuclear@0
|
380 case 0xD0: /* Channel Pressure. */
|
nuclear@0
|
381 return (2);
|
nuclear@0
|
382
|
nuclear@0
|
383 default:
|
nuclear@0
|
384 fg_critical("SMF error: unknown status byte '0x%x'.", status);
|
nuclear@0
|
385 return (-3);
|
nuclear@0
|
386 }
|
nuclear@0
|
387 }
|
nuclear@0
|
388
|
nuclear@0
|
389 static int
|
nuclear@0
|
390 extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
|
nuclear@0
|
391 {
|
nuclear@0
|
392 int status, message_length, vlq_length;
|
nuclear@0
|
393 const unsigned char *c = buf;
|
nuclear@0
|
394
|
nuclear@0
|
395 status = *buf;
|
nuclear@0
|
396
|
nuclear@0
|
397 assert(is_sysex_byte(status));
|
nuclear@0
|
398
|
nuclear@0
|
399 c++;
|
nuclear@0
|
400
|
nuclear@0
|
401 message_length = expected_sysex_length(status, c, buffer_length - 1, &vlq_length);
|
nuclear@0
|
402
|
nuclear@0
|
403 if (message_length < 0)
|
nuclear@0
|
404 return (-3);
|
nuclear@0
|
405
|
nuclear@0
|
406 c += vlq_length;
|
nuclear@0
|
407
|
nuclear@0
|
408 if (vlq_length + message_length >= buffer_length) {
|
nuclear@0
|
409 fg_critical("End of buffer in extract_sysex_event().");
|
nuclear@0
|
410 return (-5);
|
nuclear@0
|
411 }
|
nuclear@0
|
412
|
nuclear@0
|
413 event->midi_buffer_length = message_length;
|
nuclear@0
|
414 event->midi_buffer = malloc(event->midi_buffer_length);
|
nuclear@0
|
415 if (event->midi_buffer == NULL) {
|
nuclear@0
|
416 fg_critical("Cannot allocate memory in extract_sysex_event(): %s", strerror(errno));
|
nuclear@0
|
417 return (-4);
|
nuclear@0
|
418 }
|
nuclear@0
|
419
|
nuclear@0
|
420 event->midi_buffer[0] = status;
|
nuclear@0
|
421 memcpy(event->midi_buffer + 1, c, message_length - 1);
|
nuclear@0
|
422
|
nuclear@0
|
423 *len = vlq_length + message_length;
|
nuclear@0
|
424
|
nuclear@0
|
425 return (0);
|
nuclear@0
|
426 }
|
nuclear@0
|
427
|
nuclear@0
|
428 static int
|
nuclear@0
|
429 extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
|
nuclear@0
|
430 {
|
nuclear@0
|
431 int status, message_length, vlq_length;
|
nuclear@0
|
432 const unsigned char *c = buf;
|
nuclear@0
|
433
|
nuclear@0
|
434 status = *buf;
|
nuclear@0
|
435
|
nuclear@0
|
436 assert(is_escape_byte(status));
|
nuclear@0
|
437
|
nuclear@0
|
438 c++;
|
nuclear@0
|
439
|
nuclear@0
|
440 message_length = expected_escaped_length(status, c, buffer_length - 1, &vlq_length);
|
nuclear@0
|
441
|
nuclear@0
|
442 if (message_length < 0)
|
nuclear@0
|
443 return (-3);
|
nuclear@0
|
444
|
nuclear@0
|
445 c += vlq_length;
|
nuclear@0
|
446
|
nuclear@0
|
447 if (vlq_length + message_length >= buffer_length) {
|
nuclear@0
|
448 fg_critical("End of buffer in extract_escaped_event().");
|
nuclear@0
|
449 return (-5);
|
nuclear@0
|
450 }
|
nuclear@0
|
451
|
nuclear@0
|
452 event->midi_buffer_length = message_length;
|
nuclear@0
|
453 event->midi_buffer = malloc(event->midi_buffer_length);
|
nuclear@0
|
454 if (event->midi_buffer == NULL) {
|
nuclear@0
|
455 fg_critical("Cannot allocate memory in extract_escaped_event(): %s", strerror(errno));
|
nuclear@0
|
456 return (-4);
|
nuclear@0
|
457 }
|
nuclear@0
|
458
|
nuclear@0
|
459 memcpy(event->midi_buffer, c, message_length);
|
nuclear@0
|
460
|
nuclear@0
|
461 if (smf_event_is_valid(event)) {
|
nuclear@0
|
462 fg_critical("Escaped event is invalid.");
|
nuclear@0
|
463 return (-1);
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466 if (smf_event_is_system_realtime(event) || smf_event_is_system_common(event)) {
|
nuclear@0
|
467 fg_warning("Escaped event is not System Realtime nor System Common.");
|
nuclear@0
|
468 }
|
nuclear@0
|
469
|
nuclear@0
|
470 *len = vlq_length + message_length;
|
nuclear@0
|
471
|
nuclear@0
|
472 return (0);
|
nuclear@0
|
473 }
|
nuclear@0
|
474
|
nuclear@0
|
475
|
nuclear@0
|
476 /**
|
nuclear@0
|
477 * Puts MIDI data extracted from from "buf" into "event" and number of consumed bytes into "len".
|
nuclear@0
|
478 * In case valid status is not found, it uses "last_status" (so called "running status").
|
nuclear@0
|
479 * Returns 0 iff everything went OK, value < 0 in case of error.
|
nuclear@0
|
480 */
|
nuclear@0
|
481 static int
|
nuclear@0
|
482 extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
|
nuclear@0
|
483 {
|
nuclear@0
|
484 int status, message_length;
|
nuclear@0
|
485 const unsigned char *c = buf;
|
nuclear@0
|
486
|
nuclear@0
|
487 assert(buffer_length > 0);
|
nuclear@0
|
488
|
nuclear@0
|
489 /* Is the first byte the status byte? */
|
nuclear@0
|
490 if (is_status_byte(*c)) {
|
nuclear@0
|
491 status = *c;
|
nuclear@0
|
492 c++;
|
nuclear@0
|
493
|
nuclear@0
|
494 } else {
|
nuclear@0
|
495 /* No, we use running status then. */
|
nuclear@0
|
496 status = last_status;
|
nuclear@0
|
497 }
|
nuclear@0
|
498
|
nuclear@0
|
499 if (!is_status_byte(status)) {
|
nuclear@0
|
500 fg_critical("SMF error: bad status byte (MSB is zero).");
|
nuclear@0
|
501 return (-1);
|
nuclear@0
|
502 }
|
nuclear@0
|
503
|
nuclear@0
|
504 if (is_sysex_byte(status))
|
nuclear@0
|
505 return (extract_sysex_event(buf, buffer_length, event, len, last_status));
|
nuclear@0
|
506
|
nuclear@0
|
507 if (is_escape_byte(status))
|
nuclear@0
|
508 return (extract_escaped_event(buf, buffer_length, event, len, last_status));
|
nuclear@0
|
509
|
nuclear@0
|
510 /* At this point, "c" points to first byte following the status byte. */
|
nuclear@0
|
511 message_length = expected_message_length(status, c, buffer_length - (c - buf));
|
nuclear@0
|
512
|
nuclear@0
|
513 if (message_length < 0)
|
nuclear@0
|
514 return (-3);
|
nuclear@0
|
515
|
nuclear@0
|
516 if (message_length - 1 > buffer_length - (c - buf)) {
|
nuclear@0
|
517 fg_critical("End of buffer in extract_midi_event().");
|
nuclear@0
|
518 return (-5);
|
nuclear@0
|
519 }
|
nuclear@0
|
520
|
nuclear@0
|
521 event->midi_buffer_length = message_length;
|
nuclear@0
|
522 event->midi_buffer = malloc(event->midi_buffer_length);
|
nuclear@0
|
523 if (event->midi_buffer == NULL) {
|
nuclear@0
|
524 fg_critical("Cannot allocate memory in extract_midi_event(): %s", strerror(errno));
|
nuclear@0
|
525 return (-4);
|
nuclear@0
|
526 }
|
nuclear@0
|
527
|
nuclear@0
|
528 event->midi_buffer[0] = status;
|
nuclear@0
|
529 memcpy(event->midi_buffer + 1, c, message_length - 1);
|
nuclear@0
|
530
|
nuclear@0
|
531 *len = c + message_length - 1 - buf;
|
nuclear@0
|
532
|
nuclear@0
|
533 return (0);
|
nuclear@0
|
534 }
|
nuclear@0
|
535
|
nuclear@0
|
536 /**
|
nuclear@0
|
537 * Locates, basing on track->next_event_offset, the next event data in track->buffer,
|
nuclear@0
|
538 * interprets it, allocates smf_event_t and fills it properly. Returns smf_event_t
|
nuclear@0
|
539 * or NULL, if there was an error. Allocating event means adding it to the track;
|
nuclear@0
|
540 * see smf_event_new().
|
nuclear@0
|
541 */
|
nuclear@0
|
542 static smf_event_t *
|
nuclear@0
|
543 parse_next_event(smf_track_t *track)
|
nuclear@0
|
544 {
|
nuclear@0
|
545 int time = 0, len, buffer_length;
|
nuclear@0
|
546 unsigned char *c, *start;
|
nuclear@0
|
547
|
nuclear@0
|
548 smf_event_t *event = smf_event_new();
|
nuclear@0
|
549 if (event == NULL)
|
nuclear@0
|
550 goto error;
|
nuclear@0
|
551
|
nuclear@0
|
552 c = start = (unsigned char *)track->file_buffer + track->next_event_offset;
|
nuclear@0
|
553
|
nuclear@0
|
554 assert(track->file_buffer != NULL);
|
nuclear@0
|
555 assert(track->file_buffer_length > 0);
|
nuclear@0
|
556 assert(track->next_event_offset > 0);
|
nuclear@0
|
557
|
nuclear@0
|
558 buffer_length = track->file_buffer_length - track->next_event_offset;
|
nuclear@0
|
559 assert(buffer_length > 0);
|
nuclear@0
|
560
|
nuclear@0
|
561 /* First, extract time offset from previous event. */
|
nuclear@0
|
562 if (extract_vlq(c, buffer_length, &time, &len))
|
nuclear@0
|
563 goto error;
|
nuclear@0
|
564
|
nuclear@0
|
565 c += len;
|
nuclear@0
|
566 buffer_length -= len;
|
nuclear@0
|
567
|
nuclear@0
|
568 if (buffer_length <= 0)
|
nuclear@0
|
569 goto error;
|
nuclear@0
|
570
|
nuclear@0
|
571 /* Now, extract the actual event. */
|
nuclear@0
|
572 if (extract_midi_event(c, buffer_length, event, &len, track->last_status))
|
nuclear@0
|
573 goto error;
|
nuclear@0
|
574
|
nuclear@0
|
575 c += len;
|
nuclear@0
|
576 buffer_length -= len;
|
nuclear@0
|
577 track->last_status = event->midi_buffer[0];
|
nuclear@0
|
578 track->next_event_offset += c - start;
|
nuclear@0
|
579
|
nuclear@0
|
580 smf_track_add_event_delta_pulses(track, event, time);
|
nuclear@0
|
581
|
nuclear@0
|
582 return (event);
|
nuclear@0
|
583
|
nuclear@0
|
584 error:
|
nuclear@0
|
585 if (event != NULL)
|
nuclear@0
|
586 smf_event_delete(event);
|
nuclear@0
|
587
|
nuclear@0
|
588 return (NULL);
|
nuclear@0
|
589 }
|
nuclear@0
|
590
|
nuclear@0
|
591 /**
|
nuclear@0
|
592 * Takes "len" characters starting in "buf", making sure it does not access past the length of the buffer,
|
nuclear@0
|
593 * and makes ordinary, zero-terminated string from it. May return NULL if there was any problem.
|
nuclear@0
|
594 */
|
nuclear@0
|
595 static char *
|
nuclear@0
|
596 make_string(const unsigned char *buf, const int buffer_length, int len)
|
nuclear@0
|
597 {
|
nuclear@0
|
598 char *str;
|
nuclear@0
|
599
|
nuclear@0
|
600 assert(buffer_length > 0);
|
nuclear@0
|
601 assert(len > 0);
|
nuclear@0
|
602
|
nuclear@0
|
603 if (len > buffer_length) {
|
nuclear@0
|
604 fg_critical("End of buffer in make_string().");
|
nuclear@0
|
605
|
nuclear@0
|
606 len = buffer_length;
|
nuclear@0
|
607 }
|
nuclear@0
|
608
|
nuclear@0
|
609 str = malloc(len + 1);
|
nuclear@0
|
610 if (str == NULL) {
|
nuclear@0
|
611 fg_critical("Cannot allocate memory in make_string().");
|
nuclear@0
|
612 return (NULL);
|
nuclear@0
|
613 }
|
nuclear@0
|
614
|
nuclear@0
|
615 memcpy(str, buf, len);
|
nuclear@0
|
616 str[len] = '\0';
|
nuclear@0
|
617
|
nuclear@0
|
618 return (str);
|
nuclear@0
|
619 }
|
nuclear@0
|
620
|
nuclear@0
|
621 /**
|
nuclear@0
|
622 * \return 1, if passed a metaevent containing text, that is, Text, Copyright,
|
nuclear@0
|
623 * Sequence/Track Name, Instrument, Lyric, Marker, Cue Point, Program Name,
|
nuclear@0
|
624 * or Device Name; 0 otherwise.
|
nuclear@0
|
625 */
|
nuclear@0
|
626 int
|
nuclear@0
|
627 smf_event_is_textual(const smf_event_t *event)
|
nuclear@0
|
628 {
|
nuclear@0
|
629 if (!smf_event_is_metadata(event))
|
nuclear@0
|
630 return (0);
|
nuclear@0
|
631
|
nuclear@0
|
632 if (event->midi_buffer_length < 4)
|
nuclear@0
|
633 return (0);
|
nuclear@0
|
634
|
nuclear@0
|
635 if (event->midi_buffer[3] < 1 && event->midi_buffer[3] > 9)
|
nuclear@0
|
636 return (0);
|
nuclear@0
|
637
|
nuclear@0
|
638 return (1);
|
nuclear@0
|
639 }
|
nuclear@0
|
640
|
nuclear@0
|
641 /**
|
nuclear@0
|
642 * Extracts text from "textual metaevents", such as Text or Lyric.
|
nuclear@0
|
643 *
|
nuclear@0
|
644 * \return Zero-terminated string extracted from "text events" or NULL, if there was any problem.
|
nuclear@0
|
645 */
|
nuclear@0
|
646 char *
|
nuclear@0
|
647 smf_event_extract_text(const smf_event_t *event)
|
nuclear@0
|
648 {
|
nuclear@0
|
649 int string_length = -1, length_length = -1;
|
nuclear@0
|
650
|
nuclear@0
|
651 if (!smf_event_is_textual(event))
|
nuclear@0
|
652 return (NULL);
|
nuclear@0
|
653
|
nuclear@0
|
654 if (event->midi_buffer_length < 3) {
|
nuclear@0
|
655 fg_critical("smf_event_extract_text: truncated MIDI message.");
|
nuclear@0
|
656 return (NULL);
|
nuclear@0
|
657 }
|
nuclear@0
|
658
|
nuclear@0
|
659 extract_vlq((void *)&(event->midi_buffer[2]), event->midi_buffer_length - 2, &string_length, &length_length);
|
nuclear@0
|
660
|
nuclear@0
|
661 if (string_length <= 0) {
|
nuclear@0
|
662 fg_critical("smf_event_extract_text: truncated MIDI message.");
|
nuclear@0
|
663 return (NULL);
|
nuclear@0
|
664 }
|
nuclear@0
|
665
|
nuclear@0
|
666 return (make_string((void *)(&event->midi_buffer[2] + length_length), event->midi_buffer_length - 2 - length_length, string_length));
|
nuclear@0
|
667 }
|
nuclear@0
|
668
|
nuclear@0
|
669 /**
|
nuclear@0
|
670 * Verify if the next chunk really is MTrk chunk, and if so, initialize some track variables and return 0.
|
nuclear@0
|
671 * Return different value otherwise.
|
nuclear@0
|
672 */
|
nuclear@0
|
673 static int
|
nuclear@0
|
674 parse_mtrk_header(smf_track_t *track)
|
nuclear@0
|
675 {
|
nuclear@0
|
676 struct chunk_header_struct *mtrk;
|
nuclear@0
|
677
|
nuclear@0
|
678 /* Make sure compiler didn't do anything stupid. */
|
nuclear@0
|
679 assert(sizeof(struct chunk_header_struct) == 8);
|
nuclear@0
|
680 assert(track->smf != NULL);
|
nuclear@0
|
681
|
nuclear@0
|
682 mtrk = next_chunk(track->smf);
|
nuclear@0
|
683
|
nuclear@0
|
684 if (mtrk == NULL)
|
nuclear@0
|
685 return (-1);
|
nuclear@0
|
686
|
nuclear@0
|
687 if (!chunk_signature_matches(mtrk, "MTrk")) {
|
nuclear@0
|
688 fg_warning("SMF warning: Expected MTrk signature, got %c%c%c%c instead; ignoring this chunk.",
|
nuclear@0
|
689 mtrk->id[0], mtrk->id[1], mtrk->id[2], mtrk->id[3]);
|
nuclear@0
|
690
|
nuclear@0
|
691 return (-2);
|
nuclear@0
|
692 }
|
nuclear@0
|
693
|
nuclear@0
|
694 track->file_buffer = mtrk;
|
nuclear@0
|
695 track->file_buffer_length = sizeof(struct chunk_header_struct) + ntohl(mtrk->length);
|
nuclear@0
|
696 track->next_event_offset = sizeof(struct chunk_header_struct);
|
nuclear@0
|
697
|
nuclear@0
|
698 return (0);
|
nuclear@0
|
699 }
|
nuclear@0
|
700
|
nuclear@0
|
701 /**
|
nuclear@0
|
702 * Return 1 if event is end-of-the-track, 0 otherwise.
|
nuclear@0
|
703 */
|
nuclear@0
|
704 static int
|
nuclear@0
|
705 event_is_end_of_track(const smf_event_t *event)
|
nuclear@0
|
706 {
|
nuclear@0
|
707 if (event->midi_buffer[0] == 0xFF && event->midi_buffer[1] == 0x2F)
|
nuclear@0
|
708 return (1);
|
nuclear@0
|
709
|
nuclear@0
|
710 return (0);
|
nuclear@0
|
711 }
|
nuclear@0
|
712
|
nuclear@0
|
713 /**
|
nuclear@0
|
714 * \return Nonzero, if event is as long as it should be, from the MIDI specification point of view.
|
nuclear@0
|
715 * Does not work for SysExes - it doesn't recognize internal structure of SysEx.
|
nuclear@0
|
716 */
|
nuclear@0
|
717 int
|
nuclear@0
|
718 smf_event_length_is_valid(const smf_event_t *event)
|
nuclear@0
|
719 {
|
nuclear@0
|
720 assert(event);
|
nuclear@0
|
721 assert(event->midi_buffer);
|
nuclear@0
|
722
|
nuclear@0
|
723 if (event->midi_buffer_length < 1)
|
nuclear@0
|
724 return (0);
|
nuclear@0
|
725
|
nuclear@0
|
726 /* We cannot use expected_message_length on sysexes. */
|
nuclear@0
|
727 if (smf_event_is_sysex(event))
|
nuclear@0
|
728 return (1);
|
nuclear@0
|
729
|
nuclear@0
|
730 if (event->midi_buffer_length != expected_message_length(event->midi_buffer[0],
|
nuclear@0
|
731 &(event->midi_buffer[1]), event->midi_buffer_length - 1)) {
|
nuclear@0
|
732
|
nuclear@0
|
733 return (0);
|
nuclear@0
|
734 }
|
nuclear@0
|
735
|
nuclear@0
|
736 return (1);
|
nuclear@0
|
737 }
|
nuclear@0
|
738
|
nuclear@0
|
739 /**
|
nuclear@0
|
740 * \return Nonzero, if MIDI data in the event is valid, 0 otherwise. For example,
|
nuclear@0
|
741 * it checks if event length is correct.
|
nuclear@0
|
742 */
|
nuclear@0
|
743 /* XXX: this routine requires some more work to detect more errors. */
|
nuclear@0
|
744 int
|
nuclear@0
|
745 smf_event_is_valid(const smf_event_t *event)
|
nuclear@0
|
746 {
|
nuclear@0
|
747 assert(event);
|
nuclear@0
|
748 assert(event->midi_buffer);
|
nuclear@0
|
749 assert(event->midi_buffer_length >= 1);
|
nuclear@0
|
750
|
nuclear@0
|
751 if (!is_status_byte(event->midi_buffer[0])) {
|
nuclear@0
|
752 fg_critical("First byte of MIDI message is not a valid status byte.");
|
nuclear@0
|
753
|
nuclear@0
|
754 return (0);
|
nuclear@0
|
755 }
|
nuclear@0
|
756
|
nuclear@0
|
757 if (!smf_event_length_is_valid(event))
|
nuclear@0
|
758 return (0);
|
nuclear@0
|
759
|
nuclear@0
|
760 return (1);
|
nuclear@0
|
761 }
|
nuclear@0
|
762
|
nuclear@0
|
763 /**
|
nuclear@0
|
764 * Parse events and put it on the track.
|
nuclear@0
|
765 */
|
nuclear@0
|
766 static int
|
nuclear@0
|
767 parse_mtrk_chunk(smf_track_t *track)
|
nuclear@0
|
768 {
|
nuclear@0
|
769 smf_event_t *event;
|
nuclear@0
|
770
|
nuclear@0
|
771 if (parse_mtrk_header(track))
|
nuclear@0
|
772 return (-1);
|
nuclear@0
|
773
|
nuclear@0
|
774 for (;;) {
|
nuclear@0
|
775 event = parse_next_event(track);
|
nuclear@0
|
776
|
nuclear@0
|
777 /* Couldn't parse an event? */
|
nuclear@0
|
778 if (event == NULL) {
|
nuclear@0
|
779 fg_critical("Unable to parse MIDI event; truncating track.");
|
nuclear@0
|
780 if (smf_track_add_eot_delta_pulses(track, 0) != 0) {
|
nuclear@0
|
781 fg_critical("smf_track_add_eot_delta_pulses failed.");
|
nuclear@0
|
782 return (-2);
|
nuclear@0
|
783 }
|
nuclear@0
|
784 break;
|
nuclear@0
|
785 }
|
nuclear@0
|
786
|
nuclear@0
|
787 assert(smf_event_is_valid(event));
|
nuclear@0
|
788
|
nuclear@0
|
789 if (event_is_end_of_track(event))
|
nuclear@0
|
790 break;
|
nuclear@0
|
791 }
|
nuclear@0
|
792
|
nuclear@0
|
793 track->file_buffer = NULL;
|
nuclear@0
|
794 track->file_buffer_length = 0;
|
nuclear@0
|
795 track->next_event_offset = -1;
|
nuclear@0
|
796
|
nuclear@0
|
797 return (0);
|
nuclear@0
|
798 }
|
nuclear@0
|
799
|
nuclear@0
|
800 /**
|
nuclear@0
|
801 * Allocate buffer of proper size and read file contents into it. Close file afterwards.
|
nuclear@0
|
802 */
|
nuclear@0
|
803 static int
|
nuclear@0
|
804 load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *file_name)
|
nuclear@0
|
805 {
|
nuclear@0
|
806 FILE *stream = fopen(file_name, "rb");
|
nuclear@0
|
807
|
nuclear@0
|
808 if (stream == NULL) {
|
nuclear@0
|
809 fg_critical("Cannot open input file: %s", strerror(errno));
|
nuclear@0
|
810
|
nuclear@0
|
811 return (-1);
|
nuclear@0
|
812 }
|
nuclear@0
|
813
|
nuclear@0
|
814 if (fseek(stream, 0, SEEK_END)) {
|
nuclear@0
|
815 fg_critical("fseek(3) failed: %s", strerror(errno));
|
nuclear@0
|
816
|
nuclear@0
|
817 return (-2);
|
nuclear@0
|
818 }
|
nuclear@0
|
819
|
nuclear@0
|
820 *file_buffer_length = ftell(stream);
|
nuclear@0
|
821 if (*file_buffer_length == -1) {
|
nuclear@0
|
822 fg_critical("ftell(3) failed: %s", strerror(errno));
|
nuclear@0
|
823
|
nuclear@0
|
824 return (-3);
|
nuclear@0
|
825 }
|
nuclear@0
|
826
|
nuclear@0
|
827 if (fseek(stream, 0, SEEK_SET)) {
|
nuclear@0
|
828 fg_critical("fseek(3) failed: %s", strerror(errno));
|
nuclear@0
|
829
|
nuclear@0
|
830 return (-4);
|
nuclear@0
|
831 }
|
nuclear@0
|
832
|
nuclear@0
|
833 *file_buffer = malloc(*file_buffer_length);
|
nuclear@0
|
834 if (*file_buffer == NULL) {
|
nuclear@0
|
835 fg_critical("malloc(3) failed: %s", strerror(errno));
|
nuclear@0
|
836
|
nuclear@0
|
837 return (-5);
|
nuclear@0
|
838 }
|
nuclear@0
|
839
|
nuclear@0
|
840 if (fread(*file_buffer, 1, *file_buffer_length, stream) != *file_buffer_length) {
|
nuclear@0
|
841 fg_critical("fread(3) failed: %s", strerror(errno));
|
nuclear@0
|
842
|
nuclear@0
|
843 return (-6);
|
nuclear@0
|
844 }
|
nuclear@0
|
845
|
nuclear@0
|
846 if (fclose(stream)) {
|
nuclear@0
|
847 fg_critical("fclose(3) failed: %s", strerror(errno));
|
nuclear@0
|
848
|
nuclear@0
|
849 return (-7);
|
nuclear@0
|
850 }
|
nuclear@0
|
851
|
nuclear@0
|
852 return (0);
|
nuclear@0
|
853 }
|
nuclear@0
|
854
|
nuclear@0
|
855 /**
|
nuclear@0
|
856 * Creates new SMF and fills it with data loaded from the given buffer.
|
nuclear@0
|
857 * \return SMF or NULL, if loading failed.
|
nuclear@0
|
858 */
|
nuclear@0
|
859 smf_t *
|
nuclear@0
|
860 smf_load_from_memory(const void *buffer, const int buffer_length)
|
nuclear@0
|
861 {
|
nuclear@0
|
862 int i;
|
nuclear@0
|
863
|
nuclear@0
|
864 smf_t *smf = smf_new();
|
nuclear@0
|
865
|
nuclear@0
|
866 smf->file_buffer = (void *)buffer;
|
nuclear@0
|
867 smf->file_buffer_length = buffer_length;
|
nuclear@0
|
868 smf->next_chunk_offset = 0;
|
nuclear@0
|
869
|
nuclear@0
|
870 if (parse_mthd_chunk(smf))
|
nuclear@0
|
871 return (NULL);
|
nuclear@0
|
872
|
nuclear@0
|
873 for (i = 1; i <= smf->expected_number_of_tracks; i++) {
|
nuclear@0
|
874 smf_track_t *track = smf_track_new();
|
nuclear@0
|
875 if (track == NULL)
|
nuclear@0
|
876 return (NULL);
|
nuclear@0
|
877
|
nuclear@0
|
878 smf_add_track(smf, track);
|
nuclear@0
|
879
|
nuclear@0
|
880 /* Skip unparseable chunks. */
|
nuclear@0
|
881 if (parse_mtrk_chunk(track)) {
|
nuclear@0
|
882 fg_warning("SMF warning: Cannot load track.");
|
nuclear@0
|
883 smf_track_delete(track);
|
nuclear@0
|
884 }
|
nuclear@0
|
885
|
nuclear@0
|
886 track->file_buffer = NULL;
|
nuclear@0
|
887 track->file_buffer_length = 0;
|
nuclear@0
|
888 track->next_event_offset = -1;
|
nuclear@0
|
889 }
|
nuclear@0
|
890
|
nuclear@0
|
891 if (smf->expected_number_of_tracks != smf->number_of_tracks) {
|
nuclear@0
|
892 fg_warning("SMF warning: MThd header declared %d tracks, but only %d found; continuing anyway.",
|
nuclear@0
|
893 smf->expected_number_of_tracks, smf->number_of_tracks);
|
nuclear@0
|
894
|
nuclear@0
|
895 smf->expected_number_of_tracks = smf->number_of_tracks;
|
nuclear@0
|
896 }
|
nuclear@0
|
897
|
nuclear@0
|
898 smf->file_buffer = NULL;
|
nuclear@0
|
899 smf->file_buffer_length = 0;
|
nuclear@0
|
900 smf->next_chunk_offset = -1;
|
nuclear@0
|
901
|
nuclear@0
|
902 return (smf);
|
nuclear@0
|
903 }
|
nuclear@0
|
904
|
nuclear@0
|
905 /**
|
nuclear@0
|
906 * Loads SMF file.
|
nuclear@0
|
907 *
|
nuclear@0
|
908 * \param file_name Path to the file.
|
nuclear@0
|
909 * \return SMF or NULL, if loading failed.
|
nuclear@0
|
910 */
|
nuclear@0
|
911 smf_t *
|
nuclear@0
|
912 smf_load(const char *file_name)
|
nuclear@0
|
913 {
|
nuclear@0
|
914 int file_buffer_length;
|
nuclear@0
|
915 void *file_buffer;
|
nuclear@0
|
916 smf_t *smf;
|
nuclear@0
|
917
|
nuclear@0
|
918 if (load_file_into_buffer(&file_buffer, &file_buffer_length, file_name))
|
nuclear@0
|
919 return (NULL);
|
nuclear@0
|
920
|
nuclear@0
|
921 smf = smf_load_from_memory(file_buffer, file_buffer_length);
|
nuclear@0
|
922
|
nuclear@0
|
923 memset(file_buffer, 0, file_buffer_length);
|
nuclear@0
|
924 free(file_buffer);
|
nuclear@0
|
925
|
nuclear@0
|
926 if (smf == NULL)
|
nuclear@0
|
927 return (NULL);
|
nuclear@0
|
928
|
nuclear@0
|
929 smf_rewind(smf);
|
nuclear@0
|
930
|
nuclear@0
|
931 return (smf);
|
nuclear@0
|
932 }
|
nuclear@0
|
933
|