45 #include <arpa/inet.h>
50 #define MAX_VLQ_LENGTH 128
67 g_critical(
"realloc(3) failed: %s", strerror(errno));
80 return ((
char *)smf->
file_buffer + previous_file_buffer_length);
88 smf_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);
107 write_mthd_header(
smf_t *smf)
111 memcpy(mthd_chunk.mthd_header.id,
"MThd", 4);
112 mthd_chunk.mthd_header.length = htonl(6);
113 mthd_chunk.format = htons(smf->
format);
115 mthd_chunk.division = htons(smf->
ppqn);
117 return (smf_append(smf, &mthd_chunk,
sizeof(mthd_chunk)));
132 buf = smf_extend(track->
smf, length);
148 track_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);
164 format_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);
398 write_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));
410 g_critical(
"fwrite(3) failed: %s", strerror(errno));
415 if (fclose(stream)) {
416 g_critical(
"fclose(3) failed: %s", strerror(errno));
425 free_buffer(
smf_t *smf)
450 pointers_are_clear(
smf_t *smf)
461 assert(track != NULL);
492 smf_validate(
smf_t *smf)
494 int trackno, eventno, eot_found;
499 g_critical(
"SMF error: smf->format is less than zero of greater than two.");
504 g_critical(
"SMF error: number of tracks is less than one.");
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.");
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.");
582 assert_smf_is_identical(
const smf_t *a,
const smf_t *b)
599 assert_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))
638 assert(track != NULL);
640 error = write_track(track);
647 error = write_file(smf, file_name);
655 assert_smf_saved_correctly(smf, file_name);
void smf_rewind(smf_t *smf)
Rewinds the SMF.
smf_event_t * smf_track_get_event_by_number(const smf_track_t *track, int event_number)
SMF chunk, used only by smf_load.c and smf_save.c.
int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT
int smf_save(smf_t *smf, const char *file_name) WARN_UNUSED_RESULT
Writes the contents of SMF to the file given.
unsigned char * midi_buffer
Pointer to the buffer containing MIDI message.
int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta)
Add End Of Track metaevent.
Represents a "song", that is, collection of one or more tracks.
smf_t * smf_load(const char *file_name) WARN_UNUSED_RESULT
Loads SMF file.
Represents a single track.
int ppqn
These fields are extracted from "division" field of MThd header.
void smf_event_delete(smf_event_t *event)
Detaches event from its track and frees it.
int event_number
Number of this event in the track.
int smf_event_is_system_common(const smf_event_t *event) WARN_UNUSED_RESULT
int smf_event_is_eot(const smf_event_t *event) WARN_UNUSED_RESULT
int time_pulses
Time, in pulses, since the start of the song.
int smf_event_is_sysex(const smf_event_t *event) WARN_UNUSED_RESULT
void smf_delete(smf_t *smf)
Frees smf and all it's descendant structures.
int midi_buffer_length
Length of the MIDI message in the buffer, in bytes.
smf_event_t * smf_event_new(void)
Allocates new smf_event_t structure.
int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT
Public interface declaration for libsmf, Standard MIDI File format library.
smf_event_t * smf_track_get_next_event(smf_track_t *track)
Returns next event from the track given and advances next event counter.
smf_track_t * smf_get_track_by_number(const smf_t *smf, int track_number)
double time_seconds
Time, in seconds, since the start of the song.
smf_event_t * smf_event_new_textual(int type, const char *text)
Represents a single MIDI event or metaevent.
void * file_buffer
These are private fields using only by loading and saving routines.
int track_number
Tracks are numbered consecutively, starting from 1.
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.