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 +