summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_midi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/fluidsynth/src/fluid_midi.c')
-rw-r--r--libs/fluidsynth/src/fluid_midi.c1457
1 files changed, 973 insertions, 484 deletions
diff --git a/libs/fluidsynth/src/fluid_midi.c b/libs/fluidsynth/src/fluid_midi.c
index fc58d839ef..bdf72dd681 100644
--- a/libs/fluidsynth/src/fluid_midi.c
+++ b/libs/fluidsynth/src/fluid_midi.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -25,15 +25,56 @@
static int fluid_midi_event_length(unsigned char event);
+static int fluid_isasciistring(char *s);
+static long fluid_getlength(unsigned char *s);
+
/* Read the entire contents of a file into memory, allocating enough memory
* for the file, and returning the length and the buffer.
* Note: This rewinds the file to the start before reading.
* Returns NULL if there was an error reading or allocating memory.
*/
-static char* fluid_file_read_full(fluid_file fp, size_t* length);
+static char *fluid_file_read_full(fluid_file fp, size_t *length);
+static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic);
#define READ_FULL_INITIAL_BUFLEN 1024
+static fluid_track_t *new_fluid_track(int num);
+static void delete_fluid_track(fluid_track_t *track);
+static int fluid_track_set_name(fluid_track_t *track, char *name);
+static int fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt);
+static fluid_midi_event_t *fluid_track_next_event(fluid_track_t *track);
+static int fluid_track_get_duration(fluid_track_t *track);
+static int fluid_track_reset(fluid_track_t *track);
+
+static int fluid_track_send_events(fluid_track_t *track,
+ fluid_synth_t *synth,
+ fluid_player_t *player,
+ unsigned int ticks);
+
+
+static int fluid_player_add_track(fluid_player_t *player, fluid_track_t *track);
+static int fluid_player_callback(void *data, unsigned int msec);
+static int fluid_player_reset(fluid_player_t *player);
+static int fluid_player_load(fluid_player_t *player, fluid_playlist_item *item);
+static void fluid_player_advancefile(fluid_player_t *player);
+static void fluid_player_playlist_load(fluid_player_t *player, unsigned int msec);
+
+static fluid_midi_file *new_fluid_midi_file(const char *buffer, size_t length);
+static void delete_fluid_midi_file(fluid_midi_file *mf);
+static int fluid_midi_file_read_mthd(fluid_midi_file *midifile);
+static int fluid_midi_file_load_tracks(fluid_midi_file *midifile, fluid_player_t *player);
+static int fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num);
+static int fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track);
+static int fluid_midi_file_read_varlen(fluid_midi_file *mf);
+static int fluid_midi_file_getc(fluid_midi_file *mf);
+static int fluid_midi_file_push(fluid_midi_file *mf, int c);
+static int fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len);
+static int fluid_midi_file_skip(fluid_midi_file *mf, int len);
+static int fluid_midi_file_eof(fluid_midi_file *mf);
+static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
+static int fluid_midi_file_eot(fluid_midi_file *mf);
+static int fluid_midi_file_get_division(fluid_midi_file *midifile);
+
#if 0 // disable file I/O with Ardour
/***************************************************************
*
@@ -49,15 +90,18 @@ static char* fluid_file_read_full(fluid_file fp, size_t* length);
* @return New MIDI file handle or NULL on error.
*/
fluid_midi_file *
-new_fluid_midi_file(const char* buffer, size_t length)
+new_fluid_midi_file(const char *buffer, size_t length)
{
fluid_midi_file *mf;
mf = FLUID_NEW(fluid_midi_file);
- if (mf == NULL) {
+
+ if(mf == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
FLUID_MEMSET(mf, 0, sizeof(fluid_midi_file));
mf->c = -1;
@@ -68,45 +112,58 @@ new_fluid_midi_file(const char* buffer, size_t length)
mf->buf_pos = 0;
mf->eof = FALSE;
- if (fluid_midi_file_read_mthd(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_mthd(mf) != FLUID_OK)
+ {
FLUID_FREE(mf);
return NULL;
}
+
return mf;
}
-static char*
-fluid_file_read_full(fluid_file fp, size_t* length)
+static char *
+fluid_file_read_full(fluid_file fp, size_t *length)
{
size_t buflen;
- char* buffer;
+ char *buffer;
size_t n;
+
/* Work out the length of the file in advance */
- if (FLUID_FSEEK(fp, 0, SEEK_END) != 0)
+ if(FLUID_FSEEK(fp, 0, SEEK_END) != 0)
{
FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
return NULL;
}
+
buflen = ftell(fp);
- if (FLUID_FSEEK(fp, 0, SEEK_SET) != 0)
+
+ if(FLUID_FSEEK(fp, 0, SEEK_SET) != 0)
{
FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
return NULL;
}
+
FLUID_LOG(FLUID_DBG, "File load: Allocating %d bytes", buflen);
buffer = FLUID_MALLOC(buflen);
- if (buffer == NULL) {
+
+ if(buffer == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
+
n = FLUID_FREAD(buffer, 1, buflen, fp);
- if (n != buflen) {
+
+ if(n != buflen)
+ {
FLUID_LOG(FLUID_ERR, "Only read %d bytes; expected %d", n,
buflen);
FLUID_FREE(buffer);
return NULL;
};
+
*length = n;
+
return buffer;
}
@@ -116,35 +173,40 @@ fluid_file_read_full(fluid_file fp, size_t* length)
* @param mf MIDI file handle to close and free.
*/
void
-delete_fluid_midi_file (fluid_midi_file *mf)
+delete_fluid_midi_file(fluid_midi_file *mf)
{
- if (mf == NULL) {
- return;
- }
+ fluid_return_if_fail(mf != NULL);
+
FLUID_FREE(mf);
- return;
}
/*
* Gets the next byte in a MIDI file, taking into account previous running status.
*
- * returns FLUID_FAILED if EOF or read error
+ * returns -1 if EOF or read error
*/
int
-fluid_midi_file_getc (fluid_midi_file *mf)
+fluid_midi_file_getc(fluid_midi_file *mf)
{
unsigned char c;
- if (mf->c >= 0) {
+
+ if(mf->c >= 0)
+ {
c = mf->c;
mf->c = -1;
- } else {
- if (mf->buf_pos >= mf->buf_len) {
+ }
+ else
+ {
+ if(mf->buf_pos >= mf->buf_len)
+ {
mf->eof = TRUE;
- return FLUID_FAILED;
+ return -1;
}
+
c = mf->buffer[mf->buf_pos++];
mf->trackpos++;
}
+
return (int) c;
}
@@ -166,23 +228,35 @@ int
fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len)
{
int num = len < mf->buf_len - mf->buf_pos
- ? len : mf->buf_len - mf->buf_pos;
- if (num != len) {
+ ? len : mf->buf_len - mf->buf_pos;
+
+ if(num != len)
+ {
mf->eof = TRUE;
}
- if (num < 0) {
+
+ if(num < 0)
+ {
num = 0;
}
+
/* Note: Read bytes, even if there aren't enough, but only increment
* trackpos if successful (emulates old behaviour of fluid_midi_file_read)
*/
- FLUID_MEMCPY(buf, mf->buffer+mf->buf_pos, num);
+ FLUID_MEMCPY(buf, mf->buffer + mf->buf_pos, num);
mf->buf_pos += num;
- if (num == len)
+
+ if(num == len)
+ {
mf->trackpos += num;
+ }
+
#if DEBUG
else
+ {
FLUID_LOG(FLUID_DBG, "Could not read the requested number of bytes");
+ }
+
#endif
return (num != len) ? FLUID_FAILED : FLUID_OK;
}
@@ -191,15 +265,18 @@ fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len)
* fluid_midi_file_skip
*/
int
-fluid_midi_file_skip (fluid_midi_file *mf, int skip)
+fluid_midi_file_skip(fluid_midi_file *mf, int skip)
{
int new_pos = mf->buf_pos + skip;
+
/* Mimic the behaviour of fseek: Error to seek past the start of file, but
* OK to seek past end (this just puts it into the EOF state). */
- if (new_pos < 0) {
+ if(new_pos < 0)
+ {
FLUID_LOG(FLUID_ERR, "Failed to seek position in file");
return FLUID_FAILED;
}
+
/* Clear the EOF flag, even if moved past the end of the file (this is
* consistent with the behaviour of fseek). */
mf->eof = FALSE;
@@ -210,15 +287,15 @@ fluid_midi_file_skip (fluid_midi_file *mf, int skip)
/*
* fluid_midi_file_eof
*/
-int fluid_midi_file_eof(fluid_midi_file* mf)
+int fluid_midi_file_eof(fluid_midi_file *mf)
{
- /* Note: This does not simply test whether the file read pointer is past
- * the end of the file. It mimics the behaviour of feof by actually
- * testing the stateful EOF condition, which is set to TRUE if getc or
- * fread have attempted to read past the end (but not if they have
- * precisely reached the end), but reset to FALSE upon a successful seek.
- */
- return mf->eof;
+ /* Note: This does not simply test whether the file read pointer is past
+ * the end of the file. It mimics the behaviour of feof by actually
+ * testing the stateful EOF condition, which is set to TRUE if getc or
+ * fread have attempted to read past the end (but not if they have
+ * precisely reached the end), but reset to FALSE upon a successful seek.
+ */
+ return mf->eof;
}
/*
@@ -227,30 +304,40 @@ int fluid_midi_file_eof(fluid_midi_file* mf)
int
fluid_midi_file_read_mthd(fluid_midi_file *mf)
{
- char mthd[15];
- if (fluid_midi_file_read(mf, mthd, 14) != FLUID_OK) {
+ char mthd[14];
+
+ if(fluid_midi_file_read(mf, mthd, sizeof(mthd)) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if ((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6)
- || (mthd[9] > 2)) {
+
+ if((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6)
+ || (mthd[9] > 2))
+ {
FLUID_LOG(FLUID_ERR,
- "Doesn't look like a MIDI file: invalid MThd header");
+ "Doesn't look like a MIDI file: invalid MThd header");
return FLUID_FAILED;
}
+
mf->type = mthd[9];
mf->ntracks = (unsigned) mthd[11];
- mf->ntracks += (unsigned int) (mthd[10]) << 16;
- if ((mthd[12]) < 0) {
+ mf->ntracks += (unsigned int)(mthd[10]) << 16;
+
+ if((signed char)mthd[12] < 0)
+ {
mf->uses_smpte = 1;
- mf->smpte_fps = -mthd[12];
+ mf->smpte_fps = -(signed char)mthd[12];
mf->smpte_res = (unsigned) mthd[13];
FLUID_LOG(FLUID_ERR, "File uses SMPTE timing -- Not implemented yet");
return FLUID_FAILED;
- } else {
+ }
+ else
+ {
mf->uses_smpte = 0;
- mf->division = (mthd[12] << 8) | (mthd[13] & 0xff);
+ mf->division = ((unsigned)mthd[12] << 8) | ((unsigned)mthd[13] & 0xff);
FLUID_LOG(FLUID_DBG, "Division=%d", mf->division);
}
+
return FLUID_OK;
}
@@ -261,11 +348,15 @@ int
fluid_midi_file_load_tracks(fluid_midi_file *mf, fluid_player_t *player)
{
int i;
- for (i = 0; i < mf->ntracks; i++) {
- if (fluid_midi_file_read_track(mf, player, i) != FLUID_OK) {
+
+ for(i = 0; i < mf->ntracks; i++)
+ {
+ if(fluid_midi_file_read_track(mf, player, i) != FLUID_OK)
+ {
return FLUID_FAILED;
}
}
+
return FLUID_OK;
}
@@ -275,14 +366,23 @@ fluid_midi_file_load_tracks(fluid_midi_file *mf, fluid_player_t *player)
int
fluid_isasciistring(char *s)
{
+ /* From ctype.h */
+#define fluid_isascii(c) (((c) & ~0x7f) == 0)
+
int i;
int len = (int) FLUID_STRLEN(s);
- for (i = 0; i < len; i++) {
- if (!fluid_isascii(s[i])) {
+
+ for(i = 0; i < len; i++)
+ {
+ if(!fluid_isascii(s[i]))
+ {
return 0;
}
}
+
return 1;
+
+#undef fluid_isascii
}
/*
@@ -303,9 +403,12 @@ int
fluid_midi_file_read_tracklen(fluid_midi_file *mf)
{
unsigned char length[5];
- if (fluid_midi_file_read(mf, length, 4) != FLUID_OK) {
+
+ if(fluid_midi_file_read(mf, length, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
mf->tracklen = fluid_getlength(length);
mf->trackpos = 0;
mf->eot = 0;
@@ -319,9 +422,12 @@ int
fluid_midi_file_eot(fluid_midi_file *mf)
{
#if DEBUG
- if (mf->trackpos > mf->tracklen) {
+
+ if(mf->trackpos > mf->tracklen)
+ {
printf("track overrun: %d > %d\n", mf->trackpos, mf->tracklen);
}
+
#endif
return mf->eot || (mf->trackpos >= mf->tracklen);
}
@@ -337,69 +443,93 @@ fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num)
int found_track = 0;
int skip;
- if (fluid_midi_file_read(mf, id, 4) != FLUID_OK) {
+ if(fluid_midi_file_read(mf, id, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
id[4] = '\0';
mf->dtime = 0;
- while (!found_track) {
+ while(!found_track)
+ {
- if (fluid_isasciistring((char *) id) == 0) {
+ if(fluid_isasciistring((char *) id) == 0)
+ {
FLUID_LOG(FLUID_ERR,
- "An non-ascii track header found, corrupt file");
+ "An non-ascii track header found, corrupt file");
return FLUID_FAILED;
- } else if (strcmp((char *) id, "MTrk") == 0) {
+ }
+ else if(FLUID_STRCMP((char *) id, "MTrk") == 0)
+ {
found_track = 1;
- if (fluid_midi_file_read_tracklen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_tracklen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
track = new_fluid_track(num);
- if (track == NULL) {
+
+ if(track == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
- while (!fluid_midi_file_eot(mf)) {
- if (fluid_midi_file_read_event(mf, track) != FLUID_OK) {
+ while(!fluid_midi_file_eot(mf))
+ {
+ if(fluid_midi_file_read_event(mf, track) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
}
/* Skip remaining track data, if any */
- if (mf->trackpos < mf->tracklen) {
- if (fluid_midi_file_skip(mf, mf->tracklen - mf->trackpos) != FLUID_OK) {
+ if(mf->trackpos < mf->tracklen)
+ {
+ if(fluid_midi_file_skip(mf, mf->tracklen - mf->trackpos) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
}
- if (fluid_player_add_track(player, track) != FLUID_OK) {
+ if(fluid_player_add_track(player, track) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
- } else {
+ }
+ else
+ {
found_track = 0;
- if (fluid_midi_file_read(mf, length, 4) != FLUID_OK) {
+
+ if(fluid_midi_file_read(mf, length, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
skip = fluid_getlength(length);
+
/* fseek(mf->fp, skip, SEEK_CUR); */
- if (fluid_midi_file_skip(mf, skip) != FLUID_OK) {
+ if(fluid_midi_file_skip(mf, skip) != FLUID_OK)
+ {
return FLUID_FAILED;
}
}
}
- if (fluid_midi_file_eof(mf)) {
+
+ if(fluid_midi_file_eof(mf))
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
+
return FLUID_OK;
}
@@ -412,24 +542,35 @@ fluid_midi_file_read_varlen(fluid_midi_file *mf)
int i;
int c;
mf->varlen = 0;
- for (i = 0;; i++) {
- if (i == 4) {
+
+ for(i = 0;; i++)
+ {
+ if(i == 4)
+ {
FLUID_LOG(FLUID_ERR, "Invalid variable length number");
return FLUID_FAILED;
}
+
c = fluid_midi_file_getc(mf);
- if (c < 0) {
+
+ if(c < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
- if (c & 0x80) {
- mf->varlen |= (int) (c & 0x7F);
+
+ if(c & 0x80)
+ {
+ mf->varlen |= (int)(c & 0x7F);
mf->varlen <<= 7;
- } else {
+ }
+ else
+ {
mf->varlen += c;
break;
}
}
+
return FLUID_OK;
}
@@ -453,24 +594,31 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
int size;
/* read the delta-time of the event */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
mf->dtime += mf->varlen;
/* read the status byte */
status = fluid_midi_file_getc(mf);
- if (status < 0) {
+
+ if(status < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
/* not a valid status byte: use the running status instead */
- if ((status & 0x80) == 0) {
- if ((mf->running_status & 0x80) == 0) {
+ if((status & 0x80) == 0)
+ {
+ if((mf->running_status & 0x80) == 0)
+ {
FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status");
return FLUID_FAILED;
}
+
fluid_midi_file_push(mf, status);
status = mf->running_status;
}
@@ -479,40 +627,49 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
mf->running_status = status;
- if ((status == MIDI_SYSEX)) { /* system exclusif */
+ if(status == MIDI_SYSEX) /* system exclusif */
+ {
/* read the length of the message */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if (mf->varlen) {
+ if(mf->varlen)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
- __LINE__, mf->varlen);
+ __LINE__, mf->varlen);
metadata = FLUID_MALLOC(mf->varlen + 1);
- if (metadata == NULL) {
+ if(metadata == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
/* read the data of the message */
- if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
- FLUID_FREE (metadata);
+ if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK)
+ {
+ FLUID_FREE(metadata);
return FLUID_FAILED;
}
evt = new_fluid_midi_event();
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE (metadata);
+ FLUID_FREE(metadata);
return FLUID_FAILED;
}
evt->dtime = mf->dtime;
size = mf->varlen;
- if (metadata[mf->varlen - 1] == MIDI_EOX)
+ if(metadata[mf->varlen - 1] == MIDI_EOX)
+ {
size--;
+ }
/* Add SYSEX event and indicate that its dynamically allocated and should be freed with event */
fluid_midi_event_set_sysex(evt, metadata, size, TRUE);
@@ -522,232 +679,318 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
return FLUID_OK;
- } else if (status == MIDI_META_EVENT) { /* meta events */
+ }
+ else if(status == MIDI_META_EVENT) /* meta events */
+ {
int result = FLUID_OK;
/* get the type of the meta message */
type = fluid_midi_file_getc(mf);
- if (type < 0) {
+
+ if(type < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
/* get the length of the data part */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if (mf->varlen < 255) {
+ if(mf->varlen < 255)
+ {
metadata = &static_buf[0];
- } else {
+ }
+ else
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
- __LINE__, mf->varlen);
+ __LINE__, mf->varlen);
dyn_buf = FLUID_MALLOC(mf->varlen + 1);
- if (dyn_buf == NULL) {
+
+ if(dyn_buf == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
+
metadata = dyn_buf;
}
/* read the data */
- if (mf->varlen) {
- if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
- if (dyn_buf) {
+ if(mf->varlen)
+ {
+ if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK)
+ {
+ if(dyn_buf)
+ {
FLUID_FREE(dyn_buf);
}
+
return FLUID_FAILED;
}
}
/* handle meta data */
- switch (type) {
+ switch(type)
+ {
- case MIDI_COPYRIGHT:
- metadata[mf->varlen] = 0;
- break;
+ case MIDI_COPYRIGHT:
+ metadata[mf->varlen] = 0;
+ break;
- case MIDI_TRACK_NAME:
- metadata[mf->varlen] = 0;
- fluid_track_set_name(track, (char *) metadata);
- break;
+ case MIDI_TRACK_NAME:
+ metadata[mf->varlen] = 0;
+ fluid_track_set_name(track, (char *) metadata);
+ break;
- case MIDI_INST_NAME:
- metadata[mf->varlen] = 0;
- break;
+ case MIDI_INST_NAME:
+ metadata[mf->varlen] = 0;
+ break;
+
+ case MIDI_LYRIC:
+ case MIDI_TEXT:
+ {
+ void *tmp;
+ int size = mf->varlen + 1;
+
+ /* NULL terminate strings for safety */
+ metadata[size - 1] = '\0';
+
+ evt = new_fluid_midi_event();
- case MIDI_LYRIC:
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
+
+ evt->dtime = mf->dtime;
- case MIDI_MARKER:
+ tmp = FLUID_MALLOC(size);
+
+ if(tmp == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ delete_fluid_midi_event(evt);
+ evt = NULL;
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_CUE_POINT:
- break; /* don't care much for text events */
+ FLUID_MEMCPY(tmp, metadata, size);
- case MIDI_EOT:
- if (mf->varlen != 0) {
- FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
- result = FLUID_FAILED;
- break;
- }
- mf->eot = 1;
- evt = new_fluid_midi_event();
- if (evt == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- result = FLUID_FAILED;
- break;
- }
- evt->dtime = mf->dtime;
- evt->type = MIDI_EOT;
- fluid_track_add_event(track, evt);
- mf->dtime = 0;
+ fluid_midi_event_set_sysex_LOCAL(evt, type, tmp, size, TRUE);
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ }
+ break;
+
+ case MIDI_MARKER:
+ break;
+
+ case MIDI_CUE_POINT:
+ break; /* don't care much for text events */
+
+ case MIDI_EOT:
+ if(mf->varlen != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SET_TEMPO:
- if (mf->varlen != 3) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for SetTempo meta event");
- result = FLUID_FAILED;
- break;
- }
- tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
- evt = new_fluid_midi_event();
- if (evt == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- result = FLUID_FAILED;
- break;
- }
- evt->dtime = mf->dtime;
- evt->type = MIDI_SET_TEMPO;
- evt->channel = 0;
- evt->param1 = tempo;
- evt->param2 = 0;
- fluid_track_add_event(track, evt);
- mf->dtime = 0;
+ mf->eot = 1;
+ evt = new_fluid_midi_event();
+
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SMPTE_OFFSET:
- if (mf->varlen != 5) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for SMPTE Offset meta event");
- result = FLUID_FAILED;
- break;
- }
- break; /* we don't use smtp */
-
- case MIDI_TIME_SIGNATURE:
- if (mf->varlen != 4) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for TimeSignature meta event");
- result = FLUID_FAILED;
- break;
- }
- nominator = metadata[0];
- denominator = pow(2.0, (double) metadata[1]);
- clocks = metadata[2];
- notes = metadata[3];
+ evt->dtime = mf->dtime;
+ evt->type = MIDI_EOT;
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ break;
- FLUID_LOG(FLUID_DBG,
- "signature=%d/%d, metronome=%d, 32nd-notes=%d",
- nominator, denominator, clocks, notes);
+ case MIDI_SET_TEMPO:
+ if(mf->varlen != 3)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for SetTempo meta event");
+ result = FLUID_FAILED;
+ break;
+ }
+ tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
+ evt = new_fluid_midi_event();
+
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_KEY_SIGNATURE:
- if (mf->varlen != 2) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for KeySignature meta event");
- result = FLUID_FAILED;
- break;
- }
- /* We don't care about key signatures anyway */
- /* sf = metadata[0];
- mi = metadata[1]; */
+ evt->dtime = mf->dtime;
+ evt->type = MIDI_SET_TEMPO;
+ evt->channel = 0;
+ evt->param1 = tempo;
+ evt->param2 = 0;
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ break;
+
+ case MIDI_SMPTE_OFFSET:
+ if(mf->varlen != 5)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for SMPTE Offset meta event");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SEQUENCER_EVENT:
+ break; /* we don't use smtp */
+
+ case MIDI_TIME_SIGNATURE:
+ if(mf->varlen != 4)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for TimeSignature meta event");
+ result = FLUID_FAILED;
break;
+ }
- default:
+ nominator = metadata[0];
+ denominator = pow(2.0, (double) metadata[1]);
+ clocks = metadata[2];
+ notes = metadata[3];
+
+ FLUID_LOG(FLUID_DBG,
+ "signature=%d/%d, metronome=%d, 32nd-notes=%d",
+ nominator, denominator, clocks, notes);
+
+ break;
+
+ case MIDI_KEY_SIGNATURE:
+ if(mf->varlen != 2)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for KeySignature meta event");
+ result = FLUID_FAILED;
break;
+ }
+
+ /* We don't care about key signatures anyway */
+ /* sf = metadata[0];
+ mi = metadata[1]; */
+ break;
+
+ case MIDI_SEQUENCER_EVENT:
+ break;
+
+ default:
+ break;
}
- if (dyn_buf) {
+ if(dyn_buf)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
FLUID_FREE(dyn_buf);
}
return result;
- } else { /* channel messages */
+ }
+ else /* channel messages */
+ {
type = status & 0xf0;
channel = status & 0x0f;
/* all channel message have at least 1 byte of associated data */
- if ((param1 = fluid_midi_file_getc(mf)) < 0) {
+ if((param1 = fluid_midi_file_getc(mf)) < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
- switch (type) {
+ switch(type)
+ {
- case NOTE_ON:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ case NOTE_ON:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case NOTE_OFF:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ break;
- case KEY_PRESSURE:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ case NOTE_OFF:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case CONTROL_CHANGE:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ break;
- case PROGRAM_CHANGE:
- break;
+ case KEY_PRESSURE:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case CHANNEL_PRESSURE:
- break;
+ break;
- case PITCH_BEND:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
+ case CONTROL_CHANGE:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
- param2 = 0;
- break;
+ break;
+
+ case PROGRAM_CHANGE:
+ break;
+
+ case CHANNEL_PRESSURE:
+ break;
- default:
- /* Can't possibly happen !? */
- FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
+ case PITCH_BEND:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
+ }
+
+ param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
+ param2 = 0;
+ break;
+
+ default:
+ /* Can't possibly happen !? */
+ FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
+ return FLUID_FAILED;
}
+
evt = new_fluid_midi_event();
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
+
evt->dtime = mf->dtime;
evt->type = type;
evt->channel = channel;
@@ -756,6 +999,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
fluid_track_add_event(track, evt);
mf->dtime = 0;
}
+
return FLUID_OK;
}
@@ -779,14 +1023,17 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
* @return New MIDI event structure or NULL when out of memory.
*/
fluid_midi_event_t *
-new_fluid_midi_event ()
+new_fluid_midi_event()
{
- fluid_midi_event_t* evt;
+ fluid_midi_event_t *evt;
evt = FLUID_NEW(fluid_midi_event_t);
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
evt->dtime = 0;
evt->type = 0;
evt->channel = 0;
@@ -800,24 +1047,27 @@ new_fluid_midi_event ()
/**
* Delete MIDI event structure.
* @param evt MIDI event structure
- * @return Always returns #FLUID_OK
*/
-int
+void
delete_fluid_midi_event(fluid_midi_event_t *evt)
{
fluid_midi_event_t *temp;
+ fluid_return_if_fail(evt != NULL);
- while (evt) {
+ while(evt)
+ {
temp = evt->next;
/* Dynamic SYSEX event? - free (param2 indicates if dynamic) */
- if (evt->type == MIDI_SYSEX && evt->paramptr && evt->param2)
- FLUID_FREE (evt->paramptr);
+ if((evt->type == MIDI_SYSEX || (evt-> type == MIDI_TEXT) || (evt->type == MIDI_LYRIC)) &&
+ evt->paramptr && evt->param2)
+ {
+ FLUID_FREE(evt->paramptr);
+ }
FLUID_FREE(evt);
evt = temp;
}
- return FLUID_OK;
}
/**
@@ -1016,22 +1266,65 @@ fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val)
* Assign sysex data to a MIDI event structure.
* @param evt MIDI event structure
* @param data Pointer to SYSEX data
- * @param size Size of SYSEX data
+ * @param size Size of SYSEX data in bytes
* @param dynamic TRUE if the SYSEX data has been dynamically allocated and
* should be freed when the event is freed (only applies if event gets destroyed
* with delete_fluid_midi_event())
* @return Always returns #FLUID_OK
*
- * NOTE: Unlike the other event assignment functions, this one sets evt->type.
+ * @note Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dynamic)
{
- evt->type = MIDI_SYSEX;
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_SYSEX, data, size, dynamic);
+ return FLUID_OK;
+}
+
+/**
+ * Assign text data to a MIDI event structure.
+ * @param evt MIDI event structure
+ * @param data Pointer to text data
+ * @param size Size of text data in bytes
+ * @param dynamic TRUE if the data has been dynamically allocated and
+ * should be freed when the event is freed via delete_fluid_midi_event()
+ * @return Always returns #FLUID_OK
+ *
+ * @since 2.0.0
+ * @note Unlike the other event assignment functions, this one sets evt->type.
+ */
+int
+fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dynamic)
+{
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_TEXT, data, size, dynamic);
+ return FLUID_OK;
+}
+
+/**
+ * Assign lyric data to a MIDI event structure.
+ * @param evt MIDI event structure
+ * @param data Pointer to lyric data
+ * @param size Size of lyric data in bytes
+ * @param dynamic TRUE if the data has been dynamically allocated and
+ * should be freed when the event is freed via delete_fluid_midi_event()
+ * @return Always returns #FLUID_OK
+ *
+ * @since 2.0.0
+ * @note Unlike the other event assignment functions, this one sets evt->type.
+ */
+int
+fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, void *data, int size, int dynamic)
+{
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_LYRIC, data, size, dynamic);
+ return FLUID_OK;
+}
+
+static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic)
+{
+ evt->type = type;
evt->paramptr = data;
evt->param1 = size;
evt->param2 = dynamic;
- return FLUID_OK;
}
/******************************************************
@@ -1047,9 +1340,12 @@ new_fluid_track(int num)
{
fluid_track_t *track;
track = FLUID_NEW(fluid_track_t);
- if (track == NULL) {
+
+ if(track == NULL)
+ {
return NULL;
}
+
track->name = NULL;
track->num = num;
track->first = NULL;
@@ -1062,17 +1358,14 @@ new_fluid_track(int num)
/*
* delete_fluid_track
*/
-int
+void
delete_fluid_track(fluid_track_t *track)
{
- if (track->name != NULL) {
- FLUID_FREE(track->name);
- }
- if (track->first != NULL) {
- delete_fluid_midi_event(track->first);
- }
+ fluid_return_if_fail(track != NULL);
+
+ FLUID_FREE(track->name);
+ delete_fluid_midi_event(track->first);
FLUID_FREE(track);
- return FLUID_OK;
}
/*
@@ -1082,33 +1375,32 @@ int
fluid_track_set_name(fluid_track_t *track, char *name)
{
int len;
- if (track->name != NULL) {
+
+ if(track->name != NULL)
+ {
FLUID_FREE(track->name);
}
- if (name == NULL) {
+
+ if(name == NULL)
+ {
track->name = NULL;
return FLUID_OK;
}
+
len = FLUID_STRLEN(name);
track->name = FLUID_MALLOC(len + 1);
- if (track->name == NULL) {
+
+ if(track->name == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
+
FLUID_STRCPY(track->name, name);
return FLUID_OK;
}
/*
- * fluid_track_get_name
- */
-char *
-fluid_track_get_name(fluid_track_t *track)
-{
- return track->name;
-}
-
-/*
* fluid_track_get_duration
*/
int
@@ -1116,29 +1408,14 @@ fluid_track_get_duration(fluid_track_t *track)
{
int time = 0;
fluid_midi_event_t *evt = track->first;
- while (evt != NULL) {
+
+ while(evt != NULL)
+ {
time += evt->dtime;
evt = evt->next;
}
- return time;
-}
-/*
- * fluid_track_count_events
- */
-static int
-fluid_track_count_events(fluid_track_t *track, int *on, int *off)
-{
- fluid_midi_event_t *evt = track->first;
- while (evt != NULL) {
- if (evt->type == NOTE_ON) {
- (*on)++;
- } else if (evt->type == NOTE_OFF) {
- (*off)++;
- }
- evt = evt->next;
- }
- return FLUID_OK;
+ return time;
}
/*
@@ -1148,25 +1425,20 @@ int
fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt)
{
evt->next = NULL;
- if (track->first == NULL) {
+
+ if(track->first == NULL)
+ {
track->first = evt;
track->cur = evt;
track->last = evt;
- } else {
+ }
+ else
+ {
track->last->next = evt;
track->last = evt;
}
- return FLUID_OK;
-}
-/*
- * fluid_track_first_event
- */
-fluid_midi_event_t *
-fluid_track_first_event(fluid_track_t *track)
-{
- track->cur = track->first;
- return track->cur;
+ return FLUID_OK;
}
/*
@@ -1175,9 +1447,11 @@ fluid_track_first_event(fluid_track_t *track)
fluid_midi_event_t *
fluid_track_next_event(fluid_track_t *track)
{
- if (track->cur != NULL) {
+ if(track->cur != NULL)
+ {
track->cur = track->cur->next;
}
+
return track->cur;
}
@@ -1197,17 +1471,31 @@ fluid_track_reset(fluid_track_t *track)
*/
int
fluid_track_send_events(fluid_track_t *track,
- fluid_synth_t *synth,
- fluid_player_t *player,
- unsigned int ticks)
+ fluid_synth_t *synth,
+ fluid_player_t *player,
+ unsigned int ticks)
{
int status = FLUID_OK;
fluid_midi_event_t *event;
+ int seeking = player->seek_ticks >= 0;
- while (1) {
+ if(seeking)
+ {
+ ticks = player->seek_ticks; /* update target ticks */
+
+ if(track->ticks > ticks)
+ {
+ fluid_track_reset(track); /* reset track if seeking backwards */
+ }
+ }
+
+ while(1)
+ {
event = track->cur;
- if (event == NULL) {
+
+ if(event == NULL)
+ {
return status;
}
@@ -1218,25 +1506,37 @@ fluid_track_send_events(fluid_track_t *track,
/* event->dtime, */
/* track->ticks + event->dtime); */
- if (track->ticks + event->dtime > ticks) {
+ if(track->ticks + event->dtime > ticks)
+ {
return status;
}
track->ticks += event->dtime;
- if (!player || event->type == MIDI_EOT) {
+ if(!player || event->type == MIDI_EOT)
+ {
}
- else if (event->type == MIDI_SET_TEMPO) {
- fluid_player_set_midi_tempo(player, event->param1);
+ else if(seeking && (event->type == NOTE_ON || event->type == NOTE_OFF))
+ {
+ /* skip on/off messages */
}
- else {
- if (player->playback_callback)
+ else
+ {
+ if(player->playback_callback)
+ {
player->playback_callback(player->playback_userdata, event);
+ }
+ }
+
+ if(event->type == MIDI_SET_TEMPO)
+ {
+ fluid_player_set_midi_tempo(player, event->param1);
}
fluid_track_next_event(track);
}
+
return status;
}
@@ -1244,6 +1544,14 @@ fluid_track_send_events(fluid_track_t *track,
*
* fluid_player
*/
+static void
+fluid_player_handle_reset_synth(void *data, const char *name, int value)
+{
+ fluid_player_t *player = data;
+ fluid_return_if_fail(player != NULL);
+
+ player->reset_synth_between_songs = value;
+}
/**
* Create a new MIDI player.
@@ -1256,16 +1564,22 @@ new_fluid_player(fluid_synth_t *synth)
int i;
fluid_player_t *player;
player = FLUID_NEW(fluid_player_t);
- if (player == NULL) {
+
+ if(player == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
player->status = FLUID_PLAYER_READY;
player->loop = 1;
player->ntracks = 0;
- for (i = 0; i < MAX_NUMBER_OF_TRACKS; i++) {
+
+ for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++)
+ {
player->track[i] = NULL;
}
+
player->synth = synth;
player->system_timer = NULL;
player->sample_timer = NULL;
@@ -1277,13 +1591,16 @@ new_fluid_player(fluid_synth_t *synth)
player->deltatime = 4.0;
player->cur_msec = 0;
player->cur_ticks = 0;
+ player->seek_ticks = -1;
fluid_player_set_playback_callback(player, fluid_synth_handle_midi_event, synth);
-
player->use_system_timer = fluid_settings_str_equal(synth->settings,
- "player.timing-source", "system");
+ "player.timing-source", "system");
fluid_settings_getint(synth->settings, "player.reset-synth", &i);
- player->reset_synth_between_songs = i;
+ fluid_player_handle_reset_synth(player, NULL, i);
+
+ fluid_settings_callback_int(synth->settings, "player.reset-synth",
+ fluid_player_handle_reset_synth, player);
return player;
}
@@ -1291,23 +1608,22 @@ new_fluid_player(fluid_synth_t *synth)
/**
* Delete a MIDI player instance.
* @param player MIDI player instance
- * @return Always returns #FLUID_OK
*/
-int
+void
delete_fluid_player(fluid_player_t *player)
{
fluid_list_t *q;
- fluid_playlist_item* pi;
+ fluid_playlist_item *pi;
+
+ fluid_return_if_fail(player != NULL);
- if (player == NULL) {
- return FLUID_OK;
- }
fluid_player_stop(player);
fluid_player_reset(player);
- while (player->playlist != NULL) {
+ while(player->playlist != NULL)
+ {
q = player->playlist->next;
- pi = (fluid_playlist_item*) player->playlist->data;
+ pi = (fluid_playlist_item *) player->playlist->data;
FLUID_FREE(pi->filename);
FLUID_FREE(pi->buffer);
FLUID_FREE(pi);
@@ -1316,7 +1632,6 @@ delete_fluid_player(fluid_player_t *player)
}
FLUID_FREE(player);
- return FLUID_OK;
}
/**
@@ -1327,14 +1642,12 @@ fluid_player_settings(fluid_settings_t *settings)
{
/* player.timing-source can be either "system" (use system timer)
or "sample" (use timer based on number of written samples) */
- fluid_settings_register_str(settings, "player.timing-source", "sample", 0,
- NULL, NULL);
+ fluid_settings_register_str(settings, "player.timing-source", "sample", 0);
fluid_settings_add_option(settings, "player.timing-source", "sample");
fluid_settings_add_option(settings, "player.timing-source", "system");
/* Selects whether the player should reset the synth between songs, or not. */
- fluid_settings_register_int(settings, "player.reset-synth", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
+ fluid_settings_register_int(settings, "player.reset-synth", 1, 0, 1, FLUID_HINT_TOGGLED);
}
@@ -1343,12 +1656,15 @@ fluid_player_reset(fluid_player_t *player)
{
int i;
- for (i = 0; i < MAX_NUMBER_OF_TRACKS; i++) {
- if (player->track[i] != NULL) {
+ for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++)
+ {
+ if(player->track[i] != NULL)
+ {
delete_fluid_track(player->track[i]);
player->track[i] = NULL;
}
}
+
/* player->current_file = NULL; */
/* player->status = FLUID_PLAYER_READY; */
/* player->loop = 1; */
@@ -1366,52 +1682,33 @@ fluid_player_reset(fluid_player_t *player)
int
fluid_player_add_track(fluid_player_t *player, fluid_track_t *track)
{
- if (player->ntracks < MAX_NUMBER_OF_TRACKS) {
+ if(player->ntracks < MAX_NUMBER_OF_TRACKS)
+ {
player->track[player->ntracks++] = track;
return FLUID_OK;
- } else {
- return FLUID_FAILED;
}
-}
-
-/*
- * fluid_player_count_tracks
- */
-int
-fluid_player_count_tracks(fluid_player_t *player)
-{
- return player->ntracks;
-}
-
-/*
- * fluid_player_get_track
- */
-fluid_track_t *
-fluid_player_get_track(fluid_player_t *player, int i)
-{
- if ((i >= 0) && (i < MAX_NUMBER_OF_TRACKS)) {
- return player->track[i];
- } else {
- return NULL;
+ else
+ {
+ return FLUID_FAILED;
}
}
/**
- * Change the MIDI callback function. This is usually set to
+ * Change the MIDI callback function. This is usually set to
* fluid_synth_handle_midi_event, but can optionally be changed
* to a user-defined function instead, for intercepting all MIDI
- * messages sent to the synth. You can also use a midi router as
+ * messages sent to the synth. You can also use a midi router as
* the callback function to modify the MIDI messages before sending
- * them to the synth.
+ * them to the synth.
* @param player MIDI player instance
* @param handler Pointer to callback function
* @param handler_data Parameter sent to the callback function
* @returns FLUID_OK
* @since 1.1.4
*/
-int
-fluid_player_set_playback_callback(fluid_player_t* player,
- handle_midi_event_func_t handler, void* handler_data)
+int
+fluid_player_set_playback_callback(fluid_player_t *player,
+ handle_midi_event_func_t handler, void *handler_data)
{
player->playback_callback = handler;
player->playback_userdata = handler_data;
@@ -1428,8 +1725,10 @@ int
fluid_player_add(fluid_player_t *player, const char *midifile)
{
fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
- char* f = FLUID_STRDUP(midifile);
- if (!pi || !f) {
+ char *f = FLUID_STRDUP(midifile);
+
+ if(!pi || !f)
+ {
FLUID_FREE(pi);
FLUID_FREE(f);
FLUID_LOG(FLUID_PANIC, "Out of memory");
@@ -1453,12 +1752,14 @@ fluid_player_add(fluid_player_t *player, const char *midifile)
* @return #FLUID_OK or #FLUID_FAILED
*/
int
-fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len)
+fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len)
{
/* Take a copy of the buffer, so the caller can free immediately. */
fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
void *buf_copy = FLUID_MALLOC(len);
- if (!pi || !buf_copy) {
+
+ if(!pi || !buf_copy)
+ {
FLUID_FREE(pi);
FLUID_FREE(buf_copy);
FLUID_LOG(FLUID_PANIC, "Out of memory");
@@ -1480,28 +1781,33 @@ int
fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
{
fluid_midi_file *midifile;
- char* buffer;
+ char *buffer;
size_t buffer_length;
int buffer_owned;
- if (item->filename != NULL)
+ if(item->filename != NULL)
{
fluid_file fp;
/* This file is specified by filename; load the file from disk */
FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile %s", __FILE__, __LINE__,
- item->filename);
+ item->filename);
/* Read the entire contents of the file into the buffer */
fp = FLUID_FOPEN(item->filename, "rb");
- if (fp == NULL) {
+
+ if(fp == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Couldn't open the MIDI file");
return FLUID_FAILED;
}
+
buffer = fluid_file_read_full(fp, &buffer_length);
- if (buffer == NULL)
+
+ if(buffer == NULL)
{
FLUID_FCLOSE(fp);
return FLUID_FAILED;
}
+
buffer_owned = 1;
FLUID_FCLOSE(fp);
}
@@ -1509,7 +1815,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
{
/* This file is specified by a pre-loaded buffer; load from memory */
FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile from memory (%p)",
- __FILE__, __LINE__, item->buffer);
+ __FILE__, __LINE__, item->buffer);
buffer = (char *) item->buffer;
buffer_length = item->buffer_len;
/* Do not free the buffer (it is owned by the playlist) */
@@ -1517,59 +1823,83 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
}
midifile = new_fluid_midi_file(buffer, buffer_length);
- if (midifile == NULL) {
- if (buffer_owned) {
+
+ if(midifile == NULL)
+ {
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
return FLUID_FAILED;
}
+
player->division = fluid_midi_file_get_division(midifile);
fluid_player_set_midi_tempo(player, player->miditempo); // Update deltatime
/*FLUID_LOG(FLUID_DBG, "quarter note division=%d\n", player->division); */
- if (fluid_midi_file_load_tracks(midifile, player) != FLUID_OK) {
- if (buffer_owned) {
+ if(fluid_midi_file_load_tracks(midifile, player) != FLUID_OK)
+ {
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
delete_fluid_midi_file(midifile);
return FLUID_FAILED;
}
+
delete_fluid_midi_file(midifile);
- if (buffer_owned) {
+
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
return FLUID_OK;
}
-static void
+void
fluid_player_advancefile(fluid_player_t *player)
{
- if (player->playlist == NULL) {
+ if(player->playlist == NULL)
+ {
return; /* No files to play */
}
- if (player->currentfile != NULL) {
+
+ if(player->currentfile != NULL)
+ {
player->currentfile = fluid_list_next(player->currentfile);
}
- if (player->currentfile == NULL) {
- if (player->loop == 0) {
+
+ if(player->currentfile == NULL)
+ {
+ if(player->loop == 0)
+ {
return; /* We're done playing */
}
- if (player->loop > 0) {
+
+ if(player->loop > 0)
+ {
player->loop--;
}
+
player->currentfile = player->playlist;
}
}
-static void
+void
fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
{
- fluid_playlist_item* current_playitem;
+ fluid_playlist_item *current_playitem;
int i;
- do {
+ do
+ {
fluid_player_advancefile(player);
- if (player->currentfile == NULL) {
+
+ if(player->currentfile == NULL)
+ {
/* Failed to find next song, probably since we're finished */
player->status = FLUID_PLAYER_DONE;
return;
@@ -1577,7 +1907,8 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
fluid_player_reset(player);
current_playitem = (fluid_playlist_item *) player->currentfile->data;
- } while (fluid_player_load(player, current_playitem) != FLUID_OK);
+ }
+ while(fluid_player_load(player, current_playitem) != FLUID_OK);
/* Successfully loaded midi file */
@@ -1586,18 +1917,20 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
player->start_ticks = 0;
player->cur_ticks = 0;
- if (player->reset_synth_between_songs) {
+ if(player->reset_synth_between_songs)
+ {
fluid_synth_system_reset(player->synth);
}
- for (i = 0; i < player->ntracks; i++) {
- if (player->track[i] != NULL) {
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(player->track[i] != NULL)
+ {
fluid_track_reset(player->track[i]);
}
}
}
-
/*
* fluid_player_callback
*/
@@ -1613,36 +1946,61 @@ fluid_player_callback(void *data, unsigned int msec)
synth = player->synth;
loadnextfile = player->currentfile == NULL ? 1 : 0;
- do {
- if (loadnextfile) {
+
+ do
+ {
+ if(loadnextfile)
+ {
loadnextfile = 0;
fluid_player_playlist_load(player, msec);
- if (player->currentfile == NULL) {
+
+ if(player->currentfile == NULL)
+ {
return 0;
}
}
player->cur_msec = msec;
player->cur_ticks = (player->start_ticks
- + (int) ((double) (player->cur_msec - player->start_msec)
- / player->deltatime));
+ + (int)((double)(player->cur_msec - player->start_msec)
+ / player->deltatime + 0.5)); /* 0.5 to average overall error when casting */
+
+ if(player->seek_ticks >= 0)
+ {
+ fluid_synth_all_sounds_off(synth, -1); /* avoid hanging notes */
+ }
- for (i = 0; i < player->ntracks; i++) {
- if (!fluid_track_eot(player->track[i])) {
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(!fluid_track_eot(player->track[i]))
+ {
status = FLUID_PLAYER_PLAYING;
- if (fluid_track_send_events(player->track[i], synth, player,
- player->cur_ticks) != FLUID_OK) {
+
+ if(fluid_track_send_events(player->track[i], synth, player,
+ player->cur_ticks) != FLUID_OK)
+ {
/* */
}
}
}
- if (status == FLUID_PLAYER_DONE) {
+ if(player->seek_ticks >= 0)
+ {
+ player->start_ticks = player->seek_ticks; /* tick position of last tempo value (which is now) */
+ player->cur_ticks = player->seek_ticks;
+ player->begin_msec = msec; /* only used to calculate the duration of playing */
+ player->start_msec = msec; /* should be the (synth)-time of the last tempo change */
+ player->seek_ticks = -1; /* clear seek_ticks */
+ }
+
+ if(status == FLUID_PLAYER_DONE)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec", __FILE__,
- __LINE__, (msec - player->begin_msec) / 1000.0);
+ __LINE__, (msec - player->begin_msec) / 1000.0);
loadnextfile = 1;
}
- } while (loadnextfile);
+ }
+ while(loadnextfile);
player->status = status;
@@ -1657,30 +2015,39 @@ fluid_player_callback(void *data, unsigned int msec)
int
fluid_player_play(fluid_player_t *player)
{
- if (player->status == FLUID_PLAYER_PLAYING) {
+ if(player->status == FLUID_PLAYER_PLAYING)
+ {
return FLUID_OK;
}
- if (player->playlist == NULL) {
+ if(player->playlist == NULL)
+ {
return FLUID_OK;
}
player->status = FLUID_PLAYER_PLAYING;
- if (player->use_system_timer) {
+ if(player->use_system_timer)
+ {
player->system_timer = new_fluid_timer((int) player->deltatime,
- fluid_player_callback, (void *) player, TRUE, FALSE, TRUE);
- if (player->system_timer == NULL) {
+ fluid_player_callback, (void *) player, TRUE, FALSE, TRUE);
+
+ if(player->system_timer == NULL)
+ {
return FLUID_FAILED;
}
- } else {
+ }
+ else
+ {
player->sample_timer = new_fluid_sample_timer(player->synth,
- fluid_player_callback, (void *) player);
+ fluid_player_callback, (void *) player);
- if (player->sample_timer == NULL) {
+ if(player->sample_timer == NULL)
+ {
return FLUID_FAILED;
}
}
+
return FLUID_OK;
}
@@ -1692,12 +2059,16 @@ fluid_player_play(fluid_player_t *player)
int
fluid_player_stop(fluid_player_t *player)
{
- if (player->system_timer != NULL) {
+ if(player->system_timer != NULL)
+ {
delete_fluid_timer(player->system_timer);
}
- if (player->sample_timer != NULL) {
+
+ if(player->sample_timer != NULL)
+ {
delete_fluid_sample_timer(player->synth, player->sample_timer);
}
+
player->status = FLUID_PLAYER_DONE;
player->sample_timer = NULL;
player->system_timer = NULL;
@@ -1717,13 +2088,35 @@ fluid_player_get_status(fluid_player_t *player)
}
/**
- * Enable looping of a MIDI player
+ * Seek in the currently playing file.
+ * @param player MIDI player instance
+ * @param ticks the position to seek to in the current file
+ * @return #FLUID_FAILED if ticks is negative or after the latest tick of the file,
+ * #FLUID_OK otherwise
+ * @since 2.0.0
+ *
+ * The actual seek is performed during the player_callback.
+ */
+int fluid_player_seek(fluid_player_t *player, int ticks)
+{
+ if(ticks < 0 || ticks > fluid_player_get_total_ticks(player))
+ {
+ return FLUID_FAILED;
+ }
+
+ player->seek_ticks = ticks;
+ return FLUID_OK;
+}
+
+
+/**
+ * Enable looping of a MIDI player
* @param player MIDI player instance
* @param loop Times left to loop the playlist. -1 means loop infinitely.
* @return Always returns #FLUID_OK
* @since 1.1.0
*
- * For example, if you want to loop the playlist twice, set loop to 2
+ * For example, if you want to loop the playlist twice, set loop to 2
* and call this function before you start the player.
*/
int fluid_player_set_loop(fluid_player_t *player, int loop)
@@ -1746,8 +2139,8 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
player->start_ticks = player->cur_ticks;
FLUID_LOG(FLUID_DBG,
- "tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
- tempo, player->deltatime, player->cur_msec, player->cur_ticks);
+ "tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
+ tempo, player->deltatime, player->cur_msec, player->cur_ticks);
return FLUID_OK;
}
@@ -1758,10 +2151,9 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
* @param bpm Tempo in beats per minute
* @return Always returns #FLUID_OK
*/
-int
-fluid_player_set_bpm(fluid_player_t *player, int bpm)
+int fluid_player_set_bpm(fluid_player_t *player, int bpm)
{
- return fluid_player_set_midi_tempo(player, (int) ((double) 60 * 1e6 / bpm));
+ return fluid_player_set_midi_tempo(player, (int)((double) 60 * 1e6 / bpm));
}
/**
@@ -1772,21 +2164,82 @@ fluid_player_set_bpm(fluid_player_t *player, int bpm)
int
fluid_player_join(fluid_player_t *player)
{
- if (player->system_timer) {
+ if(player->system_timer)
+ {
return fluid_timer_join(player->system_timer);
- } else if (player->sample_timer) {
+ }
+ else if(player->sample_timer)
+ {
/* Busy-wait loop, since there's no thread to wait for... */
- while (player->status != FLUID_PLAYER_DONE) {
-#if defined(WIN32)
- Sleep(10);
-#else
- usleep(10000);
-#endif
+ while(player->status != FLUID_PLAYER_DONE)
+ {
+ fluid_msleep(10);
}
}
+
return FLUID_OK;
}
+/**
+ * Get the number of tempo ticks passed.
+ * @param player MIDI player instance
+ * @return The number of tempo ticks passed
+ * @since 1.1.7
+ */
+int fluid_player_get_current_tick(fluid_player_t *player)
+{
+ return player->cur_ticks;
+}
+
+/**
+ * Looks through all available MIDI tracks and gets the absolute tick of the very last event to play.
+ * @param player MIDI player instance
+ * @return Total tick count of the sequence
+ * @since 1.1.7
+ */
+int fluid_player_get_total_ticks(fluid_player_t *player)
+{
+ int i;
+ int maxTicks = 0;
+
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(player->track[i] != NULL)
+ {
+ int ticks = fluid_track_get_duration(player->track[i]);
+
+ if(ticks > maxTicks)
+ {
+ maxTicks = ticks;
+ }
+ }
+ }
+
+ return maxTicks;
+}
+
+/**
+ * Get the tempo of a MIDI player in beats per minute.
+ * @param player MIDI player instance
+ * @return MIDI player tempo in BPM
+ * @since 1.1.7
+ */
+int fluid_player_get_bpm(fluid_player_t *player)
+{
+ return (int)(60e6 / player->miditempo);
+}
+
+/**
+ * Get the tempo of a MIDI player.
+ * @param player MIDI player instance
+ * @return Tempo of the MIDI player (in microseconds per quarter note, as per MIDI file spec)
+ * @since 1.1.7
+ */
+int fluid_player_get_midi_tempo(fluid_player_t *player)
+{
+ return player->miditempo;
+}
+
/************************************************************************
* MIDI PARSER
*
@@ -1796,14 +2249,17 @@ fluid_player_join(fluid_player_t *player)
* new_fluid_midi_parser
*/
fluid_midi_parser_t *
-new_fluid_midi_parser ()
+new_fluid_midi_parser()
{
fluid_midi_parser_t *parser;
parser = FLUID_NEW(fluid_midi_parser_t);
- if (parser == NULL) {
+
+ if(parser == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
parser->status = 0; /* As long as the status is 0, the parser won't do anything -> no need to initialize all the fields. */
return parser;
}
@@ -1811,11 +2267,12 @@ new_fluid_midi_parser ()
/*
* delete_fluid_midi_parser
*/
-int
+void
delete_fluid_midi_parser(fluid_midi_parser_t *parser)
{
+ fluid_return_if_fail(parser != NULL);
+
FLUID_FREE(parser);
- return FLUID_OK;
}
/**
@@ -1824,6 +2281,11 @@ delete_fluid_midi_parser(fluid_midi_parser_t *parser)
* @param c Next character in MIDI stream
* @return A parsed MIDI event or NULL if none. Event is internal and should
* not be modified or freed and is only valid until next call to this function.
+ * @internal Do not expose this function to the public API. It would allow downstream
+ * apps to abuse fluidsynth as midi parser, e.g. feeding it with rawmidi and pull out
+ * the needed midi information using the getter functions of fluid_midi_event_t.
+ * This parser however is incomplete as it e.g. only provides a limited buffer to
+ * store and process SYSEX data (i.e. doesnt allow arbitrary lengths)
*/
fluid_midi_event_t *
fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
@@ -1832,8 +2294,10 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
/* Real-time messages (0xF8-0xFF) can occur anywhere, even in the middle
* of another message. */
- if (c >= 0xF8) {
- if (c == MIDI_SYSTEM_RESET) {
+ if(c >= 0xF8)
+ {
+ if(c == MIDI_SYSTEM_RESET)
+ {
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
@@ -1843,30 +2307,40 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
}
/* Status byte? - If previous message not yet complete, it is discarded (re-sync). */
- if (c & 0x80) {
+ if(c & 0x80)
+ {
/* Any status byte terminates SYSEX messages (not just 0xF7) */
- if (parser->status == MIDI_SYSEX && parser->nr_bytes > 0) {
+ if(parser->status == MIDI_SYSEX && parser->nr_bytes > 0)
+ {
event = &parser->event;
fluid_midi_event_set_sysex(event, parser->data, parser->nr_bytes,
- FALSE);
- } else
+ FALSE);
+ }
+ else
+ {
event = NULL;
+ }
- if (c < 0xF0) /* Voice category message? */
+ if(c < 0xF0) /* Voice category message? */
{
parser->channel = c & 0x0F;
parser->status = c & 0xF0;
/* The event consumes x bytes of data... (subtract 1 for the status byte) */
parser->nr_bytes_total = fluid_midi_event_length(parser->status)
- - 1;
+ - 1;
parser->nr_bytes = 0; /* 0 bytes read so far */
- } else if (c == MIDI_SYSEX) {
+ }
+ else if(c == MIDI_SYSEX)
+ {
parser->status = MIDI_SYSEX;
parser->nr_bytes = 0;
- } else
- parser->status = 0; /* Discard other system messages (0xF1-0xF7) */
+ }
+ else
+ {
+ parser->status = 0; /* Discard other system messages (0xF1-0xF7) */
+ }
return event; /* Return SYSEX event or NULL */
}
@@ -1874,11 +2348,14 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
/* Data/parameter byte */
/* Discard data bytes for events we don't care about */
- if (parser->status == 0)
+ if(parser->status == 0)
+ {
return NULL;
+ }
/* Max data size exceeded? (SYSEX messages only really) */
- if (parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE) {
+ if(parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE)
+ {
parser->status = 0; /* Discard the rest of the message */
return NULL;
}
@@ -1887,8 +2364,10 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
parser->data[parser->nr_bytes++] = c;
/* Do we still need more data to get this event complete? */
- if (parser->nr_bytes < parser->nr_bytes_total)
+ if(parser->status == MIDI_SYSEX || parser->nr_bytes < parser->nr_bytes_total)
+ {
return NULL;
+ }
/* Event is complete, return it.
* Running status byte MIDI feature is also handled here. */
@@ -1896,22 +2375,25 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
parser->event.channel = parser->channel;
parser->nr_bytes = 0; /* Reset data size, in case there are additional running status messages */
- switch (parser->status) {
- case NOTE_OFF:
- case NOTE_ON:
- case KEY_PRESSURE:
- case CONTROL_CHANGE:
- case PROGRAM_CHANGE:
- case CHANNEL_PRESSURE:
- parser->event.param1 = parser->data[0]; /* For example key number */
- parser->event.param2 = parser->data[1]; /* For example velocity */
- break;
- case PITCH_BEND:
- /* Pitch-bend is transmitted with 14-bit precision. */
- parser->event.param1 = (parser->data[1] << 7) | parser->data[0];
- break;
- default: /* Unlikely */
- return NULL;
+ switch(parser->status)
+ {
+ case NOTE_OFF:
+ case NOTE_ON:
+ case KEY_PRESSURE:
+ case CONTROL_CHANGE:
+ case PROGRAM_CHANGE:
+ case CHANNEL_PRESSURE:
+ parser->event.param1 = parser->data[0]; /* For example key number */
+ parser->event.param2 = parser->data[1]; /* For example velocity */
+ break;
+
+ case PITCH_BEND:
+ /* Pitch-bend is transmitted with 14-bit precision. */
+ parser->event.param1 = (parser->data[1] << 7) | parser->data[0];
+ break;
+
+ default: /* Unlikely */
+ return NULL;
}
return &parser->event;
@@ -1922,28 +2404,35 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
static int
fluid_midi_event_length(unsigned char event)
{
- switch (event & 0xF0) {
- case NOTE_OFF:
- case NOTE_ON:
- case KEY_PRESSURE:
- case CONTROL_CHANGE:
- case PITCH_BEND:
- return 3;
- case PROGRAM_CHANGE:
- case CHANNEL_PRESSURE:
- return 2;
- }
- switch (event) {
- case MIDI_TIME_CODE:
- case MIDI_SONG_SELECT:
- case 0xF4:
- case 0xF5:
- return 2;
- case MIDI_TUNE_REQUEST:
- return 1;
- case MIDI_SONG_POSITION:
- return 3;
+ switch(event & 0xF0)
+ {
+ case NOTE_OFF:
+ case NOTE_ON:
+ case KEY_PRESSURE:
+ case CONTROL_CHANGE:
+ case PITCH_BEND:
+ return 3;
+
+ case PROGRAM_CHANGE:
+ case CHANNEL_PRESSURE:
+ return 2;
+ }
+
+ switch(event)
+ {
+ case MIDI_TIME_CODE:
+ case MIDI_SONG_SELECT:
+ case 0xF4:
+ case 0xF5:
+ return 2;
+
+ case MIDI_TUNE_REQUEST:
+ return 1;
+
+ case MIDI_SONG_POSITION:
+ return 3;
}
+
return 1;
}
#endif