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