50#define MAX_VLQ_LENGTH 128
58smf_extend(
smf_t *
smf,
const int length)
60 int i, previous_file_buffer_length =
smf->file_buffer_length;
61 char *previous_file_buffer =
smf->file_buffer;
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;
73 for (i = 1; i <=
smf->number_of_tracks; i++) {
80 return ((
char *)
smf->file_buffer + previous_file_buffer_length);
88smf_append(
smf_t *
smf,
const void *buffer,
const int buffer_length)
92 dest = smf_extend(
smf, buffer_length);
94 g_critical(
"Cannot extend track buffer.");
98 memcpy(dest, buffer, buffer_length);
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);
117 return (smf_append(
smf, &mthd_chunk,
sizeof(mthd_chunk)));
132 buf = smf_extend(track->
smf, length);
148track_append(
smf_track_t *track,
const void *buffer,
const int buffer_length)
152 dest = track_extend(track, buffer_length);
154 g_critical(
"Cannot extend track buffer.");
158 memcpy(dest, buffer, buffer_length);
164format_vlq(
unsigned char *buf,
int length,
unsigned long value)
167 unsigned long buffer;
170 buffer = value & 0x7F;
172 while ((value >>= 7)) {
174 buffer |= ((value & 0x7F) | 0x80);
195 int vlq_length, text_length, copied_length;
198 assert(type >= 1 && type <= 9);
200 text_length = strlen(text);
207 event->midi_buffer_length = 2 + text_length + MAX_VLQ_LENGTH;
210 g_critical(
"Cannot allocate MIDI buffer structure: %s", strerror(errno));
216 event->midi_buffer[0] = 0xFF;
217 event->midi_buffer[1] = type;
219 vlq_length = format_vlq(event->
midi_buffer + 2, MAX_VLQ_LENGTH - 2, text_length);
222 assert(copied_length == text_length);
224 event->midi_buffer_length = 2 + vlq_length + text_length;
235 unsigned char buf[MAX_VLQ_LENGTH];
238 vlq_length = format_vlq(buf, MAX_VLQ_LENGTH, value);
240 return (track_append(event->
track, buf, vlq_length));
259 unsigned char sysex_status = 0xF0;
263 ret = track_append(event->
track, &sysex_status, 1);
286 unsigned char escape_status = 0xF7;
289 return (write_sysex_contents(event));
291 ret = track_append(event->
track, &escape_status, 1);
314 return (write_escaped_event_contents(event));
327 ret = write_event_time(event);
331 ret = write_event_contents(event);
346 memcpy(mtrk_header.id,
"MTrk", 4);
348 return (track_append(track, &mtrk_header,
sizeof(mtrk_header)));
377 ret = write_mtrk_header(track);
382 ret = write_event(event);
387 ret = write_mtrk_length(track);
398write_file(
smf_t *
smf,
const char *file_name)
402 stream = fopen(file_name,
"wb+");
403 if (stream == NULL) {
404 g_critical(
"Cannot open input file: %s", strerror(errno));
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));
415 if (fclose(stream)) {
416 g_critical(
"fclose(3) failed: %s", strerror(errno));
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;
436 for (i = 1; i <=
smf->number_of_tracks; i++) {
455 assert(
smf->file_buffer == NULL);
456 assert(
smf->file_buffer_length == 0);
458 for (i = 1; i <=
smf->number_of_tracks; i++) {
461 assert(track != NULL);
494 int trackno, eventno, eot_found;
498 if (
smf->format < 0 ||
smf->format > 2) {
499 g_critical(
"SMF error: smf->format is less than zero of greater than two.");
503 if (
smf->number_of_tracks < 1) {
504 g_critical(
"SMF error: number of tracks is less than one.");
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.");
513 if (
smf->ppqn <= 0) {
514 g_critical(
"SMF error: PPQN has to be > 0.");
518 for (trackno = 1; trackno <=
smf->number_of_tracks; trackno++) {
529 g_critical(
"Event #%d on track #%d is invalid.", eventno, trackno);
535 g_critical(
"Duplicate End Of Track event on track #%d.", trackno);
545 g_critical(
"smf_track_add_eot_delta_pulses failed.");
582assert_smf_is_identical(
const smf_t *a,
const smf_t *b)
599assert_smf_saved_correctly(
const smf_t *
smf,
const char *file_name)
604 assert(saved != NULL);
606 assert_smf_is_identical(
smf, saved);
627 assert(pointers_are_clear(
smf));
629 if (smf_validate(
smf))
632 if (write_mthd_header(
smf))
635 for (i = 1; i <=
smf->number_of_tracks; i++) {
638 assert(track != NULL);
640 error = write_track(track);
647 error = write_file(
smf, file_name);
655 assert_smf_saved_correctly(
smf, file_name);
smf_event_t * smf_event_new(void)
Allocates new smf_event_t structure.
smf_event_t * smf_track_get_event_by_number(const smf_track_t *track, int event_number)
smf_track_t * smf_get_track_by_number(const smf_t *smf, int track_number)
void smf_delete(smf_t *smf)
Frees smf and all it's descendant structures.
int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta)
Add End Of Track metaevent.
smf_event_t * smf_track_get_next_event(smf_track_t *track)
Returns next event from the track given and advances next event counter.
void smf_rewind(smf_t *smf)
Rewinds the SMF.
void smf_event_delete(smf_event_t *event)
Detaches event from its track and frees it.
Public interface declaration for libsmf, Standard MIDI File format library.
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
struct smf_event_struct smf_event_t
struct smf_track_struct smf_track_t
int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT
int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT
smf_t * smf_load(const char *file_name) WARN_UNUSED_RESULT
Loads SMF file.
int smf_save(smf_t *smf, const char *file_name)
Writes the contents of SMF to the file given.
smf_event_t * smf_event_new_textual(int type, const char *text)
int smf_event_is_eot(const smf_event_t *event)
SMF chunk, used only by smf_load.c and smf_save.c.
int time_pulses
Time, in pulses, since the start of the song.
int event_number
Number of this event in the track.
unsigned char * midi_buffer
Pointer to the buffer containing MIDI message.
double time_seconds
Time, in seconds, since the start of the song.
int track_number
Tracks are numbered consecutively, starting from 1.
int midi_buffer_length
Length of the MIDI message in the buffer, in bytes.
int delta_time_pulses
Note that the time fields are invalid, if event is not attached to a track.
smf_track_t * track
Pointer to the track, or NULL if event is not attached.
int ppqn
These fields are extracted from "division" field of MThd header.
void * file_buffer
These are private fields using only by loading and saving routines.