smflite
changeset 0:4264abea8b06
smf-lite initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 26 Jan 2012 11:25:11 +0200 |
parents | |
children | 8e535ca4bb86 |
files | .hgignore Makefile src/config.h src/fake_glib.c src/fake_glib.h src/smf.c src/smf.h src/smf_decode.c src/smf_load.c src/smf_private.h src/smf_save.c src/smf_tempo.c |
diffstat | 12 files changed, 4534 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Thu Jan 26 11:25:11 2012 +0200 1.3 @@ -0,0 +1,6 @@ 1.4 +\.d$ 1.5 +\.o$ 1.6 +\.swp$ 1.7 +smflite.a$ 1.8 +^libsmflite.so 1.9 +^smflite.dylib$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Thu Jan 26 11:25:11 2012 +0200 2.3 @@ -0,0 +1,61 @@ 2.4 +PREFIX = /usr/local 2.5 + 2.6 +src = $(wildcard src/*.c) 2.7 +obj = $(src:.c=.o) 2.8 +dep = $(obj:.o=.d) 2.9 + 2.10 +name = smflite 2.11 +lib_a = lib$(name).a 2.12 + 2.13 +ifeq ($(shell uname -s), Darwin) 2.14 + lib_so = $(name).dylib 2.15 + shared = -dynamiclib 2.16 +else 2.17 + abi = 0 2.18 + rev = 0 2.19 + devlink = lib$(name).so 2.20 + soname = $(devlink).$(abi) 2.21 + lib_so = $(soname).$(rev) 2.22 + shared = -shared -Wl,-soname=$(soname) 2.23 + pic = -fPIC 2.24 +endif 2.25 + 2.26 +CFLAGS = -pedantic -Wall -g $(pic) 2.27 + 2.28 +.PHONY: all 2.29 +all: $(lib_a) $(lib_so) 2.30 + 2.31 +$(lib_so): $(obj) 2.32 + $(CC) $(shared) -o $@ $(obj) $(LDFLAGS) 2.33 + 2.34 +$(lib_a): $(obj) 2.35 + $(AR) rcs $@ $(obj) 2.36 + 2.37 +-include $(dep) 2.38 + 2.39 +%.d: %.c 2.40 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.41 + 2.42 +.PHONY: clean 2.43 +clean: 2.44 + rm -f $(obj) $(lib_so) $(lib_a) 2.45 + 2.46 +.PHONY: install 2.47 +install: $(lib_so) $(lib_a) 2.48 + mkdir -p $(INSTDIR)$(PREFIX)/include $(INSTDIR)$(PREFIX)/lib 2.49 + cp src/smf.h $(INSTDIR)$(PREFIX)/include/smf.h 2.50 + cp $(lib_a) $(INSTDIR)$(PREFIX)/lib/$(lib_a) 2.51 + cp $(lib_so) $(INSTDIR)$(PREFIX)/lib/$(lib_so) 2.52 + [ -n "$(soname)" ] && \ 2.53 + cd $(INSTDIR)$(PREFIX)/lib && \ 2.54 + ln -s $(lib_so) $(soname) && \ 2.55 + ln -s $(soname) $(devlink) || true 2.56 + 2.57 +.PHONY: uninstall 2.58 +uninstall: 2.59 + rm -f $(INSTDIR)$(PREFIX)/include/smf.h 2.60 + rm -f $(INSTDIR)$(PREFIX)/lib/$(lib_a) 2.61 + rm -f $(INSTDIR)$(PREFIX)/lib/$(lib_so) 2.62 + [ -n "$(soname)" ] && \ 2.63 + rm -f $(INSTDIR)$(PREFIX)/lib/$(soname) && \ 2.64 + rm -f $(INSTDIR)$(PREFIX)/lib/$(devlink) || true
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/config.h Thu Jan 26 11:25:11 2012 +0200 3.3 @@ -0,0 +1,6 @@ 3.4 +#ifndef CONFIG_H_ 3.5 +#define CONFIG_H_ 3.6 + 3.7 +#define PACKAGE_VERSION "1.3-lite" 3.8 + 3.9 +#endif /* CONFIG_H_ */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/fake_glib.c Thu Jan 26 11:25:11 2012 +0200 4.3 @@ -0,0 +1,126 @@ 4.4 +#include <stdio.h> 4.5 +#include <stdlib.h> 4.6 +#include <string.h> 4.7 +#include <stdarg.h> 4.8 +#include <assert.h> 4.9 +#include "fake_glib.h" 4.10 + 4.11 +FakeGPtrArray *fg_ptr_array_new(void) 4.12 +{ 4.13 + FakeGPtrArray *arr; 4.14 + 4.15 + if(!(arr = malloc(sizeof *arr))) { 4.16 + return 0; 4.17 + } 4.18 + arr->pdata = 0; 4.19 + arr->len = 0; 4.20 + return arr; 4.21 +} 4.22 + 4.23 +void **fg_ptr_array_free(FakeGPtrArray *arr, int free_seg) 4.24 +{ 4.25 + void **res; 4.26 + 4.27 + if(!arr) { 4.28 + return 0; 4.29 + } 4.30 + 4.31 + if(free_seg) { 4.32 + free(arr->pdata); 4.33 + res = 0; 4.34 + } else { 4.35 + res = arr->pdata; 4.36 + } 4.37 + free(arr); 4.38 + return res; 4.39 +} 4.40 + 4.41 +void fg_ptr_array_add(FakeGPtrArray *arr, void *data) 4.42 +{ 4.43 + int idx = arr->len++; 4.44 + 4.45 + arr->pdata = realloc(arr->pdata, arr->len * sizeof *arr->pdata); 4.46 + assert(arr->pdata); 4.47 + 4.48 + arr->pdata[idx] = data; 4.49 +} 4.50 + 4.51 +int fg_ptr_array_remove(FakeGPtrArray *arr, void *data) 4.52 +{ 4.53 + int i; 4.54 + 4.55 + for(i=0; i<arr->len; i++) { 4.56 + if(arr->pdata[i] == data) { 4.57 + fg_ptr_array_remove_index(arr, i); 4.58 + return 1; 4.59 + } 4.60 + } 4.61 + 4.62 + return 0; 4.63 +} 4.64 + 4.65 +void *fg_ptr_array_remove_index(FakeGPtrArray *arr, unsigned int idx) 4.66 +{ 4.67 + void *data = arr->pdata[idx]; 4.68 + int rest = --arr->len - idx; 4.69 + if(rest > 0) { 4.70 + memmove(arr->pdata + idx, arr->pdata + idx + 1, rest * sizeof *arr->pdata); 4.71 + } 4.72 + return data; 4.73 +} 4.74 + 4.75 +void fg_ptr_array_sort(FakeGPtrArray *arr, FakeGCompareFunc cmp) 4.76 +{ 4.77 + qsort(arr->pdata, arr->len, sizeof *arr->pdata, cmp); 4.78 +} 4.79 + 4.80 +/* -- logging -- */ 4.81 + 4.82 +void fg_warning(const char *fmt, ...) 4.83 +{ 4.84 + va_list ap; 4.85 + 4.86 + printf("warning: "); 4.87 + 4.88 + va_start(ap, fmt); 4.89 + vprintf(fmt, ap); 4.90 + va_end(ap); 4.91 +} 4.92 + 4.93 +void fg_critical(const char *fmt, ...) 4.94 +{ 4.95 + va_list ap; 4.96 + 4.97 + printf("critical: "); 4.98 + 4.99 + va_start(ap, fmt); 4.100 + vfprintf(stderr, fmt, ap); 4.101 + va_end(ap); 4.102 + 4.103 + if(getenv("G_DEBUG")) { 4.104 + abort(); 4.105 + } 4.106 +} 4.107 + 4.108 +void fg_error(const char *fmt, ...) 4.109 +{ 4.110 + va_list ap; 4.111 + 4.112 + printf("error: "); 4.113 + 4.114 + va_start(ap, fmt); 4.115 + vfprintf(stderr, fmt, ap); 4.116 + va_end(ap); 4.117 + abort(); 4.118 +} 4.119 + 4.120 +void fg_debug(const char *fmt, ...) 4.121 +{ 4.122 + va_list ap; 4.123 + 4.124 + printf("debug: "); 4.125 + 4.126 + va_start(ap, fmt); 4.127 + vprintf(fmt, ap); 4.128 + va_end(ap); 4.129 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/fake_glib.h Thu Jan 26 11:25:11 2012 +0200 5.3 @@ -0,0 +1,40 @@ 5.4 +#ifndef FAKE_GLIB_H_ 5.5 +#define FAKE_GLIB_H_ 5.6 + 5.7 +typedef struct FakeGPtrArray { 5.8 + void **pdata; 5.9 + unsigned int len; 5.10 +} FakeGPtrArray; 5.11 + 5.12 +typedef int (*FakeGCompareFunc)(const void*, const void*); 5.13 + 5.14 +#ifndef TRUE 5.15 +#define TRUE 1 5.16 +#endif 5.17 +#ifndef FALSE 5.18 +#define FALSE 0 5.19 +#endif 5.20 + 5.21 +typedef int gint; 5.22 +typedef void* gpointer; 5.23 +typedef const void* gconstpointer; 5.24 + 5.25 +#define fg_ptr_array_index(arr, idx) ((arr)->pdata[idx]) 5.26 + 5.27 +FakeGPtrArray *fg_ptr_array_new(void); 5.28 +void **fg_ptr_array_free(FakeGPtrArray *arr, int free_seg); 5.29 + 5.30 +void fg_ptr_array_add(FakeGPtrArray *arr, void *data); 5.31 +int fg_ptr_array_remove(FakeGPtrArray *arr, void *data); 5.32 +void *fg_ptr_array_remove_index(FakeGPtrArray *arr, unsigned int idx); 5.33 + 5.34 +void fg_ptr_array_sort(FakeGPtrArray *arr, FakeGCompareFunc cmp); 5.35 + 5.36 +/* -- logging -- */ 5.37 +#define fg_message printf 5.38 +void fg_warning(const char *fmt, ...); 5.39 +void fg_critical(const char *fmt, ...); 5.40 +void fg_error(const char *fmt, ...); 5.41 +void fg_debug(const char *fmt, ...); 5.42 + 5.43 +#endif /* FAKE_GLIB_H_ */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/smf.c Thu Jan 26 11:25:11 2012 +0200 6.3 @@ -0,0 +1,1116 @@ 6.4 +/*- 6.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 6.6 + * All rights reserved. 6.7 + * 6.8 + * Redistribution and use in source and binary forms, with or without 6.9 + * modification, are permitted provided that the following conditions 6.10 + * are met: 6.11 + * 1. Redistributions of source code must retain the above copyright 6.12 + * notice, this list of conditions and the following disclaimer. 6.13 + * 2. Redistributions in binary form must reproduce the above copyright 6.14 + * notice, this list of conditions and the following disclaimer in the 6.15 + * documentation and/or other materials provided with the distribution. 6.16 + * 6.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 6.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 6.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 6.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 6.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 6.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 6.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 6.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 6.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 6.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 6.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6.28 + * 6.29 + */ 6.30 + 6.31 +/** 6.32 + * \file 6.33 + * 6.34 + * Various functions. 6.35 + * 6.36 + */ 6.37 + 6.38 +/* Reference: http://www.borg.com/~jglatt/tech/midifile.htm */ 6.39 + 6.40 +#include <stdlib.h> 6.41 +#include <string.h> 6.42 +#include <assert.h> 6.43 +#include <math.h> 6.44 +#include <errno.h> 6.45 +#ifdef __MINGW32__ 6.46 +#include <windows.h> 6.47 +#else /* ! __MINGW32__ */ 6.48 +#include <arpa/inet.h> 6.49 +#endif /* ! __MINGW32__ */ 6.50 +#include "smf.h" 6.51 +#include "smf_private.h" 6.52 + 6.53 +/** 6.54 + * Allocates new smf_t structure. 6.55 + * \return pointer to smf_t or NULL. 6.56 + */ 6.57 +smf_t * 6.58 +smf_new(void) 6.59 +{ 6.60 + int cantfail; 6.61 + 6.62 + smf_t *smf = malloc(sizeof(smf_t)); 6.63 + if (smf == NULL) { 6.64 + fg_critical("Cannot allocate smf_t structure: %s", strerror(errno)); 6.65 + return (NULL); 6.66 + } 6.67 + 6.68 + memset(smf, 0, sizeof(smf_t)); 6.69 + 6.70 + smf->tracks_array = fg_ptr_array_new(); 6.71 + assert(smf->tracks_array); 6.72 + 6.73 + smf->tempo_array = fg_ptr_array_new(); 6.74 + assert(smf->tempo_array); 6.75 + 6.76 + cantfail = smf_set_ppqn(smf, 120); 6.77 + assert(!cantfail); 6.78 + 6.79 + cantfail = smf_set_format(smf, 0); 6.80 + assert(!cantfail); 6.81 + 6.82 + smf_init_tempo(smf); 6.83 + 6.84 + return (smf); 6.85 +} 6.86 + 6.87 +/** 6.88 + * Frees smf and all it's descendant structures. 6.89 + */ 6.90 +void 6.91 +smf_delete(smf_t *smf) 6.92 +{ 6.93 + /* Remove all the tracks, from last to first. */ 6.94 + while (smf->tracks_array->len > 0) 6.95 + smf_track_delete(fg_ptr_array_index(smf->tracks_array, smf->tracks_array->len - 1)); 6.96 + 6.97 + smf_fini_tempo(smf); 6.98 + 6.99 + assert(smf->tracks_array->len == 0); 6.100 + assert(smf->number_of_tracks == 0); 6.101 + fg_ptr_array_free(smf->tracks_array, TRUE); 6.102 + fg_ptr_array_free(smf->tempo_array, TRUE); 6.103 + 6.104 + memset(smf, 0, sizeof(smf_t)); 6.105 + free(smf); 6.106 +} 6.107 + 6.108 +/** 6.109 + * Allocates new smf_track_t structure. 6.110 + * \return pointer to smf_track_t or NULL. 6.111 + */ 6.112 +smf_track_t * 6.113 +smf_track_new(void) 6.114 +{ 6.115 + smf_track_t *track = malloc(sizeof(smf_track_t)); 6.116 + if (track == NULL) { 6.117 + fg_critical("Cannot allocate smf_track_t structure: %s", strerror(errno)); 6.118 + return (NULL); 6.119 + } 6.120 + 6.121 + memset(track, 0, sizeof(smf_track_t)); 6.122 + track->next_event_number = -1; 6.123 + 6.124 + track->events_array = fg_ptr_array_new(); 6.125 + assert(track->events_array); 6.126 + 6.127 + return (track); 6.128 +} 6.129 + 6.130 +/** 6.131 + * Detaches track from its smf and frees it. 6.132 + */ 6.133 +void 6.134 +smf_track_delete(smf_track_t *track) 6.135 +{ 6.136 + assert(track); 6.137 + assert(track->events_array); 6.138 + 6.139 + /* Remove all the events, from last to first. */ 6.140 + while (track->events_array->len > 0) 6.141 + smf_event_delete(fg_ptr_array_index(track->events_array, track->events_array->len - 1)); 6.142 + 6.143 + if (track->smf) 6.144 + smf_track_remove_from_smf(track); 6.145 + 6.146 + assert(track->events_array->len == 0); 6.147 + assert(track->number_of_events == 0); 6.148 + fg_ptr_array_free(track->events_array, TRUE); 6.149 + 6.150 + memset(track, 0, sizeof(smf_track_t)); 6.151 + free(track); 6.152 +} 6.153 + 6.154 + 6.155 +/** 6.156 + * Appends smf_track_t to smf. 6.157 + */ 6.158 +void 6.159 +smf_add_track(smf_t *smf, smf_track_t *track) 6.160 +{ 6.161 + int cantfail; 6.162 + 6.163 + assert(track->smf == NULL); 6.164 + 6.165 + track->smf = smf; 6.166 + fg_ptr_array_add(smf->tracks_array, track); 6.167 + 6.168 + smf->number_of_tracks++; 6.169 + track->track_number = smf->number_of_tracks; 6.170 + 6.171 + if (smf->number_of_tracks > 1) { 6.172 + cantfail = smf_set_format(smf, 1); 6.173 + assert(!cantfail); 6.174 + } 6.175 +} 6.176 + 6.177 +/** 6.178 + * Detaches track from the smf. 6.179 + */ 6.180 +void 6.181 +smf_track_remove_from_smf(smf_track_t *track) 6.182 +{ 6.183 + int i, j; 6.184 + smf_track_t *tmp; 6.185 + smf_event_t *ev; 6.186 + 6.187 + assert(track->smf != NULL); 6.188 + 6.189 + track->smf->number_of_tracks--; 6.190 + 6.191 + assert(track->smf->tracks_array); 6.192 + fg_ptr_array_remove(track->smf->tracks_array, track); 6.193 + 6.194 + /* Renumber the rest of the tracks, so they are consecutively numbered. */ 6.195 + for (i = track->track_number; i <= track->smf->number_of_tracks; i++) { 6.196 + tmp = smf_get_track_by_number(track->smf, i); 6.197 + tmp->track_number = i; 6.198 + 6.199 + /* 6.200 + * Events have track numbers too. I guess this wasn't a wise 6.201 + * decision. ;-/ 6.202 + */ 6.203 + for (j = 1; j <= tmp->number_of_events; j++) { 6.204 + ev = smf_track_get_event_by_number(tmp, j); 6.205 + ev->track_number = i; 6.206 + } 6.207 + } 6.208 + 6.209 + track->track_number = -1; 6.210 + track->smf = NULL; 6.211 +} 6.212 + 6.213 +/** 6.214 + * Allocates new smf_event_t structure. The caller is responsible for allocating 6.215 + * event->midi_buffer, filling it with MIDI data and setting event->midi_buffer_length properly. 6.216 + * Note that event->midi_buffer will be freed by smf_event_delete. 6.217 + * \return pointer to smf_event_t or NULL. 6.218 + */ 6.219 +smf_event_t * 6.220 +smf_event_new(void) 6.221 +{ 6.222 + smf_event_t *event = malloc(sizeof(smf_event_t)); 6.223 + if (event == NULL) { 6.224 + fg_critical("Cannot allocate smf_event_t structure: %s", strerror(errno)); 6.225 + return (NULL); 6.226 + } 6.227 + 6.228 + memset(event, 0, sizeof(smf_event_t)); 6.229 + 6.230 + event->delta_time_pulses = -1; 6.231 + event->time_pulses = -1; 6.232 + event->time_seconds = -1.0; 6.233 + event->track_number = -1; 6.234 + 6.235 + return (event); 6.236 +} 6.237 + 6.238 +/** 6.239 + * Allocates an smf_event_t structure and fills it with "len" bytes copied 6.240 + * from "midi_data". 6.241 + * \param midi_data Pointer to MIDI data. It sill be copied to the newly allocated event->midi_buffer. 6.242 + * \param len Length of the buffer. It must be proper MIDI event length, e.g. 3 for Note On event. 6.243 + * \return Event containing MIDI data or NULL. 6.244 + */ 6.245 +smf_event_t * 6.246 +smf_event_new_from_pointer(void *midi_data, int len) 6.247 +{ 6.248 + smf_event_t *event; 6.249 + 6.250 + event = smf_event_new(); 6.251 + if (event == NULL) 6.252 + return (NULL); 6.253 + 6.254 + event->midi_buffer_length = len; 6.255 + event->midi_buffer = malloc(event->midi_buffer_length); 6.256 + if (event->midi_buffer == NULL) { 6.257 + fg_critical("Cannot allocate MIDI buffer structure: %s", strerror(errno)); 6.258 + smf_event_delete(event); 6.259 + 6.260 + return (NULL); 6.261 + } 6.262 + 6.263 + memcpy(event->midi_buffer, midi_data, len); 6.264 + 6.265 + return (event); 6.266 +} 6.267 + 6.268 +/** 6.269 + * Allocates an smf_event_t structure and fills it with at most three bytes of data. 6.270 + * For example, if you need to create Note On event, do something like this: 6.271 + * 6.272 + * smf_event_new_from_bytes(0x90, 0x3C, 0x7f); 6.273 + * 6.274 + * To create event for MIDI message that is shorter than three bytes, do something 6.275 + * like this: 6.276 + * 6.277 + * smf_event_new_from_bytes(0xC0, 0x42, -1); 6.278 + * 6.279 + * \param first_byte First byte of MIDI message. Must be valid status byte. 6.280 + * \param second_byte Second byte of MIDI message or -1, if message is one byte long. 6.281 + * \param third_byte Third byte of MIDI message or -1, if message is two bytes long. 6.282 + * \return Event containing MIDI data or NULL. 6.283 + */ 6.284 +smf_event_t * 6.285 +smf_event_new_from_bytes(int first_byte, int second_byte, int third_byte) 6.286 +{ 6.287 + int len; 6.288 + 6.289 + smf_event_t *event; 6.290 + 6.291 + event = smf_event_new(); 6.292 + if (event == NULL) 6.293 + return (NULL); 6.294 + 6.295 + if (first_byte < 0) { 6.296 + fg_critical("First byte of MIDI message cannot be < 0"); 6.297 + smf_event_delete(event); 6.298 + 6.299 + return (NULL); 6.300 + } 6.301 + 6.302 + if (first_byte > 255) { 6.303 + fg_critical("smf_event_new_from_bytes: first byte is %d, which is larger than 255.", first_byte); 6.304 + return (NULL); 6.305 + } 6.306 + 6.307 + if (!is_status_byte(first_byte)) { 6.308 + fg_critical("smf_event_new_from_bytes: first byte is not a valid status byte."); 6.309 + return (NULL); 6.310 + } 6.311 + 6.312 + 6.313 + if (second_byte < 0) 6.314 + len = 1; 6.315 + else if (third_byte < 0) 6.316 + len = 2; 6.317 + else 6.318 + len = 3; 6.319 + 6.320 + if (len > 1) { 6.321 + if (second_byte > 255) { 6.322 + fg_critical("smf_event_new_from_bytes: second byte is %d, which is larger than 255.", second_byte); 6.323 + return (NULL); 6.324 + } 6.325 + 6.326 + if (is_status_byte(second_byte)) { 6.327 + fg_critical("smf_event_new_from_bytes: second byte cannot be a status byte."); 6.328 + return (NULL); 6.329 + } 6.330 + } 6.331 + 6.332 + if (len > 2) { 6.333 + if (third_byte > 255) { 6.334 + fg_critical("smf_event_new_from_bytes: third byte is %d, which is larger than 255.", third_byte); 6.335 + return (NULL); 6.336 + } 6.337 + 6.338 + if (is_status_byte(third_byte)) { 6.339 + fg_critical("smf_event_new_from_bytes: third byte cannot be a status byte."); 6.340 + return (NULL); 6.341 + } 6.342 + } 6.343 + 6.344 + event->midi_buffer_length = len; 6.345 + event->midi_buffer = malloc(event->midi_buffer_length); 6.346 + if (event->midi_buffer == NULL) { 6.347 + fg_critical("Cannot allocate MIDI buffer structure: %s", strerror(errno)); 6.348 + smf_event_delete(event); 6.349 + 6.350 + return (NULL); 6.351 + } 6.352 + 6.353 + event->midi_buffer[0] = first_byte; 6.354 + if (len > 1) 6.355 + event->midi_buffer[1] = second_byte; 6.356 + if (len > 2) 6.357 + event->midi_buffer[2] = third_byte; 6.358 + 6.359 + return (event); 6.360 +} 6.361 + 6.362 +/** 6.363 + * Detaches event from its track and frees it. 6.364 + */ 6.365 +void 6.366 +smf_event_delete(smf_event_t *event) 6.367 +{ 6.368 + if (event->track != NULL) 6.369 + smf_event_remove_from_track(event); 6.370 + 6.371 + if (event->midi_buffer != NULL) { 6.372 + memset(event->midi_buffer, 0, event->midi_buffer_length); 6.373 + free(event->midi_buffer); 6.374 + } 6.375 + 6.376 + memset(event, 0, sizeof(smf_event_t)); 6.377 + free(event); 6.378 +} 6.379 + 6.380 +/** 6.381 + * Used for sorting track->events_array. 6.382 + */ 6.383 +static gint 6.384 +events_array_compare_function(gconstpointer aa, gconstpointer bb) 6.385 +{ 6.386 + smf_event_t *a, *b; 6.387 + 6.388 + /* "The comparison function for fg_ptr_array_sort() doesn't take the pointers 6.389 + from the array as arguments, it takes pointers to the pointers in the array." */ 6.390 + a = (smf_event_t *)*(gpointer *)aa; 6.391 + b = (smf_event_t *)*(gpointer *)bb; 6.392 + 6.393 + if (a->time_pulses < b->time_pulses) 6.394 + return (-1); 6.395 + 6.396 + if (a->time_pulses > b->time_pulses) 6.397 + return (1); 6.398 + 6.399 + /* 6.400 + * We need to preserve original order, otherwise things will break 6.401 + * when there are several events with the same ->time_pulses. 6.402 + * XXX: This is an ugly hack; we should remove sorting altogether. 6.403 + */ 6.404 + 6.405 + if (a->event_number < b->event_number) 6.406 + return (-1); 6.407 + 6.408 + if (a->event_number > b->event_number) 6.409 + return (1); 6.410 + 6.411 + return (0); 6.412 +} 6.413 + 6.414 +/* 6.415 + * An assumption here is that if there is an EOT event, it will be at the end of the track. 6.416 + */ 6.417 +static void 6.418 +remove_eot_if_before_pulses(smf_track_t *track, int pulses) 6.419 +{ 6.420 + smf_event_t *event; 6.421 + 6.422 + event = smf_track_get_last_event(track); 6.423 + 6.424 + if (event == NULL) 6.425 + return; 6.426 + 6.427 + if (!smf_event_is_eot(event)) 6.428 + return; 6.429 + 6.430 + if (event->time_pulses > pulses) 6.431 + return; 6.432 + 6.433 + smf_event_remove_from_track(event); 6.434 +} 6.435 + 6.436 +/** 6.437 + * Adds the event to the track and computes ->delta_pulses. Note that it is faster 6.438 + * to append events to the end of the track than to insert them in the middle. 6.439 + * Usually you want to use smf_track_add_event_seconds or smf_track_add_event_pulses 6.440 + * instead of this one. Event needs to have ->time_pulses and ->time_seconds already set. 6.441 + * If you try to add event after an EOT, EOT event will be automatically deleted. 6.442 + */ 6.443 +void 6.444 +smf_track_add_event(smf_track_t *track, smf_event_t *event) 6.445 +{ 6.446 + int i, last_pulses = 0; 6.447 + 6.448 + assert(track->smf != NULL); 6.449 + assert(event->track == NULL); 6.450 + assert(event->delta_time_pulses == -1); 6.451 + assert(event->time_pulses >= 0); 6.452 + assert(event->time_seconds >= 0.0); 6.453 + 6.454 + remove_eot_if_before_pulses(track, event->time_pulses); 6.455 + 6.456 + event->track = track; 6.457 + event->track_number = track->track_number; 6.458 + 6.459 + if (track->number_of_events == 0) { 6.460 + assert(track->next_event_number == -1); 6.461 + track->next_event_number = 1; 6.462 + } 6.463 + 6.464 + if (track->number_of_events > 0) 6.465 + last_pulses = smf_track_get_last_event(track)->time_pulses; 6.466 + 6.467 + track->number_of_events++; 6.468 + 6.469 + /* Are we just appending element at the end of the track? */ 6.470 + if (last_pulses <= event->time_pulses) { 6.471 + event->delta_time_pulses = event->time_pulses - last_pulses; 6.472 + assert(event->delta_time_pulses >= 0); 6.473 + fg_ptr_array_add(track->events_array, event); 6.474 + event->event_number = track->number_of_events; 6.475 + 6.476 + /* We need to insert in the middle of the track. XXX: This is slow. */ 6.477 + } else { 6.478 + /* Append, then sort according to ->time_pulses. */ 6.479 + fg_ptr_array_add(track->events_array, event); 6.480 + fg_ptr_array_sort(track->events_array, events_array_compare_function); 6.481 + 6.482 + /* Renumber entries and fix their ->delta_pulses. */ 6.483 + for (i = 1; i <= track->number_of_events; i++) { 6.484 + smf_event_t *tmp = smf_track_get_event_by_number(track, i); 6.485 + tmp->event_number = i; 6.486 + 6.487 + if (tmp->delta_time_pulses != -1) 6.488 + continue; 6.489 + 6.490 + if (i == 1) { 6.491 + tmp->delta_time_pulses = tmp->time_pulses; 6.492 + } else { 6.493 + tmp->delta_time_pulses = tmp->time_pulses - 6.494 + smf_track_get_event_by_number(track, i - 1)->time_pulses; 6.495 + assert(tmp->delta_time_pulses >= 0); 6.496 + } 6.497 + } 6.498 + 6.499 + /* Adjust ->delta_time_pulses of the next event. */ 6.500 + if (event->event_number < track->number_of_events) { 6.501 + smf_event_t *next_event = smf_track_get_event_by_number(track, event->event_number + 1); 6.502 + assert(next_event); 6.503 + assert(next_event->time_pulses >= event->time_pulses); 6.504 + next_event->delta_time_pulses -= event->delta_time_pulses; 6.505 + assert(next_event->delta_time_pulses >= 0); 6.506 + } 6.507 + } 6.508 + 6.509 + if (smf_event_is_tempo_change_or_time_signature(event)) { 6.510 + if (smf_event_is_last(event)) 6.511 + maybe_add_to_tempo_map(event); 6.512 + else 6.513 + smf_create_tempo_map_and_compute_seconds(event->track->smf); 6.514 + } 6.515 +} 6.516 + 6.517 +/** 6.518 + * Add End Of Track metaevent. Using it is optional, libsmf will automatically 6.519 + * add EOT to the tracks during smf_save, with delta_pulses 0. If you try to add EOT 6.520 + * in the middle of the track, it will fail and nonzero value will be returned. 6.521 + * If you try to add EOT after another EOT event, it will be added, but the existing 6.522 + * EOT event will be removed. 6.523 + * 6.524 + * \return 0 if everything went ok, nonzero otherwise. 6.525 + */ 6.526 +int 6.527 +smf_track_add_eot_delta_pulses(smf_track_t *track, int delta) 6.528 +{ 6.529 + smf_event_t *event; 6.530 + 6.531 + event = smf_event_new_from_bytes(0xFF, 0x2F, 0x00); 6.532 + if (event == NULL) 6.533 + return (-1); 6.534 + 6.535 + smf_track_add_event_delta_pulses(track, event, delta); 6.536 + 6.537 + return (0); 6.538 +} 6.539 + 6.540 +int 6.541 +smf_track_add_eot_pulses(smf_track_t *track, int pulses) 6.542 +{ 6.543 + smf_event_t *event, *last_event; 6.544 + 6.545 + last_event = smf_track_get_last_event(track); 6.546 + if (last_event != NULL) { 6.547 + if (last_event->time_pulses > pulses) 6.548 + return (-2); 6.549 + } 6.550 + 6.551 + event = smf_event_new_from_bytes(0xFF, 0x2F, 0x00); 6.552 + if (event == NULL) 6.553 + return (-3); 6.554 + 6.555 + smf_track_add_event_pulses(track, event, pulses); 6.556 + 6.557 + return (0); 6.558 +} 6.559 + 6.560 +int 6.561 +smf_track_add_eot_seconds(smf_track_t *track, double seconds) 6.562 +{ 6.563 + smf_event_t *event, *last_event; 6.564 + 6.565 + last_event = smf_track_get_last_event(track); 6.566 + if (last_event != NULL) { 6.567 + if (last_event->time_seconds > seconds) 6.568 + return (-2); 6.569 + } 6.570 + 6.571 + event = smf_event_new_from_bytes(0xFF, 0x2F, 0x00); 6.572 + if (event == NULL) 6.573 + return (-1); 6.574 + 6.575 + smf_track_add_event_seconds(track, event, seconds); 6.576 + 6.577 + return (0); 6.578 +} 6.579 + 6.580 +/** 6.581 + * Detaches event from its track. 6.582 + */ 6.583 +void 6.584 +smf_event_remove_from_track(smf_event_t *event) 6.585 +{ 6.586 + int i, was_last; 6.587 + smf_event_t *tmp; 6.588 + smf_track_t *track; 6.589 + 6.590 + assert(event->track != NULL); 6.591 + assert(event->track->smf != NULL); 6.592 + 6.593 + track = event->track; 6.594 + was_last = smf_event_is_last(event); 6.595 + 6.596 + /* Adjust ->delta_time_pulses of the next event. */ 6.597 + if (event->event_number < track->number_of_events) { 6.598 + tmp = smf_track_get_event_by_number(track, event->event_number + 1); 6.599 + assert(tmp); 6.600 + tmp->delta_time_pulses += event->delta_time_pulses; 6.601 + } 6.602 + 6.603 + track->number_of_events--; 6.604 + fg_ptr_array_remove(track->events_array, event); 6.605 + 6.606 + if (track->number_of_events == 0) 6.607 + track->next_event_number = -1; 6.608 + 6.609 + /* Renumber the rest of the events, so they are consecutively numbered. */ 6.610 + for (i = event->event_number; i <= track->number_of_events; i++) { 6.611 + tmp = smf_track_get_event_by_number(track, i); 6.612 + tmp->event_number = i; 6.613 + } 6.614 + 6.615 + if (smf_event_is_tempo_change_or_time_signature(event)) { 6.616 + /* XXX: This will cause problems, when there is more than one Tempo Change event at a given time. */ 6.617 + if (was_last) 6.618 + remove_last_tempo_with_pulses(event->track->smf, event->time_pulses); 6.619 + else 6.620 + smf_create_tempo_map_and_compute_seconds(track->smf); 6.621 + } 6.622 + 6.623 + event->track = NULL; 6.624 + event->event_number = -1; 6.625 + event->delta_time_pulses = -1; 6.626 + event->time_pulses = -1; 6.627 + event->time_seconds = -1.0; 6.628 +} 6.629 + 6.630 +/** 6.631 + * \return Nonzero if event is Tempo Change or Time Signature metaevent. 6.632 + */ 6.633 +int 6.634 +smf_event_is_tempo_change_or_time_signature(const smf_event_t *event) 6.635 +{ 6.636 + if (!smf_event_is_metadata(event)) 6.637 + return (0); 6.638 + 6.639 + assert(event->midi_buffer_length >= 2); 6.640 + 6.641 + if (event->midi_buffer[1] == 0x51 || event->midi_buffer[1] == 0x58) 6.642 + return (1); 6.643 + 6.644 + return (0); 6.645 +} 6.646 + 6.647 +/** 6.648 + * Sets "Format" field of MThd header to the specified value. Note that you 6.649 + * don't really need to use this, as libsmf will automatically change format 6.650 + * from 0 to 1 when you add the second track. 6.651 + * \param smf SMF. 6.652 + * \param format 0 for one track per file, 1 for several tracks per file. 6.653 + */ 6.654 +int 6.655 +smf_set_format(smf_t *smf, int format) 6.656 +{ 6.657 + assert(format == 0 || format == 1); 6.658 + 6.659 + if (smf->number_of_tracks > 1 && format == 0) { 6.660 + fg_critical("There is more than one track, cannot set format to 0."); 6.661 + return (-1); 6.662 + } 6.663 + 6.664 + smf->format = format; 6.665 + 6.666 + return (0); 6.667 +} 6.668 + 6.669 +/** 6.670 + * Sets the PPQN ("Division") field of MThd header. This is mandatory, you 6.671 + * should call it right after smf_new. Note that changing PPQN will change time_seconds 6.672 + * of all the events. 6.673 + * \param smf SMF. 6.674 + * \param ppqn New PPQN. 6.675 + */ 6.676 +int 6.677 +smf_set_ppqn(smf_t *smf, int ppqn) 6.678 +{ 6.679 + assert(ppqn > 0); 6.680 + 6.681 + smf->ppqn = ppqn; 6.682 + 6.683 + return (0); 6.684 +} 6.685 + 6.686 +/** 6.687 + * Returns next event from the track given and advances next event counter. 6.688 + * Do not depend on End Of Track event being the last event on the track - it 6.689 + * is possible that the track will not end with EOT if you haven't added it 6.690 + * yet. EOTs are added automatically during smf_save(). 6.691 + * 6.692 + * \return Event or NULL, if there are no more events left in this track. 6.693 + */ 6.694 +smf_event_t * 6.695 +smf_track_get_next_event(smf_track_t *track) 6.696 +{ 6.697 + smf_event_t *event, *next_event; 6.698 + 6.699 + /* End of track? */ 6.700 + if (track->next_event_number == -1) 6.701 + return (NULL); 6.702 + 6.703 + assert(track->next_event_number >= 1); 6.704 + assert(track->number_of_events > 0); 6.705 + 6.706 + event = smf_track_get_event_by_number(track, track->next_event_number); 6.707 + 6.708 + assert(event != NULL); 6.709 + 6.710 + /* Is this the last event in the track? */ 6.711 + if (track->next_event_number < track->number_of_events) { 6.712 + next_event = smf_track_get_event_by_number(track, track->next_event_number + 1); 6.713 + assert(next_event); 6.714 + 6.715 + track->time_of_next_event = next_event->time_pulses; 6.716 + track->next_event_number++; 6.717 + } else { 6.718 + track->next_event_number = -1; 6.719 + } 6.720 + 6.721 + return (event); 6.722 +} 6.723 + 6.724 +/** 6.725 + * Returns next event from the track given. Does not change next event counter, 6.726 + * so repeatedly calling this routine will return the same event. 6.727 + * \return Event or NULL, if there are no more events left in this track. 6.728 + */ 6.729 +static smf_event_t * 6.730 +smf_peek_next_event_from_track(smf_track_t *track) 6.731 +{ 6.732 + smf_event_t *event; 6.733 + 6.734 + /* End of track? */ 6.735 + if (track->next_event_number == -1) 6.736 + return (NULL); 6.737 + 6.738 + assert(track->next_event_number >= 1); 6.739 + assert(track->events_array->len != 0); 6.740 + 6.741 + event = smf_track_get_event_by_number(track, track->next_event_number); 6.742 + 6.743 + return (event); 6.744 +} 6.745 + 6.746 +/** 6.747 + * \return Track with a given number or NULL, if there is no such track. 6.748 + * Tracks are numbered consecutively starting from one. 6.749 + */ 6.750 +smf_track_t * 6.751 +smf_get_track_by_number(const smf_t *smf, int track_number) 6.752 +{ 6.753 + smf_track_t *track; 6.754 + 6.755 + assert(track_number >= 1); 6.756 + 6.757 + if (track_number > smf->number_of_tracks) 6.758 + return (NULL); 6.759 + 6.760 + track = (smf_track_t *)fg_ptr_array_index(smf->tracks_array, track_number - 1); 6.761 + 6.762 + assert(track); 6.763 + 6.764 + return (track); 6.765 +} 6.766 + 6.767 +/** 6.768 + * \return Event with a given number or NULL, if there is no such event. 6.769 + * Events are numbered consecutively starting from one. 6.770 + */ 6.771 +smf_event_t * 6.772 +smf_track_get_event_by_number(const smf_track_t *track, int event_number) 6.773 +{ 6.774 + smf_event_t *event; 6.775 + 6.776 + assert(event_number >= 1); 6.777 + 6.778 + if (event_number > track->number_of_events) 6.779 + return (NULL); 6.780 + 6.781 + event = fg_ptr_array_index(track->events_array, event_number - 1); 6.782 + 6.783 + assert(event); 6.784 + 6.785 + return (event); 6.786 +} 6.787 + 6.788 +/** 6.789 + * \return Last event on the track or NULL, if track is empty. 6.790 + */ 6.791 +smf_event_t * 6.792 +smf_track_get_last_event(const smf_track_t *track) 6.793 +{ 6.794 + smf_event_t *event; 6.795 + 6.796 + if (track->number_of_events == 0) 6.797 + return (NULL); 6.798 + 6.799 + event = smf_track_get_event_by_number(track, track->number_of_events); 6.800 + 6.801 + return (event); 6.802 +} 6.803 + 6.804 +/** 6.805 + * Searches for track that contains next event, in time order. In other words, 6.806 + * returns the track that contains event that should be played next. 6.807 + * \return Track with next event or NULL, if there are no events left. 6.808 + */ 6.809 +smf_track_t * 6.810 +smf_find_track_with_next_event(smf_t *smf) 6.811 +{ 6.812 + int i, min_time = 0; 6.813 + smf_track_t *track = NULL, *min_time_track = NULL; 6.814 + 6.815 + /* Find track with event that should be played next. */ 6.816 + for (i = 1; i <= smf->number_of_tracks; i++) { 6.817 + track = smf_get_track_by_number(smf, i); 6.818 + 6.819 + assert(track); 6.820 + 6.821 + /* No more events in this track? */ 6.822 + if (track->next_event_number == -1) 6.823 + continue; 6.824 + 6.825 + if (track->time_of_next_event < min_time || min_time_track == NULL) { 6.826 + min_time = track->time_of_next_event; 6.827 + min_time_track = track; 6.828 + } 6.829 + } 6.830 + 6.831 + return (min_time_track); 6.832 +} 6.833 + 6.834 +/** 6.835 + * \return Next event, in time order, or NULL, if there are none left. 6.836 + */ 6.837 +smf_event_t * 6.838 +smf_get_next_event(smf_t *smf) 6.839 +{ 6.840 + smf_event_t *event; 6.841 + smf_track_t *track = smf_find_track_with_next_event(smf); 6.842 + 6.843 + if (track == NULL) { 6.844 +#if 0 6.845 + g_debug("End of the song."); 6.846 +#endif 6.847 + 6.848 + return (NULL); 6.849 + } 6.850 + 6.851 + event = smf_track_get_next_event(track); 6.852 + 6.853 + assert(event != NULL); 6.854 + 6.855 + event->track->smf->last_seek_position = -1.0; 6.856 + 6.857 + return (event); 6.858 +} 6.859 + 6.860 +/** 6.861 + * Advance the "next event counter". This is functionally the same as calling 6.862 + * smf_get_next_event and ignoring the return value. 6.863 + */ 6.864 +void 6.865 +smf_skip_next_event(smf_t *smf) 6.866 +{ 6.867 + void *notused; 6.868 + 6.869 + notused = smf_get_next_event(smf); 6.870 +} 6.871 + 6.872 +/** 6.873 + * \return Next event, in time order, or NULL, if there are none left. Does 6.874 + * not advance position in song. 6.875 + */ 6.876 +smf_event_t * 6.877 +smf_peek_next_event(smf_t *smf) 6.878 +{ 6.879 + smf_event_t *event; 6.880 + smf_track_t *track = smf_find_track_with_next_event(smf); 6.881 + 6.882 + if (track == NULL) { 6.883 +#if 0 6.884 + g_debug("End of the song."); 6.885 +#endif 6.886 + 6.887 + return (NULL); 6.888 + } 6.889 + 6.890 + event = smf_peek_next_event_from_track(track); 6.891 + 6.892 + assert(event != NULL); 6.893 + 6.894 + return (event); 6.895 +} 6.896 + 6.897 +/** 6.898 + * Rewinds the SMF. What that means is, after calling this routine, smf_get_next_event 6.899 + * will return first event in the song. 6.900 + */ 6.901 +void 6.902 +smf_rewind(smf_t *smf) 6.903 +{ 6.904 + int i; 6.905 + smf_track_t *track = NULL; 6.906 + smf_event_t *event; 6.907 + 6.908 + assert(smf); 6.909 + 6.910 + smf->last_seek_position = 0.0; 6.911 + 6.912 + for (i = 1; i <= smf->number_of_tracks; i++) { 6.913 + track = smf_get_track_by_number(smf, i); 6.914 + 6.915 + assert(track != NULL); 6.916 + 6.917 + if (track->number_of_events > 0) { 6.918 + track->next_event_number = 1; 6.919 + event = smf_peek_next_event_from_track(track); 6.920 + assert(event); 6.921 + track->time_of_next_event = event->time_pulses; 6.922 + } else { 6.923 + track->next_event_number = -1; 6.924 + track->time_of_next_event = 0; 6.925 +#if 0 6.926 + g_warning("Warning: empty track."); 6.927 +#endif 6.928 + } 6.929 + } 6.930 +} 6.931 + 6.932 +/** 6.933 + * Seeks the SMF to the given event. After calling this routine, smf_get_next_event 6.934 + * will return the event that was the second argument of this call. 6.935 + */ 6.936 +int 6.937 +smf_seek_to_event(smf_t *smf, const smf_event_t *target) 6.938 +{ 6.939 + smf_event_t *event; 6.940 + 6.941 + smf_rewind(smf); 6.942 + 6.943 +#if 0 6.944 + g_debug("Seeking to event %d, track %d.", target->event_number, target->track->track_number); 6.945 +#endif 6.946 + 6.947 + for (;;) { 6.948 + event = smf_peek_next_event(smf); 6.949 + 6.950 + /* There can't be NULL here, unless "target" is not in this smf. */ 6.951 + assert(event); 6.952 + 6.953 + if (event != target) 6.954 + smf_skip_next_event(smf); 6.955 + else 6.956 + break; 6.957 + } 6.958 + 6.959 + smf->last_seek_position = event->time_seconds; 6.960 + 6.961 + return (0); 6.962 +} 6.963 + 6.964 +/** 6.965 + * Seeks the SMF to the given position. For example, after seeking to 1.0 seconds, 6.966 + * smf_get_next_event will return first event that happens after the first second of song. 6.967 + */ 6.968 +int 6.969 +smf_seek_to_seconds(smf_t *smf, double seconds) 6.970 +{ 6.971 + smf_event_t *event; 6.972 + 6.973 + assert(seconds >= 0.0); 6.974 + 6.975 + if (seconds == smf->last_seek_position) { 6.976 +#if 0 6.977 + g_debug("Avoiding seek to %f seconds.", seconds); 6.978 +#endif 6.979 + return (0); 6.980 + } 6.981 + 6.982 + smf_rewind(smf); 6.983 + 6.984 +#if 0 6.985 + g_debug("Seeking to %f seconds.", seconds); 6.986 +#endif 6.987 + 6.988 + for (;;) { 6.989 + event = smf_peek_next_event(smf); 6.990 + 6.991 + if (event == NULL) { 6.992 + fg_critical("Trying to seek past the end of song."); 6.993 + return (-1); 6.994 + } 6.995 + 6.996 + if (event->time_seconds < seconds) 6.997 + smf_skip_next_event(smf); 6.998 + else 6.999 + break; 6.1000 + } 6.1001 + 6.1002 + smf->last_seek_position = seconds; 6.1003 + 6.1004 + return (0); 6.1005 +} 6.1006 + 6.1007 +/** 6.1008 + * Seeks the SMF to the given position. For example, after seeking to 10 pulses, 6.1009 + * smf_get_next_event will return first event that happens after the first ten pulses. 6.1010 + */ 6.1011 +int 6.1012 +smf_seek_to_pulses(smf_t *smf, int pulses) 6.1013 +{ 6.1014 + smf_event_t *event; 6.1015 + 6.1016 + assert(pulses >= 0); 6.1017 + 6.1018 + smf_rewind(smf); 6.1019 + 6.1020 +#if 0 6.1021 + g_debug("Seeking to %d pulses.", pulses); 6.1022 +#endif 6.1023 + 6.1024 + for (;;) { 6.1025 + event = smf_peek_next_event(smf); 6.1026 + 6.1027 + if (event == NULL) { 6.1028 + fg_critical("Trying to seek past the end of song."); 6.1029 + return (-1); 6.1030 + } 6.1031 + 6.1032 + if (event->time_pulses < pulses) 6.1033 + smf_skip_next_event(smf); 6.1034 + else 6.1035 + break; 6.1036 + } 6.1037 + 6.1038 + smf->last_seek_position = event->time_seconds; 6.1039 + 6.1040 + return (0); 6.1041 +} 6.1042 + 6.1043 +/** 6.1044 + * \return Length of SMF, in pulses. 6.1045 + */ 6.1046 +int 6.1047 +smf_get_length_pulses(const smf_t *smf) 6.1048 +{ 6.1049 + int pulses = 0, i; 6.1050 + 6.1051 + for (i = 1; i <= smf->number_of_tracks; i++) { 6.1052 + smf_track_t *track; 6.1053 + smf_event_t *event; 6.1054 + 6.1055 + track = smf_get_track_by_number(smf, i); 6.1056 + assert(track); 6.1057 + 6.1058 + event = smf_track_get_last_event(track); 6.1059 + /* Empty track? */ 6.1060 + if (event == NULL) 6.1061 + continue; 6.1062 + 6.1063 + if (event->time_pulses > pulses) 6.1064 + pulses = event->time_pulses; 6.1065 + } 6.1066 + 6.1067 + return (pulses); 6.1068 +} 6.1069 + 6.1070 +/** 6.1071 + * \return Length of SMF, in seconds. 6.1072 + */ 6.1073 +double 6.1074 +smf_get_length_seconds(const smf_t *smf) 6.1075 +{ 6.1076 + int i; 6.1077 + double seconds = 0.0; 6.1078 + 6.1079 + for (i = 1; i <= smf->number_of_tracks; i++) { 6.1080 + smf_track_t *track; 6.1081 + smf_event_t *event; 6.1082 + 6.1083 + track = smf_get_track_by_number(smf, i); 6.1084 + assert(track); 6.1085 + 6.1086 + event = smf_track_get_last_event(track); 6.1087 + /* Empty track? */ 6.1088 + if (event == NULL) 6.1089 + continue; 6.1090 + 6.1091 + if (event->time_seconds > seconds) 6.1092 + seconds = event->time_seconds; 6.1093 + } 6.1094 + 6.1095 + return (seconds); 6.1096 +} 6.1097 + 6.1098 +/** 6.1099 + * \return Nonzero, if there are no events in the SMF after this one. 6.1100 + * Note that may be more than one "last event", if they occur at the same time. 6.1101 + */ 6.1102 +int 6.1103 +smf_event_is_last(const smf_event_t *event) 6.1104 +{ 6.1105 + if (smf_get_length_pulses(event->track->smf) <= event->time_pulses) 6.1106 + return (1); 6.1107 + 6.1108 + return (0); 6.1109 +} 6.1110 + 6.1111 +/** 6.1112 + * \return Version of libsmf. 6.1113 + */ 6.1114 +const char * 6.1115 +smf_get_version(void) 6.1116 +{ 6.1117 + return (SMF_VERSION); 6.1118 +} 6.1119 +
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/smf.h Thu Jan 26 11:25:11 2012 +0200 7.3 @@ -0,0 +1,417 @@ 7.4 +/*- 7.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 7.6 + * All rights reserved. 7.7 + * 7.8 + * Redistribution and use in source and binary forms, with or without 7.9 + * modification, are permitted provided that the following conditions 7.10 + * are met: 7.11 + * 1. Redistributions of source code must retain the above copyright 7.12 + * notice, this list of conditions and the following disclaimer. 7.13 + * 2. Redistributions in binary form must reproduce the above copyright 7.14 + * notice, this list of conditions and the following disclaimer in the 7.15 + * documentation and/or other materials provided with the distribution. 7.16 + * 7.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 7.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 7.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 7.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 7.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 7.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 7.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 7.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 7.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 7.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 7.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 7.28 + * 7.29 + */ 7.30 + 7.31 +/** 7.32 + * \file 7.33 + * 7.34 + * Public interface declaration for libsmf, Standard MIDI File format library. 7.35 + */ 7.36 + 7.37 +/** 7.38 + * 7.39 + * \mainpage libsmf - general usage instructions 7.40 + * 7.41 + * An smf_t structure represents a "song". Every valid smf contains one or more tracks. 7.42 + * Tracks contain zero or more events. Libsmf doesn't care about actual MIDI data, as long 7.43 + * as it is valid from the MIDI specification point of view - it may be realtime message, 7.44 + * SysEx, whatever. 7.45 + * 7.46 + * The only field in smf_t, smf_track_t, smf_event_t and smf_tempo_t structures your 7.47 + * code may modify is event->midi_buffer and event->midi_buffer_length. Do not modify 7.48 + * other fields, _ever_. You may read them, though. Do not declare static instances 7.49 + * of these types, i.e. never do something like this: "smf_t smf;". Always use 7.50 + * "smf_t *smf = smf_new();". The same applies to smf_track_t and smf_event_t. 7.51 + * 7.52 + * Say you want to load a Standard MIDI File (.mid) file and play it back somehow. This is (roughly) 7.53 + * how you do this: 7.54 + * 7.55 + * \code 7.56 + * smf_t *smf; 7.57 + * smf_event_t *event; 7.58 + * 7.59 + * smf = smf_load(file_name); 7.60 + * if (smf == NULL) { 7.61 + * Whoops, something went wrong. 7.62 + * return; 7.63 + * } 7.64 + * 7.65 + * while ((event = smf_get_next_event(smf)) != NULL) { 7.66 + * if (smf_event_is_metadata(event)) 7.67 + * continue; 7.68 + * 7.69 + * wait until event->time_seconds. 7.70 + * feed_to_midi_output(event->midi_buffer, event->midi_buffer_length); 7.71 + * } 7.72 + * 7.73 + * smf_delete(smf); 7.74 + * 7.75 + * \endcode 7.76 + * 7.77 + * Saving works like this: 7.78 + * 7.79 + * \code 7.80 + * 7.81 + * smf_t *smf; 7.82 + * smf_track_t *track; 7.83 + * smf_event_t *event; 7.84 + * 7.85 + * smf = smf_new(); 7.86 + * if (smf == NULL) { 7.87 + * Whoops. 7.88 + * return; 7.89 + * } 7.90 + * 7.91 + * for (int i = 1; i <= number of tracks; i++) { 7.92 + * track = smf_track_new(); 7.93 + * if (track == NULL) { 7.94 + * Whoops. 7.95 + * return; 7.96 + * } 7.97 + * 7.98 + * smf_add_track(smf, track); 7.99 + * 7.100 + * for (int j = 1; j <= number of events you want to put into this track; j++) { 7.101 + * event = smf_event_new_from_pointer(your MIDI message, message length); 7.102 + * if (event == NULL) { 7.103 + * Whoops. 7.104 + * return; 7.105 + * } 7.106 + * 7.107 + * smf_track_add_event_seconds(track, event, seconds since start of the song); 7.108 + * } 7.109 + * } 7.110 + * 7.111 + * ret = smf_save(smf, file_name); 7.112 + * if (ret) { 7.113 + * Whoops, saving failed for some reason. 7.114 + * return; 7.115 + * } 7.116 + * 7.117 + * smf_delete(smf); 7.118 + * 7.119 + * \endcode 7.120 + * 7.121 + * There are two basic ways of getting MIDI data out of smf - sequential or by track/event number. You may 7.122 + * mix them if you need to. First one is used in the example above - seek to the point from which you want 7.123 + * the playback to start (using smf_seek_to_seconds(), smf_seek_to_pulses() or smf_seek_to_event()) and then 7.124 + * do smf_get_next_event() in loop, until it returns NULL. Calling smf_load() causes the smf to be rewound 7.125 + * to the start of the song. 7.126 + * 7.127 + * Getting events by number works like this: 7.128 + * 7.129 + * \code 7.130 + * 7.131 + * smf_track_t *track = smf_get_track_by_number(smf, track_number); 7.132 + * smf_event_t *event = smf_track_get_event_by_number(track, event_number); 7.133 + * 7.134 + * \endcode 7.135 + * 7.136 + * To create new event, use smf_event_new(), smf_event_new_from_pointer() or smf_event_new_from_bytes(). 7.137 + * First one creates an empty event - you need to manually allocate (using malloc(3)) buffer for 7.138 + * MIDI data, write MIDI data into it, put the address of that buffer into event->midi_buffer, 7.139 + * and the length of MIDI data into event->midi_buffer_length. Note that deleting the event 7.140 + * (using smf_event_delete()) will free the buffer. 7.141 + * 7.142 + * Second form does most of this for you: it takes an address of the buffer containing MIDI data, 7.143 + * allocates storage and copies MIDI data into it. 7.144 + * 7.145 + * Third form is useful for manually creating short events, up to three bytes in length, for 7.146 + * example Note On or Note Off events. It simply takes three bytes and creates MIDI event containing 7.147 + * them. If you need to create MIDI message that takes only two bytes, pass -1 as the third byte. 7.148 + * For one byte message (System Realtime), pass -1 as second and third byte. 7.149 + * 7.150 + * To free an event, use smf_event_delete(). 7.151 + * 7.152 + * To add event to the track, use smf_track_add_event_delta_pulses(), smf_track_add_event_pulses(), 7.153 + * or smf_track_add_event_seconds(). The difference between them is in the way you specify the time of 7.154 + * the event - with the first one, you specify it as an interval, in pulses, from the previous event 7.155 + * in this track; with the second one, you specify it as pulses from the start of the song, and with the 7.156 + * last one, you specify it as seconds from the start of the song. Obviously, the first version can 7.157 + * only append events at the end of the track. 7.158 + * 7.159 + * To remove an event from the track it's attached to, use smf_event_remove_from_track(). You may 7.160 + * want to free the event (using smf_event_delete()) afterwards. 7.161 + * 7.162 + * To create new track, use smf_track_new(). To add track to the smf, use smf_add_track(). 7.163 + * To remove track from its smf, use smf_track_remove_from_smf(). To free the track structure, 7.164 + * use smf_track_delete(). 7.165 + * 7.166 + * Note that libsmf keeps things consistent. If you free (using smf_track_delete()) a track that 7.167 + * is attached to an smf and contains events, libsmf will detach the events, free them, detach 7.168 + * the track, free it etc. 7.169 + * 7.170 + * Tracks and events are numbered consecutively, starting from one. If you remove a track or event, 7.171 + * the rest of tracks/events will get renumbered. To get the number of a given event in its track, use event->event_number. 7.172 + * To get the number of track in its smf, use track->track_number. To get the number of events in the track, 7.173 + * use track->number_of_events. To get the number of tracks in the smf, use smf->number_of_tracks. 7.174 + * 7.175 + * In SMF File Format, each track has to end with End Of Track metaevent. If you load SMF file using smf_load(), 7.176 + * that will be the case. If you want to create or edit an SMF, you don't need to worry about EOT events; 7.177 + * libsmf automatically takes care of them for you. If you try to save an SMF with tracks that do not end 7.178 + * with EOTs, smf_save() will append them. If you try to add event that happens after EOT metaevent, libsmf 7.179 + * will remove the EOT. If you want to add EOT manually, you can, of course, using smf_track_add_eot_seconds() 7.180 + * or smf_track_add_eot_pulses(). 7.181 + * 7.182 + * Each event carries three time values - event->time_seconds, which is seconds since the start of the song, 7.183 + * event->time_pulses, which is PPQN clocks since the start of the song, and event->delta_pulses, which is PPQN clocks 7.184 + * since the previous event in that track. These values are invalid if the event is not attached to the track. 7.185 + * If event is attached, all three values are valid. Time of the event is specified when adding the event 7.186 + * (using smf_track_add_event_seconds(), smf_track_add_event_pulses() or smf_track_add_event_delta_pulses()); the remaining 7.187 + * two values are computed from that. 7.188 + * 7.189 + * Tempo related stuff happens automatically - when you add a metaevent that 7.190 + * is Tempo Change or Time Signature, libsmf adds that event to the tempo map. If you remove 7.191 + * Tempo Change event that is in the middle of the song, the rest of the events will have their 7.192 + * event->time_seconds recomputed from event->time_pulses before smf_event_remove_from_track() function returns. 7.193 + * Adding Tempo Change in the middle of the song works in a similar way. 7.194 + * 7.195 + * MIDI data (event->midi_buffer) is always kept in normalized form - it always begins with status byte 7.196 + * (no running status), there are no System Realtime events embedded in them etc. Events like SysExes 7.197 + * are in "on the wire" form, without embedded length that is used in SMF file format. Obviously 7.198 + * libsmf "normalizes" MIDI data during loading and "denormalizes" (adding length to SysExes, escaping 7.199 + * System Common and System Realtime messages etc) during writing. 7.200 + * 7.201 + * Note that you always have to first add the track to smf, and then add events to the track. 7.202 + * Doing it the other way around will trip asserts. Also, try to add events at the end of the track and remove 7.203 + * them from the end of the track, that's much more efficient. 7.204 + * 7.205 + * All the libsmf functions have prefix "smf_". First argument for routines whose names start with 7.206 + * "smf_event_" is "smf_event_t *", for routines whose names start with "smf_track_" - "smf_track_t *", 7.207 + * and for plain "smf_" - "smf_t *". The only exception are smf_whatever_new routines. 7.208 + * Library does not use any global variables and is thread-safe, 7.209 + * as long as you don't try to work on the same SMF (smf_t and its descendant tracks and events) from several 7.210 + * threads at once without protecting it with mutex. Library depends on glib and nothing else. License is 7.211 + * BSD, two clause, which basically means you can use it freely in your software, both Open Source (including 7.212 + * GPL) and closed source. 7.213 + * 7.214 + */ 7.215 + 7.216 +#ifndef SMF_H 7.217 +#define SMF_H 7.218 + 7.219 +#ifdef __cplusplus 7.220 +extern "C" { 7.221 +#endif 7.222 + 7.223 +#include <stdio.h> 7.224 + 7.225 +#if defined(__GNUC__) && __GNUC__ >= 4 7.226 +#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) 7.227 +#else 7.228 +#define WARN_UNUSED_RESULT 7.229 +#endif 7.230 + 7.231 +struct FakeGPtrArray; 7.232 + 7.233 +/** Represents a "song", that is, collection of one or more tracks. */ 7.234 +struct smf_struct { 7.235 + int format; 7.236 + 7.237 + /** These fields are extracted from "division" field of MThd header. Valid is _either_ ppqn or frames_per_second/resolution. */ 7.238 + int ppqn; 7.239 + int frames_per_second; 7.240 + int resolution; 7.241 + int number_of_tracks; 7.242 + 7.243 + /** These are private fields using only by loading and saving routines. */ 7.244 + FILE *stream; 7.245 + void *file_buffer; 7.246 + int file_buffer_length; 7.247 + int next_chunk_offset; 7.248 + int expected_number_of_tracks; 7.249 + 7.250 + /** Private, used by smf.c. */ 7.251 + struct FakeGPtrArray *tracks_array; 7.252 + double last_seek_position; 7.253 + 7.254 + /** Private, used by smf_tempo.c. */ 7.255 + /** Array of pointers to smf_tempo_struct. */ 7.256 + struct FakeGPtrArray *tempo_array; 7.257 +}; 7.258 + 7.259 +typedef struct smf_struct smf_t; 7.260 + 7.261 +/** Describes a single tempo or time signature change. */ 7.262 +struct smf_tempo_struct { 7.263 + int time_pulses; 7.264 + double time_seconds; 7.265 + int microseconds_per_quarter_note; 7.266 + int numerator; 7.267 + int denominator; 7.268 + int clocks_per_click; 7.269 + int notes_per_note; 7.270 +}; 7.271 + 7.272 +typedef struct smf_tempo_struct smf_tempo_t; 7.273 + 7.274 +/** Represents a single track. */ 7.275 +struct smf_track_struct { 7.276 + smf_t *smf; 7.277 + 7.278 + int track_number; 7.279 + int number_of_events; 7.280 + 7.281 + /** These are private fields using only by loading and saving routines. */ 7.282 + void *file_buffer; 7.283 + int file_buffer_length; 7.284 + int last_status; /* Used for "running status". */ 7.285 + 7.286 + /** Private, used by smf.c. */ 7.287 + /** Offset into buffer, used in parse_next_event(). */ 7.288 + int next_event_offset; 7.289 + int next_event_number; 7.290 + 7.291 + /** Absolute time of next event on events_queue. */ 7.292 + int time_of_next_event; 7.293 + struct FakeGPtrArray *events_array; 7.294 + 7.295 + /** API consumer is free to use this for whatever purpose. NULL in freshly allocated track. 7.296 + Note that tracks might be deallocated not only explicitly, by calling smf_track_delete(), 7.297 + but also implicitly, e.g. when calling smf_delete() with tracks still added to 7.298 + the smf; there is no mechanism for libsmf to notify you about removal of the track. */ 7.299 + void *user_pointer; 7.300 +}; 7.301 + 7.302 +typedef struct smf_track_struct smf_track_t; 7.303 + 7.304 +/** Represents a single MIDI event or metaevent. */ 7.305 +struct smf_event_struct { 7.306 + /** Pointer to the track, or NULL if event is not attached. */ 7.307 + smf_track_t *track; 7.308 + 7.309 + /** Number of this event in the track. Events are numbered consecutively, starting from one. */ 7.310 + int event_number; 7.311 + 7.312 + /** Note that the time fields are invalid, if event is not attached to a track. */ 7.313 + /** Time, in pulses, since the previous event on this track. */ 7.314 + int delta_time_pulses; 7.315 + 7.316 + /** Time, in pulses, since the start of the song. */ 7.317 + int time_pulses; 7.318 + 7.319 + /** Time, in seconds, since the start of the song. */ 7.320 + double time_seconds; 7.321 + 7.322 + /** Tracks are numbered consecutively, starting from 1. */ 7.323 + int track_number; 7.324 + 7.325 + /** Pointer to the buffer containing MIDI message. This is freed by smf_event_delete. */ 7.326 + unsigned char *midi_buffer; 7.327 + 7.328 + /** Length of the MIDI message in the buffer, in bytes. */ 7.329 + int midi_buffer_length; 7.330 + 7.331 + /** API consumer is free to use this for whatever purpose. NULL in freshly allocated event. 7.332 + Note that events might be deallocated not only explicitly, by calling smf_event_delete(), 7.333 + but also implicitly, e.g. when calling smf_track_delete() with events still added to 7.334 + the track; there is no mechanism for libsmf to notify you about removal of the event. */ 7.335 + void *user_pointer; 7.336 +}; 7.337 + 7.338 +typedef struct smf_event_struct smf_event_t; 7.339 + 7.340 +/* Routines for manipulating smf_t. */ 7.341 +smf_t *smf_new(void) WARN_UNUSED_RESULT; 7.342 +void smf_delete(smf_t *smf); 7.343 + 7.344 +int smf_set_format(smf_t *smf, int format) WARN_UNUSED_RESULT; 7.345 +int smf_set_ppqn(smf_t *smf, int format) WARN_UNUSED_RESULT; 7.346 + 7.347 +char *smf_decode(const smf_t *smf) WARN_UNUSED_RESULT; 7.348 + 7.349 +smf_track_t *smf_get_track_by_number(const smf_t *smf, int track_number) WARN_UNUSED_RESULT; 7.350 + 7.351 +smf_event_t *smf_peek_next_event(smf_t *smf) WARN_UNUSED_RESULT; 7.352 +smf_event_t *smf_get_next_event(smf_t *smf) WARN_UNUSED_RESULT; 7.353 +void smf_skip_next_event(smf_t *smf); 7.354 + 7.355 +void smf_rewind(smf_t *smf); 7.356 +int smf_seek_to_seconds(smf_t *smf, double seconds) WARN_UNUSED_RESULT; 7.357 +int smf_seek_to_pulses(smf_t *smf, int pulses) WARN_UNUSED_RESULT; 7.358 +int smf_seek_to_event(smf_t *smf, const smf_event_t *event) WARN_UNUSED_RESULT; 7.359 + 7.360 +int smf_get_length_pulses(const smf_t *smf) WARN_UNUSED_RESULT; 7.361 +double smf_get_length_seconds(const smf_t *smf) WARN_UNUSED_RESULT; 7.362 +int smf_event_is_last(const smf_event_t *event) WARN_UNUSED_RESULT; 7.363 + 7.364 +void smf_add_track(smf_t *smf, smf_track_t *track); 7.365 +void smf_track_remove_from_smf(smf_track_t *track); 7.366 + 7.367 +/* Routines for manipulating smf_track_t. */ 7.368 +smf_track_t *smf_track_new(void) WARN_UNUSED_RESULT; 7.369 +void smf_track_delete(smf_track_t *track); 7.370 + 7.371 +smf_event_t *smf_track_get_next_event(smf_track_t *track) WARN_UNUSED_RESULT; 7.372 +smf_event_t *smf_track_get_event_by_number(const smf_track_t *track, int event_number) WARN_UNUSED_RESULT; 7.373 +smf_event_t *smf_track_get_last_event(const smf_track_t *track) WARN_UNUSED_RESULT; 7.374 + 7.375 +void smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int pulses); 7.376 +void smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses); 7.377 +void smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds); 7.378 +int smf_track_add_eot_delta_pulses(smf_track_t *track, int delta) WARN_UNUSED_RESULT; 7.379 +int smf_track_add_eot_pulses(smf_track_t *track, int pulses) WARN_UNUSED_RESULT; 7.380 +int smf_track_add_eot_seconds(smf_track_t *track, double seconds) WARN_UNUSED_RESULT; 7.381 +void smf_event_remove_from_track(smf_event_t *event); 7.382 + 7.383 +/* Routines for manipulating smf_event_t. */ 7.384 +smf_event_t *smf_event_new(void) WARN_UNUSED_RESULT; 7.385 +smf_event_t *smf_event_new_from_pointer(void *midi_data, int len) WARN_UNUSED_RESULT; 7.386 +smf_event_t *smf_event_new_from_bytes(int first_byte, int second_byte, int third_byte) WARN_UNUSED_RESULT; 7.387 +smf_event_t *smf_event_new_textual(int type, const char *text); 7.388 +void smf_event_delete(smf_event_t *event); 7.389 + 7.390 +int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT; 7.391 +int smf_event_is_metadata(const smf_event_t *event) WARN_UNUSED_RESULT; 7.392 +int smf_event_is_system_realtime(const smf_event_t *event) WARN_UNUSED_RESULT; 7.393 +int smf_event_is_system_common(const smf_event_t *event) WARN_UNUSED_RESULT; 7.394 +int smf_event_is_sysex(const smf_event_t *event) WARN_UNUSED_RESULT; 7.395 +int smf_event_is_eot(const smf_event_t *event) WARN_UNUSED_RESULT; 7.396 +int smf_event_is_textual(const smf_event_t *event) WARN_UNUSED_RESULT; 7.397 +char *smf_event_decode(const smf_event_t *event) WARN_UNUSED_RESULT; 7.398 +char *smf_event_extract_text(const smf_event_t *event) WARN_UNUSED_RESULT; 7.399 + 7.400 +/* Routines for loading SMF files. */ 7.401 +smf_t *smf_load(const char *file_name) WARN_UNUSED_RESULT; 7.402 +smf_t *smf_load_from_memory(const void *buffer, const int buffer_length) WARN_UNUSED_RESULT; 7.403 + 7.404 +/* Routine for writing SMF files. */ 7.405 +int smf_save(smf_t *smf, const char *file_name) WARN_UNUSED_RESULT; 7.406 + 7.407 +/* Routines for manipulating smf_tempo_t. */ 7.408 +smf_tempo_t *smf_get_tempo_by_pulses(const smf_t *smf, int pulses) WARN_UNUSED_RESULT; 7.409 +smf_tempo_t *smf_get_tempo_by_seconds(const smf_t *smf, double seconds) WARN_UNUSED_RESULT; 7.410 +smf_tempo_t *smf_get_tempo_by_number(const smf_t *smf, int number) WARN_UNUSED_RESULT; 7.411 +smf_tempo_t *smf_get_last_tempo(const smf_t *smf) WARN_UNUSED_RESULT; 7.412 + 7.413 +const char *smf_get_version(void) WARN_UNUSED_RESULT; 7.414 + 7.415 +#ifdef __cplusplus 7.416 +} 7.417 +#endif 7.418 + 7.419 +#endif /* SMF_H */ 7.420 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/smf_decode.c Thu Jan 26 11:25:11 2012 +0200 8.3 @@ -0,0 +1,638 @@ 8.4 +/*- 8.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 8.6 + * All rights reserved. 8.7 + * 8.8 + * Redistribution and use in source and binary forms, with or without 8.9 + * modification, are permitted provided that the following conditions 8.10 + * are met: 8.11 + * 1. Redistributions of source code must retain the above copyright 8.12 + * notice, this list of conditions and the following disclaimer. 8.13 + * 2. Redistributions in binary form must reproduce the above copyright 8.14 + * notice, this list of conditions and the following disclaimer in the 8.15 + * documentation and/or other materials provided with the distribution. 8.16 + * 8.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 8.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 8.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 8.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 8.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 8.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 8.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 8.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 8.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 8.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8.28 + * 8.29 + */ 8.30 + 8.31 +/** 8.32 + * \file 8.33 + * 8.34 + * Event decoding routines. 8.35 + * 8.36 + */ 8.37 + 8.38 +#include <stdlib.h> 8.39 +#include <string.h> 8.40 +#include <assert.h> 8.41 +#include <math.h> 8.42 +#include <errno.h> 8.43 +#ifdef __MINGW32__ 8.44 +#include <windows.h> 8.45 +#else /* ! __MINGW32__ */ 8.46 +#include <arpa/inet.h> 8.47 +#endif /* ! __MINGW32__ */ 8.48 +#include <stdint.h> 8.49 +#include "smf.h" 8.50 +#include "smf_private.h" 8.51 + 8.52 +#define BUFFER_SIZE 1024 8.53 + 8.54 +/** 8.55 + * \return Nonzero if event is metaevent. You should never send metaevents; 8.56 + * they are not really MIDI messages. They carry information like track title, 8.57 + * time signature etc. 8.58 + */ 8.59 +int 8.60 +smf_event_is_metadata(const smf_event_t *event) 8.61 +{ 8.62 + assert(event->midi_buffer); 8.63 + assert(event->midi_buffer_length > 0); 8.64 + 8.65 + if (event->midi_buffer[0] == 0xFF) 8.66 + return (1); 8.67 + 8.68 + return (0); 8.69 +} 8.70 + 8.71 +/** 8.72 + * \return Nonzero if event is System Realtime. 8.73 + */ 8.74 +int 8.75 +smf_event_is_system_realtime(const smf_event_t *event) 8.76 +{ 8.77 + assert(event->midi_buffer); 8.78 + assert(event->midi_buffer_length > 0); 8.79 + 8.80 + if (smf_event_is_metadata(event)) 8.81 + return (0); 8.82 + 8.83 + if (event->midi_buffer[0] >= 0xF8) 8.84 + return (1); 8.85 + 8.86 + return (0); 8.87 +} 8.88 + 8.89 +/** 8.90 + * \return Nonzero if event is System Common. 8.91 + */ 8.92 +int 8.93 +smf_event_is_system_common(const smf_event_t *event) 8.94 +{ 8.95 + assert(event->midi_buffer); 8.96 + assert(event->midi_buffer_length > 0); 8.97 + 8.98 + if (event->midi_buffer[0] >= 0xF0 && event->midi_buffer[0] <= 0xF7) 8.99 + return (1); 8.100 + 8.101 + return (0); 8.102 +} 8.103 +/** 8.104 + * \return Nonzero if event is SysEx message. 8.105 + */ 8.106 +int 8.107 +smf_event_is_sysex(const smf_event_t *event) 8.108 +{ 8.109 + assert(event->midi_buffer); 8.110 + assert(event->midi_buffer_length > 0); 8.111 + 8.112 + if (event->midi_buffer[0] == 0xF0) 8.113 + return (1); 8.114 + 8.115 + return (0); 8.116 +} 8.117 + 8.118 +static char * 8.119 +smf_event_decode_textual(const smf_event_t *event, const char *name) 8.120 +{ 8.121 + int off = 0; 8.122 + char *buf, *extracted; 8.123 + 8.124 + buf = malloc(BUFFER_SIZE); 8.125 + if (buf == NULL) { 8.126 + fg_critical("smf_event_decode_textual: malloc failed."); 8.127 + return (NULL); 8.128 + } 8.129 + 8.130 + extracted = smf_event_extract_text(event); 8.131 + if (extracted == NULL) { 8.132 + free(buf); 8.133 + return (NULL); 8.134 + } 8.135 + 8.136 + snprintf(buf + off, BUFFER_SIZE - off, "%s: %s", name, extracted); 8.137 + 8.138 + return (buf); 8.139 +} 8.140 + 8.141 +static char * 8.142 +smf_event_decode_metadata(const smf_event_t *event) 8.143 +{ 8.144 + int off = 0, mspqn, flats, isminor; 8.145 + char *buf; 8.146 + 8.147 + static const char *const major_keys[] = {"Fb", "Cb", "Gb", "Db", "Ab", 8.148 + "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#"}; 8.149 + 8.150 + static const char *const minor_keys[] = {"Dbm", "Abm", "Ebm", "Bbm", "Fm", 8.151 + "Cm", "Gm", "Dm", "Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m", "E#m"}; 8.152 + 8.153 + assert(smf_event_is_metadata(event)); 8.154 + 8.155 + switch (event->midi_buffer[1]) { 8.156 + case 0x01: 8.157 + return (smf_event_decode_textual(event, "Text")); 8.158 + 8.159 + case 0x02: 8.160 + return (smf_event_decode_textual(event, "Copyright")); 8.161 + 8.162 + case 0x03: 8.163 + return (smf_event_decode_textual(event, "Sequence/Track Name")); 8.164 + 8.165 + case 0x04: 8.166 + return (smf_event_decode_textual(event, "Instrument")); 8.167 + 8.168 + case 0x05: 8.169 + return (smf_event_decode_textual(event, "Lyric")); 8.170 + 8.171 + case 0x06: 8.172 + return (smf_event_decode_textual(event, "Marker")); 8.173 + 8.174 + case 0x07: 8.175 + return (smf_event_decode_textual(event, "Cue Point")); 8.176 + 8.177 + case 0x08: 8.178 + return (smf_event_decode_textual(event, "Program Name")); 8.179 + 8.180 + case 0x09: 8.181 + return (smf_event_decode_textual(event, "Device (Port) Name")); 8.182 + 8.183 + default: 8.184 + break; 8.185 + } 8.186 + 8.187 + buf = malloc(BUFFER_SIZE); 8.188 + if (buf == NULL) { 8.189 + fg_critical("smf_event_decode_metadata: malloc failed."); 8.190 + return (NULL); 8.191 + } 8.192 + 8.193 + switch (event->midi_buffer[1]) { 8.194 + case 0x00: 8.195 + off += snprintf(buf + off, BUFFER_SIZE - off, "Sequence number"); 8.196 + break; 8.197 + 8.198 + /* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */ 8.199 + case 0x20: 8.200 + if (event->midi_buffer_length < 4) { 8.201 + fg_critical("smf_event_decode_metadata: truncated MIDI message."); 8.202 + goto error; 8.203 + } 8.204 + 8.205 + off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Prefix: %d", event->midi_buffer[3]); 8.206 + break; 8.207 + 8.208 + case 0x21: 8.209 + if (event->midi_buffer_length < 4) { 8.210 + fg_critical("smf_event_decode_metadata: truncated MIDI message."); 8.211 + goto error; 8.212 + } 8.213 + 8.214 + off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Port: %d", event->midi_buffer[3]); 8.215 + break; 8.216 + 8.217 + case 0x2F: 8.218 + off += snprintf(buf + off, BUFFER_SIZE - off, "End Of Track"); 8.219 + break; 8.220 + 8.221 + case 0x51: 8.222 + if (event->midi_buffer_length < 6) { 8.223 + fg_critical("smf_event_decode_metadata: truncated MIDI message."); 8.224 + goto error; 8.225 + } 8.226 + 8.227 + mspqn = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5]; 8.228 + 8.229 + off += snprintf(buf + off, BUFFER_SIZE - off, "Tempo: %d microseconds per quarter note, %.2f BPM", 8.230 + mspqn, 60000000.0 / (double)mspqn); 8.231 + break; 8.232 + 8.233 + case 0x54: 8.234 + off += snprintf(buf + off, BUFFER_SIZE - off, "SMPTE Offset"); 8.235 + break; 8.236 + 8.237 + case 0x58: 8.238 + if (event->midi_buffer_length < 7) { 8.239 + fg_critical("smf_event_decode_metadata: truncated MIDI message."); 8.240 + goto error; 8.241 + } 8.242 + 8.243 + off += snprintf(buf + off, BUFFER_SIZE - off, 8.244 + "Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note", 8.245 + event->midi_buffer[3], (int)pow(2, event->midi_buffer[4]), event->midi_buffer[5], 8.246 + event->midi_buffer[6]); 8.247 + break; 8.248 + 8.249 + case 0x59: 8.250 + if (event->midi_buffer_length < 5) { 8.251 + fg_critical("smf_event_decode_metadata: truncated MIDI message."); 8.252 + goto error; 8.253 + } 8.254 + 8.255 + flats = event->midi_buffer[3]; 8.256 + isminor = event->midi_buffer[4]; 8.257 + 8.258 + if (isminor != 0 && isminor != 1) { 8.259 + fg_critical("smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor); 8.260 + goto error; 8.261 + } 8.262 + 8.263 + off += snprintf(buf + off, BUFFER_SIZE - off, "Key Signature: "); 8.264 + 8.265 + if (flats > 8 && flats < 248) { 8.266 + off += snprintf(buf + off, BUFFER_SIZE - off, "%d %s, %s key", abs((int8_t)flats), 8.267 + flats > 127 ? "flats" : "sharps", isminor ? "minor" : "major"); 8.268 + } else { 8.269 + int i = (flats - 248) & 255; 8.270 + 8.271 + assert(i >= 0 && i < sizeof(minor_keys) / sizeof(*minor_keys)); 8.272 + assert(i >= 0 && i < sizeof(major_keys) / sizeof(*major_keys)); 8.273 + 8.274 + if (isminor) 8.275 + off += snprintf(buf + off, BUFFER_SIZE - off, "%s", minor_keys[i]); 8.276 + else 8.277 + off += snprintf(buf + off, BUFFER_SIZE - off, "%s", major_keys[i]); 8.278 + } 8.279 + 8.280 + break; 8.281 + 8.282 + case 0x7F: 8.283 + off += snprintf(buf + off, BUFFER_SIZE - off, "Proprietary (aka Sequencer) Event, length %d", 8.284 + event->midi_buffer_length); 8.285 + break; 8.286 + 8.287 + default: 8.288 + goto error; 8.289 + } 8.290 + 8.291 + return (buf); 8.292 + 8.293 +error: 8.294 + free(buf); 8.295 + 8.296 + return (NULL); 8.297 +} 8.298 + 8.299 +static char * 8.300 +smf_event_decode_system_realtime(const smf_event_t *event) 8.301 +{ 8.302 + int off = 0; 8.303 + char *buf; 8.304 + 8.305 + assert(smf_event_is_system_realtime(event)); 8.306 + 8.307 + if (event->midi_buffer_length != 1) { 8.308 + fg_critical("smf_event_decode_system_realtime: event length is not 1."); 8.309 + return (NULL); 8.310 + } 8.311 + 8.312 + buf = malloc(BUFFER_SIZE); 8.313 + if (buf == NULL) { 8.314 + fg_critical("smf_event_decode_system_realtime: malloc failed."); 8.315 + return (NULL); 8.316 + } 8.317 + 8.318 + switch (event->midi_buffer[0]) { 8.319 + case 0xF8: 8.320 + off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Clock (realtime)"); 8.321 + break; 8.322 + 8.323 + case 0xF9: 8.324 + off += snprintf(buf + off, BUFFER_SIZE - off, "Tick (realtime)"); 8.325 + break; 8.326 + 8.327 + case 0xFA: 8.328 + off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Start (realtime)"); 8.329 + break; 8.330 + 8.331 + case 0xFB: 8.332 + off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Continue (realtime)"); 8.333 + break; 8.334 + 8.335 + case 0xFC: 8.336 + off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Stop (realtime)"); 8.337 + break; 8.338 + 8.339 + case 0xFE: 8.340 + off += snprintf(buf + off, BUFFER_SIZE - off, "Active Sense (realtime)"); 8.341 + break; 8.342 + 8.343 + default: 8.344 + free(buf); 8.345 + return (NULL); 8.346 + } 8.347 + 8.348 + return (buf); 8.349 +} 8.350 + 8.351 +static char * 8.352 +smf_event_decode_sysex(const smf_event_t *event) 8.353 +{ 8.354 + int off = 0; 8.355 + char *buf, manufacturer, subid, subid2; 8.356 + 8.357 + assert(smf_event_is_sysex(event)); 8.358 + 8.359 + if (event->midi_buffer_length < 5) { 8.360 + fg_critical("smf_event_decode_sysex: truncated MIDI message."); 8.361 + return (NULL); 8.362 + } 8.363 + 8.364 + buf = malloc(BUFFER_SIZE); 8.365 + if (buf == NULL) { 8.366 + fg_critical("smf_event_decode_sysex: malloc failed."); 8.367 + return (NULL); 8.368 + } 8.369 + 8.370 + manufacturer = event->midi_buffer[1]; 8.371 + 8.372 + if (manufacturer == 0x7F) { 8.373 + off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, realtime, channel %d", event->midi_buffer[2]); 8.374 + } else if (manufacturer == 0x7E) { 8.375 + off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, non-realtime, channel %d", event->midi_buffer[2]); 8.376 + } else { 8.377 + off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, manufacturer 0x%x", manufacturer); 8.378 + 8.379 + return (buf); 8.380 + } 8.381 + 8.382 + subid = event->midi_buffer[3]; 8.383 + subid2 = event->midi_buffer[4]; 8.384 + 8.385 + if (subid == 0x01) 8.386 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Header"); 8.387 + 8.388 + else if (subid == 0x02) 8.389 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Data Packet"); 8.390 + 8.391 + else if (subid == 0x03) 8.392 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Request"); 8.393 + 8.394 + else if (subid == 0x04 && subid2 == 0x01) 8.395 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Master Volume"); 8.396 + 8.397 + else if (subid == 0x05 && subid2 == 0x01) 8.398 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Retransmit"); 8.399 + 8.400 + else if (subid == 0x05 && subid2 == 0x02) 8.401 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Request"); 8.402 + 8.403 + else if (subid == 0x06 && subid2 == 0x01) 8.404 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Request"); 8.405 + 8.406 + else if (subid == 0x06 && subid2 == 0x02) 8.407 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Reply"); 8.408 + 8.409 + else if (subid == 0x08 && subid2 == 0x00) 8.410 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request"); 8.411 + 8.412 + else if (subid == 0x08 && subid2 == 0x01) 8.413 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump"); 8.414 + 8.415 + else if (subid == 0x08 && subid2 == 0x02) 8.416 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change"); 8.417 + 8.418 + else if (subid == 0x08 && subid2 == 0x03) 8.419 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request (Bank)"); 8.420 + 8.421 + else if (subid == 0x08 && subid2 == 0x04) 8.422 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Key Based Tuning Dump"); 8.423 + 8.424 + else if (subid == 0x08 && subid2 == 0x05) 8.425 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 1 byte format"); 8.426 + 8.427 + else if (subid == 0x08 && subid2 == 0x06) 8.428 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 2 byte format"); 8.429 + 8.430 + else if (subid == 0x08 && subid2 == 0x07) 8.431 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change (Bank)"); 8.432 + 8.433 + else if (subid == 0x09) 8.434 + off += snprintf(buf + off, BUFFER_SIZE - off, ", General MIDI %s", subid2 == 0 ? "disable" : "enable"); 8.435 + 8.436 + else if (subid == 0x7C) 8.437 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Wait"); 8.438 + 8.439 + else if (subid == 0x7D) 8.440 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Cancel"); 8.441 + 8.442 + else if (subid == 0x7E) 8.443 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump NAK"); 8.444 + 8.445 + else if (subid == 0x7F) 8.446 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump ACK"); 8.447 + 8.448 + else 8.449 + off += snprintf(buf + off, BUFFER_SIZE - off, ", Unknown"); 8.450 + 8.451 + return (buf); 8.452 +} 8.453 + 8.454 +static char * 8.455 +smf_event_decode_system_common(const smf_event_t *event) 8.456 +{ 8.457 + int off = 0; 8.458 + char *buf; 8.459 + 8.460 + assert(smf_event_is_system_common(event)); 8.461 + 8.462 + if (smf_event_is_sysex(event)) 8.463 + return (smf_event_decode_sysex(event)); 8.464 + 8.465 + buf = malloc(BUFFER_SIZE); 8.466 + if (buf == NULL) { 8.467 + fg_critical("smf_event_decode_system_realtime: malloc failed."); 8.468 + return (NULL); 8.469 + } 8.470 + 8.471 + switch (event->midi_buffer[0]) { 8.472 + case 0xF1: 8.473 + off += snprintf(buf + off, BUFFER_SIZE - off, "MTC Quarter Frame"); 8.474 + break; 8.475 + 8.476 + case 0xF2: 8.477 + off += snprintf(buf + off, BUFFER_SIZE - off, "Song Position Pointer"); 8.478 + break; 8.479 + 8.480 + case 0xF3: 8.481 + off += snprintf(buf + off, BUFFER_SIZE - off, "Song Select"); 8.482 + break; 8.483 + 8.484 + case 0xF6: 8.485 + off += snprintf(buf + off, BUFFER_SIZE - off, "Tune Request"); 8.486 + break; 8.487 + 8.488 + default: 8.489 + free(buf); 8.490 + return (NULL); 8.491 + } 8.492 + 8.493 + return (buf); 8.494 +} 8.495 + 8.496 +static void 8.497 +note_from_int(char *buf, int note_number) 8.498 +{ 8.499 + int note, octave; 8.500 + char *names[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; 8.501 + 8.502 + octave = note_number / 12 - 1; 8.503 + note = note_number % 12; 8.504 + 8.505 + sprintf(buf, "%s%d", names[note], octave); 8.506 +} 8.507 + 8.508 +/** 8.509 + * \return Textual representation of the event given, or NULL, if event is unknown. 8.510 + * Returned string looks like this: 8.511 + * 8.512 + * Note On, channel 1, note F#3, velocity 0 8.513 + * 8.514 + * You should free the returned string afterwards, using free(3). 8.515 + */ 8.516 +char * 8.517 +smf_event_decode(const smf_event_t *event) 8.518 +{ 8.519 + int off = 0, channel; 8.520 + char *buf, note[5]; 8.521 + 8.522 + if (smf_event_is_metadata(event)) 8.523 + return (smf_event_decode_metadata(event)); 8.524 + 8.525 + if (smf_event_is_system_realtime(event)) 8.526 + return (smf_event_decode_system_realtime(event)); 8.527 + 8.528 + if (smf_event_is_system_common(event)) 8.529 + return (smf_event_decode_system_common(event)); 8.530 + 8.531 + if (!smf_event_length_is_valid(event)) { 8.532 + fg_critical("smf_event_decode: incorrect MIDI message length."); 8.533 + return (NULL); 8.534 + } 8.535 + 8.536 + buf = malloc(BUFFER_SIZE); 8.537 + if (buf == NULL) { 8.538 + fg_critical("smf_event_decode: malloc failed."); 8.539 + return (NULL); 8.540 + } 8.541 + 8.542 + /* + 1, because user-visible channels used to be in range <1-16>. */ 8.543 + channel = (event->midi_buffer[0] & 0x0F) + 1; 8.544 + 8.545 + switch (event->midi_buffer[0] & 0xF0) { 8.546 + case 0x80: 8.547 + note_from_int(note, event->midi_buffer[1]); 8.548 + off += snprintf(buf + off, BUFFER_SIZE - off, "Note Off, channel %d, note %s, velocity %d", 8.549 + channel, note, event->midi_buffer[2]); 8.550 + break; 8.551 + 8.552 + case 0x90: 8.553 + note_from_int(note, event->midi_buffer[1]); 8.554 + off += snprintf(buf + off, BUFFER_SIZE - off, "Note On, channel %d, note %s, velocity %d", 8.555 + channel, note, event->midi_buffer[2]); 8.556 + break; 8.557 + 8.558 + case 0xA0: 8.559 + note_from_int(note, event->midi_buffer[1]); 8.560 + off += snprintf(buf + off, BUFFER_SIZE - off, "Aftertouch, channel %d, note %s, pressure %d", 8.561 + channel, note, event->midi_buffer[2]); 8.562 + break; 8.563 + 8.564 + case 0xB0: 8.565 + off += snprintf(buf + off, BUFFER_SIZE - off, "Controller, channel %d, controller %d, value %d", 8.566 + channel, event->midi_buffer[1], event->midi_buffer[2]); 8.567 + break; 8.568 + 8.569 + case 0xC0: 8.570 + off += snprintf(buf + off, BUFFER_SIZE - off, "Program Change, channel %d, controller %d", 8.571 + channel, event->midi_buffer[1]); 8.572 + break; 8.573 + 8.574 + case 0xD0: 8.575 + off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Pressure, channel %d, pressure %d", 8.576 + channel, event->midi_buffer[1]); 8.577 + break; 8.578 + 8.579 + case 0xE0: 8.580 + off += snprintf(buf + off, BUFFER_SIZE - off, "Pitch Wheel, channel %d, value %d", 8.581 + channel, ((int)event->midi_buffer[2] << 7) | (int)event->midi_buffer[2]); 8.582 + break; 8.583 + 8.584 + default: 8.585 + free(buf); 8.586 + return (NULL); 8.587 + } 8.588 + 8.589 + return (buf); 8.590 +} 8.591 + 8.592 +/** 8.593 + * \return Textual representation of the data extracted from MThd header, or NULL, if something goes wrong. 8.594 + * Returned string looks like this: 8.595 + * 8.596 + * format: 1 (several simultaneous tracks); number of tracks: 4; division: 192 PPQN. 8.597 + * 8.598 + * You should free the returned string afterwards, using free(3). 8.599 + */ 8.600 +char * 8.601 +smf_decode(const smf_t *smf) 8.602 +{ 8.603 + int off = 0; 8.604 + char *buf; 8.605 + 8.606 + buf = malloc(BUFFER_SIZE); 8.607 + if (buf == NULL) { 8.608 + fg_critical("smf_event_decode: malloc failed."); 8.609 + return (NULL); 8.610 + } 8.611 + 8.612 + off += snprintf(buf + off, BUFFER_SIZE - off, "format: %d ", smf->format); 8.613 + 8.614 + switch (smf->format) { 8.615 + case 0: 8.616 + off += snprintf(buf + off, BUFFER_SIZE - off, "(single track)"); 8.617 + break; 8.618 + 8.619 + case 1: 8.620 + off += snprintf(buf + off, BUFFER_SIZE - off, "(several simultaneous tracks)"); 8.621 + break; 8.622 + 8.623 + case 2: 8.624 + off += snprintf(buf + off, BUFFER_SIZE - off, "(several independent tracks)"); 8.625 + break; 8.626 + 8.627 + default: 8.628 + off += snprintf(buf + off, BUFFER_SIZE - off, "(INVALID FORMAT)"); 8.629 + break; 8.630 + } 8.631 + 8.632 + off += snprintf(buf + off, BUFFER_SIZE - off, "; number of tracks: %d", smf->number_of_tracks); 8.633 + 8.634 + if (smf->ppqn != 0) 8.635 + off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d PPQN", smf->ppqn); 8.636 + else 8.637 + off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d FPS, %d resolution", smf->frames_per_second, smf->resolution); 8.638 + 8.639 + return (buf); 8.640 +} 8.641 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/smf_load.c Thu Jan 26 11:25:11 2012 +0200 9.3 @@ -0,0 +1,933 @@ 9.4 +/*- 9.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 9.6 + * All rights reserved. 9.7 + * 9.8 + * Redistribution and use in source and binary forms, with or without 9.9 + * modification, are permitted provided that the following conditions 9.10 + * are met: 9.11 + * 1. Redistributions of source code must retain the above copyright 9.12 + * notice, this list of conditions and the following disclaimer. 9.13 + * 2. Redistributions in binary form must reproduce the above copyright 9.14 + * notice, this list of conditions and the following disclaimer in the 9.15 + * documentation and/or other materials provided with the distribution. 9.16 + * 9.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 9.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 9.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 9.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 9.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 9.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 9.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 9.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 9.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 9.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 9.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 9.28 + * 9.29 + */ 9.30 + 9.31 +/** 9.32 + * \file 9.33 + * 9.34 + * Standard MIDI File format loader. 9.35 + * 9.36 + */ 9.37 + 9.38 +/* Reference: http://www.borg.com/~jglatt/tech/midifile.htm */ 9.39 + 9.40 +#include <stdlib.h> 9.41 +#include <string.h> 9.42 +#include <assert.h> 9.43 +#include <math.h> 9.44 +#include <errno.h> 9.45 +#include <ctype.h> 9.46 +#ifdef __MINGW32__ 9.47 +#include <windows.h> 9.48 +#else /* ! __MINGW32__ */ 9.49 +#include <arpa/inet.h> 9.50 +#endif /* ! __MINGW32__ */ 9.51 +#include "smf.h" 9.52 +#include "smf_private.h" 9.53 + 9.54 +/** 9.55 + * Returns pointer to the next SMF chunk in smf->buffer, based on length of the previous one. 9.56 + * Returns NULL in case of error. 9.57 + */ 9.58 +static struct chunk_header_struct * 9.59 +next_chunk(smf_t *smf) 9.60 +{ 9.61 + struct chunk_header_struct *chunk; 9.62 + void *next_chunk_ptr; 9.63 + 9.64 + assert(smf->file_buffer != NULL); 9.65 + assert(smf->file_buffer_length > 0); 9.66 + assert(smf->next_chunk_offset >= 0); 9.67 + 9.68 + if (smf->next_chunk_offset + sizeof(struct chunk_header_struct) >= smf->file_buffer_length) { 9.69 + fg_critical("SMF warning: no more chunks left."); 9.70 + return (NULL); 9.71 + } 9.72 + 9.73 + next_chunk_ptr = (unsigned char *)smf->file_buffer + smf->next_chunk_offset; 9.74 + 9.75 + chunk = (struct chunk_header_struct *)next_chunk_ptr; 9.76 + 9.77 + if (!isalpha(chunk->id[0]) || !isalpha(chunk->id[1]) || !isalpha(chunk->id[2]) || !isalpha(chunk->id[3])) { 9.78 + fg_critical("SMF error: chunk signature contains at least one non-alphanumeric byte."); 9.79 + return (NULL); 9.80 + } 9.81 + 9.82 + /* 9.83 + * XXX: On SPARC, after compiling with "-fast" option there will be SIGBUS here. 9.84 + * Please compile with -xmemalign=8i". 9.85 + */ 9.86 + smf->next_chunk_offset += sizeof(struct chunk_header_struct) + ntohl(chunk->length); 9.87 + 9.88 + if (smf->next_chunk_offset > smf->file_buffer_length) { 9.89 + fg_critical("SMF warning: malformed chunk; truncated file?"); 9.90 + smf->next_chunk_offset = smf->file_buffer_length; 9.91 + } 9.92 + 9.93 + return (chunk); 9.94 +} 9.95 + 9.96 +/** 9.97 + * Returns 1, iff signature of the "chunk" is the same as string passed as "signature". 9.98 + */ 9.99 +static int 9.100 +chunk_signature_matches(const struct chunk_header_struct *chunk, const char *signature) 9.101 +{ 9.102 + if (!memcmp(chunk->id, signature, 4)) 9.103 + return (1); 9.104 + 9.105 + return (0); 9.106 +} 9.107 + 9.108 +/** 9.109 + * Verifies if MThd header looks OK. Returns 0 iff it does. 9.110 + */ 9.111 +static int 9.112 +parse_mthd_header(smf_t *smf) 9.113 +{ 9.114 + int len; 9.115 + struct chunk_header_struct *mthd, *tmp_mthd; 9.116 + 9.117 + /* Make sure compiler didn't do anything stupid. */ 9.118 + assert(sizeof(struct chunk_header_struct) == 8); 9.119 + 9.120 + /* 9.121 + * We could just do "mthd = smf->file_buffer;" here, but this way we wouldn't 9.122 + * get useful error messages. 9.123 + */ 9.124 + if (smf->file_buffer_length < 6) { 9.125 + fg_critical("SMF error: file is too short, it cannot be a MIDI file."); 9.126 + 9.127 + return (-1); 9.128 + } 9.129 + 9.130 + tmp_mthd = smf->file_buffer; 9.131 + 9.132 + if (!chunk_signature_matches(tmp_mthd, "MThd")) { 9.133 + fg_critical("SMF error: MThd signature not found, is that a MIDI file?"); 9.134 + 9.135 + return (-2); 9.136 + } 9.137 + 9.138 + /* Ok, now use next_chunk(). */ 9.139 + mthd = next_chunk(smf); 9.140 + if (mthd == NULL) 9.141 + return (-3); 9.142 + 9.143 + assert(mthd == tmp_mthd); 9.144 + 9.145 + len = ntohl(mthd->length); 9.146 + if (len != 6) { 9.147 + fg_critical("SMF error: MThd chunk length %d, must be 6.", len); 9.148 + 9.149 + return (-4); 9.150 + } 9.151 + 9.152 + return (0); 9.153 +} 9.154 + 9.155 +/** 9.156 + * Parses MThd chunk, filling "smf" structure with values extracted from it. Returns 0 iff everything went OK. 9.157 + */ 9.158 +static int 9.159 +parse_mthd_chunk(smf_t *smf) 9.160 +{ 9.161 + signed char first_byte_of_division, second_byte_of_division; 9.162 + 9.163 + struct mthd_chunk_struct *mthd; 9.164 + 9.165 + assert(sizeof(struct mthd_chunk_struct) == 14); 9.166 + 9.167 + if (parse_mthd_header(smf)) 9.168 + return (1); 9.169 + 9.170 + mthd = (struct mthd_chunk_struct *)smf->file_buffer; 9.171 + 9.172 + smf->format = ntohs(mthd->format); 9.173 + if (smf->format < 0 || smf->format > 2) { 9.174 + fg_critical("SMF error: bad MThd format field value: %d, valid values are 0-2, inclusive.", smf->format); 9.175 + return (-1); 9.176 + } 9.177 + 9.178 + if (smf->format == 2) { 9.179 + fg_critical("SMF file uses format #2, no support for that yet."); 9.180 + return (-2); 9.181 + } 9.182 + 9.183 + smf->expected_number_of_tracks = ntohs(mthd->number_of_tracks); 9.184 + if (smf->expected_number_of_tracks <= 0) { 9.185 + fg_critical("SMF error: bad number of tracks: %d, must be greater than zero.", smf->expected_number_of_tracks); 9.186 + return (-3); 9.187 + } 9.188 + 9.189 + /* XXX: endianess? */ 9.190 + first_byte_of_division = *((signed char *)&(mthd->division)); 9.191 + second_byte_of_division = *((signed char *)&(mthd->division) + 1); 9.192 + 9.193 + if (first_byte_of_division >= 0) { 9.194 + smf->ppqn = ntohs(mthd->division); 9.195 + smf->frames_per_second = 0; 9.196 + smf->resolution = 0; 9.197 + } else { 9.198 + smf->ppqn = 0; 9.199 + smf->frames_per_second = - first_byte_of_division; 9.200 + smf->resolution = second_byte_of_division; 9.201 + } 9.202 + 9.203 + if (smf->ppqn == 0) { 9.204 + fg_critical("SMF file uses FPS timing instead of PPQN, no support for that yet."); 9.205 + return (-4); 9.206 + } 9.207 + 9.208 + return (0); 9.209 +} 9.210 + 9.211 +/** 9.212 + * Interprets Variable Length Quantity pointed at by "buf" and puts its value into "value" and number 9.213 + * of bytes consumed into "len", making sure it does not read past "buf" + "buffer_length". 9.214 + * Explanation of Variable Length Quantities is here: http://www.borg.com/~jglatt/tech/midifile/vari.htm 9.215 + * Returns 0 iff everything went OK, different value in case of error. 9.216 + */ 9.217 +static int 9.218 +extract_vlq(const unsigned char *buf, const int buffer_length, int *value, int *len) 9.219 +{ 9.220 + int val = 0; 9.221 + const unsigned char *c = buf; 9.222 + 9.223 + assert(buffer_length > 0); 9.224 + 9.225 + for (;;) { 9.226 + if (c >= buf + buffer_length) { 9.227 + fg_critical("End of buffer in extract_vlq()."); 9.228 + return (-1); 9.229 + } 9.230 + 9.231 + val = (val << 7) + (*c & 0x7F); 9.232 + 9.233 + if (*c & 0x80) 9.234 + c++; 9.235 + else 9.236 + break; 9.237 + }; 9.238 + 9.239 + *value = val; 9.240 + *len = c - buf + 1; 9.241 + 9.242 + if (*len > 4) { 9.243 + fg_critical("SMF error: Variable Length Quantities longer than four bytes are not supported yet."); 9.244 + return (-2); 9.245 + } 9.246 + 9.247 + return (0); 9.248 +} 9.249 + 9.250 +/** 9.251 + * Returns 1 if the given byte is a valid status byte, 0 otherwise. 9.252 + */ 9.253 +int 9.254 +is_status_byte(const unsigned char status) 9.255 +{ 9.256 + return (status & 0x80); 9.257 +} 9.258 + 9.259 +static int 9.260 +is_sysex_byte(const unsigned char status) 9.261 +{ 9.262 + if (status == 0xF0) 9.263 + return (1); 9.264 + 9.265 + return (0); 9.266 +} 9.267 + 9.268 +static int 9.269 +is_escape_byte(const unsigned char status) 9.270 +{ 9.271 + if (status == 0xF7) 9.272 + return (1); 9.273 + 9.274 + return (0); 9.275 +} 9.276 + 9.277 +/** 9.278 + * Just like expected_message_length(), but only for System Exclusive messages. 9.279 + * Note that value returned by this thing here is the length of SysEx "on the wire", 9.280 + * not the number of bytes that this sysex takes in the file - in SMF format sysex 9.281 + * contains VLQ telling how many bytes it takes, "on the wire" format does not have 9.282 + * this. 9.283 + */ 9.284 +static int 9.285 +expected_sysex_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes) 9.286 +{ 9.287 + int sysex_length, len; 9.288 + 9.289 + assert(status == 0xF0); 9.290 + 9.291 + if (buffer_length < 3) { 9.292 + fg_critical("SMF error: end of buffer in expected_sysex_length()."); 9.293 + return (-1); 9.294 + } 9.295 + 9.296 + if (extract_vlq(second_byte, buffer_length, &sysex_length, &len)) 9.297 + return (-1); 9.298 + 9.299 + if (consumed_bytes != NULL) 9.300 + *consumed_bytes = len; 9.301 + 9.302 + /* +1, because the length does not include status byte. */ 9.303 + return (sysex_length + 1); 9.304 +} 9.305 + 9.306 +static int 9.307 +expected_escaped_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes) 9.308 +{ 9.309 + /* -1, because we do not want to account for 0x7F status. */ 9.310 + return (expected_sysex_length(status, second_byte, buffer_length, consumed_bytes) - 1); 9.311 +} 9.312 + 9.313 +/** 9.314 + * Returns expected length of the midi message (including the status byte), in bytes, for the given status byte. 9.315 + * The "second_byte" points to the expected second byte of the MIDI message. "buffer_length" is the buffer 9.316 + * length limit, counting from "second_byte". Returns value < 0 iff there was an error. 9.317 + */ 9.318 +static int 9.319 +expected_message_length(unsigned char status, const unsigned char *second_byte, const int buffer_length) 9.320 +{ 9.321 + /* Make sure this really is a valid status byte. */ 9.322 + assert(is_status_byte(status)); 9.323 + 9.324 + /* We cannot use this routine for sysexes. */ 9.325 + assert(!is_sysex_byte(status)); 9.326 + 9.327 + /* We cannot use this routine for escaped events. */ 9.328 + assert(!is_escape_byte(status)); 9.329 + 9.330 + /* Buffer length may be zero, for e.g. realtime messages. */ 9.331 + assert(buffer_length >= 0); 9.332 + 9.333 + /* Is this a metamessage? */ 9.334 + if (status == 0xFF) { 9.335 + if (buffer_length < 2) { 9.336 + fg_critical("SMF error: end of buffer in expected_message_length()."); 9.337 + return (-1); 9.338 + } 9.339 + 9.340 + /* 9.341 + * Format of this kind of messages is like this: 0xFF 0xwhatever 0xlength and then "length" bytes. 9.342 + * Second byte points to this: ^^^^^^^^^^ 9.343 + */ 9.344 + return (*(second_byte + 1) + 3); 9.345 + } 9.346 + 9.347 + if ((status & 0xF0) == 0xF0) { 9.348 + switch (status) { 9.349 + case 0xF2: /* Song Position Pointer. */ 9.350 + return (3); 9.351 + 9.352 + case 0xF1: /* MTC Quarter Frame. */ 9.353 + case 0xF3: /* Song Select. */ 9.354 + return (2); 9.355 + 9.356 + case 0xF6: /* Tune Request. */ 9.357 + case 0xF8: /* MIDI Clock. */ 9.358 + case 0xF9: /* Tick. */ 9.359 + case 0xFA: /* MIDI Start. */ 9.360 + case 0xFB: /* MIDI Continue. */ 9.361 + case 0xFC: /* MIDI Stop. */ 9.362 + case 0xFE: /* Active Sense. */ 9.363 + return (1); 9.364 + 9.365 + default: 9.366 + fg_critical("SMF error: unknown 0xFx-type status byte '0x%x'.", status); 9.367 + return (-2); 9.368 + } 9.369 + } 9.370 + 9.371 + /* Filter out the channel. */ 9.372 + status &= 0xF0; 9.373 + 9.374 + switch (status) { 9.375 + case 0x80: /* Note Off. */ 9.376 + case 0x90: /* Note On. */ 9.377 + case 0xA0: /* AfterTouch. */ 9.378 + case 0xB0: /* Control Change. */ 9.379 + case 0xE0: /* Pitch Wheel. */ 9.380 + return (3); 9.381 + 9.382 + case 0xC0: /* Program Change. */ 9.383 + case 0xD0: /* Channel Pressure. */ 9.384 + return (2); 9.385 + 9.386 + default: 9.387 + fg_critical("SMF error: unknown status byte '0x%x'.", status); 9.388 + return (-3); 9.389 + } 9.390 +} 9.391 + 9.392 +static int 9.393 +extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 9.394 +{ 9.395 + int status, message_length, vlq_length; 9.396 + const unsigned char *c = buf; 9.397 + 9.398 + status = *buf; 9.399 + 9.400 + assert(is_sysex_byte(status)); 9.401 + 9.402 + c++; 9.403 + 9.404 + message_length = expected_sysex_length(status, c, buffer_length - 1, &vlq_length); 9.405 + 9.406 + if (message_length < 0) 9.407 + return (-3); 9.408 + 9.409 + c += vlq_length; 9.410 + 9.411 + if (vlq_length + message_length >= buffer_length) { 9.412 + fg_critical("End of buffer in extract_sysex_event()."); 9.413 + return (-5); 9.414 + } 9.415 + 9.416 + event->midi_buffer_length = message_length; 9.417 + event->midi_buffer = malloc(event->midi_buffer_length); 9.418 + if (event->midi_buffer == NULL) { 9.419 + fg_critical("Cannot allocate memory in extract_sysex_event(): %s", strerror(errno)); 9.420 + return (-4); 9.421 + } 9.422 + 9.423 + event->midi_buffer[0] = status; 9.424 + memcpy(event->midi_buffer + 1, c, message_length - 1); 9.425 + 9.426 + *len = vlq_length + message_length; 9.427 + 9.428 + return (0); 9.429 +} 9.430 + 9.431 +static int 9.432 +extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 9.433 +{ 9.434 + int status, message_length, vlq_length; 9.435 + const unsigned char *c = buf; 9.436 + 9.437 + status = *buf; 9.438 + 9.439 + assert(is_escape_byte(status)); 9.440 + 9.441 + c++; 9.442 + 9.443 + message_length = expected_escaped_length(status, c, buffer_length - 1, &vlq_length); 9.444 + 9.445 + if (message_length < 0) 9.446 + return (-3); 9.447 + 9.448 + c += vlq_length; 9.449 + 9.450 + if (vlq_length + message_length >= buffer_length) { 9.451 + fg_critical("End of buffer in extract_escaped_event()."); 9.452 + return (-5); 9.453 + } 9.454 + 9.455 + event->midi_buffer_length = message_length; 9.456 + event->midi_buffer = malloc(event->midi_buffer_length); 9.457 + if (event->midi_buffer == NULL) { 9.458 + fg_critical("Cannot allocate memory in extract_escaped_event(): %s", strerror(errno)); 9.459 + return (-4); 9.460 + } 9.461 + 9.462 + memcpy(event->midi_buffer, c, message_length); 9.463 + 9.464 + if (smf_event_is_valid(event)) { 9.465 + fg_critical("Escaped event is invalid."); 9.466 + return (-1); 9.467 + } 9.468 + 9.469 + if (smf_event_is_system_realtime(event) || smf_event_is_system_common(event)) { 9.470 + fg_warning("Escaped event is not System Realtime nor System Common."); 9.471 + } 9.472 + 9.473 + *len = vlq_length + message_length; 9.474 + 9.475 + return (0); 9.476 +} 9.477 + 9.478 + 9.479 +/** 9.480 + * Puts MIDI data extracted from from "buf" into "event" and number of consumed bytes into "len". 9.481 + * In case valid status is not found, it uses "last_status" (so called "running status"). 9.482 + * Returns 0 iff everything went OK, value < 0 in case of error. 9.483 + */ 9.484 +static int 9.485 +extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status) 9.486 +{ 9.487 + int status, message_length; 9.488 + const unsigned char *c = buf; 9.489 + 9.490 + assert(buffer_length > 0); 9.491 + 9.492 + /* Is the first byte the status byte? */ 9.493 + if (is_status_byte(*c)) { 9.494 + status = *c; 9.495 + c++; 9.496 + 9.497 + } else { 9.498 + /* No, we use running status then. */ 9.499 + status = last_status; 9.500 + } 9.501 + 9.502 + if (!is_status_byte(status)) { 9.503 + fg_critical("SMF error: bad status byte (MSB is zero)."); 9.504 + return (-1); 9.505 + } 9.506 + 9.507 + if (is_sysex_byte(status)) 9.508 + return (extract_sysex_event(buf, buffer_length, event, len, last_status)); 9.509 + 9.510 + if (is_escape_byte(status)) 9.511 + return (extract_escaped_event(buf, buffer_length, event, len, last_status)); 9.512 + 9.513 + /* At this point, "c" points to first byte following the status byte. */ 9.514 + message_length = expected_message_length(status, c, buffer_length - (c - buf)); 9.515 + 9.516 + if (message_length < 0) 9.517 + return (-3); 9.518 + 9.519 + if (message_length - 1 > buffer_length - (c - buf)) { 9.520 + fg_critical("End of buffer in extract_midi_event()."); 9.521 + return (-5); 9.522 + } 9.523 + 9.524 + event->midi_buffer_length = message_length; 9.525 + event->midi_buffer = malloc(event->midi_buffer_length); 9.526 + if (event->midi_buffer == NULL) { 9.527 + fg_critical("Cannot allocate memory in extract_midi_event(): %s", strerror(errno)); 9.528 + return (-4); 9.529 + } 9.530 + 9.531 + event->midi_buffer[0] = status; 9.532 + memcpy(event->midi_buffer + 1, c, message_length - 1); 9.533 + 9.534 + *len = c + message_length - 1 - buf; 9.535 + 9.536 + return (0); 9.537 +} 9.538 + 9.539 +/** 9.540 + * Locates, basing on track->next_event_offset, the next event data in track->buffer, 9.541 + * interprets it, allocates smf_event_t and fills it properly. Returns smf_event_t 9.542 + * or NULL, if there was an error. Allocating event means adding it to the track; 9.543 + * see smf_event_new(). 9.544 + */ 9.545 +static smf_event_t * 9.546 +parse_next_event(smf_track_t *track) 9.547 +{ 9.548 + int time = 0, len, buffer_length; 9.549 + unsigned char *c, *start; 9.550 + 9.551 + smf_event_t *event = smf_event_new(); 9.552 + if (event == NULL) 9.553 + goto error; 9.554 + 9.555 + c = start = (unsigned char *)track->file_buffer + track->next_event_offset; 9.556 + 9.557 + assert(track->file_buffer != NULL); 9.558 + assert(track->file_buffer_length > 0); 9.559 + assert(track->next_event_offset > 0); 9.560 + 9.561 + buffer_length = track->file_buffer_length - track->next_event_offset; 9.562 + assert(buffer_length > 0); 9.563 + 9.564 + /* First, extract time offset from previous event. */ 9.565 + if (extract_vlq(c, buffer_length, &time, &len)) 9.566 + goto error; 9.567 + 9.568 + c += len; 9.569 + buffer_length -= len; 9.570 + 9.571 + if (buffer_length <= 0) 9.572 + goto error; 9.573 + 9.574 + /* Now, extract the actual event. */ 9.575 + if (extract_midi_event(c, buffer_length, event, &len, track->last_status)) 9.576 + goto error; 9.577 + 9.578 + c += len; 9.579 + buffer_length -= len; 9.580 + track->last_status = event->midi_buffer[0]; 9.581 + track->next_event_offset += c - start; 9.582 + 9.583 + smf_track_add_event_delta_pulses(track, event, time); 9.584 + 9.585 + return (event); 9.586 + 9.587 +error: 9.588 + if (event != NULL) 9.589 + smf_event_delete(event); 9.590 + 9.591 + return (NULL); 9.592 +} 9.593 + 9.594 +/** 9.595 + * Takes "len" characters starting in "buf", making sure it does not access past the length of the buffer, 9.596 + * and makes ordinary, zero-terminated string from it. May return NULL if there was any problem. 9.597 + */ 9.598 +static char * 9.599 +make_string(const unsigned char *buf, const int buffer_length, int len) 9.600 +{ 9.601 + char *str; 9.602 + 9.603 + assert(buffer_length > 0); 9.604 + assert(len > 0); 9.605 + 9.606 + if (len > buffer_length) { 9.607 + fg_critical("End of buffer in make_string()."); 9.608 + 9.609 + len = buffer_length; 9.610 + } 9.611 + 9.612 + str = malloc(len + 1); 9.613 + if (str == NULL) { 9.614 + fg_critical("Cannot allocate memory in make_string()."); 9.615 + return (NULL); 9.616 + } 9.617 + 9.618 + memcpy(str, buf, len); 9.619 + str[len] = '\0'; 9.620 + 9.621 + return (str); 9.622 +} 9.623 + 9.624 +/** 9.625 + * \return 1, if passed a metaevent containing text, that is, Text, Copyright, 9.626 + * Sequence/Track Name, Instrument, Lyric, Marker, Cue Point, Program Name, 9.627 + * or Device Name; 0 otherwise. 9.628 + */ 9.629 +int 9.630 +smf_event_is_textual(const smf_event_t *event) 9.631 +{ 9.632 + if (!smf_event_is_metadata(event)) 9.633 + return (0); 9.634 + 9.635 + if (event->midi_buffer_length < 4) 9.636 + return (0); 9.637 + 9.638 + if (event->midi_buffer[3] < 1 && event->midi_buffer[3] > 9) 9.639 + return (0); 9.640 + 9.641 + return (1); 9.642 +} 9.643 + 9.644 +/** 9.645 + * Extracts text from "textual metaevents", such as Text or Lyric. 9.646 + * 9.647 + * \return Zero-terminated string extracted from "text events" or NULL, if there was any problem. 9.648 + */ 9.649 +char * 9.650 +smf_event_extract_text(const smf_event_t *event) 9.651 +{ 9.652 + int string_length = -1, length_length = -1; 9.653 + 9.654 + if (!smf_event_is_textual(event)) 9.655 + return (NULL); 9.656 + 9.657 + if (event->midi_buffer_length < 3) { 9.658 + fg_critical("smf_event_extract_text: truncated MIDI message."); 9.659 + return (NULL); 9.660 + } 9.661 + 9.662 + extract_vlq((void *)&(event->midi_buffer[2]), event->midi_buffer_length - 2, &string_length, &length_length); 9.663 + 9.664 + if (string_length <= 0) { 9.665 + fg_critical("smf_event_extract_text: truncated MIDI message."); 9.666 + return (NULL); 9.667 + } 9.668 + 9.669 + return (make_string((void *)(&event->midi_buffer[2] + length_length), event->midi_buffer_length - 2 - length_length, string_length)); 9.670 +} 9.671 + 9.672 +/** 9.673 + * Verify if the next chunk really is MTrk chunk, and if so, initialize some track variables and return 0. 9.674 + * Return different value otherwise. 9.675 + */ 9.676 +static int 9.677 +parse_mtrk_header(smf_track_t *track) 9.678 +{ 9.679 + struct chunk_header_struct *mtrk; 9.680 + 9.681 + /* Make sure compiler didn't do anything stupid. */ 9.682 + assert(sizeof(struct chunk_header_struct) == 8); 9.683 + assert(track->smf != NULL); 9.684 + 9.685 + mtrk = next_chunk(track->smf); 9.686 + 9.687 + if (mtrk == NULL) 9.688 + return (-1); 9.689 + 9.690 + if (!chunk_signature_matches(mtrk, "MTrk")) { 9.691 + fg_warning("SMF warning: Expected MTrk signature, got %c%c%c%c instead; ignoring this chunk.", 9.692 + mtrk->id[0], mtrk->id[1], mtrk->id[2], mtrk->id[3]); 9.693 + 9.694 + return (-2); 9.695 + } 9.696 + 9.697 + track->file_buffer = mtrk; 9.698 + track->file_buffer_length = sizeof(struct chunk_header_struct) + ntohl(mtrk->length); 9.699 + track->next_event_offset = sizeof(struct chunk_header_struct); 9.700 + 9.701 + return (0); 9.702 +} 9.703 + 9.704 +/** 9.705 + * Return 1 if event is end-of-the-track, 0 otherwise. 9.706 + */ 9.707 +static int 9.708 +event_is_end_of_track(const smf_event_t *event) 9.709 +{ 9.710 + if (event->midi_buffer[0] == 0xFF && event->midi_buffer[1] == 0x2F) 9.711 + return (1); 9.712 + 9.713 + return (0); 9.714 +} 9.715 + 9.716 +/** 9.717 + * \return Nonzero, if event is as long as it should be, from the MIDI specification point of view. 9.718 + * Does not work for SysExes - it doesn't recognize internal structure of SysEx. 9.719 + */ 9.720 +int 9.721 +smf_event_length_is_valid(const smf_event_t *event) 9.722 +{ 9.723 + assert(event); 9.724 + assert(event->midi_buffer); 9.725 + 9.726 + if (event->midi_buffer_length < 1) 9.727 + return (0); 9.728 + 9.729 + /* We cannot use expected_message_length on sysexes. */ 9.730 + if (smf_event_is_sysex(event)) 9.731 + return (1); 9.732 + 9.733 + if (event->midi_buffer_length != expected_message_length(event->midi_buffer[0], 9.734 + &(event->midi_buffer[1]), event->midi_buffer_length - 1)) { 9.735 + 9.736 + return (0); 9.737 + } 9.738 + 9.739 + return (1); 9.740 +} 9.741 + 9.742 +/** 9.743 + * \return Nonzero, if MIDI data in the event is valid, 0 otherwise. For example, 9.744 + * it checks if event length is correct. 9.745 + */ 9.746 +/* XXX: this routine requires some more work to detect more errors. */ 9.747 +int 9.748 +smf_event_is_valid(const smf_event_t *event) 9.749 +{ 9.750 + assert(event); 9.751 + assert(event->midi_buffer); 9.752 + assert(event->midi_buffer_length >= 1); 9.753 + 9.754 + if (!is_status_byte(event->midi_buffer[0])) { 9.755 + fg_critical("First byte of MIDI message is not a valid status byte."); 9.756 + 9.757 + return (0); 9.758 + } 9.759 + 9.760 + if (!smf_event_length_is_valid(event)) 9.761 + return (0); 9.762 + 9.763 + return (1); 9.764 +} 9.765 + 9.766 +/** 9.767 + * Parse events and put it on the track. 9.768 + */ 9.769 +static int 9.770 +parse_mtrk_chunk(smf_track_t *track) 9.771 +{ 9.772 + smf_event_t *event; 9.773 + 9.774 + if (parse_mtrk_header(track)) 9.775 + return (-1); 9.776 + 9.777 + for (;;) { 9.778 + event = parse_next_event(track); 9.779 + 9.780 + /* Couldn't parse an event? */ 9.781 + if (event == NULL) { 9.782 + fg_critical("Unable to parse MIDI event; truncating track."); 9.783 + if (smf_track_add_eot_delta_pulses(track, 0) != 0) { 9.784 + fg_critical("smf_track_add_eot_delta_pulses failed."); 9.785 + return (-2); 9.786 + } 9.787 + break; 9.788 + } 9.789 + 9.790 + assert(smf_event_is_valid(event)); 9.791 + 9.792 + if (event_is_end_of_track(event)) 9.793 + break; 9.794 + } 9.795 + 9.796 + track->file_buffer = NULL; 9.797 + track->file_buffer_length = 0; 9.798 + track->next_event_offset = -1; 9.799 + 9.800 + return (0); 9.801 +} 9.802 + 9.803 +/** 9.804 + * Allocate buffer of proper size and read file contents into it. Close file afterwards. 9.805 + */ 9.806 +static int 9.807 +load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *file_name) 9.808 +{ 9.809 + FILE *stream = fopen(file_name, "rb"); 9.810 + 9.811 + if (stream == NULL) { 9.812 + fg_critical("Cannot open input file: %s", strerror(errno)); 9.813 + 9.814 + return (-1); 9.815 + } 9.816 + 9.817 + if (fseek(stream, 0, SEEK_END)) { 9.818 + fg_critical("fseek(3) failed: %s", strerror(errno)); 9.819 + 9.820 + return (-2); 9.821 + } 9.822 + 9.823 + *file_buffer_length = ftell(stream); 9.824 + if (*file_buffer_length == -1) { 9.825 + fg_critical("ftell(3) failed: %s", strerror(errno)); 9.826 + 9.827 + return (-3); 9.828 + } 9.829 + 9.830 + if (fseek(stream, 0, SEEK_SET)) { 9.831 + fg_critical("fseek(3) failed: %s", strerror(errno)); 9.832 + 9.833 + return (-4); 9.834 + } 9.835 + 9.836 + *file_buffer = malloc(*file_buffer_length); 9.837 + if (*file_buffer == NULL) { 9.838 + fg_critical("malloc(3) failed: %s", strerror(errno)); 9.839 + 9.840 + return (-5); 9.841 + } 9.842 + 9.843 + if (fread(*file_buffer, 1, *file_buffer_length, stream) != *file_buffer_length) { 9.844 + fg_critical("fread(3) failed: %s", strerror(errno)); 9.845 + 9.846 + return (-6); 9.847 + } 9.848 + 9.849 + if (fclose(stream)) { 9.850 + fg_critical("fclose(3) failed: %s", strerror(errno)); 9.851 + 9.852 + return (-7); 9.853 + } 9.854 + 9.855 + return (0); 9.856 +} 9.857 + 9.858 +/** 9.859 + * Creates new SMF and fills it with data loaded from the given buffer. 9.860 + * \return SMF or NULL, if loading failed. 9.861 + */ 9.862 +smf_t * 9.863 +smf_load_from_memory(const void *buffer, const int buffer_length) 9.864 +{ 9.865 + int i; 9.866 + 9.867 + smf_t *smf = smf_new(); 9.868 + 9.869 + smf->file_buffer = (void *)buffer; 9.870 + smf->file_buffer_length = buffer_length; 9.871 + smf->next_chunk_offset = 0; 9.872 + 9.873 + if (parse_mthd_chunk(smf)) 9.874 + return (NULL); 9.875 + 9.876 + for (i = 1; i <= smf->expected_number_of_tracks; i++) { 9.877 + smf_track_t *track = smf_track_new(); 9.878 + if (track == NULL) 9.879 + return (NULL); 9.880 + 9.881 + smf_add_track(smf, track); 9.882 + 9.883 + /* Skip unparseable chunks. */ 9.884 + if (parse_mtrk_chunk(track)) { 9.885 + fg_warning("SMF warning: Cannot load track."); 9.886 + smf_track_delete(track); 9.887 + } 9.888 + 9.889 + track->file_buffer = NULL; 9.890 + track->file_buffer_length = 0; 9.891 + track->next_event_offset = -1; 9.892 + } 9.893 + 9.894 + if (smf->expected_number_of_tracks != smf->number_of_tracks) { 9.895 + fg_warning("SMF warning: MThd header declared %d tracks, but only %d found; continuing anyway.", 9.896 + smf->expected_number_of_tracks, smf->number_of_tracks); 9.897 + 9.898 + smf->expected_number_of_tracks = smf->number_of_tracks; 9.899 + } 9.900 + 9.901 + smf->file_buffer = NULL; 9.902 + smf->file_buffer_length = 0; 9.903 + smf->next_chunk_offset = -1; 9.904 + 9.905 + return (smf); 9.906 +} 9.907 + 9.908 +/** 9.909 + * Loads SMF file. 9.910 + * 9.911 + * \param file_name Path to the file. 9.912 + * \return SMF or NULL, if loading failed. 9.913 + */ 9.914 +smf_t * 9.915 +smf_load(const char *file_name) 9.916 +{ 9.917 + int file_buffer_length; 9.918 + void *file_buffer; 9.919 + smf_t *smf; 9.920 + 9.921 + if (load_file_into_buffer(&file_buffer, &file_buffer_length, file_name)) 9.922 + return (NULL); 9.923 + 9.924 + smf = smf_load_from_memory(file_buffer, file_buffer_length); 9.925 + 9.926 + memset(file_buffer, 0, file_buffer_length); 9.927 + free(file_buffer); 9.928 + 9.929 + if (smf == NULL) 9.930 + return (NULL); 9.931 + 9.932 + smf_rewind(smf); 9.933 + 9.934 + return (smf); 9.935 +} 9.936 +
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/smf_private.h Thu Jan 26 11:25:11 2012 +0200 10.3 @@ -0,0 +1,83 @@ 10.4 +/*- 10.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 10.6 + * All rights reserved. 10.7 + * 10.8 + * Redistribution and use in source and binary forms, with or without 10.9 + * modification, are permitted provided that the following conditions 10.10 + * are met: 10.11 + * 1. Redistributions of source code must retain the above copyright 10.12 + * notice, this list of conditions and the following disclaimer. 10.13 + * 2. Redistributions in binary form must reproduce the above copyright 10.14 + * notice, this list of conditions and the following disclaimer in the 10.15 + * documentation and/or other materials provided with the distribution. 10.16 + * 10.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 10.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 10.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 10.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 10.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 10.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 10.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 10.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 10.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10.28 + * 10.29 + */ 10.30 + 10.31 +#ifndef SMF_PRIVATE_H 10.32 +#define SMF_PRIVATE_H 10.33 + 10.34 +#include <stdint.h> 10.35 +#include <sys/types.h> 10.36 + 10.37 +#include "fake_glib.h" 10.38 + 10.39 +#include "config.h" 10.40 + 10.41 +#define SMF_VERSION PACKAGE_VERSION 10.42 + 10.43 +/** 10.44 + * \file 10.45 + * 10.46 + * Private header. Applications using libsmf should use smf.h. 10.47 + * 10.48 + */ 10.49 + 10.50 +#if defined(__GNUC__) 10.51 +#define ATTRIBUTE_PACKED __attribute__((__packed__)) 10.52 +#else 10.53 +#define ATTRIBUTE_PACKED 10.54 +#pragma pack(1) 10.55 +#endif 10.56 + 10.57 +/** SMF chunk header, used only by smf_load.c and smf_save.c. */ 10.58 +struct chunk_header_struct { 10.59 + char id[4]; 10.60 + uint32_t length; 10.61 +} ATTRIBUTE_PACKED; 10.62 + 10.63 +/** SMF chunk, used only by smf_load.c and smf_save.c. */ 10.64 +struct mthd_chunk_struct { 10.65 + struct chunk_header_struct mthd_header; 10.66 + uint16_t format; 10.67 + uint16_t number_of_tracks; 10.68 + uint16_t division; 10.69 +} ATTRIBUTE_PACKED; 10.70 + 10.71 +#if (!defined __GNUC__) 10.72 +#pragma pack() 10.73 +#endif 10.74 + 10.75 +void smf_track_add_event(smf_track_t *track, smf_event_t *event); 10.76 +void smf_init_tempo(smf_t *smf); 10.77 +void smf_fini_tempo(smf_t *smf); 10.78 +void smf_create_tempo_map_and_compute_seconds(smf_t *smf); 10.79 +void maybe_add_to_tempo_map(smf_event_t *event); 10.80 +void remove_last_tempo_with_pulses(smf_t *smf, int pulses); 10.81 +int smf_event_is_tempo_change_or_time_signature(const smf_event_t *event) WARN_UNUSED_RESULT; 10.82 +int smf_event_length_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT; 10.83 +int is_status_byte(const unsigned char status) WARN_UNUSED_RESULT; 10.84 + 10.85 +#endif /* SMF_PRIVATE_H */ 10.86 +
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/smf_save.c Thu Jan 26 11:25:11 2012 +0200 11.3 @@ -0,0 +1,660 @@ 11.4 +/*- 11.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 11.6 + * All rights reserved. 11.7 + * 11.8 + * Redistribution and use in source and binary forms, with or without 11.9 + * modification, are permitted provided that the following conditions 11.10 + * are met: 11.11 + * 1. Redistributions of source code must retain the above copyright 11.12 + * notice, this list of conditions and the following disclaimer. 11.13 + * 2. Redistributions in binary form must reproduce the above copyright 11.14 + * notice, this list of conditions and the following disclaimer in the 11.15 + * documentation and/or other materials provided with the distribution. 11.16 + * 11.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 11.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 11.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 11.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 11.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 11.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 11.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 11.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 11.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 11.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11.28 + * 11.29 + */ 11.30 + 11.31 +/** 11.32 + * \file 11.33 + * 11.34 + * Standard MIDI File writer. 11.35 + * 11.36 + */ 11.37 + 11.38 +/* Reference: http://www.borg.com/~jglatt/tech/midifile.htm */ 11.39 + 11.40 +#include <stdlib.h> 11.41 +#include <string.h> 11.42 +#include <assert.h> 11.43 +#include <math.h> 11.44 +#include <errno.h> 11.45 +#ifdef __MINGW32__ 11.46 +#include <windows.h> 11.47 +#else /* ! __MINGW32__ */ 11.48 +#include <arpa/inet.h> 11.49 +#endif /* ! __MINGW32__ */ 11.50 +#include "smf.h" 11.51 +#include "smf_private.h" 11.52 + 11.53 +#define MAX_VLQ_LENGTH 128 11.54 + 11.55 +/** 11.56 + * Extends (reallocates) smf->file_buffer and returns pointer to the newly added space, 11.57 + * that is, pointer to the first byte after the previous buffer end. Returns NULL in case 11.58 + * of error. 11.59 + */ 11.60 +static void * 11.61 +smf_extend(smf_t *smf, const int length) 11.62 +{ 11.63 + int i, previous_file_buffer_length = smf->file_buffer_length; 11.64 + char *previous_file_buffer = smf->file_buffer; 11.65 + 11.66 + /* XXX: Not terribly efficient. */ 11.67 + smf->file_buffer_length += length; 11.68 + smf->file_buffer = realloc(smf->file_buffer, smf->file_buffer_length); 11.69 + if (smf->file_buffer == NULL) { 11.70 + fg_critical("realloc(3) failed: %s", strerror(errno)); 11.71 + smf->file_buffer_length = 0; 11.72 + return (NULL); 11.73 + } 11.74 + 11.75 + /* Fix up pointers. XXX: omgwtf. */ 11.76 + for (i = 1; i <= smf->number_of_tracks; i++) { 11.77 + smf_track_t *track; 11.78 + track = smf_get_track_by_number(smf, i); 11.79 + if (track->file_buffer != NULL) 11.80 + track->file_buffer = (char *)track->file_buffer + ((char *)smf->file_buffer - previous_file_buffer); 11.81 + } 11.82 + 11.83 + return ((char *)smf->file_buffer + previous_file_buffer_length); 11.84 +} 11.85 + 11.86 +/** 11.87 + * Appends "buffer_length" bytes pointed to by "buffer" to the smf, reallocating storage as needed. Returns 0 11.88 + * if everything went ok, different value if there was any problem. 11.89 + */ 11.90 +static int 11.91 +smf_append(smf_t *smf, const void *buffer, const int buffer_length) 11.92 +{ 11.93 + void *dest; 11.94 + 11.95 + dest = smf_extend(smf, buffer_length); 11.96 + if (dest == NULL) { 11.97 + fg_critical("Cannot extend track buffer."); 11.98 + return (-1); 11.99 + } 11.100 + 11.101 + memcpy(dest, buffer, buffer_length); 11.102 + 11.103 + return (0); 11.104 +} 11.105 + 11.106 +/** 11.107 + * Appends MThd header to the track. Returns 0 if everything went ok, different value if not. 11.108 + */ 11.109 +static int 11.110 +write_mthd_header(smf_t *smf) 11.111 +{ 11.112 + struct mthd_chunk_struct mthd_chunk; 11.113 + 11.114 + memcpy(mthd_chunk.mthd_header.id, "MThd", 4); 11.115 + mthd_chunk.mthd_header.length = htonl(6); 11.116 + mthd_chunk.format = htons(smf->format); 11.117 + mthd_chunk.number_of_tracks = htons(smf->number_of_tracks); 11.118 + mthd_chunk.division = htons(smf->ppqn); 11.119 + 11.120 + return (smf_append(smf, &mthd_chunk, sizeof(mthd_chunk))); 11.121 +} 11.122 + 11.123 +/** 11.124 + * Extends (reallocates) track->file_buffer and returns pointer to the newly added space, 11.125 + * that is, pointer to the first byte after the previous buffer end. Returns NULL in case 11.126 + * of error. 11.127 + */ 11.128 +static void * 11.129 +track_extend(smf_track_t *track, const int length) 11.130 +{ 11.131 + void *buf; 11.132 + 11.133 + assert(track->smf); 11.134 + 11.135 + buf = smf_extend(track->smf, length); 11.136 + if (buf == NULL) 11.137 + return (NULL); 11.138 + 11.139 + track->file_buffer_length += length; 11.140 + if (track->file_buffer == NULL) 11.141 + track->file_buffer = buf; 11.142 + 11.143 + return (buf); 11.144 +} 11.145 + 11.146 +/** 11.147 + * Appends "buffer_length" bytes pointed to by "buffer" to the track, reallocating storage as needed. Returns 0 11.148 + * if everything went ok, different value if there was any problem. 11.149 + */ 11.150 +static int 11.151 +track_append(smf_track_t *track, const void *buffer, const int buffer_length) 11.152 +{ 11.153 + void *dest; 11.154 + 11.155 + dest = track_extend(track, buffer_length); 11.156 + if (dest == NULL) { 11.157 + fg_critical("Cannot extend track buffer."); 11.158 + return (-1); 11.159 + } 11.160 + 11.161 + memcpy(dest, buffer, buffer_length); 11.162 + 11.163 + return (0); 11.164 +} 11.165 + 11.166 +static int 11.167 +format_vlq(unsigned char *buf, int length, unsigned long value) 11.168 +{ 11.169 + int i; 11.170 + unsigned long buffer; 11.171 + 11.172 + /* Taken from http://www.borg.com/~jglatt/tech/midifile/vari.htm */ 11.173 + buffer = value & 0x7F; 11.174 + 11.175 + while ((value >>= 7)) { 11.176 + buffer <<= 8; 11.177 + buffer |= ((value & 0x7F) | 0x80); 11.178 + } 11.179 + 11.180 + for (i = 0;; i++) { 11.181 + buf[i] = buffer; 11.182 + 11.183 + if (buffer & 0x80) 11.184 + buffer >>= 8; 11.185 + else 11.186 + break; 11.187 + } 11.188 + 11.189 + assert(i <= length); 11.190 + 11.191 + /* + 1, because "i" is an offset, not a count. */ 11.192 + return (i + 1); 11.193 +} 11.194 + 11.195 +smf_event_t * 11.196 +smf_event_new_textual(int type, const char *text) 11.197 +{ 11.198 + int vlq_length, text_length, copied_length; 11.199 + smf_event_t *event; 11.200 + 11.201 + assert(type >= 1 && type <= 9); 11.202 + 11.203 + text_length = strlen(text); 11.204 + 11.205 + event = smf_event_new(); 11.206 + if (event == NULL) 11.207 + return (NULL); 11.208 + 11.209 + /* "2 +" is for leading 0xFF 0xtype. */ 11.210 + event->midi_buffer_length = 2 + text_length + MAX_VLQ_LENGTH; 11.211 + event->midi_buffer = malloc(event->midi_buffer_length); 11.212 + if (event->midi_buffer == NULL) { 11.213 + fg_critical("Cannot allocate MIDI buffer structure: %s", strerror(errno)); 11.214 + smf_event_delete(event); 11.215 + 11.216 + return (NULL); 11.217 + } 11.218 + 11.219 + event->midi_buffer[0] = 0xFF; 11.220 + event->midi_buffer[1] = type; 11.221 + 11.222 + vlq_length = format_vlq(event->midi_buffer + 2, MAX_VLQ_LENGTH - 2, text_length); 11.223 + copied_length = snprintf((char *)event->midi_buffer + vlq_length + 2, event->midi_buffer_length - vlq_length - 2, "%s", text); 11.224 + 11.225 + assert(copied_length == text_length); 11.226 + 11.227 + event->midi_buffer_length = 2 + vlq_length + text_length; 11.228 + 11.229 + return event; 11.230 +} 11.231 + 11.232 +/** 11.233 + * Appends value, expressed as Variable Length Quantity, to event->track. 11.234 + */ 11.235 +static int 11.236 +write_vlq(smf_event_t *event, unsigned long value) 11.237 +{ 11.238 + unsigned char buf[MAX_VLQ_LENGTH]; 11.239 + int vlq_length; 11.240 + 11.241 + vlq_length = format_vlq(buf, MAX_VLQ_LENGTH, value); 11.242 + 11.243 + return (track_append(event->track, buf, vlq_length)); 11.244 +} 11.245 + 11.246 +/** 11.247 + * Appends event time as Variable Length Quantity. Returns 0 if everything went ok, 11.248 + * different value in case of error. 11.249 + */ 11.250 +static int 11.251 +write_event_time(smf_event_t *event) 11.252 +{ 11.253 + assert(event->delta_time_pulses >= 0); 11.254 + 11.255 + return (write_vlq(event, event->delta_time_pulses)); 11.256 +} 11.257 + 11.258 +static int 11.259 +write_sysex_contents(smf_event_t *event) 11.260 +{ 11.261 + int ret; 11.262 + unsigned char sysex_status = 0xF0; 11.263 + 11.264 + assert(smf_event_is_sysex(event)); 11.265 + 11.266 + ret = track_append(event->track, &sysex_status, 1); 11.267 + if (ret) 11.268 + return (ret); 11.269 + 11.270 + /* -1, because length does not include status byte. */ 11.271 + ret = write_vlq(event, event->midi_buffer_length - 1); 11.272 + if (ret) 11.273 + return (ret); 11.274 + 11.275 + ret = track_append(event->track, event->midi_buffer + 1, event->midi_buffer_length - 1); 11.276 + if (ret) 11.277 + return (ret); 11.278 + 11.279 + return (0); 11.280 +} 11.281 + 11.282 +/** 11.283 + * Appends contents of event->midi_buffer wrapped into 0xF7 MIDI event. 11.284 + */ 11.285 +static int 11.286 +write_escaped_event_contents(smf_event_t *event) 11.287 +{ 11.288 + int ret; 11.289 + unsigned char escape_status = 0xF7; 11.290 + 11.291 + if (smf_event_is_sysex(event)) 11.292 + return (write_sysex_contents(event)); 11.293 + 11.294 + ret = track_append(event->track, &escape_status, 1); 11.295 + if (ret) 11.296 + return (ret); 11.297 + 11.298 + ret = write_vlq(event, event->midi_buffer_length); 11.299 + if (ret) 11.300 + return (ret); 11.301 + 11.302 + ret = track_append(event->track, event->midi_buffer, event->midi_buffer_length); 11.303 + if (ret) 11.304 + return (ret); 11.305 + 11.306 + return (0); 11.307 +} 11.308 + 11.309 +/** 11.310 + * Appends contents of event->midi_buffer. Returns 0 if everything went 0, 11.311 + * different value in case of error. 11.312 + */ 11.313 +static int 11.314 +write_event_contents(smf_event_t *event) 11.315 +{ 11.316 + if (smf_event_is_system_realtime(event) || smf_event_is_system_common(event)) 11.317 + return (write_escaped_event_contents(event)); 11.318 + 11.319 + return (track_append(event->track, event->midi_buffer, event->midi_buffer_length)); 11.320 +} 11.321 + 11.322 +/** 11.323 + * Writes out an event. 11.324 + */ 11.325 +static int 11.326 +write_event(smf_event_t *event) 11.327 +{ 11.328 + int ret; 11.329 + 11.330 + ret = write_event_time(event); 11.331 + if (ret) 11.332 + return (ret); 11.333 + 11.334 + ret = write_event_contents(event); 11.335 + if (ret) 11.336 + return (ret); 11.337 + 11.338 + return (0); 11.339 +} 11.340 + 11.341 +/** 11.342 + * Writes out MTrk header, except of MTrk chunk length, which is written by write_mtrk_length(). 11.343 + */ 11.344 +static int 11.345 +write_mtrk_header(smf_track_t *track) 11.346 +{ 11.347 + struct chunk_header_struct mtrk_header; 11.348 + 11.349 + memcpy(mtrk_header.id, "MTrk", 4); 11.350 + 11.351 + return (track_append(track, &mtrk_header, sizeof(mtrk_header))); 11.352 +} 11.353 + 11.354 +/** 11.355 + * Updates MTrk chunk length of a given track. 11.356 + */ 11.357 +static int 11.358 +write_mtrk_length(smf_track_t *track) 11.359 +{ 11.360 + struct chunk_header_struct *mtrk_header; 11.361 + 11.362 + assert(track->file_buffer != NULL); 11.363 + assert(track->file_buffer_length >= 6); 11.364 + 11.365 + mtrk_header = (struct chunk_header_struct *)track->file_buffer; 11.366 + mtrk_header->length = htonl(track->file_buffer_length - sizeof(struct chunk_header_struct)); 11.367 + 11.368 + return (0); 11.369 +} 11.370 + 11.371 +/** 11.372 + * Writes out the track. 11.373 + */ 11.374 +static int 11.375 +write_track(smf_track_t *track) 11.376 +{ 11.377 + int ret; 11.378 + smf_event_t *event; 11.379 + 11.380 + ret = write_mtrk_header(track); 11.381 + if (ret) 11.382 + return (ret); 11.383 + 11.384 + while ((event = smf_track_get_next_event(track)) != NULL) { 11.385 + ret = write_event(event); 11.386 + if (ret) 11.387 + return (ret); 11.388 + } 11.389 + 11.390 + ret = write_mtrk_length(track); 11.391 + if (ret) 11.392 + return (ret); 11.393 + 11.394 + return (0); 11.395 +} 11.396 + 11.397 +/** 11.398 + * Takes smf->file_buffer and saves it to the file. 11.399 + */ 11.400 +static int 11.401 +write_file(smf_t *smf, const char *file_name) 11.402 +{ 11.403 + FILE *stream; 11.404 + 11.405 + stream = fopen(file_name, "wb+"); 11.406 + if (stream == NULL) { 11.407 + fg_critical("Cannot open input file: %s", strerror(errno)); 11.408 + 11.409 + return (-1); 11.410 + } 11.411 + 11.412 + if (fwrite(smf->file_buffer, 1, smf->file_buffer_length, stream) != smf->file_buffer_length) { 11.413 + fg_critical("fwrite(3) failed: %s", strerror(errno)); 11.414 + 11.415 + return (-2); 11.416 + } 11.417 + 11.418 + if (fclose(stream)) { 11.419 + fg_critical("fclose(3) failed: %s", strerror(errno)); 11.420 + 11.421 + return (-3); 11.422 + } 11.423 + 11.424 + return (0); 11.425 +} 11.426 + 11.427 +static void 11.428 +free_buffer(smf_t *smf) 11.429 +{ 11.430 + int i; 11.431 + smf_track_t *track; 11.432 + 11.433 + /* Clear the pointers. */ 11.434 + memset(smf->file_buffer, 0, smf->file_buffer_length); 11.435 + free(smf->file_buffer); 11.436 + smf->file_buffer = NULL; 11.437 + smf->file_buffer_length = 0; 11.438 + 11.439 + for (i = 1; i <= smf->number_of_tracks; i++) { 11.440 + track = smf_get_track_by_number(smf, i); 11.441 + assert(track); 11.442 + track->file_buffer = NULL; 11.443 + track->file_buffer_length = 0; 11.444 + } 11.445 +} 11.446 + 11.447 +#ifndef NDEBUG 11.448 + 11.449 +/** 11.450 + * \return Nonzero, if all pointers supposed to be NULL are NULL. Triggers assertion if not. 11.451 + */ 11.452 +static int 11.453 +pointers_are_clear(smf_t *smf) 11.454 +{ 11.455 + int i; 11.456 + 11.457 + smf_track_t *track; 11.458 + assert(smf->file_buffer == NULL); 11.459 + assert(smf->file_buffer_length == 0); 11.460 + 11.461 + for (i = 1; i <= smf->number_of_tracks; i++) { 11.462 + track = smf_get_track_by_number(smf, i); 11.463 + 11.464 + assert(track != NULL); 11.465 + assert(track->file_buffer == NULL); 11.466 + assert(track->file_buffer_length == 0); 11.467 + } 11.468 + 11.469 + return (1); 11.470 +} 11.471 + 11.472 +#endif /* !NDEBUG */ 11.473 + 11.474 +/** 11.475 + * \return Nonzero, if event is End Of Track metaevent. 11.476 + */ 11.477 +int 11.478 +smf_event_is_eot(const smf_event_t *event) 11.479 +{ 11.480 + if (event->midi_buffer_length != 3) 11.481 + return (0); 11.482 + 11.483 + if (event->midi_buffer[0] != 0xFF || event->midi_buffer[1] != 0x2F || event->midi_buffer[2] != 0x00) 11.484 + return (0); 11.485 + 11.486 + return (1); 11.487 +} 11.488 + 11.489 +/** 11.490 + * Check if SMF is valid and add missing EOT events. 11.491 + * 11.492 + * \return 0, if SMF is valid. 11.493 + */ 11.494 +static int 11.495 +smf_validate(smf_t *smf) 11.496 +{ 11.497 + int trackno, eventno, eot_found; 11.498 + smf_track_t *track; 11.499 + smf_event_t *event; 11.500 + 11.501 + if (smf->format < 0 || smf->format > 2) { 11.502 + fg_critical("SMF error: smf->format is less than zero of greater than two."); 11.503 + return (-1); 11.504 + } 11.505 + 11.506 + if (smf->number_of_tracks < 1) { 11.507 + fg_critical("SMF error: number of tracks is less than one."); 11.508 + return (-2); 11.509 + } 11.510 + 11.511 + if (smf->format == 0 && smf->number_of_tracks > 1) { 11.512 + fg_critical("SMF error: format is 0, but number of tracks is more than one."); 11.513 + return (-3); 11.514 + } 11.515 + 11.516 + if (smf->ppqn <= 0) { 11.517 + fg_critical("SMF error: PPQN has to be > 0."); 11.518 + return (-4); 11.519 + } 11.520 + 11.521 + for (trackno = 1; trackno <= smf->number_of_tracks; trackno++) { 11.522 + track = smf_get_track_by_number(smf, trackno); 11.523 + assert(track); 11.524 + 11.525 + eot_found = 0; 11.526 + 11.527 + for (eventno = 1; eventno <= track->number_of_events; eventno++) { 11.528 + event = smf_track_get_event_by_number(track, eventno); 11.529 + assert(event); 11.530 + 11.531 + if (!smf_event_is_valid(event)) { 11.532 + fg_critical("Event #%d on track #%d is invalid.", eventno, trackno); 11.533 + return (-5); 11.534 + } 11.535 + 11.536 + if (smf_event_is_eot(event)) { 11.537 + if (eot_found) { 11.538 + fg_critical("Duplicate End Of Track event on track #%d.", trackno); 11.539 + return (-6); 11.540 + } 11.541 + 11.542 + eot_found = 1; 11.543 + } 11.544 + } 11.545 + 11.546 + if (!eot_found) { 11.547 + if (smf_track_add_eot_delta_pulses(track, 0)) { 11.548 + fg_critical("smf_track_add_eot_delta_pulses failed."); 11.549 + return (-6); 11.550 + } 11.551 + } 11.552 + 11.553 + } 11.554 + 11.555 + return (0); 11.556 +} 11.557 + 11.558 +#ifndef NDEBUG 11.559 + 11.560 +static void 11.561 +assert_smf_event_is_identical(const smf_event_t *a, const smf_event_t *b) 11.562 +{ 11.563 + assert(a->event_number == b->event_number); 11.564 + assert(a->delta_time_pulses == b->delta_time_pulses); 11.565 + assert(abs(a->time_pulses - b->time_pulses) <= 2); 11.566 + assert(fabs(a->time_seconds - b->time_seconds) <= 0.01); 11.567 + assert(a->track_number == b->track_number); 11.568 + assert(a->midi_buffer_length == b->midi_buffer_length); 11.569 + assert(memcmp(a->midi_buffer, b->midi_buffer, a->midi_buffer_length) == 0); 11.570 +} 11.571 + 11.572 +static void 11.573 +assert_smf_track_is_identical(const smf_track_t *a, const smf_track_t *b) 11.574 +{ 11.575 + int i; 11.576 + 11.577 + assert(a->track_number == b->track_number); 11.578 + assert(a->number_of_events == b->number_of_events); 11.579 + 11.580 + for (i = 1; i <= a->number_of_events; i++) 11.581 + assert_smf_event_is_identical(smf_track_get_event_by_number(a, i), smf_track_get_event_by_number(b, i)); 11.582 +} 11.583 + 11.584 +static void 11.585 +assert_smf_is_identical(const smf_t *a, const smf_t *b) 11.586 +{ 11.587 + int i; 11.588 + 11.589 + assert(a->format == b->format); 11.590 + assert(a->ppqn == b->ppqn); 11.591 + assert(a->frames_per_second == b->frames_per_second); 11.592 + assert(a->resolution == b->resolution); 11.593 + assert(a->number_of_tracks == b->number_of_tracks); 11.594 + 11.595 + for (i = 1; i <= a->number_of_tracks; i++) 11.596 + assert_smf_track_is_identical(smf_get_track_by_number(a, i), smf_get_track_by_number(b, i)); 11.597 + 11.598 + /* We do not need to compare tempos explicitly, as tempo is always computed from track contents. */ 11.599 +} 11.600 + 11.601 +static void 11.602 +assert_smf_saved_correctly(const smf_t *smf, const char *file_name) 11.603 +{ 11.604 + smf_t *saved; 11.605 + 11.606 + saved = smf_load(file_name); 11.607 + assert(saved != NULL); 11.608 + 11.609 + assert_smf_is_identical(smf, saved); 11.610 + 11.611 + smf_delete(saved); 11.612 +} 11.613 + 11.614 +#endif /* !NDEBUG */ 11.615 + 11.616 +/** 11.617 + * Writes the contents of SMF to the file given. 11.618 + * \param smf SMF. 11.619 + * \param file_name Path to the file. 11.620 + * \return 0, if saving was successfull. 11.621 + */ 11.622 +int 11.623 +smf_save(smf_t *smf, const char *file_name) 11.624 +{ 11.625 + int i, error; 11.626 + smf_track_t *track; 11.627 + 11.628 + smf_rewind(smf); 11.629 + 11.630 + assert(pointers_are_clear(smf)); 11.631 + 11.632 + if (smf_validate(smf)) 11.633 + return (-1); 11.634 + 11.635 + if (write_mthd_header(smf)) 11.636 + return (-2); 11.637 + 11.638 + for (i = 1; i <= smf->number_of_tracks; i++) { 11.639 + track = smf_get_track_by_number(smf, i); 11.640 + 11.641 + assert(track != NULL); 11.642 + 11.643 + error = write_track(track); 11.644 + if (error) { 11.645 + free_buffer(smf); 11.646 + return (error); 11.647 + } 11.648 + } 11.649 + 11.650 + error = write_file(smf, file_name); 11.651 + 11.652 + free_buffer(smf); 11.653 + 11.654 + if (error) 11.655 + return (error); 11.656 + 11.657 +#ifndef NDEBUG 11.658 + assert_smf_saved_correctly(smf, file_name); 11.659 +#endif 11.660 + 11.661 + return (0); 11.662 +} 11.663 +
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/smf_tempo.c Thu Jan 26 11:25:11 2012 +0200 12.3 @@ -0,0 +1,448 @@ 12.4 +/*- 12.5 + * Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 12.6 + * All rights reserved. 12.7 + * 12.8 + * Redistribution and use in source and binary forms, with or without 12.9 + * modification, are permitted provided that the following conditions 12.10 + * are met: 12.11 + * 1. Redistributions of source code must retain the above copyright 12.12 + * notice, this list of conditions and the following disclaimer. 12.13 + * 2. Redistributions in binary form must reproduce the above copyright 12.14 + * notice, this list of conditions and the following disclaimer in the 12.15 + * documentation and/or other materials provided with the distribution. 12.16 + * 12.17 + * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE 12.18 + * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 12.19 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 12.20 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 12.21 + * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 12.22 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 12.23 + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 12.24 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 12.25 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 12.26 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 12.27 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12.28 + * 12.29 + */ 12.30 + 12.31 +/** 12.32 + * \file 12.33 + * 12.34 + * Tempo map related part. 12.35 + * 12.36 + */ 12.37 + 12.38 +#include <stdlib.h> 12.39 +#include <assert.h> 12.40 +#include <math.h> 12.41 +#include <string.h> 12.42 +#include "smf.h" 12.43 +#include "smf_private.h" 12.44 + 12.45 +static double seconds_from_pulses(const smf_t *smf, int pulses); 12.46 + 12.47 +/** 12.48 + * If there is tempo starting at "pulses" already, return it. Otherwise, 12.49 + * allocate new one, fill it with values from previous one (or default ones, 12.50 + * if there is no previous one) and attach it to "smf". 12.51 + */ 12.52 +static smf_tempo_t * 12.53 +new_tempo(smf_t *smf, int pulses) 12.54 +{ 12.55 + smf_tempo_t *tempo, *previous_tempo = NULL; 12.56 + 12.57 + if (smf->tempo_array->len > 0) { 12.58 + previous_tempo = smf_get_last_tempo(smf); 12.59 + 12.60 + /* If previous tempo starts at the same time as new one, reuse it, updating in place. */ 12.61 + if (previous_tempo->time_pulses == pulses) 12.62 + return (previous_tempo); 12.63 + } 12.64 + 12.65 + tempo = malloc(sizeof(smf_tempo_t)); 12.66 + if (tempo == NULL) { 12.67 + fg_critical("Cannot allocate smf_tempo_t."); 12.68 + return (NULL); 12.69 + } 12.70 + 12.71 + tempo->time_pulses = pulses; 12.72 + 12.73 + if (previous_tempo != NULL) { 12.74 + tempo->microseconds_per_quarter_note = previous_tempo->microseconds_per_quarter_note; 12.75 + tempo->numerator = previous_tempo->numerator; 12.76 + tempo->denominator = previous_tempo->denominator; 12.77 + tempo->clocks_per_click = previous_tempo->clocks_per_click; 12.78 + tempo->notes_per_note = previous_tempo->notes_per_note; 12.79 + } else { 12.80 + tempo->microseconds_per_quarter_note = 500000; /* Initial tempo is 120 BPM. */ 12.81 + tempo->numerator = 4; 12.82 + tempo->denominator = 4; 12.83 + tempo->clocks_per_click = -1; 12.84 + tempo->notes_per_note = -1; 12.85 + } 12.86 + 12.87 + fg_ptr_array_add(smf->tempo_array, tempo); 12.88 + 12.89 + if (pulses == 0) 12.90 + tempo->time_seconds = 0.0; 12.91 + else 12.92 + tempo->time_seconds = seconds_from_pulses(smf, pulses); 12.93 + 12.94 + return (tempo); 12.95 +} 12.96 + 12.97 +static int 12.98 +add_tempo(smf_t *smf, int pulses, int tempo) 12.99 +{ 12.100 + smf_tempo_t *smf_tempo = new_tempo(smf, pulses); 12.101 + if (smf_tempo == NULL) 12.102 + return (-1); 12.103 + 12.104 + smf_tempo->microseconds_per_quarter_note = tempo; 12.105 + 12.106 + return (0); 12.107 +} 12.108 + 12.109 +static int 12.110 +add_time_signature(smf_t *smf, int pulses, int numerator, int denominator, int clocks_per_click, int notes_per_note) 12.111 +{ 12.112 + smf_tempo_t *smf_tempo = new_tempo(smf, pulses); 12.113 + if (smf_tempo == NULL) 12.114 + return (-1); 12.115 + 12.116 + smf_tempo->numerator = numerator; 12.117 + smf_tempo->denominator = denominator; 12.118 + smf_tempo->clocks_per_click = clocks_per_click; 12.119 + smf_tempo->notes_per_note = notes_per_note; 12.120 + 12.121 + return (0); 12.122 +} 12.123 + 12.124 +/** 12.125 + * \internal 12.126 + */ 12.127 +void 12.128 +maybe_add_to_tempo_map(smf_event_t *event) 12.129 +{ 12.130 + if (!smf_event_is_metadata(event)) 12.131 + return; 12.132 + 12.133 + assert(event->track != NULL); 12.134 + assert(event->track->smf != NULL); 12.135 + assert(event->midi_buffer_length >= 1); 12.136 + 12.137 + /* Tempo Change? */ 12.138 + if (event->midi_buffer[1] == 0x51) { 12.139 + int new_tempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5]; 12.140 + if (new_tempo <= 0) { 12.141 + fg_critical("Ignoring invalid tempo change."); 12.142 + return; 12.143 + } 12.144 + 12.145 + add_tempo(event->track->smf, event->time_pulses, new_tempo); 12.146 + } 12.147 + 12.148 + /* Time Signature? */ 12.149 + if (event->midi_buffer[1] == 0x58) { 12.150 + int numerator, denominator, clocks_per_click, notes_per_note; 12.151 + 12.152 + if (event->midi_buffer_length < 7) { 12.153 + fg_critical("Time Signature event seems truncated."); 12.154 + return; 12.155 + } 12.156 + 12.157 + numerator = event->midi_buffer[3]; 12.158 + denominator = (int)pow(2, event->midi_buffer[4]); 12.159 + clocks_per_click = event->midi_buffer[5]; 12.160 + notes_per_note = event->midi_buffer[6]; 12.161 + 12.162 + add_time_signature(event->track->smf, event->time_pulses, numerator, denominator, clocks_per_click, notes_per_note); 12.163 + } 12.164 + 12.165 + return; 12.166 +} 12.167 + 12.168 +/** 12.169 + * \internal 12.170 + * 12.171 + * This is an internal function, called from smf_track_remove_event when tempo-related 12.172 + * event being removed does not require recreation of tempo map, i.e. there are no events 12.173 + * after that one. 12.174 + */ 12.175 +void 12.176 +remove_last_tempo_with_pulses(smf_t *smf, int pulses) 12.177 +{ 12.178 + smf_tempo_t *tempo; 12.179 + 12.180 + /* XXX: This is a partial workaround for the following problem: we have two tempo-related 12.181 + events, A and B, that occur at the same time. We remove B, then try to remove 12.182 + A. However, both tempo changes got coalesced in new_tempo(), so it is impossible 12.183 + to remove B. */ 12.184 + if (smf->tempo_array->len == 0) 12.185 + return; 12.186 + 12.187 + tempo = smf_get_last_tempo(smf); 12.188 + 12.189 + /* Workaround part two. */ 12.190 + if (tempo->time_pulses != pulses) 12.191 + return; 12.192 + 12.193 + memset(tempo, 0, sizeof(smf_tempo_t)); 12.194 + free(tempo); 12.195 + 12.196 + fg_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1); 12.197 +} 12.198 + 12.199 +static double 12.200 +seconds_from_pulses(const smf_t *smf, int pulses) 12.201 +{ 12.202 + double seconds; 12.203 + smf_tempo_t *tempo; 12.204 + 12.205 + tempo = smf_get_tempo_by_pulses(smf, pulses); 12.206 + assert(tempo); 12.207 + assert(tempo->time_pulses <= pulses); 12.208 + 12.209 + seconds = tempo->time_seconds + (double)(pulses - tempo->time_pulses) * 12.210 + (tempo->microseconds_per_quarter_note / ((double)smf->ppqn * 1000000.0)); 12.211 + 12.212 + return (seconds); 12.213 +} 12.214 + 12.215 +static int 12.216 +pulses_from_seconds(const smf_t *smf, double seconds) 12.217 +{ 12.218 + int pulses = 0; 12.219 + smf_tempo_t *tempo; 12.220 + 12.221 + tempo = smf_get_tempo_by_seconds(smf, seconds); 12.222 + assert(tempo); 12.223 + assert(tempo->time_seconds <= seconds); 12.224 + 12.225 + pulses = tempo->time_pulses + (seconds - tempo->time_seconds) * 12.226 + ((double)smf->ppqn * 1000000.0 / tempo->microseconds_per_quarter_note); 12.227 + 12.228 + return (pulses); 12.229 +} 12.230 + 12.231 +/** 12.232 + * \internal 12.233 + * 12.234 + * Computes value of event->time_seconds for all events in smf. 12.235 + * Warning: rewinds the smf. 12.236 + */ 12.237 +void 12.238 +smf_create_tempo_map_and_compute_seconds(smf_t *smf) 12.239 +{ 12.240 + smf_event_t *event; 12.241 + 12.242 + smf_rewind(smf); 12.243 + smf_init_tempo(smf); 12.244 + 12.245 + for (;;) { 12.246 + event = smf_get_next_event(smf); 12.247 + 12.248 + if (event == NULL) 12.249 + return; 12.250 + 12.251 + maybe_add_to_tempo_map(event); 12.252 + 12.253 + event->time_seconds = seconds_from_pulses(smf, event->time_pulses); 12.254 + } 12.255 + 12.256 + /* Not reached. */ 12.257 +} 12.258 + 12.259 +smf_tempo_t * 12.260 +smf_get_tempo_by_number(const smf_t *smf, int number) 12.261 +{ 12.262 + assert(number >= 0); 12.263 + 12.264 + if (number >= smf->tempo_array->len) 12.265 + return (NULL); 12.266 + 12.267 + return (fg_ptr_array_index(smf->tempo_array, number)); 12.268 +} 12.269 + 12.270 +/** 12.271 + * Return last tempo (i.e. tempo with greatest time_pulses) that happens before "pulses". 12.272 + */ 12.273 +smf_tempo_t * 12.274 +smf_get_tempo_by_pulses(const smf_t *smf, int pulses) 12.275 +{ 12.276 + int i; 12.277 + smf_tempo_t *tempo; 12.278 + 12.279 + assert(pulses >= 0); 12.280 + 12.281 + if (pulses == 0) 12.282 + return (smf_get_tempo_by_number(smf, 0)); 12.283 + 12.284 + assert(smf->tempo_array != NULL); 12.285 + 12.286 + for (i = smf->tempo_array->len - 1; i >= 0; i--) { 12.287 + tempo = smf_get_tempo_by_number(smf, i); 12.288 + 12.289 + assert(tempo); 12.290 + if (tempo->time_pulses < pulses) 12.291 + return (tempo); 12.292 + } 12.293 + 12.294 + return (NULL); 12.295 +} 12.296 + 12.297 +/** 12.298 + * Return last tempo (i.e. tempo with greatest time_seconds) that happens before "seconds". 12.299 + */ 12.300 +smf_tempo_t * 12.301 +smf_get_tempo_by_seconds(const smf_t *smf, double seconds) 12.302 +{ 12.303 + int i; 12.304 + smf_tempo_t *tempo; 12.305 + 12.306 + assert(seconds >= 0.0); 12.307 + 12.308 + if (seconds == 0.0) 12.309 + return (smf_get_tempo_by_number(smf, 0)); 12.310 + 12.311 + assert(smf->tempo_array != NULL); 12.312 + 12.313 + for (i = smf->tempo_array->len - 1; i >= 0; i--) { 12.314 + tempo = smf_get_tempo_by_number(smf, i); 12.315 + 12.316 + assert(tempo); 12.317 + if (tempo->time_seconds < seconds) 12.318 + return (tempo); 12.319 + } 12.320 + 12.321 + return (NULL); 12.322 +} 12.323 + 12.324 + 12.325 +/** 12.326 + * Return last tempo. 12.327 + */ 12.328 +smf_tempo_t * 12.329 +smf_get_last_tempo(const smf_t *smf) 12.330 +{ 12.331 + smf_tempo_t *tempo; 12.332 + 12.333 + tempo = smf_get_tempo_by_number(smf, smf->tempo_array->len - 1); 12.334 + assert(tempo); 12.335 + 12.336 + return (tempo); 12.337 +} 12.338 + 12.339 +/** 12.340 + * \internal 12.341 + * 12.342 + * Remove all smf_tempo_t structures from SMF. 12.343 + */ 12.344 +void 12.345 +smf_fini_tempo(smf_t *smf) 12.346 +{ 12.347 + smf_tempo_t *tempo; 12.348 + 12.349 + while (smf->tempo_array->len > 0) { 12.350 + tempo = fg_ptr_array_index(smf->tempo_array, smf->tempo_array->len - 1); 12.351 + assert(tempo); 12.352 + 12.353 + memset(tempo, 0, sizeof(smf_tempo_t)); 12.354 + free(tempo); 12.355 + 12.356 + fg_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1); 12.357 + } 12.358 + 12.359 + assert(smf->tempo_array->len == 0); 12.360 +} 12.361 + 12.362 +/** 12.363 + * \internal 12.364 + * 12.365 + * Remove any existing tempos and add default one. 12.366 + * 12.367 + * \bug This will abort (by calling fg_error) if new_tempo() (memory allocation there) fails. 12.368 + */ 12.369 +void 12.370 +smf_init_tempo(smf_t *smf) 12.371 +{ 12.372 + smf_tempo_t *tempo; 12.373 + 12.374 + smf_fini_tempo(smf); 12.375 + 12.376 + tempo = new_tempo(smf, 0); 12.377 + if (tempo == NULL) 12.378 + fg_error("tempo_init failed, sorry."); 12.379 +} 12.380 + 12.381 +/** 12.382 + * Returns ->time_pulses of last event on the given track, or 0, if track is empty. 12.383 + */ 12.384 +static int 12.385 +last_event_pulses(const smf_track_t *track) 12.386 +{ 12.387 + /* Get time of last event on this track. */ 12.388 + if (track->number_of_events > 0) { 12.389 + smf_event_t *previous_event = smf_track_get_last_event(track); 12.390 + assert(previous_event); 12.391 + assert(previous_event->time_pulses >= 0); 12.392 + 12.393 + return (previous_event->time_pulses); 12.394 + } 12.395 + 12.396 + return (0); 12.397 +} 12.398 + 12.399 +/** 12.400 + * Adds event to the track at the time "pulses" clocks from the previous event in this track. 12.401 + * The remaining two time fields will be computed automatically based on the third argument 12.402 + * and current tempo map. Note that ->delta_pulses is computed by smf.c:smf_track_add_event, 12.403 + * not here. 12.404 + */ 12.405 +void 12.406 +smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int delta) 12.407 +{ 12.408 + assert(delta >= 0); 12.409 + assert(event->time_pulses == -1); 12.410 + assert(event->time_seconds == -1.0); 12.411 + assert(track->smf != NULL); 12.412 + 12.413 + smf_track_add_event_pulses(track, event, last_event_pulses(track) + delta); 12.414 +} 12.415 + 12.416 +/** 12.417 + * Adds event to the track at the time "pulses" clocks from the start of song. 12.418 + * The remaining two time fields will be computed automatically based on the third argument 12.419 + * and current tempo map. 12.420 + */ 12.421 +void 12.422 +smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses) 12.423 +{ 12.424 + assert(pulses >= 0); 12.425 + assert(event->time_pulses == -1); 12.426 + assert(event->time_seconds == -1.0); 12.427 + assert(track->smf != NULL); 12.428 + 12.429 + event->time_pulses = pulses; 12.430 + event->time_seconds = seconds_from_pulses(track->smf, pulses); 12.431 + smf_track_add_event(track, event); 12.432 +} 12.433 + 12.434 +/** 12.435 + * Adds event to the track at the time "seconds" seconds from the start of song. 12.436 + * The remaining two time fields will be computed automatically based on the third argument 12.437 + * and current tempo map. 12.438 + */ 12.439 +void 12.440 +smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds) 12.441 +{ 12.442 + assert(seconds >= 0.0); 12.443 + assert(event->time_pulses == -1); 12.444 + assert(event->time_seconds == -1.0); 12.445 + assert(track->smf != NULL); 12.446 + 12.447 + event->time_seconds = seconds; 12.448 + event->time_pulses = pulses_from_seconds(track->smf, seconds); 12.449 + smf_track_add_event(track, event); 12.450 +} 12.451 +