Hi! I was thinking of having libfluidsynth playing background music in a game, and tried it out a bit. The ability to change the music while playing was important in this case (e g change track volumes without restarting the file), so this made libfluidsynth a better choice than other midi engines.
However, the default buffer size of 64 meant a lot of glitches in the audio stream, and in this case latency was less important, so a large buffer size was a must. It didn't take long to realize what this actually did to the MIDI timing. So, I went ahead and fixed it. I guess this opens up for the possibility to render MIDI files faster as well, but I haven't looked into that. Anyway, here's the patch. I made it in debdiff format, and against the 1.0.8 source, because that was the simplest way for me, but I can probably fix another patch format if needed. Enjoy! // David
diff -u fluidsynth-1.0.8/debian/changelog fluidsynth-1.0.8/debian/changelog --- fluidsynth-1.0.8/debian/changelog +++ fluidsynth-1.0.8/debian/changelog @@ -1,3 +1,9 @@ +fluidsynth (1.0.8-1.1ubuntu1) intrepid; urgency=low + + * Fix timing problems with playing MIDI files at large buffer sizes + + -- David Henningsson <fluidsynth....@epost.diwic.se> Fri, 13 Mar 2009 09:16:40 +0100 + fluidsynth (1.0.8-1.1) unstable; urgency=low * Non-maintainer upload. only in patch2: unchanged: --- fluidsynth-1.0.8.orig/src/fluid_synth.c +++ fluidsynth-1.0.8/src/fluid_synth.c @@ -330,6 +330,70 @@ } /*************************************************************** + * FLUID SYNTH TIMERS + * Timers that use written audio data as timing reference + */ +struct _fluid_synth_timer_t +{ + fluid_synth_timer_t* next; /* Single linked list of timers */ + unsigned long starttick; + fluid_timer_callback_t callback; + void* data; + int isfinished; +}; + +/* + * fluid_synth_timer_process - called when synth->ticks is updated + */ +void fluid_synth_timer_process(fluid_synth_t* synth) +{ + fluid_synth_timer_t* st; + for (st=synth->synth_timers; st; st=st->next) { + if (st->isfinished) { + continue; + } + + long msec = (long) (1000.0*((double) (synth->ticks - st->starttick))/synth->sample_rate); + int cont = (*st->callback)(st->data, msec); + if (cont == 0) { + st->isfinished = 1; + } + } +} + +fluid_synth_timer_t* new_fluid_synth_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data) +{ + fluid_synth_timer_t* result = FLUID_NEW(fluid_synth_timer_t); + if (result == NULL) { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + result->starttick = synth->ticks; + result->isfinished = 0; + result->data = data; + result->callback = callback; + result->next = synth->synth_timers; + synth->synth_timers = result; + return result; +} + +int delete_fluid_synth_timer(fluid_synth_t* synth, fluid_synth_timer_t* timer) +{ + fluid_synth_timer_t** ptr = &synth->synth_timers; + while (*ptr) { + if (*ptr == timer) { + *ptr = timer->next; + FLUID_FREE(timer); + return FLUID_OK; + } + ptr = &((*ptr)->next); + } + FLUID_LOG(FLUID_ERR,"delete_fluid_synth_timer failed, no timer found"); + return FLUID_FAILED; +} + + +/*************************************************************** * * FLUID SYNTH */ @@ -1957,6 +2021,10 @@ /* fluid_mutex_unlock(synth->busy); /\* Allow other threads to touch the synth *\/ */ + fluid_synth_timer_process(synth); + + fluid_check_fpe("fluid_synth_timer_process"); + return 0; } only in patch2: unchanged: --- fluidsynth-1.0.8.orig/src/fluid_midi.h +++ fluidsynth-1.0.8/src/fluid_midi.h @@ -239,7 +239,7 @@ int ntracks; fluid_track_t *track[MAX_NUMBER_OF_TRACKS]; fluid_synth_t* synth; - fluid_timer_t* timer; + fluid_synth_timer_t* timer; fluid_list_t* playlist; char* current_file; char send_program_change; /* should we ignore the program changes? */ only in patch2: unchanged: --- fluidsynth-1.0.8.orig/src/fluid_midi.c +++ fluidsynth-1.0.8/src/fluid_midi.c @@ -1325,8 +1325,11 @@ player->status = FLUID_PLAYER_PLAYING; - player->timer = new_fluid_timer((int) player->deltatime, fluid_player_callback, - (void*) player, 1, 0); + player->timer = new_fluid_synth_timer(player->synth, fluid_player_callback, + (void*) player); + +/* player->timer = new_fluid_timer((int) player->deltatime, fluid_player_callback, + (void*) player, 1, 0);*/ if (player->timer == NULL) { return FLUID_FAILED; } @@ -1341,7 +1344,8 @@ int fluid_player_stop(fluid_player_t* player) { if (player->timer != NULL) { - delete_fluid_timer(player->timer); + delete_fluid_synth_timer(player->synth, player->timer); + /*delete_fluid_timer(player->timer);*/ } player->status = FLUID_PLAYER_DONE; player->timer = NULL; @@ -1401,7 +1405,11 @@ */ int fluid_player_join(fluid_player_t* player) { - return player->timer? fluid_timer_join(player->timer) : FLUID_OK; + if (player->timer) { + fluid_player_stop(player); + } + return FLUID_OK; +/* return player->timer? fluid_timer_join(player->timer) : FLUID_OK;*/ } /************************************************************************ only in patch2: unchanged: --- fluidsynth-1.0.8.orig/src/fluidsynth_priv.h +++ fluidsynth-1.0.8/src/fluidsynth_priv.h @@ -232,6 +232,7 @@ typedef struct _fluid_hashtable_t fluid_hashtable_t; typedef struct _fluid_client_t fluid_client_t; typedef struct _fluid_server_socket_t fluid_server_socket_t; +typedef struct _fluid_synth_timer_t fluid_synth_timer_t; /*************************************************************** * only in patch2: unchanged: --- fluidsynth-1.0.8.orig/src/fluid_synth.h +++ fluidsynth-1.0.8/src/fluid_synth.h @@ -144,6 +144,7 @@ * Note: This simple scheme does -not- provide 100 % protection against * thread problems, for example from MIDI thread and shell thread */ + fluid_synth_timer_t* synth_timers; #ifdef LADSPA fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */ #endif @@ -208,6 +209,12 @@ void fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin, void* lout, int loff, int lincr, void* rout, int roff, int rincr); +/* Synth timers */ + +fluid_synth_timer_t* new_fluid_synth_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data); + +int delete_fluid_synth_timer(fluid_synth_t* synth, fluid_synth_timer_t* timer); + /* * misc */
_______________________________________________ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev