libsmf
smf_save.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 
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 #ifdef __MINGW32__
43 #include <windows.h>
44 #else /* ! __MINGW32__ */
45 #include <arpa/inet.h>
46 #endif /* ! __MINGW32__ */
47 #include "smf.h"
48 #include "smf_private.h"
49 
50 #define MAX_VLQ_LENGTH 128
51 
57 static void *
58 smf_extend(smf_t *smf, const int length)
59 {
60  int i, previous_file_buffer_length = smf->file_buffer_length;
61  char *previous_file_buffer = smf->file_buffer;
62 
63  /* XXX: Not terribly efficient. */
64  smf->file_buffer_length += length;
65  smf->file_buffer = realloc(smf->file_buffer, smf->file_buffer_length);
66  if (smf->file_buffer == NULL) {
67  g_critical("realloc(3) failed: %s", strerror(errno));
68  smf->file_buffer_length = 0;
69  return (NULL);
70  }
71 
72  /* Fix up pointers. XXX: omgwtf. */
73  for (i = 1; i <= smf->number_of_tracks; i++) {
74  smf_track_t *track;
75  track = smf_get_track_by_number(smf, i);
76  if (track->file_buffer != NULL)
77  track->file_buffer = (char *)track->file_buffer + ((char *)smf->file_buffer - previous_file_buffer);
78  }
79 
80  return ((char *)smf->file_buffer + previous_file_buffer_length);
81 }
82 
87 static int
88 smf_append(smf_t *smf, const void *buffer, const int buffer_length)
89 {
90  void *dest;
91 
92  dest = smf_extend(smf, buffer_length);
93  if (dest == NULL) {
94  g_critical("Cannot extend track buffer.");
95  return (-1);
96  }
97 
98  memcpy(dest, buffer, buffer_length);
99 
100  return (0);
101 }
102 
106 static int
107 write_mthd_header(smf_t *smf)
108 {
109  struct mthd_chunk_struct mthd_chunk;
110 
111  memcpy(mthd_chunk.mthd_header.id, "MThd", 4);
112  mthd_chunk.mthd_header.length = htonl(6);
113  mthd_chunk.format = htons(smf->format);
114  mthd_chunk.number_of_tracks = htons(smf->number_of_tracks);
115  mthd_chunk.division = htons(smf->ppqn);
116 
117  return (smf_append(smf, &mthd_chunk, sizeof(mthd_chunk)));
118 }
119 
125 static void *
126 track_extend(smf_track_t *track, const int length)
127 {
128  void *buf;
129 
130  assert(track->smf);
131 
132  buf = smf_extend(track->smf, length);
133  if (buf == NULL)
134  return (NULL);
135 
136  track->file_buffer_length += length;
137  if (track->file_buffer == NULL)
138  track->file_buffer = buf;
139 
140  return (buf);
141 }
142 
147 static int
148 track_append(smf_track_t *track, const void *buffer, const int buffer_length)
149 {
150  void *dest;
151 
152  dest = track_extend(track, buffer_length);
153  if (dest == NULL) {
154  g_critical("Cannot extend track buffer.");
155  return (-1);
156  }
157 
158  memcpy(dest, buffer, buffer_length);
159 
160  return (0);
161 }
162 
163 static int
164 format_vlq(unsigned char *buf, int length, unsigned long value)
165 {
166  int i;
167  unsigned long buffer;
168 
169  /* Taken from http://www.borg.com/~jglatt/tech/midifile/vari.htm */
170  buffer = value & 0x7F;
171 
172  while ((value >>= 7)) {
173  buffer <<= 8;
174  buffer |= ((value & 0x7F) | 0x80);
175  }
176 
177  for (i = 0;; i++) {
178  buf[i] = buffer;
179 
180  if (buffer & 0x80)
181  buffer >>= 8;
182  else
183  break;
184  }
185 
186  assert(i <= length);
187 
188  /* + 1, because "i" is an offset, not a count. */
189  return (i + 1);
190 }
191 
192 smf_event_t *
193 smf_event_new_textual(int type, const char *text)
194 {
195  int vlq_length, text_length, copied_length;
196  smf_event_t *event;
197 
198  assert(type >= 1 && type <= 9);
199 
200  text_length = strlen(text);
201 
202  event = smf_event_new();
203  if (event == NULL)
204  return (NULL);
205 
206  /* "2 +" is for leading 0xFF 0xtype. */
207  event->midi_buffer_length = 2 + text_length + MAX_VLQ_LENGTH;
208  event->midi_buffer = malloc(event->midi_buffer_length);
209  if (event->midi_buffer == NULL) {
210  g_critical("Cannot allocate MIDI buffer structure: %s", strerror(errno));
211  smf_event_delete(event);
212 
213  return (NULL);
214  }
215 
216  event->midi_buffer[0] = 0xFF;
217  event->midi_buffer[1] = type;
218 
219  vlq_length = format_vlq(event->midi_buffer + 2, MAX_VLQ_LENGTH - 2, text_length);
220  copied_length = snprintf((char *)event->midi_buffer + vlq_length + 2, event->midi_buffer_length - vlq_length - 2, "%s", text);
221 
222  assert(copied_length == text_length);
223 
224  event->midi_buffer_length = 2 + vlq_length + text_length;
225 
226  return event;
227 }
228 
232 static int
233 write_vlq(smf_event_t *event, unsigned long value)
234 {
235  unsigned char buf[MAX_VLQ_LENGTH];
236  int vlq_length;
237 
238  vlq_length = format_vlq(buf, MAX_VLQ_LENGTH, value);
239 
240  return (track_append(event->track, buf, vlq_length));
241 }
242 
247 static int
248 write_event_time(smf_event_t *event)
249 {
250  assert(event->delta_time_pulses >= 0);
251 
252  return (write_vlq(event, event->delta_time_pulses));
253 }
254 
255 static int
256 write_sysex_contents(smf_event_t *event)
257 {
258  int ret;
259  unsigned char sysex_status = 0xF0;
260 
261  assert(smf_event_is_sysex(event));
262 
263  ret = track_append(event->track, &sysex_status, 1);
264  if (ret)
265  return (ret);
266 
267  /* -1, because length does not include status byte. */
268  ret = write_vlq(event, event->midi_buffer_length - 1);
269  if (ret)
270  return (ret);
271 
272  ret = track_append(event->track, event->midi_buffer + 1, event->midi_buffer_length - 1);
273  if (ret)
274  return (ret);
275 
276  return (0);
277 }
278 
282 static int
283 write_escaped_event_contents(smf_event_t *event)
284 {
285  int ret;
286  unsigned char escape_status = 0xF7;
287 
288  if (smf_event_is_sysex(event))
289  return (write_sysex_contents(event));
290 
291  ret = track_append(event->track, &escape_status, 1);
292  if (ret)
293  return (ret);
294 
295  ret = write_vlq(event, event->midi_buffer_length);
296  if (ret)
297  return (ret);
298 
299  ret = track_append(event->track, event->midi_buffer, event->midi_buffer_length);
300  if (ret)
301  return (ret);
302 
303  return (0);
304 }
305 
310 static int
311 write_event_contents(smf_event_t *event)
312 {
314  return (write_escaped_event_contents(event));
315 
316  return (track_append(event->track, event->midi_buffer, event->midi_buffer_length));
317 }
318 
322 static int
323 write_event(smf_event_t *event)
324 {
325  int ret;
326 
327  ret = write_event_time(event);
328  if (ret)
329  return (ret);
330 
331  ret = write_event_contents(event);
332  if (ret)
333  return (ret);
334 
335  return (0);
336 }
337 
341 static int
342 write_mtrk_header(smf_track_t *track)
343 {
344  struct chunk_header_struct mtrk_header;
345 
346  memcpy(mtrk_header.id, "MTrk", 4);
347 
348  return (track_append(track, &mtrk_header, sizeof(mtrk_header)));
349 }
350 
354 static int
355 write_mtrk_length(smf_track_t *track)
356 {
357  struct chunk_header_struct *mtrk_header;
358 
359  assert(track->file_buffer != NULL);
360  assert(track->file_buffer_length >= 6);
361 
362  mtrk_header = (struct chunk_header_struct *)track->file_buffer;
363  mtrk_header->length = htonl(track->file_buffer_length - sizeof(struct chunk_header_struct));
364 
365  return (0);
366 }
367 
371 static int
372 write_track(smf_track_t *track)
373 {
374  int ret;
375  smf_event_t *event;
376 
377  ret = write_mtrk_header(track);
378  if (ret)
379  return (ret);
380 
381  while ((event = smf_track_get_next_event(track)) != NULL) {
382  ret = write_event(event);
383  if (ret)
384  return (ret);
385  }
386 
387  ret = write_mtrk_length(track);
388  if (ret)
389  return (ret);
390 
391  return (0);
392 }
393 
397 static int
398 write_file(smf_t *smf, const char *file_name)
399 {
400  FILE *stream;
401 
402  stream = fopen(file_name, "wb+");
403  if (stream == NULL) {
404  g_critical("Cannot open input file: %s", strerror(errno));
405 
406  return (-1);
407  }
408 
409  if (fwrite(smf->file_buffer, 1, smf->file_buffer_length, stream) != smf->file_buffer_length) {
410  g_critical("fwrite(3) failed: %s", strerror(errno));
411 
412  return (-2);
413  }
414 
415  if (fclose(stream)) {
416  g_critical("fclose(3) failed: %s", strerror(errno));
417 
418  return (-3);
419  }
420 
421  return (0);
422 }
423 
424 static void
425 free_buffer(smf_t *smf)
426 {
427  int i;
428  smf_track_t *track;
429 
430  /* Clear the pointers. */
431  memset(smf->file_buffer, 0, smf->file_buffer_length);
432  free(smf->file_buffer);
433  smf->file_buffer = NULL;
434  smf->file_buffer_length = 0;
435 
436  for (i = 1; i <= smf->number_of_tracks; i++) {
437  track = smf_get_track_by_number(smf, i);
438  assert(track);
439  track->file_buffer = NULL;
440  track->file_buffer_length = 0;
441  }
442 }
443 
444 #ifndef NDEBUG
445 
449 static int
450 pointers_are_clear(smf_t *smf)
451 {
452  int i;
453 
454  smf_track_t *track;
455  assert(smf->file_buffer == NULL);
456  assert(smf->file_buffer_length == 0);
457 
458  for (i = 1; i <= smf->number_of_tracks; i++) {
459  track = smf_get_track_by_number(smf, i);
460 
461  assert(track != NULL);
462  assert(track->file_buffer == NULL);
463  assert(track->file_buffer_length == 0);
464  }
465 
466  return (1);
467 }
468 
469 #endif /* !NDEBUG */
470 
474 int
476 {
477  if (event->midi_buffer_length != 3)
478  return (0);
479 
480  if (event->midi_buffer[0] != 0xFF || event->midi_buffer[1] != 0x2F || event->midi_buffer[2] != 0x00)
481  return (0);
482 
483  return (1);
484 }
485 
491 static int
492 smf_validate(smf_t *smf)
493 {
494  int trackno, eventno, eot_found;
495  smf_track_t *track;
496  smf_event_t *event;
497 
498  if (smf->format < 0 || smf->format > 2) {
499  g_critical("SMF error: smf->format is less than zero of greater than two.");
500  return (-1);
501  }
502 
503  if (smf->number_of_tracks < 1) {
504  g_critical("SMF error: number of tracks is less than one.");
505  return (-2);
506  }
507 
508  if (smf->format == 0 && smf->number_of_tracks > 1) {
509  g_critical("SMF error: format is 0, but number of tracks is more than one.");
510  return (-3);
511  }
512 
513  if (smf->ppqn <= 0) {
514  g_critical("SMF error: PPQN has to be > 0.");
515  return (-4);
516  }
517 
518  for (trackno = 1; trackno <= smf->number_of_tracks; trackno++) {
519  track = smf_get_track_by_number(smf, trackno);
520  assert(track);
521 
522  eot_found = 0;
523 
524  for (eventno = 1; eventno <= track->number_of_events; eventno++) {
525  event = smf_track_get_event_by_number(track, eventno);
526  assert(event);
527 
528  if (!smf_event_is_valid(event)) {
529  g_critical("Event #%d on track #%d is invalid.", eventno, trackno);
530  return (-5);
531  }
532 
533  if (smf_event_is_eot(event)) {
534  if (eot_found) {
535  g_critical("Duplicate End Of Track event on track #%d.", trackno);
536  return (-6);
537  }
538 
539  eot_found = 1;
540  }
541  }
542 
543  if (!eot_found) {
544  if (smf_track_add_eot_delta_pulses(track, 0)) {
545  g_critical("smf_track_add_eot_delta_pulses failed.");
546  return (-6);
547  }
548  }
549 
550  }
551 
552  return (0);
553 }
554 
555 #ifndef NDEBUG
556 
557 static void
558 assert_smf_event_is_identical(const smf_event_t *a, const smf_event_t *b)
559 {
560  assert(a->event_number == b->event_number);
561  assert(a->delta_time_pulses == b->delta_time_pulses);
562  assert(abs(a->time_pulses - b->time_pulses) <= 2);
563  assert(fabs(a->time_seconds - b->time_seconds) <= 0.01);
564  assert(a->track_number == b->track_number);
565  assert(a->midi_buffer_length == b->midi_buffer_length);
566  assert(memcmp(a->midi_buffer, b->midi_buffer, a->midi_buffer_length) == 0);
567 }
568 
569 static void
570 assert_smf_track_is_identical(const smf_track_t *a, const smf_track_t *b)
571 {
572  int i;
573 
574  assert(a->track_number == b->track_number);
575  assert(a->number_of_events == b->number_of_events);
576 
577  for (i = 1; i <= a->number_of_events; i++)
578  assert_smf_event_is_identical(smf_track_get_event_by_number(a, i), smf_track_get_event_by_number(b, i));
579 }
580 
581 static void
582 assert_smf_is_identical(const smf_t *a, const smf_t *b)
583 {
584  int i;
585 
586  assert(a->format == b->format);
587  assert(a->ppqn == b->ppqn);
588  assert(a->frames_per_second == b->frames_per_second);
589  assert(a->resolution == b->resolution);
590  assert(a->number_of_tracks == b->number_of_tracks);
591 
592  for (i = 1; i <= a->number_of_tracks; i++)
593  assert_smf_track_is_identical(smf_get_track_by_number(a, i), smf_get_track_by_number(b, i));
594 
595  /* We do not need to compare tempos explicitly, as tempo is always computed from track contents. */
596 }
597 
598 static void
599 assert_smf_saved_correctly(const smf_t *smf, const char *file_name)
600 {
601  smf_t *saved;
602 
603  saved = smf_load(file_name);
604  assert(saved != NULL);
605 
606  assert_smf_is_identical(smf, saved);
607 
608  smf_delete(saved);
609 }
610 
611 #endif /* !NDEBUG */
612 
619 int
620 smf_save(smf_t *smf, const char *file_name)
621 {
622  int i, error;
623  smf_track_t *track;
624 
625  smf_rewind(smf);
626 
627  assert(pointers_are_clear(smf));
628 
629  if (smf_validate(smf))
630  return (-1);
631 
632  if (write_mthd_header(smf))
633  return (-2);
634 
635  for (i = 1; i <= smf->number_of_tracks; i++) {
636  track = smf_get_track_by_number(smf, i);
637 
638  assert(track != NULL);
639 
640  error = write_track(track);
641  if (error) {
642  free_buffer(smf);
643  return (error);
644  }
645  }
646 
647  error = write_file(smf, file_name);
648 
649  free_buffer(smf);
650 
651  if (error)
652  return (error);
653 
654 #ifndef NDEBUG
655  assert_smf_saved_correctly(smf, file_name);
656 #endif
657 
658  return (0);
659 }
660 
void smf_rewind(smf_t *smf)
Rewinds the SMF.
Definition: smf.c:899
smf_event_t * smf_track_get_event_by_number(const smf_track_t *track, int event_number)
Definition: smf.c:769
SMF chunk, used only by smf_load.c and smf_save.c.
Definition: smf_private.h:59
int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_load.c:745
int format
Definition: smf.h:231
int smf_save(smf_t *smf, const char *file_name) WARN_UNUSED_RESULT
Writes the contents of SMF to the file given.
Definition: smf_save.c:620
void * file_buffer
Definition: smf.h:241
SMF chunk header, used only by smf_load.c and smf_save.c.
Definition: smf_private.h:53
unsigned char * midi_buffer
Pointer to the buffer containing MIDI message.
Definition: smf.h:322
int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta)
Add End Of Track metaevent.
Definition: smf.c:524
Represents a &quot;song&quot;, that is, collection of one or more tracks.
Definition: smf.h:230
smf_t * smf_load(const char *file_name) WARN_UNUSED_RESULT
Loads SMF file.
Definition: smf_load.c:912
Represents a single track.
Definition: smf.h:271
int ppqn
These fields are extracted from &quot;division&quot; field of MThd header.
Definition: smf.h:234
int track_number
Definition: smf.h:274
void smf_event_delete(smf_event_t *event)
Detaches event from its track and frees it.
Definition: smf.c:363
int event_number
Number of this event in the track.
Definition: smf.h:306
int smf_event_is_system_common(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_decode.c:90
smf_t * smf
Definition: smf.h:272
int smf_event_is_eot(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_save.c:475
int time_pulses
Time, in pulses, since the start of the song.
Definition: smf.h:313
int smf_event_is_sysex(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_decode.c:104
void smf_delete(smf_t *smf)
Frees smf and all it&#39;s descendant structures.
Definition: smf.c:88
int midi_buffer_length
Length of the MIDI message in the buffer, in bytes.
Definition: smf.h:325
int frames_per_second
Definition: smf.h:235
int number_of_tracks
Definition: smf.h:237
smf_event_t * smf_event_new(void)
Allocates new smf_event_t structure.
Definition: smf.c:217
int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_decode.c:72
int number_of_events
Definition: smf.h:275
Public interface declaration for libsmf, Standard MIDI File format library.
int resolution
Definition: smf.h:236
smf_event_t * smf_track_get_next_event(smf_track_t *track)
Returns next event from the track given and advances next event counter.
Definition: smf.c:692
int file_buffer_length
Definition: smf.h:242
smf_track_t * smf_get_track_by_number(const smf_t *smf, int track_number)
Definition: smf.c:748
double time_seconds
Time, in seconds, since the start of the song.
Definition: smf.h:316
int file_buffer_length
Definition: smf.h:279
smf_event_t * smf_event_new_textual(int type, const char *text)
Definition: smf_save.c:193
Represents a single MIDI event or metaevent.
Definition: smf.h:301
Private header.
void * file_buffer
These are private fields using only by loading and saving routines.
Definition: smf.h:278
int track_number
Tracks are numbered consecutively, starting from 1.
Definition: smf.h:319
int delta_time_pulses
Note that the time fields are invalid, if event is not attached to a track.
Definition: smf.h:310
smf_track_t * track
Pointer to the track, or NULL if event is not attached.
Definition: smf.h:303
smf_t * smf
Definition: smfsh.c:56