smflite
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/smf.h Thu Jan 26 11:25:11 2012 +0200 1.3 @@ -0,0 +1,417 @@ 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 + * Public interface declaration for libsmf, Standard MIDI File format library. 1.35 + */ 1.36 + 1.37 +/** 1.38 + * 1.39 + * \mainpage libsmf - general usage instructions 1.40 + * 1.41 + * An smf_t structure represents a "song". Every valid smf contains one or more tracks. 1.42 + * Tracks contain zero or more events. Libsmf doesn't care about actual MIDI data, as long 1.43 + * as it is valid from the MIDI specification point of view - it may be realtime message, 1.44 + * SysEx, whatever. 1.45 + * 1.46 + * The only field in smf_t, smf_track_t, smf_event_t and smf_tempo_t structures your 1.47 + * code may modify is event->midi_buffer and event->midi_buffer_length. Do not modify 1.48 + * other fields, _ever_. You may read them, though. Do not declare static instances 1.49 + * of these types, i.e. never do something like this: "smf_t smf;". Always use 1.50 + * "smf_t *smf = smf_new();". The same applies to smf_track_t and smf_event_t. 1.51 + * 1.52 + * Say you want to load a Standard MIDI File (.mid) file and play it back somehow. This is (roughly) 1.53 + * how you do this: 1.54 + * 1.55 + * \code 1.56 + * smf_t *smf; 1.57 + * smf_event_t *event; 1.58 + * 1.59 + * smf = smf_load(file_name); 1.60 + * if (smf == NULL) { 1.61 + * Whoops, something went wrong. 1.62 + * return; 1.63 + * } 1.64 + * 1.65 + * while ((event = smf_get_next_event(smf)) != NULL) { 1.66 + * if (smf_event_is_metadata(event)) 1.67 + * continue; 1.68 + * 1.69 + * wait until event->time_seconds. 1.70 + * feed_to_midi_output(event->midi_buffer, event->midi_buffer_length); 1.71 + * } 1.72 + * 1.73 + * smf_delete(smf); 1.74 + * 1.75 + * \endcode 1.76 + * 1.77 + * Saving works like this: 1.78 + * 1.79 + * \code 1.80 + * 1.81 + * smf_t *smf; 1.82 + * smf_track_t *track; 1.83 + * smf_event_t *event; 1.84 + * 1.85 + * smf = smf_new(); 1.86 + * if (smf == NULL) { 1.87 + * Whoops. 1.88 + * return; 1.89 + * } 1.90 + * 1.91 + * for (int i = 1; i <= number of tracks; i++) { 1.92 + * track = smf_track_new(); 1.93 + * if (track == NULL) { 1.94 + * Whoops. 1.95 + * return; 1.96 + * } 1.97 + * 1.98 + * smf_add_track(smf, track); 1.99 + * 1.100 + * for (int j = 1; j <= number of events you want to put into this track; j++) { 1.101 + * event = smf_event_new_from_pointer(your MIDI message, message length); 1.102 + * if (event == NULL) { 1.103 + * Whoops. 1.104 + * return; 1.105 + * } 1.106 + * 1.107 + * smf_track_add_event_seconds(track, event, seconds since start of the song); 1.108 + * } 1.109 + * } 1.110 + * 1.111 + * ret = smf_save(smf, file_name); 1.112 + * if (ret) { 1.113 + * Whoops, saving failed for some reason. 1.114 + * return; 1.115 + * } 1.116 + * 1.117 + * smf_delete(smf); 1.118 + * 1.119 + * \endcode 1.120 + * 1.121 + * There are two basic ways of getting MIDI data out of smf - sequential or by track/event number. You may 1.122 + * mix them if you need to. First one is used in the example above - seek to the point from which you want 1.123 + * the playback to start (using smf_seek_to_seconds(), smf_seek_to_pulses() or smf_seek_to_event()) and then 1.124 + * do smf_get_next_event() in loop, until it returns NULL. Calling smf_load() causes the smf to be rewound 1.125 + * to the start of the song. 1.126 + * 1.127 + * Getting events by number works like this: 1.128 + * 1.129 + * \code 1.130 + * 1.131 + * smf_track_t *track = smf_get_track_by_number(smf, track_number); 1.132 + * smf_event_t *event = smf_track_get_event_by_number(track, event_number); 1.133 + * 1.134 + * \endcode 1.135 + * 1.136 + * To create new event, use smf_event_new(), smf_event_new_from_pointer() or smf_event_new_from_bytes(). 1.137 + * First one creates an empty event - you need to manually allocate (using malloc(3)) buffer for 1.138 + * MIDI data, write MIDI data into it, put the address of that buffer into event->midi_buffer, 1.139 + * and the length of MIDI data into event->midi_buffer_length. Note that deleting the event 1.140 + * (using smf_event_delete()) will free the buffer. 1.141 + * 1.142 + * Second form does most of this for you: it takes an address of the buffer containing MIDI data, 1.143 + * allocates storage and copies MIDI data into it. 1.144 + * 1.145 + * Third form is useful for manually creating short events, up to three bytes in length, for 1.146 + * example Note On or Note Off events. It simply takes three bytes and creates MIDI event containing 1.147 + * them. If you need to create MIDI message that takes only two bytes, pass -1 as the third byte. 1.148 + * For one byte message (System Realtime), pass -1 as second and third byte. 1.149 + * 1.150 + * To free an event, use smf_event_delete(). 1.151 + * 1.152 + * To add event to the track, use smf_track_add_event_delta_pulses(), smf_track_add_event_pulses(), 1.153 + * or smf_track_add_event_seconds(). The difference between them is in the way you specify the time of 1.154 + * the event - with the first one, you specify it as an interval, in pulses, from the previous event 1.155 + * in this track; with the second one, you specify it as pulses from the start of the song, and with the 1.156 + * last one, you specify it as seconds from the start of the song. Obviously, the first version can 1.157 + * only append events at the end of the track. 1.158 + * 1.159 + * To remove an event from the track it's attached to, use smf_event_remove_from_track(). You may 1.160 + * want to free the event (using smf_event_delete()) afterwards. 1.161 + * 1.162 + * To create new track, use smf_track_new(). To add track to the smf, use smf_add_track(). 1.163 + * To remove track from its smf, use smf_track_remove_from_smf(). To free the track structure, 1.164 + * use smf_track_delete(). 1.165 + * 1.166 + * Note that libsmf keeps things consistent. If you free (using smf_track_delete()) a track that 1.167 + * is attached to an smf and contains events, libsmf will detach the events, free them, detach 1.168 + * the track, free it etc. 1.169 + * 1.170 + * Tracks and events are numbered consecutively, starting from one. If you remove a track or event, 1.171 + * the rest of tracks/events will get renumbered. To get the number of a given event in its track, use event->event_number. 1.172 + * To get the number of track in its smf, use track->track_number. To get the number of events in the track, 1.173 + * use track->number_of_events. To get the number of tracks in the smf, use smf->number_of_tracks. 1.174 + * 1.175 + * In SMF File Format, each track has to end with End Of Track metaevent. If you load SMF file using smf_load(), 1.176 + * that will be the case. If you want to create or edit an SMF, you don't need to worry about EOT events; 1.177 + * libsmf automatically takes care of them for you. If you try to save an SMF with tracks that do not end 1.178 + * with EOTs, smf_save() will append them. If you try to add event that happens after EOT metaevent, libsmf 1.179 + * will remove the EOT. If you want to add EOT manually, you can, of course, using smf_track_add_eot_seconds() 1.180 + * or smf_track_add_eot_pulses(). 1.181 + * 1.182 + * Each event carries three time values - event->time_seconds, which is seconds since the start of the song, 1.183 + * event->time_pulses, which is PPQN clocks since the start of the song, and event->delta_pulses, which is PPQN clocks 1.184 + * since the previous event in that track. These values are invalid if the event is not attached to the track. 1.185 + * If event is attached, all three values are valid. Time of the event is specified when adding the event 1.186 + * (using smf_track_add_event_seconds(), smf_track_add_event_pulses() or smf_track_add_event_delta_pulses()); the remaining 1.187 + * two values are computed from that. 1.188 + * 1.189 + * Tempo related stuff happens automatically - when you add a metaevent that 1.190 + * is Tempo Change or Time Signature, libsmf adds that event to the tempo map. If you remove 1.191 + * Tempo Change event that is in the middle of the song, the rest of the events will have their 1.192 + * event->time_seconds recomputed from event->time_pulses before smf_event_remove_from_track() function returns. 1.193 + * Adding Tempo Change in the middle of the song works in a similar way. 1.194 + * 1.195 + * MIDI data (event->midi_buffer) is always kept in normalized form - it always begins with status byte 1.196 + * (no running status), there are no System Realtime events embedded in them etc. Events like SysExes 1.197 + * are in "on the wire" form, without embedded length that is used in SMF file format. Obviously 1.198 + * libsmf "normalizes" MIDI data during loading and "denormalizes" (adding length to SysExes, escaping 1.199 + * System Common and System Realtime messages etc) during writing. 1.200 + * 1.201 + * Note that you always have to first add the track to smf, and then add events to the track. 1.202 + * Doing it the other way around will trip asserts. Also, try to add events at the end of the track and remove 1.203 + * them from the end of the track, that's much more efficient. 1.204 + * 1.205 + * All the libsmf functions have prefix "smf_". First argument for routines whose names start with 1.206 + * "smf_event_" is "smf_event_t *", for routines whose names start with "smf_track_" - "smf_track_t *", 1.207 + * and for plain "smf_" - "smf_t *". The only exception are smf_whatever_new routines. 1.208 + * Library does not use any global variables and is thread-safe, 1.209 + * as long as you don't try to work on the same SMF (smf_t and its descendant tracks and events) from several 1.210 + * threads at once without protecting it with mutex. Library depends on glib and nothing else. License is 1.211 + * BSD, two clause, which basically means you can use it freely in your software, both Open Source (including 1.212 + * GPL) and closed source. 1.213 + * 1.214 + */ 1.215 + 1.216 +#ifndef SMF_H 1.217 +#define SMF_H 1.218 + 1.219 +#ifdef __cplusplus 1.220 +extern "C" { 1.221 +#endif 1.222 + 1.223 +#include <stdio.h> 1.224 + 1.225 +#if defined(__GNUC__) && __GNUC__ >= 4 1.226 +#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) 1.227 +#else 1.228 +#define WARN_UNUSED_RESULT 1.229 +#endif 1.230 + 1.231 +struct FakeGPtrArray; 1.232 + 1.233 +/** Represents a "song", that is, collection of one or more tracks. */ 1.234 +struct smf_struct { 1.235 + int format; 1.236 + 1.237 + /** These fields are extracted from "division" field of MThd header. Valid is _either_ ppqn or frames_per_second/resolution. */ 1.238 + int ppqn; 1.239 + int frames_per_second; 1.240 + int resolution; 1.241 + int number_of_tracks; 1.242 + 1.243 + /** These are private fields using only by loading and saving routines. */ 1.244 + FILE *stream; 1.245 + void *file_buffer; 1.246 + int file_buffer_length; 1.247 + int next_chunk_offset; 1.248 + int expected_number_of_tracks; 1.249 + 1.250 + /** Private, used by smf.c. */ 1.251 + struct FakeGPtrArray *tracks_array; 1.252 + double last_seek_position; 1.253 + 1.254 + /** Private, used by smf_tempo.c. */ 1.255 + /** Array of pointers to smf_tempo_struct. */ 1.256 + struct FakeGPtrArray *tempo_array; 1.257 +}; 1.258 + 1.259 +typedef struct smf_struct smf_t; 1.260 + 1.261 +/** Describes a single tempo or time signature change. */ 1.262 +struct smf_tempo_struct { 1.263 + int time_pulses; 1.264 + double time_seconds; 1.265 + int microseconds_per_quarter_note; 1.266 + int numerator; 1.267 + int denominator; 1.268 + int clocks_per_click; 1.269 + int notes_per_note; 1.270 +}; 1.271 + 1.272 +typedef struct smf_tempo_struct smf_tempo_t; 1.273 + 1.274 +/** Represents a single track. */ 1.275 +struct smf_track_struct { 1.276 + smf_t *smf; 1.277 + 1.278 + int track_number; 1.279 + int number_of_events; 1.280 + 1.281 + /** These are private fields using only by loading and saving routines. */ 1.282 + void *file_buffer; 1.283 + int file_buffer_length; 1.284 + int last_status; /* Used for "running status". */ 1.285 + 1.286 + /** Private, used by smf.c. */ 1.287 + /** Offset into buffer, used in parse_next_event(). */ 1.288 + int next_event_offset; 1.289 + int next_event_number; 1.290 + 1.291 + /** Absolute time of next event on events_queue. */ 1.292 + int time_of_next_event; 1.293 + struct FakeGPtrArray *events_array; 1.294 + 1.295 + /** API consumer is free to use this for whatever purpose. NULL in freshly allocated track. 1.296 + Note that tracks might be deallocated not only explicitly, by calling smf_track_delete(), 1.297 + but also implicitly, e.g. when calling smf_delete() with tracks still added to 1.298 + the smf; there is no mechanism for libsmf to notify you about removal of the track. */ 1.299 + void *user_pointer; 1.300 +}; 1.301 + 1.302 +typedef struct smf_track_struct smf_track_t; 1.303 + 1.304 +/** Represents a single MIDI event or metaevent. */ 1.305 +struct smf_event_struct { 1.306 + /** Pointer to the track, or NULL if event is not attached. */ 1.307 + smf_track_t *track; 1.308 + 1.309 + /** Number of this event in the track. Events are numbered consecutively, starting from one. */ 1.310 + int event_number; 1.311 + 1.312 + /** Note that the time fields are invalid, if event is not attached to a track. */ 1.313 + /** Time, in pulses, since the previous event on this track. */ 1.314 + int delta_time_pulses; 1.315 + 1.316 + /** Time, in pulses, since the start of the song. */ 1.317 + int time_pulses; 1.318 + 1.319 + /** Time, in seconds, since the start of the song. */ 1.320 + double time_seconds; 1.321 + 1.322 + /** Tracks are numbered consecutively, starting from 1. */ 1.323 + int track_number; 1.324 + 1.325 + /** Pointer to the buffer containing MIDI message. This is freed by smf_event_delete. */ 1.326 + unsigned char *midi_buffer; 1.327 + 1.328 + /** Length of the MIDI message in the buffer, in bytes. */ 1.329 + int midi_buffer_length; 1.330 + 1.331 + /** API consumer is free to use this for whatever purpose. NULL in freshly allocated event. 1.332 + Note that events might be deallocated not only explicitly, by calling smf_event_delete(), 1.333 + but also implicitly, e.g. when calling smf_track_delete() with events still added to 1.334 + the track; there is no mechanism for libsmf to notify you about removal of the event. */ 1.335 + void *user_pointer; 1.336 +}; 1.337 + 1.338 +typedef struct smf_event_struct smf_event_t; 1.339 + 1.340 +/* Routines for manipulating smf_t. */ 1.341 +smf_t *smf_new(void) WARN_UNUSED_RESULT; 1.342 +void smf_delete(smf_t *smf); 1.343 + 1.344 +int smf_set_format(smf_t *smf, int format) WARN_UNUSED_RESULT; 1.345 +int smf_set_ppqn(smf_t *smf, int format) WARN_UNUSED_RESULT; 1.346 + 1.347 +char *smf_decode(const smf_t *smf) WARN_UNUSED_RESULT; 1.348 + 1.349 +smf_track_t *smf_get_track_by_number(const smf_t *smf, int track_number) WARN_UNUSED_RESULT; 1.350 + 1.351 +smf_event_t *smf_peek_next_event(smf_t *smf) WARN_UNUSED_RESULT; 1.352 +smf_event_t *smf_get_next_event(smf_t *smf) WARN_UNUSED_RESULT; 1.353 +void smf_skip_next_event(smf_t *smf); 1.354 + 1.355 +void smf_rewind(smf_t *smf); 1.356 +int smf_seek_to_seconds(smf_t *smf, double seconds) WARN_UNUSED_RESULT; 1.357 +int smf_seek_to_pulses(smf_t *smf, int pulses) WARN_UNUSED_RESULT; 1.358 +int smf_seek_to_event(smf_t *smf, const smf_event_t *event) WARN_UNUSED_RESULT; 1.359 + 1.360 +int smf_get_length_pulses(const smf_t *smf) WARN_UNUSED_RESULT; 1.361 +double smf_get_length_seconds(const smf_t *smf) WARN_UNUSED_RESULT; 1.362 +int smf_event_is_last(const smf_event_t *event) WARN_UNUSED_RESULT; 1.363 + 1.364 +void smf_add_track(smf_t *smf, smf_track_t *track); 1.365 +void smf_track_remove_from_smf(smf_track_t *track); 1.366 + 1.367 +/* Routines for manipulating smf_track_t. */ 1.368 +smf_track_t *smf_track_new(void) WARN_UNUSED_RESULT; 1.369 +void smf_track_delete(smf_track_t *track); 1.370 + 1.371 +smf_event_t *smf_track_get_next_event(smf_track_t *track) WARN_UNUSED_RESULT; 1.372 +smf_event_t *smf_track_get_event_by_number(const smf_track_t *track, int event_number) WARN_UNUSED_RESULT; 1.373 +smf_event_t *smf_track_get_last_event(const smf_track_t *track) WARN_UNUSED_RESULT; 1.374 + 1.375 +void smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int pulses); 1.376 +void smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses); 1.377 +void smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds); 1.378 +int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta) WARN_UNUSED_RESULT; 1.379 +int smf_track_add_eot_pulses(smf_track_t *track, int pulses) WARN_UNUSED_RESULT; 1.380 +int smf_track_add_eot_seconds(smf_track_t *track, double seconds) WARN_UNUSED_RESULT; 1.381 +void smf_event_remove_from_track(smf_event_t *event); 1.382 + 1.383 +/* Routines for manipulating smf_event_t. */ 1.384 +smf_event_t *smf_event_new(void) WARN_UNUSED_RESULT; 1.385 +smf_event_t *smf_event_new_from_pointer(void *midi_data, int len) WARN_UNUSED_RESULT; 1.386 +smf_event_t *smf_event_new_from_bytes(int first_byte, int second_byte, int third_byte) WARN_UNUSED_RESULT; 1.387 +smf_event_t *smf_event_new_textual(int type, const char *text); 1.388 +void smf_event_delete(smf_event_t *event); 1.389 + 1.390 +int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT; 1.391 +int smf_event_is_metadata(const smf_event_t *event) WARN_UNUSED_RESULT; 1.392 +int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT; 1.393 +int smf_event_is_system_common(const smf_event_t *event) WARN_UNUSED_RESULT; 1.394 +int smf_event_is_sysex(const smf_event_t *event) WARN_UNUSED_RESULT; 1.395 +int smf_event_is_eot(const smf_event_t *event) WARN_UNUSED_RESULT; 1.396 +int smf_event_is_textual(const smf_event_t *event) WARN_UNUSED_RESULT; 1.397 +char *smf_event_decode(const smf_event_t *event) WARN_UNUSED_RESULT; 1.398 +char *smf_event_extract_text(const smf_event_t *event) WARN_UNUSED_RESULT; 1.399 + 1.400 +/* Routines for loading SMF files. */ 1.401 +smf_t *smf_load(const char *file_name) WARN_UNUSED_RESULT; 1.402 +smf_t *smf_load_from_memory(const void *buffer, const int buffer_length) WARN_UNUSED_RESULT; 1.403 + 1.404 +/* Routine for writing SMF files. */ 1.405 +int smf_save(smf_t *smf, const char *file_name) WARN_UNUSED_RESULT; 1.406 + 1.407 +/* Routines for manipulating smf_tempo_t. */ 1.408 +smf_tempo_t *smf_get_tempo_by_pulses(const smf_t *smf, int pulses) WARN_UNUSED_RESULT; 1.409 +smf_tempo_t *smf_get_tempo_by_seconds(const smf_t *smf, double seconds) WARN_UNUSED_RESULT; 1.410 +smf_tempo_t *smf_get_tempo_by_number(const smf_t *smf, int number) WARN_UNUSED_RESULT; 1.411 +smf_tempo_t *smf_get_last_tempo(const smf_t *smf) WARN_UNUSED_RESULT; 1.412 + 1.413 +const char *smf_get_version(void) WARN_UNUSED_RESULT; 1.414 + 1.415 +#ifdef __cplusplus 1.416 +} 1.417 +#endif 1.418 + 1.419 +#endif /* SMF_H */ 1.420 +