smflite

annotate src/smf.h @ 0:4264abea8b06

smf-lite initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 26 Jan 2012 11:25:11 +0200
parents
children
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 * Public interface declaration for libsmf, Standard MIDI File format library.
nuclear@0 32 */
nuclear@0 33
nuclear@0 34 /**
nuclear@0 35 *
nuclear@0 36 * \mainpage libsmf - general usage instructions
nuclear@0 37 *
nuclear@0 38 * An smf_t structure represents a "song". Every valid smf contains one or more tracks.
nuclear@0 39 * Tracks contain zero or more events. Libsmf doesn't care about actual MIDI data, as long
nuclear@0 40 * as it is valid from the MIDI specification point of view - it may be realtime message,
nuclear@0 41 * SysEx, whatever.
nuclear@0 42 *
nuclear@0 43 * The only field in smf_t, smf_track_t, smf_event_t and smf_tempo_t structures your
nuclear@0 44 * code may modify is event->midi_buffer and event->midi_buffer_length. Do not modify
nuclear@0 45 * other fields, _ever_. You may read them, though. Do not declare static instances
nuclear@0 46 * of these types, i.e. never do something like this: "smf_t smf;". Always use
nuclear@0 47 * "smf_t *smf = smf_new();". The same applies to smf_track_t and smf_event_t.
nuclear@0 48 *
nuclear@0 49 * Say you want to load a Standard MIDI File (.mid) file and play it back somehow. This is (roughly)
nuclear@0 50 * how you do this:
nuclear@0 51 *
nuclear@0 52 * \code
nuclear@0 53 * smf_t *smf;
nuclear@0 54 * smf_event_t *event;
nuclear@0 55 *
nuclear@0 56 * smf = smf_load(file_name);
nuclear@0 57 * if (smf == NULL) {
nuclear@0 58 * Whoops, something went wrong.
nuclear@0 59 * return;
nuclear@0 60 * }
nuclear@0 61 *
nuclear@0 62 * while ((event = smf_get_next_event(smf)) != NULL) {
nuclear@0 63 * if (smf_event_is_metadata(event))
nuclear@0 64 * continue;
nuclear@0 65 *
nuclear@0 66 * wait until event->time_seconds.
nuclear@0 67 * feed_to_midi_output(event->midi_buffer, event->midi_buffer_length);
nuclear@0 68 * }
nuclear@0 69 *
nuclear@0 70 * smf_delete(smf);
nuclear@0 71 *
nuclear@0 72 * \endcode
nuclear@0 73 *
nuclear@0 74 * Saving works like this:
nuclear@0 75 *
nuclear@0 76 * \code
nuclear@0 77 *
nuclear@0 78 * smf_t *smf;
nuclear@0 79 * smf_track_t *track;
nuclear@0 80 * smf_event_t *event;
nuclear@0 81 *
nuclear@0 82 * smf = smf_new();
nuclear@0 83 * if (smf == NULL) {
nuclear@0 84 * Whoops.
nuclear@0 85 * return;
nuclear@0 86 * }
nuclear@0 87 *
nuclear@0 88 * for (int i = 1; i <= number of tracks; i++) {
nuclear@0 89 * track = smf_track_new();
nuclear@0 90 * if (track == NULL) {
nuclear@0 91 * Whoops.
nuclear@0 92 * return;
nuclear@0 93 * }
nuclear@0 94 *
nuclear@0 95 * smf_add_track(smf, track);
nuclear@0 96 *
nuclear@0 97 * for (int j = 1; j <= number of events you want to put into this track; j++) {
nuclear@0 98 * event = smf_event_new_from_pointer(your MIDI message, message length);
nuclear@0 99 * if (event == NULL) {
nuclear@0 100 * Whoops.
nuclear@0 101 * return;
nuclear@0 102 * }
nuclear@0 103 *
nuclear@0 104 * smf_track_add_event_seconds(track, event, seconds since start of the song);
nuclear@0 105 * }
nuclear@0 106 * }
nuclear@0 107 *
nuclear@0 108 * ret = smf_save(smf, file_name);
nuclear@0 109 * if (ret) {
nuclear@0 110 * Whoops, saving failed for some reason.
nuclear@0 111 * return;
nuclear@0 112 * }
nuclear@0 113 *
nuclear@0 114 * smf_delete(smf);
nuclear@0 115 *
nuclear@0 116 * \endcode
nuclear@0 117 *
nuclear@0 118 * There are two basic ways of getting MIDI data out of smf - sequential or by track/event number. You may
nuclear@0 119 * mix them if you need to. First one is used in the example above - seek to the point from which you want
nuclear@0 120 * the playback to start (using smf_seek_to_seconds(), smf_seek_to_pulses() or smf_seek_to_event()) and then
nuclear@0 121 * do smf_get_next_event() in loop, until it returns NULL. Calling smf_load() causes the smf to be rewound
nuclear@0 122 * to the start of the song.
nuclear@0 123 *
nuclear@0 124 * Getting events by number works like this:
nuclear@0 125 *
nuclear@0 126 * \code
nuclear@0 127 *
nuclear@0 128 * smf_track_t *track = smf_get_track_by_number(smf, track_number);
nuclear@0 129 * smf_event_t *event = smf_track_get_event_by_number(track, event_number);
nuclear@0 130 *
nuclear@0 131 * \endcode
nuclear@0 132 *
nuclear@0 133 * To create new event, use smf_event_new(), smf_event_new_from_pointer() or smf_event_new_from_bytes().
nuclear@0 134 * First one creates an empty event - you need to manually allocate (using malloc(3)) buffer for
nuclear@0 135 * MIDI data, write MIDI data into it, put the address of that buffer into event->midi_buffer,
nuclear@0 136 * and the length of MIDI data into event->midi_buffer_length. Note that deleting the event
nuclear@0 137 * (using smf_event_delete()) will free the buffer.
nuclear@0 138 *
nuclear@0 139 * Second form does most of this for you: it takes an address of the buffer containing MIDI data,
nuclear@0 140 * allocates storage and copies MIDI data into it.
nuclear@0 141 *
nuclear@0 142 * Third form is useful for manually creating short events, up to three bytes in length, for
nuclear@0 143 * example Note On or Note Off events. It simply takes three bytes and creates MIDI event containing
nuclear@0 144 * them. If you need to create MIDI message that takes only two bytes, pass -1 as the third byte.
nuclear@0 145 * For one byte message (System Realtime), pass -1 as second and third byte.
nuclear@0 146 *
nuclear@0 147 * To free an event, use smf_event_delete().
nuclear@0 148 *
nuclear@0 149 * To add event to the track, use smf_track_add_event_delta_pulses(), smf_track_add_event_pulses(),
nuclear@0 150 * or smf_track_add_event_seconds(). The difference between them is in the way you specify the time of
nuclear@0 151 * the event - with the first one, you specify it as an interval, in pulses, from the previous event
nuclear@0 152 * in this track; with the second one, you specify it as pulses from the start of the song, and with the
nuclear@0 153 * last one, you specify it as seconds from the start of the song. Obviously, the first version can
nuclear@0 154 * only append events at the end of the track.
nuclear@0 155 *
nuclear@0 156 * To remove an event from the track it's attached to, use smf_event_remove_from_track(). You may
nuclear@0 157 * want to free the event (using smf_event_delete()) afterwards.
nuclear@0 158 *
nuclear@0 159 * To create new track, use smf_track_new(). To add track to the smf, use smf_add_track().
nuclear@0 160 * To remove track from its smf, use smf_track_remove_from_smf(). To free the track structure,
nuclear@0 161 * use smf_track_delete().
nuclear@0 162 *
nuclear@0 163 * Note that libsmf keeps things consistent. If you free (using smf_track_delete()) a track that
nuclear@0 164 * is attached to an smf and contains events, libsmf will detach the events, free them, detach
nuclear@0 165 * the track, free it etc.
nuclear@0 166 *
nuclear@0 167 * Tracks and events are numbered consecutively, starting from one. If you remove a track or event,
nuclear@0 168 * the rest of tracks/events will get renumbered. To get the number of a given event in its track, use event->event_number.
nuclear@0 169 * To get the number of track in its smf, use track->track_number. To get the number of events in the track,
nuclear@0 170 * use track->number_of_events. To get the number of tracks in the smf, use smf->number_of_tracks.
nuclear@0 171 *
nuclear@0 172 * In SMF File Format, each track has to end with End Of Track metaevent. If you load SMF file using smf_load(),
nuclear@0 173 * that will be the case. If you want to create or edit an SMF, you don't need to worry about EOT events;
nuclear@0 174 * libsmf automatically takes care of them for you. If you try to save an SMF with tracks that do not end
nuclear@0 175 * with EOTs, smf_save() will append them. If you try to add event that happens after EOT metaevent, libsmf
nuclear@0 176 * will remove the EOT. If you want to add EOT manually, you can, of course, using smf_track_add_eot_seconds()
nuclear@0 177 * or smf_track_add_eot_pulses().
nuclear@0 178 *
nuclear@0 179 * Each event carries three time values - event->time_seconds, which is seconds since the start of the song,
nuclear@0 180 * event->time_pulses, which is PPQN clocks since the start of the song, and event->delta_pulses, which is PPQN clocks
nuclear@0 181 * since the previous event in that track. These values are invalid if the event is not attached to the track.
nuclear@0 182 * If event is attached, all three values are valid. Time of the event is specified when adding the event
nuclear@0 183 * (using smf_track_add_event_seconds(), smf_track_add_event_pulses() or smf_track_add_event_delta_pulses()); the remaining
nuclear@0 184 * two values are computed from that.
nuclear@0 185 *
nuclear@0 186 * Tempo related stuff happens automatically - when you add a metaevent that
nuclear@0 187 * is Tempo Change or Time Signature, libsmf adds that event to the tempo map. If you remove
nuclear@0 188 * Tempo Change event that is in the middle of the song, the rest of the events will have their
nuclear@0 189 * event->time_seconds recomputed from event->time_pulses before smf_event_remove_from_track() function returns.
nuclear@0 190 * Adding Tempo Change in the middle of the song works in a similar way.
nuclear@0 191 *
nuclear@0 192 * MIDI data (event->midi_buffer) is always kept in normalized form - it always begins with status byte
nuclear@0 193 * (no running status), there are no System Realtime events embedded in them etc. Events like SysExes
nuclear@0 194 * are in "on the wire" form, without embedded length that is used in SMF file format. Obviously
nuclear@0 195 * libsmf "normalizes" MIDI data during loading and "denormalizes" (adding length to SysExes, escaping
nuclear@0 196 * System Common and System Realtime messages etc) during writing.
nuclear@0 197 *
nuclear@0 198 * Note that you always have to first add the track to smf, and then add events to the track.
nuclear@0 199 * Doing it the other way around will trip asserts. Also, try to add events at the end of the track and remove
nuclear@0 200 * them from the end of the track, that's much more efficient.
nuclear@0 201 *
nuclear@0 202 * All the libsmf functions have prefix "smf_". First argument for routines whose names start with
nuclear@0 203 * "smf_event_" is "smf_event_t *", for routines whose names start with "smf_track_" - "smf_track_t *",
nuclear@0 204 * and for plain "smf_" - "smf_t *". The only exception are smf_whatever_new routines.
nuclear@0 205 * Library does not use any global variables and is thread-safe,
nuclear@0 206 * as long as you don't try to work on the same SMF (smf_t and its descendant tracks and events) from several
nuclear@0 207 * threads at once without protecting it with mutex. Library depends on glib and nothing else. License is
nuclear@0 208 * BSD, two clause, which basically means you can use it freely in your software, both Open Source (including
nuclear@0 209 * GPL) and closed source.
nuclear@0 210 *
nuclear@0 211 */
nuclear@0 212
nuclear@0 213 #ifndef SMF_H
nuclear@0 214 #define SMF_H
nuclear@0 215
nuclear@0 216 #ifdef __cplusplus
nuclear@0 217 extern "C" {
nuclear@0 218 #endif
nuclear@0 219
nuclear@0 220 #include <stdio.h>
nuclear@0 221
nuclear@0 222 #if defined(__GNUC__) && __GNUC__ >= 4
nuclear@0 223 #define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
nuclear@0 224 #else
nuclear@0 225 #define WARN_UNUSED_RESULT
nuclear@0 226 #endif
nuclear@0 227
nuclear@0 228 struct FakeGPtrArray;
nuclear@0 229
nuclear@0 230 /** Represents a "song", that is, collection of one or more tracks. */
nuclear@0 231 struct smf_struct {
nuclear@0 232 int format;
nuclear@0 233
nuclear@0 234 /** These fields are extracted from "division" field of MThd header. Valid is _either_ ppqn or frames_per_second/resolution. */
nuclear@0 235 int ppqn;
nuclear@0 236 int frames_per_second;
nuclear@0 237 int resolution;
nuclear@0 238 int number_of_tracks;
nuclear@0 239
nuclear@0 240 /** These are private fields using only by loading and saving routines. */
nuclear@0 241 FILE *stream;
nuclear@0 242 void *file_buffer;
nuclear@0 243 int file_buffer_length;
nuclear@0 244 int next_chunk_offset;
nuclear@0 245 int expected_number_of_tracks;
nuclear@0 246
nuclear@0 247 /** Private, used by smf.c. */
nuclear@0 248 struct FakeGPtrArray *tracks_array;
nuclear@0 249 double last_seek_position;
nuclear@0 250
nuclear@0 251 /** Private, used by smf_tempo.c. */
nuclear@0 252 /** Array of pointers to smf_tempo_struct. */
nuclear@0 253 struct FakeGPtrArray *tempo_array;
nuclear@0 254 };
nuclear@0 255
nuclear@0 256 typedef struct smf_struct smf_t;
nuclear@0 257
nuclear@0 258 /** Describes a single tempo or time signature change. */
nuclear@0 259 struct smf_tempo_struct {
nuclear@0 260 int time_pulses;
nuclear@0 261 double time_seconds;
nuclear@0 262 int microseconds_per_quarter_note;
nuclear@0 263 int numerator;
nuclear@0 264 int denominator;
nuclear@0 265 int clocks_per_click;
nuclear@0 266 int notes_per_note;
nuclear@0 267 };
nuclear@0 268
nuclear@0 269 typedef struct smf_tempo_struct smf_tempo_t;
nuclear@0 270
nuclear@0 271 /** Represents a single track. */
nuclear@0 272 struct smf_track_struct {
nuclear@0 273 smf_t *smf;
nuclear@0 274
nuclear@0 275 int track_number;
nuclear@0 276 int number_of_events;
nuclear@0 277
nuclear@0 278 /** These are private fields using only by loading and saving routines. */
nuclear@0 279 void *file_buffer;
nuclear@0 280 int file_buffer_length;
nuclear@0 281 int last_status; /* Used for "running status". */
nuclear@0 282
nuclear@0 283 /** Private, used by smf.c. */
nuclear@0 284 /** Offset into buffer, used in parse_next_event(). */
nuclear@0 285 int next_event_offset;
nuclear@0 286 int next_event_number;
nuclear@0 287
nuclear@0 288 /** Absolute time of next event on events_queue. */
nuclear@0 289 int time_of_next_event;
nuclear@0 290 struct FakeGPtrArray *events_array;
nuclear@0 291
nuclear@0 292 /** API consumer is free to use this for whatever purpose. NULL in freshly allocated track.
nuclear@0 293 Note that tracks might be deallocated not only explicitly, by calling smf_track_delete(),
nuclear@0 294 but also implicitly, e.g. when calling smf_delete() with tracks still added to
nuclear@0 295 the smf; there is no mechanism for libsmf to notify you about removal of the track. */
nuclear@0 296 void *user_pointer;
nuclear@0 297 };
nuclear@0 298
nuclear@0 299 typedef struct smf_track_struct smf_track_t;
nuclear@0 300
nuclear@0 301 /** Represents a single MIDI event or metaevent. */
nuclear@0 302 struct smf_event_struct {
nuclear@0 303 /** Pointer to the track, or NULL if event is not attached. */
nuclear@0 304 smf_track_t *track;
nuclear@0 305
nuclear@0 306 /** Number of this event in the track. Events are numbered consecutively, starting from one. */
nuclear@0 307 int event_number;
nuclear@0 308
nuclear@0 309 /** Note that the time fields are invalid, if event is not attached to a track. */
nuclear@0 310 /** Time, in pulses, since the previous event on this track. */
nuclear@0 311 int delta_time_pulses;
nuclear@0 312
nuclear@0 313 /** Time, in pulses, since the start of the song. */
nuclear@0 314 int time_pulses;
nuclear@0 315
nuclear@0 316 /** Time, in seconds, since the start of the song. */
nuclear@0 317 double time_seconds;
nuclear@0 318
nuclear@0 319 /** Tracks are numbered consecutively, starting from 1. */
nuclear@0 320 int track_number;
nuclear@0 321
nuclear@0 322 /** Pointer to the buffer containing MIDI message. This is freed by smf_event_delete. */
nuclear@0 323 unsigned char *midi_buffer;
nuclear@0 324
nuclear@0 325 /** Length of the MIDI message in the buffer, in bytes. */
nuclear@0 326 int midi_buffer_length;
nuclear@0 327
nuclear@0 328 /** API consumer is free to use this for whatever purpose. NULL in freshly allocated event.
nuclear@0 329 Note that events might be deallocated not only explicitly, by calling smf_event_delete(),
nuclear@0 330 but also implicitly, e.g. when calling smf_track_delete() with events still added to
nuclear@0 331 the track; there is no mechanism for libsmf to notify you about removal of the event. */
nuclear@0 332 void *user_pointer;
nuclear@0 333 };
nuclear@0 334
nuclear@0 335 typedef struct smf_event_struct smf_event_t;
nuclear@0 336
nuclear@0 337 /* Routines for manipulating smf_t. */
nuclear@0 338 smf_t *smf_new(void) WARN_UNUSED_RESULT;
nuclear@0 339 void smf_delete(smf_t *smf);
nuclear@0 340
nuclear@0 341 int smf_set_format(smf_t *smf, int format) WARN_UNUSED_RESULT;
nuclear@0 342 int smf_set_ppqn(smf_t *smf, int format) WARN_UNUSED_RESULT;
nuclear@0 343
nuclear@0 344 char *smf_decode(const smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 345
nuclear@0 346 smf_track_t *smf_get_track_by_number(const smf_t *smf, int track_number) WARN_UNUSED_RESULT;
nuclear@0 347
nuclear@0 348 smf_event_t *smf_peek_next_event(smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 349 smf_event_t *smf_get_next_event(smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 350 void smf_skip_next_event(smf_t *smf);
nuclear@0 351
nuclear@0 352 void smf_rewind(smf_t *smf);
nuclear@0 353 int smf_seek_to_seconds(smf_t *smf, double seconds) WARN_UNUSED_RESULT;
nuclear@0 354 int smf_seek_to_pulses(smf_t *smf, int pulses) WARN_UNUSED_RESULT;
nuclear@0 355 int smf_seek_to_event(smf_t *smf, const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 356
nuclear@0 357 int smf_get_length_pulses(const smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 358 double smf_get_length_seconds(const smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 359 int smf_event_is_last(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 360
nuclear@0 361 void smf_add_track(smf_t *smf, smf_track_t *track);
nuclear@0 362 void smf_track_remove_from_smf(smf_track_t *track);
nuclear@0 363
nuclear@0 364 /* Routines for manipulating smf_track_t. */
nuclear@0 365 smf_track_t *smf_track_new(void) WARN_UNUSED_RESULT;
nuclear@0 366 void smf_track_delete(smf_track_t *track);
nuclear@0 367
nuclear@0 368 smf_event_t *smf_track_get_next_event(smf_track_t *track) WARN_UNUSED_RESULT;
nuclear@0 369 smf_event_t *smf_track_get_event_by_number(const smf_track_t *track, int event_number) WARN_UNUSED_RESULT;
nuclear@0 370 smf_event_t *smf_track_get_last_event(const smf_track_t *track) WARN_UNUSED_RESULT;
nuclear@0 371
nuclear@0 372 void smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int pulses);
nuclear@0 373 void smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses);
nuclear@0 374 void smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds);
nuclear@0 375 int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta) WARN_UNUSED_RESULT;
nuclear@0 376 int smf_track_add_eot_pulses(smf_track_t *track, int pulses) WARN_UNUSED_RESULT;
nuclear@0 377 int smf_track_add_eot_seconds(smf_track_t *track, double seconds) WARN_UNUSED_RESULT;
nuclear@0 378 void smf_event_remove_from_track(smf_event_t *event);
nuclear@0 379
nuclear@0 380 /* Routines for manipulating smf_event_t. */
nuclear@0 381 smf_event_t *smf_event_new(void) WARN_UNUSED_RESULT;
nuclear@0 382 smf_event_t *smf_event_new_from_pointer(void *midi_data, int len) WARN_UNUSED_RESULT;
nuclear@0 383 smf_event_t *smf_event_new_from_bytes(int first_byte, int second_byte, int third_byte) WARN_UNUSED_RESULT;
nuclear@0 384 smf_event_t *smf_event_new_textual(int type, const char *text);
nuclear@0 385 void smf_event_delete(smf_event_t *event);
nuclear@0 386
nuclear@0 387 int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 388 int smf_event_is_metadata(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 389 int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 390 int smf_event_is_system_common(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 391 int smf_event_is_sysex(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 392 int smf_event_is_eot(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 393 int smf_event_is_textual(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 394 char *smf_event_decode(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 395 char *smf_event_extract_text(const smf_event_t *event) WARN_UNUSED_RESULT;
nuclear@0 396
nuclear@0 397 /* Routines for loading SMF files. */
nuclear@0 398 smf_t *smf_load(const char *file_name) WARN_UNUSED_RESULT;
nuclear@0 399 smf_t *smf_load_from_memory(const void *buffer, const int buffer_length) WARN_UNUSED_RESULT;
nuclear@0 400
nuclear@0 401 /* Routine for writing SMF files. */
nuclear@0 402 int smf_save(smf_t *smf, const char *file_name) WARN_UNUSED_RESULT;
nuclear@0 403
nuclear@0 404 /* Routines for manipulating smf_tempo_t. */
nuclear@0 405 smf_tempo_t *smf_get_tempo_by_pulses(const smf_t *smf, int pulses) WARN_UNUSED_RESULT;
nuclear@0 406 smf_tempo_t *smf_get_tempo_by_seconds(const smf_t *smf, double seconds) WARN_UNUSED_RESULT;
nuclear@0 407 smf_tempo_t *smf_get_tempo_by_number(const smf_t *smf, int number) WARN_UNUSED_RESULT;
nuclear@0 408 smf_tempo_t *smf_get_last_tempo(const smf_t *smf) WARN_UNUSED_RESULT;
nuclear@0 409
nuclear@0 410 const char *smf_get_version(void) WARN_UNUSED_RESULT;
nuclear@0 411
nuclear@0 412 #ifdef __cplusplus
nuclear@0 413 }
nuclear@0 414 #endif
nuclear@0 415
nuclear@0 416 #endif /* SMF_H */
nuclear@0 417