smflite
diff src/smf_load.c @ 0:4264abea8b06
smf-lite initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 26 Jan 2012 11:25:11 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/smf_load.c Thu Jan 26 11:25:11 2012 +0200 1.3 @@ -0,0 +1,933 @@ 1.4 +/*- 1.5 + * Copyright (c) 2007, 2008 Edward Tomasz NapieraĆa <trasz@FreeBSD.org> 1.6 + * All rights reserved. 1.7 + * 1.8 + * Redistribution and use in source and binary forms, with or without 1.9 + * modification, are permitted provided that the following conditions 1.10 + * are met: 1.11 + * 1. Redistributions of source code must retain the above copyright 1.12 + * notice, this list of conditions and the following disclaimer. 1.13 + * 2. Redistributions in binary form must reproduce the above copyright 1.14 + * notice, this list of conditions and the following disclaimer in the 1.15 + * documentation and/or other materials provided with the distribution. 1.16 + * 1.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 1.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 1.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 1.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 1.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 1.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 1.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 1.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 1.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 1.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.28 + * 1.29 + */ 1.30 + 1.31 +/** 1.32 + * \file 1.33 + * 1.34 + * Standard MIDI File format loader. 1.35 + * 1.36 + */ 1.37 + 1.38 +/* Reference: http://www.borg.com/~jglatt/tech/midifile.htm */ 1.39 + 1.40 +#include <stdlib.h> 1.41 +#include <string.h> 1.42 +#include <assert.h> 1.43 +#include <math.h> 1.44 +#include <errno.h> 1.45 +#include <ctype.h> 1.46 +#ifdef __MINGW32__ 1.47 +#include <windows.h> 1.48 +#else /* ! __MINGW32__ */ 1.49 +#include <arpa/inet.h> 1.50 +#endif /* ! __MINGW32__ */ 1.51 +#include "smf.h" 1.52 +#include "smf_private.h" 1.53 + 1.54 +/** 1.55 + * Returns pointer to the next SMF chunk in smf->buffer, based on length of the previous one. 1.56 + * Returns NULL in case of error. 1.57 + */ 1.58 +static struct chunk_header_struct * 1.59 +next_chunk(smf_t *smf) 1.60 +{ 1.61 + struct chunk_header_struct *chunk; 1.62 + void *next_chunk_ptr; 1.63 + 1.64 + assert(smf->file_buffer != NULL); 1.65 + assert(smf->file_buffer_length > 0); 1.66 + assert(smf->next_chunk_offset >= 0); 1.67 + 1.68 + if (smf->next_chunk_offset + sizeof(struct chunk_header_struct) >= smf->file_buffer_length) { 1.69 + fg_critical("SMF warning: no more chunks left."); 1.70 + return (NULL); 1.71 + } 1.72 + 1.73 + next_chunk_ptr = (unsigned char *)smf->file_buffer + smf->next_chunk_offset; 1.74 + 1.75 + chunk = (struct chunk_header_struct *)next_chunk_ptr; 1.76 + 1.77 + if (!isalpha(chunk->id[0]) || !isalpha(chunk->id[1]) || !isalpha(chunk->id[2]) || !isalpha(chunk->id[3])) { 1.78 + fg_critical("SMF error: chunk signature contains at least one non-alphanumeric byte."); 1.79 + return (NULL); 1.80 + } 1.81 + 1.82 + /* 1.83 + * XXX: On SPARC, after compiling with "-fast" option there will be SIGBUS here. 1.84 + * Please compile with -xmemalign=8i". 1.85 + */ 1.86 + smf->next_chunk_offset += sizeof(struct chunk_header_struct) + ntohl(chunk->length); 1.87 + 1.88 + if (smf->next_chunk_offset > smf->file_buffer_length) { 1.89 + fg_critical("SMF warning: malformed chunk; truncated file?"); 1.90 + smf->next_chunk_offset = smf->file_buffer_length; 1.91 + } 1.92 + 1.93 + return (chunk); 1.94 +} 1.95 + 1.96 +/** 1.97 + * Returns 1, iff signature of the "chunk" is the same as string passed as "signature". 1.98 + */ 1.99 +static int 1.100 +chunk_signature_matches(const struct chunk_header_struct *chunk, const char *signature) 1.101 +{ 1.102 + if (!memcmp(chunk->id, signature, 4)) 1.103 + return (1); 1.104 + 1.105 + return (0); 1.106 +} 1.107 + 1.108 +/** 1.109 + * Verifies if MThd header looks OK. Returns 0 iff it does. 1.110 + */ 1.111 +static int 1.112 +parse_mthd_header(smf_t *smf) 1.113 +{ 1.114 + int len; 1.115 + struct chunk_header_struct *mthd, *tmp_mthd; 1.116 + 1.117 + /* Make sure compiler didn't do anything stupid. */ 1.118 + assert(sizeof(struct chunk_header_struct) == 8); 1.119 + 1.120 + /* 1.121 + * We could just do "mthd = smf->file_buffer;" here, but this way we wouldn't 1.122 + * get useful error messages. 1.123 + */ 1.124 + if (smf->file_buffer_length < 6) { 1.125 + fg_critical("SMF error: file is too short, it cannot be a MIDI file."); 1.126 + 1.127 + return (-1); 1.128 + } 1.129 + 1.130 + tmp_mthd = smf->file_buffer; 1.131 + 1.132 + if (!chunk_signature_matches(tmp_mthd, "MThd")) { 1.133 + fg_critical("SMF error: MThd signature not found, is that a MIDI file?"); 1.134 + 1.135 + return (-2); 1.136 + } 1.137 + 1.138 + /* Ok, now use next_chunk(). */ 1.139 + mthd = next_chunk(smf); 1.140 + if (mthd == NULL) 1.141 + return (-3); 1.142 + 1.143 + assert(mthd == tmp_mthd); 1.144 + 1.145 + len = ntohl(mthd->length); 1.146 + if (len != 6) { 1.147 + fg_critical("SMF error: MThd chunk length %d, must be 6.", len); 1.148 + 1.149 + return (-4); 1.150 + } 1.151 + 1.152 + return (0); 1.153 +} 1.154 + 1.155 +/** 1.156 + * Parses MThd chunk, filling "smf" structure with values extracted from it. Returns 0 iff everything went OK. 1.157 + */ 1.158 +static int 1.159 +parse_mthd_chunk(smf_t *smf) 1.160 +{ 1.161 + signed char first_byte_of_division, second_byte_of_division; 1.162 + 1.163 + struct mthd_chunk_struct *mthd; 1.164 + 1.165 + assert(sizeof(struct mthd_chunk_struct) == 14); 1.166 + 1.167 + if (parse_mthd_header(smf)) 1.168 + return (1); 1.169 + 1.170 + mthd = (struct mthd_chunk_struct *)smf->file_buffer; 1.171 + 1.172 + smf->format = ntohs(mthd->format); 1.173 + if (smf->format < 0 || smf->format > 2) { 1.174 + fg_critical("SMF error: bad MThd format field value: %d, valid values are 0-2, inclusive.", smf->format); 1.175 + return (-1); 1.176 + } 1.177 + 1.178 + if (smf->format == 2) { 1.179 + fg_critical("SMF file uses format #2, no support for that yet."); 1.180 + return (-2); 1.181 + } 1.182 + 1.183 + smf->expected_number_of_tracks = ntohs(mthd->number_of_tracks); 1.184 + if (smf->expected_number_of_tracks <= 0) { 1.185 + fg_critical("SMF error: bad number of tracks: %d, must be greater than zero.", smf->expected_number_of_tracks); 1.186 + return (-3); 1.187 + } 1.188 + 1.189 + /* XXX: endianess? */ 1.190 + first_byte_of_division = *((signed char *)&(mthd->division)); 1.191 + second_byte_of_division = *((signed char *)&(mthd->division) + 1); 1.192 + 1.193 + if (first_byte_of_division >= 0) { 1.194 + smf->ppqn = ntohs(mthd->division); 1.195 + smf->frames_per_second = 0; 1.196 + smf->resolution = 0; 1.197 + } else { 1.198 + smf->ppqn = 0; 1.199 + smf->frames_per_second = - first_byte_of_division; 1.200 + smf->resolution = second_byte_of_division; 1.201 + } 1.202 + 1.203 + if (smf->ppqn == 0) { 1.204 + fg_critical("SMF file uses FPS timing instead of PPQN, no support for that yet."); 1.205 + return (-4); 1.206 + } 1.207 + 1.208 + return (0); 1.209 +} 1.210 + 1.211 +/** 1.212 + * Interprets Variable Length Quantity pointed at by "buf" and puts its value into "value" and number 1.213 + * of bytes consumed into "len", making sure it does not read past "buf" + "buffer_length". 1.214 + * Explanation of Variable Length Quantities is here: http://www.borg.com/~jglatt/tech/midifile/vari.htm 1.215 + * Returns 0 iff everything went OK, different value in case of error. 1.216 + */ 1.217 +static int 1.218 +extract_vlq(const unsigned char *buf, const int buffer_length, int *value, int *len) 1.219 +{ 1.220 + int val = 0; 1.221 + const unsigned char *c = buf; 1.222 + 1.223 + assert(buffer_length > 0); 1.224 + 1.225 + for (;;) { 1.226 + if (c >= buf + buffer_length) { 1.227 + fg_critical("End of buffer in extract_vlq()."); 1.228 + return (-1); 1.229 + } 1.230 + 1.231 + val = (val << 7) + (*c & 0x7F); 1.232 + 1.233 + if (*c & 0x80) 1.234 + c++; 1.235 + else 1.236 + break; 1.237 + }; 1.238 + 1.239 + *value = val; 1.240 + *len = c - buf + 1; 1.241 + 1.242 + if (*len > 4) { 1.243 + fg_critical("SMF error: Variable Length Quantities longer than four bytes are not supported yet."); 1.244 + return (-2); 1.245 + } 1.246 + 1.247 + return (0); 1.248 +} 1.249 + 1.250 +/** 1.251 + * Returns 1 if the given byte is a valid status byte, 0 otherwise. 1.252 + */ 1.253 +int 1.254 +is_status_byte(const unsigned char status) 1.255 +{ 1.256 + return (status & 0x80); 1.257 +} 1.258 + 1.259 +static int 1.260 +is_sysex_byte(const unsigned char status) 1.261 +{ 1.262 + if (status == 0xF0) 1.263 + return (1); 1.264 + 1.265 + return (0); 1.266 +} 1.267 + 1.268 +static int 1.269 +is_escape_byte(const unsigned char status) 1.270 +{ 1.271 + if (status == 0xF7) 1.272 + return (1); 1.273 + 1.274 + return (0); 1.275 +} 1.276 + 1.277 +/** 1.278 + * Just like expected_message_length(), but only for System Exclusive messages. 1.279 + * Note that value returned by this thing here is the length of SysEx "on the wire", 1.280 + * not the number of bytes that this sysex takes in the file - in SMF format sysex 1.281 + * contains VLQ telling how many bytes it takes, "on the wire" format does not have 1.282 + * this. 1.283 + */ 1.284 +static int 1.285 +expected_sysex_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes) 1.286 +{ 1.287 + int sysex_length, len; 1.288 + 1.289 + assert(status == 0xF0); 1.290 + 1.291 + if (buffer_length < 3) { 1.292 + fg_critical("SMF error: end of buffer in expected_sysex_length()."); 1.293 + return (-1); 1.294 + } 1.295 + 1.296 + if (extract_vlq(second_byte, buffer_length, &sysex_length, &len)) 1.297 + return (-1); 1.298 + 1.299 + if (consumed_bytes != NULL) 1.300 + *consumed_bytes = len; 1.301 + 1.302 + /* +1, because the length does not include status byte. */ 1.303 + return (sysex_length + 1); 1.304 +} 1.305 + 1.306 +static int 1.307 +expected_escaped_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes) 1.308 +{ 1.309 + /* -1, because we do not want to account for 0x7F status. */ 1.310 + return (expected_sysex_length(status, second_byte, buffer_length, consumed_bytes) - 1); 1.311 +} 1.312 + 1.313 +/** 1.314 + * Returns expected length of the midi message (including the status byte), in bytes, for the given status byte. 1.315 + * The "second_byte" points to the expected second byte of the MIDI message. "buffer_length" is the buffer 1.316 + * length limit, counting from "second_byte". Returns value < 0 iff there was an error. 1.317 + */ 1.318 +static int 1.319 +expected_message_length(unsigned char status, const unsigned char *second_byte, const int buffer_length) 1.320 +{ 1.321 + /* Make sure this really is a valid status byte. */ 1.322 + assert(is_status_byte(status)); 1.323 + 1.324 + /* We cannot use this routine for sysexes. */ 1.325 + assert(!is_sysex_byte(status)); 1.326 + 1.327 + /* We cannot use this routine for escaped events. */ 1.328 + assert(!is_escape_byte(status)); 1.329 + 1.330 + /* Buffer length may be zero, for e.g. realtime messages. */ 1.331 + assert(buffer_length >= 0); 1.332 + 1.333 + /* Is this a metamessage? */ 1.334 + if (status == 0xFF) { 1.335 + if (buffer_length < 2) { 1.336 + fg_critical("SMF error: end of buffer in expected_message_length()."); 1.337 + return (-1); 1.338 + } 1.339 + 1.340 + /* 1.341 + * Format of this kind of messages is like this: 0xFF 0xwhatever 0xlength and then "length" bytes. 1.342 + * Second byte points to this: ^^^^^^^^^^ 1.343 + */ 1.344 + return (*(second_byte + 1) + 3); 1.345 + } 1.346 + 1.347 + if ((status & 0xF0) == 0xF0) { 1.348 + switch (status) { 1.349 + case 0xF2: /* Song Position Pointer. */ 1.350 + return (3); 1.351 + 1.352 + case 0xF1: /* MTC Quarter Frame. */ 1.353 + case 0xF3: /* Song Select. */ 1.354 + return (2); 1.355 + 1.356 + case 0xF6: /* Tune Request. */ 1.357 + case 0xF8: /* MIDI Clock. */ 1.358 + case 0xF9: /* Tick. */ 1.359 + case 0xFA: /* MIDI Start. */ 1.360 + case 0xFB: /* MIDI Continue. */ 1.361 + case 0xFC: /* MIDI Stop. */ 1.362 + case 0xFE: /* Active Sense. */ 1.363 + return (1); 1.364 + 1.365 + default: 1.366 + fg_critical("SMF error: unknown 0xFx-type status byte '0x%x'.", status); 1.367 + return (-2); 1.368 + } 1.369 + } 1.370 + 1.371 + /* Filter out the channel. */ 1.372 + status &= 0xF0; 1.373 + 1.374 + switch (status) { 1.375 + case 0x80: /* Note Off. */ 1.376 + case 0x90: /* Note On. */ 1.377 + case 0xA0: /* AfterTouch. */ 1.378 + case 0xB0: /* Control Change. */ 1.379 + case 0xE0: /* Pitch Wheel. */ 1.380 + return (3); 1.381 + 1.382 + case 0xC0: /* Program Change. */ 1.383 + case 0xD0: /* Channel Pressure. */ 1.384 + return (2); 1.385 + 1.386 + default: 1.387 + fg_critical("SMF error: unknown status byte '0x%x'.", status); 1.388 + return (-3); 1.389 + } 1.390 +} 1.391 + 1.392 +static int 1.393 +extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 1.394 +{ 1.395 + int status, message_length, vlq_length; 1.396 + const unsigned char *c = buf; 1.397 + 1.398 + status = *buf; 1.399 + 1.400 + assert(is_sysex_byte(status)); 1.401 + 1.402 + c++; 1.403 + 1.404 + message_length = expected_sysex_length(status, c, buffer_length - 1, &vlq_length); 1.405 + 1.406 + if (message_length < 0) 1.407 + return (-3); 1.408 + 1.409 + c += vlq_length; 1.410 + 1.411 + if (vlq_length + message_length >= buffer_length) { 1.412 + fg_critical("End of buffer in extract_sysex_event()."); 1.413 + return (-5); 1.414 + } 1.415 + 1.416 + event->midi_buffer_length = message_length; 1.417 + event->midi_buffer = malloc(event->midi_buffer_length); 1.418 + if (event->midi_buffer == NULL) { 1.419 + fg_critical("Cannot allocate memory in extract_sysex_event(): %s", strerror(errno)); 1.420 + return (-4); 1.421 + } 1.422 + 1.423 + event->midi_buffer[0] = status; 1.424 + memcpy(event->midi_buffer + 1, c, message_length - 1); 1.425 + 1.426 + *len = vlq_length + message_length; 1.427 + 1.428 + return (0); 1.429 +} 1.430 + 1.431 +static int 1.432 +extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 1.433 +{ 1.434 + int status, message_length, vlq_length; 1.435 + const unsigned char *c = buf; 1.436 + 1.437 + status = *buf; 1.438 + 1.439 + assert(is_escape_byte(status)); 1.440 + 1.441 + c++; 1.442 + 1.443 + message_length = expected_escaped_length(status, c, buffer_length - 1, &vlq_length); 1.444 + 1.445 + if (message_length < 0) 1.446 + return (-3); 1.447 + 1.448 + c += vlq_length; 1.449 + 1.450 + if (vlq_length + message_length >= buffer_length) { 1.451 + fg_critical("End of buffer in extract_escaped_event()."); 1.452 + return (-5); 1.453 + } 1.454 + 1.455 + event->midi_buffer_length = message_length; 1.456 + event->midi_buffer = malloc(event->midi_buffer_length); 1.457 + if (event->midi_buffer == NULL) { 1.458 + fg_critical("Cannot allocate memory in extract_escaped_event(): %s", strerror(errno)); 1.459 + return (-4); 1.460 + } 1.461 + 1.462 + memcpy(event->midi_buffer, c, message_length); 1.463 + 1.464 + if (smf_event_is_valid(event)) { 1.465 + fg_critical("Escaped event is invalid."); 1.466 + return (-1); 1.467 + } 1.468 + 1.469 + if (smf_event_is_system_realtime(event) || smf_event_is_system_common(event)) { 1.470 + fg_warning("Escaped event is not System Realtime nor System Common."); 1.471 + } 1.472 + 1.473 + *len = vlq_length + message_length; 1.474 + 1.475 + return (0); 1.476 +} 1.477 + 1.478 + 1.479 +/** 1.480 + * Puts MIDI data extracted from from "buf" into "event" and number of consumed bytes into "len". 1.481 + * In case valid status is not found, it uses "last_status" (so called "running status"). 1.482 + * Returns 0 iff everything went OK, value < 0 in case of error. 1.483 + */ 1.484 +static int 1.485 +extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 1.486 +{ 1.487 + int status, message_length; 1.488 + const unsigned char *c = buf; 1.489 + 1.490 + assert(buffer_length > 0); 1.491 + 1.492 + /* Is the first byte the status byte? */ 1.493 + if (is_status_byte(*c)) { 1.494 + status = *c; 1.495 + c++; 1.496 + 1.497 + } else { 1.498 + /* No, we use running status then. */ 1.499 + status = last_status; 1.500 + } 1.501 + 1.502 + if (!is_status_byte(status)) { 1.503 + fg_critical("SMF error: bad status byte (MSB is zero)."); 1.504 + return (-1); 1.505 + } 1.506 + 1.507 + if (is_sysex_byte(status)) 1.508 + return (extract_sysex_event(buf, buffer_length, event, len, last_status)); 1.509 + 1.510 + if (is_escape_byte(status)) 1.511 + return (extract_escaped_event(buf, buffer_length, event, len, last_status)); 1.512 + 1.513 + /* At this point, "c" points to first byte following the status byte. */ 1.514 + message_length = expected_message_length(status, c, buffer_length - (c - buf)); 1.515 + 1.516 + if (message_length < 0) 1.517 + return (-3); 1.518 + 1.519 + if (message_length - 1 > buffer_length - (c - buf)) { 1.520 + fg_critical("End of buffer in extract_midi_event()."); 1.521 + return (-5); 1.522 + } 1.523 + 1.524 + event->midi_buffer_length = message_length; 1.525 + event->midi_buffer = malloc(event->midi_buffer_length); 1.526 + if (event->midi_buffer == NULL) { 1.527 + fg_critical("Cannot allocate memory in extract_midi_event(): %s", strerror(errno)); 1.528 + return (-4); 1.529 + } 1.530 + 1.531 + event->midi_buffer[0] = status; 1.532 + memcpy(event->midi_buffer + 1, c, message_length - 1); 1.533 + 1.534 + *len = c + message_length - 1 - buf; 1.535 + 1.536 + return (0); 1.537 +} 1.538 + 1.539 +/** 1.540 + * Locates, basing on track->next_event_offset, the next event data in track->buffer, 1.541 + * interprets it, allocates smf_event_t and fills it properly. Returns smf_event_t 1.542 + * or NULL, if there was an error. Allocating event means adding it to the track; 1.543 + * see smf_event_new(). 1.544 + */ 1.545 +static smf_event_t * 1.546 +parse_next_event(smf_track_t *track) 1.547 +{ 1.548 + int time = 0, len, buffer_length; 1.549 + unsigned char *c, *start; 1.550 + 1.551 + smf_event_t *event = smf_event_new(); 1.552 + if (event == NULL) 1.553 + goto error; 1.554 + 1.555 + c = start = (unsigned char *)track->file_buffer + track->next_event_offset; 1.556 + 1.557 + assert(track->file_buffer != NULL); 1.558 + assert(track->file_buffer_length > 0); 1.559 + assert(track->next_event_offset > 0); 1.560 + 1.561 + buffer_length = track->file_buffer_length - track->next_event_offset; 1.562 + assert(buffer_length > 0); 1.563 + 1.564 + /* First, extract time offset from previous event. */ 1.565 + if (extract_vlq(c, buffer_length, &time, &len)) 1.566 + goto error; 1.567 + 1.568 + c += len; 1.569 + buffer_length -= len; 1.570 + 1.571 + if (buffer_length <= 0) 1.572 + goto error; 1.573 + 1.574 + /* Now, extract the actual event. */ 1.575 + if (extract_midi_event(c, buffer_length, event, &len, track->last_status)) 1.576 + goto error; 1.577 + 1.578 + c += len; 1.579 + buffer_length -= len; 1.580 + track->last_status = event->midi_buffer[0]; 1.581 + track->next_event_offset += c - start; 1.582 + 1.583 + smf_track_add_event_delta_pulses(track, event, time); 1.584 + 1.585 + return (event); 1.586 + 1.587 +error: 1.588 + if (event != NULL) 1.589 + smf_event_delete(event); 1.590 + 1.591 + return (NULL); 1.592 +} 1.593 + 1.594 +/** 1.595 + * Takes "len" characters starting in "buf", making sure it does not access past the length of the buffer, 1.596 + * and makes ordinary, zero-terminated string from it. May return NULL if there was any problem. 1.597 + */ 1.598 +static char * 1.599 +make_string(const unsigned char *buf, const int buffer_length, int len) 1.600 +{ 1.601 + char *str; 1.602 + 1.603 + assert(buffer_length > 0); 1.604 + assert(len > 0); 1.605 + 1.606 + if (len > buffer_length) { 1.607 + fg_critical("End of buffer in make_string()."); 1.608 + 1.609 + len = buffer_length; 1.610 + } 1.611 + 1.612 + str = malloc(len + 1); 1.613 + if (str == NULL) { 1.614 + fg_critical("Cannot allocate memory in make_string()."); 1.615 + return (NULL); 1.616 + } 1.617 + 1.618 + memcpy(str, buf, len); 1.619 + str[len] = '\0'; 1.620 + 1.621 + return (str); 1.622 +} 1.623 + 1.624 +/** 1.625 + * \return 1, if passed a metaevent containing text, that is, Text, Copyright, 1.626 + * Sequence/Track Name, Instrument, Lyric, Marker, Cue Point, Program Name, 1.627 + * or Device Name; 0 otherwise. 1.628 + */ 1.629 +int 1.630 +smf_event_is_textual(const smf_event_t *event) 1.631 +{ 1.632 + if (!smf_event_is_metadata(event)) 1.633 + return (0); 1.634 + 1.635 + if (event->midi_buffer_length < 4) 1.636 + return (0); 1.637 + 1.638 + if (event->midi_buffer[3] < 1 && event->midi_buffer[3] > 9) 1.639 + return (0); 1.640 + 1.641 + return (1); 1.642 +} 1.643 + 1.644 +/** 1.645 + * Extracts text from "textual metaevents", such as Text or Lyric. 1.646 + * 1.647 + * \return Zero-terminated string extracted from "text events" or NULL, if there was any problem. 1.648 + */ 1.649 +char * 1.650 +smf_event_extract_text(const smf_event_t *event) 1.651 +{ 1.652 + int string_length = -1, length_length = -1; 1.653 + 1.654 + if (!smf_event_is_textual(event)) 1.655 + return (NULL); 1.656 + 1.657 + if (event->midi_buffer_length < 3) { 1.658 + fg_critical("smf_event_extract_text: truncated MIDI message."); 1.659 + return (NULL); 1.660 + } 1.661 + 1.662 + extract_vlq((void *)&(event->midi_buffer[2]), event->midi_buffer_length - 2, &string_length, &length_length); 1.663 + 1.664 + if (string_length <= 0) { 1.665 + fg_critical("smf_event_extract_text: truncated MIDI message."); 1.666 + return (NULL); 1.667 + } 1.668 + 1.669 + return (make_string((void *)(&event->midi_buffer[2] + length_length), event->midi_buffer_length - 2 - length_length, string_length)); 1.670 +} 1.671 + 1.672 +/** 1.673 + * Verify if the next chunk really is MTrk chunk, and if so, initialize some track variables and return 0. 1.674 + * Return different value otherwise. 1.675 + */ 1.676 +static int 1.677 +parse_mtrk_header(smf_track_t *track) 1.678 +{ 1.679 + struct chunk_header_struct *mtrk; 1.680 + 1.681 + /* Make sure compiler didn't do anything stupid. */ 1.682 + assert(sizeof(struct chunk_header_struct) == 8); 1.683 + assert(track->smf != NULL); 1.684 + 1.685 + mtrk = next_chunk(track->smf); 1.686 + 1.687 + if (mtrk == NULL) 1.688 + return (-1); 1.689 + 1.690 + if (!chunk_signature_matches(mtrk, "MTrk")) { 1.691 + fg_warning("SMF warning: Expected MTrk signature, got %c%c%c%c instead; ignoring this chunk.", 1.692 + mtrk->id[0], mtrk->id[1], mtrk->id[2], mtrk->id[3]); 1.693 + 1.694 + return (-2); 1.695 + } 1.696 + 1.697 + track->file_buffer = mtrk; 1.698 + track->file_buffer_length = sizeof(struct chunk_header_struct) + ntohl(mtrk->length); 1.699 + track->next_event_offset = sizeof(struct chunk_header_struct); 1.700 + 1.701 + return (0); 1.702 +} 1.703 + 1.704 +/** 1.705 + * Return 1 if event is end-of-the-track, 0 otherwise. 1.706 + */ 1.707 +static int 1.708 +event_is_end_of_track(const smf_event_t *event) 1.709 +{ 1.710 + if (event->midi_buffer[0] == 0xFF && event->midi_buffer[1] == 0x2F) 1.711 + return (1); 1.712 + 1.713 + return (0); 1.714 +} 1.715 + 1.716 +/** 1.717 + * \return Nonzero, if event is as long as it should be, from the MIDI specification point of view. 1.718 + * Does not work for SysExes - it doesn't recognize internal structure of SysEx. 1.719 + */ 1.720 +int 1.721 +smf_event_length_is_valid(const smf_event_t *event) 1.722 +{ 1.723 + assert(event); 1.724 + assert(event->midi_buffer); 1.725 + 1.726 + if (event->midi_buffer_length < 1) 1.727 + return (0); 1.728 + 1.729 + /* We cannot use expected_message_length on sysexes. */ 1.730 + if (smf_event_is_sysex(event)) 1.731 + return (1); 1.732 + 1.733 + if (event->midi_buffer_length != expected_message_length(event->midi_buffer[0], 1.734 + &(event->midi_buffer[1]), event->midi_buffer_length - 1)) { 1.735 + 1.736 + return (0); 1.737 + } 1.738 + 1.739 + return (1); 1.740 +} 1.741 + 1.742 +/** 1.743 + * \return Nonzero, if MIDI data in the event is valid, 0 otherwise. For example, 1.744 + * it checks if event length is correct. 1.745 + */ 1.746 +/* XXX: this routine requires some more work to detect more errors. */ 1.747 +int 1.748 +smf_event_is_valid(const smf_event_t *event) 1.749 +{ 1.750 + assert(event); 1.751 + assert(event->midi_buffer); 1.752 + assert(event->midi_buffer_length >= 1); 1.753 + 1.754 + if (!is_status_byte(event->midi_buffer[0])) { 1.755 + fg_critical("First byte of MIDI message is not a valid status byte."); 1.756 + 1.757 + return (0); 1.758 + } 1.759 + 1.760 + if (!smf_event_length_is_valid(event)) 1.761 + return (0); 1.762 + 1.763 + return (1); 1.764 +} 1.765 + 1.766 +/** 1.767 + * Parse events and put it on the track. 1.768 + */ 1.769 +static int 1.770 +parse_mtrk_chunk(smf_track_t *track) 1.771 +{ 1.772 + smf_event_t *event; 1.773 + 1.774 + if (parse_mtrk_header(track)) 1.775 + return (-1); 1.776 + 1.777 + for (;;) { 1.778 + event = parse_next_event(track); 1.779 + 1.780 + /* Couldn't parse an event? */ 1.781 + if (event == NULL) { 1.782 + fg_critical("Unable to parse MIDI event; truncating track."); 1.783 + if (smf_track_add_eot_delta_pulses(track, 0) != 0) { 1.784 + fg_critical("smf_track_add_eot_delta_pulses failed."); 1.785 + return (-2); 1.786 + } 1.787 + break; 1.788 + } 1.789 + 1.790 + assert(smf_event_is_valid(event)); 1.791 + 1.792 + if (event_is_end_of_track(event)) 1.793 + break; 1.794 + } 1.795 + 1.796 + track->file_buffer = NULL; 1.797 + track->file_buffer_length = 0; 1.798 + track->next_event_offset = -1; 1.799 + 1.800 + return (0); 1.801 +} 1.802 + 1.803 +/** 1.804 + * Allocate buffer of proper size and read file contents into it. Close file afterwards. 1.805 + */ 1.806 +static int 1.807 +load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *file_name) 1.808 +{ 1.809 + FILE *stream = fopen(file_name, "rb"); 1.810 + 1.811 + if (stream == NULL) { 1.812 + fg_critical("Cannot open input file: %s", strerror(errno)); 1.813 + 1.814 + return (-1); 1.815 + } 1.816 + 1.817 + if (fseek(stream, 0, SEEK_END)) { 1.818 + fg_critical("fseek(3) failed: %s", strerror(errno)); 1.819 + 1.820 + return (-2); 1.821 + } 1.822 + 1.823 + *file_buffer_length = ftell(stream); 1.824 + if (*file_buffer_length == -1) { 1.825 + fg_critical("ftell(3) failed: %s", strerror(errno)); 1.826 + 1.827 + return (-3); 1.828 + } 1.829 + 1.830 + if (fseek(stream, 0, SEEK_SET)) { 1.831 + fg_critical("fseek(3) failed: %s", strerror(errno)); 1.832 + 1.833 + return (-4); 1.834 + } 1.835 + 1.836 + *file_buffer = malloc(*file_buffer_length); 1.837 + if (*file_buffer == NULL) { 1.838 + fg_critical("malloc(3) failed: %s", strerror(errno)); 1.839 + 1.840 + return (-5); 1.841 + } 1.842 + 1.843 + if (fread(*file_buffer, 1, *file_buffer_length, stream) != *file_buffer_length) { 1.844 + fg_critical("fread(3) failed: %s", strerror(errno)); 1.845 + 1.846 + return (-6); 1.847 + } 1.848 + 1.849 + if (fclose(stream)) { 1.850 + fg_critical("fclose(3) failed: %s", strerror(errno)); 1.851 + 1.852 + return (-7); 1.853 + } 1.854 + 1.855 + return (0); 1.856 +} 1.857 + 1.858 +/** 1.859 + * Creates new SMF and fills it with data loaded from the given buffer. 1.860 + * \return SMF or NULL, if loading failed. 1.861 + */ 1.862 +smf_t * 1.863 +smf_load_from_memory(const void *buffer, const int buffer_length) 1.864 +{ 1.865 + int i; 1.866 + 1.867 + smf_t *smf = smf_new(); 1.868 + 1.869 + smf->file_buffer = (void *)buffer; 1.870 + smf->file_buffer_length = buffer_length; 1.871 + smf->next_chunk_offset = 0; 1.872 + 1.873 + if (parse_mthd_chunk(smf)) 1.874 + return (NULL); 1.875 + 1.876 + for (i = 1; i <= smf->expected_number_of_tracks; i++) { 1.877 + smf_track_t *track = smf_track_new(); 1.878 + if (track == NULL) 1.879 + return (NULL); 1.880 + 1.881 + smf_add_track(smf, track); 1.882 + 1.883 + /* Skip unparseable chunks. */ 1.884 + if (parse_mtrk_chunk(track)) { 1.885 + fg_warning("SMF warning: Cannot load track."); 1.886 + smf_track_delete(track); 1.887 + } 1.888 + 1.889 + track->file_buffer = NULL; 1.890 + track->file_buffer_length = 0; 1.891 + track->next_event_offset = -1; 1.892 + } 1.893 + 1.894 + if (smf->expected_number_of_tracks != smf->number_of_tracks) { 1.895 + fg_warning("SMF warning: MThd header declared %d tracks, but only %d found; continuing anyway.", 1.896 + smf->expected_number_of_tracks, smf->number_of_tracks); 1.897 + 1.898 + smf->expected_number_of_tracks = smf->number_of_tracks; 1.899 + } 1.900 + 1.901 + smf->file_buffer = NULL; 1.902 + smf->file_buffer_length = 0; 1.903 + smf->next_chunk_offset = -1; 1.904 + 1.905 + return (smf); 1.906 +} 1.907 + 1.908 +/** 1.909 + * Loads SMF file. 1.910 + * 1.911 + * \param file_name Path to the file. 1.912 + * \return SMF or NULL, if loading failed. 1.913 + */ 1.914 +smf_t * 1.915 +smf_load(const char *file_name) 1.916 +{ 1.917 + int file_buffer_length; 1.918 + void *file_buffer; 1.919 + smf_t *smf; 1.920 + 1.921 + if (load_file_into_buffer(&file_buffer, &file_buffer_length, file_name)) 1.922 + return (NULL); 1.923 + 1.924 + smf = smf_load_from_memory(file_buffer, file_buffer_length); 1.925 + 1.926 + memset(file_buffer, 0, file_buffer_length); 1.927 + free(file_buffer); 1.928 + 1.929 + if (smf == NULL) 1.930 + return (NULL); 1.931 + 1.932 + smf_rewind(smf); 1.933 + 1.934 + return (smf); 1.935 +} 1.936 +