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