Josh Green skrev: > A FluidSynth release is long overdue. I already let the tentative date > of March 9th slip. I'm buried in work right now, so I've had very > little time to put into any free software projects. > > This patch seems like a pretty fundamental change, though good one. Its > tempting to try and include it in 1.0.9. If there was a build time or > runtime option to select this new timing source, that would be ideal.
According to a later e-mail you seem to have reconsidered about this, or maybe I misunderstood you. So here's a patch that enables "slave timers" (I call them "sample timers" in the source) only if a new option is enabled, "player.timing-source=sample". The pro's of applying this patch for 1.0.9 are: - We get the same output every time (although not faster than real-time) - Faster-than-real-time will be possible for everyone using the library and want to process the audio themselves. - Risk for regressions are minimized since the option is disabled by default (although it should be enabled by default for 1.1.0). - And, after all, every 0.9 release should contain a sneak preview of the upcoming 1.0 features ;-) // David
Index: src/fluid_settings.c =================================================================== --- src/fluid_settings.c (revision 162) +++ src/fluid_settings.c (arbetskopia) @@ -26,6 +26,7 @@ #include "fluid_adriver.h" #include "fluid_mdriver.h" #include "fluid_settings.h" +#include "fluid_midi.h" /* maximum allowed components of a settings variable (separated by '.') */ #define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */ @@ -195,6 +196,7 @@ { fluid_synth_settings(settings); fluid_shell_settings(settings); + fluid_player_settings(settings); fluid_audio_driver_settings(settings); fluid_midi_driver_settings(settings); } Index: src/fluid_settings.h =================================================================== --- src/fluid_settings.h (revision 162) +++ src/fluid_settings.h (arbetskopia) @@ -35,18 +35,18 @@ typedef int (*fluid_str_update_t)(void* data, char* name, char* value); typedef int (*fluid_int_update_t)(void* data, char* name, int value); -/** returns 0 if the value has been resgister correctly, non-zero +/** returns 0 if the value has been registered correctly, non-zero otherwise */ int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints, fluid_str_update_t fun, void* data); -/** returns 0 if the value has been resgister correctly, non-zero +/** returns 0 if the value has been registered correctly, non-zero otherwise */ int fluid_settings_register_num(fluid_settings_t* settings, char* name, double min, double max, double def, int hints, fluid_num_update_t fun, void* data); -/** returns 0 if the value has been resgister correctly, non-zero +/** returns 0 if the value has been registered correctly, non-zero otherwise */ int fluid_settings_register_int(fluid_settings_t* settings, char* name, int min, int max, int def, int hints, fluid_int_update_t fun, void* data); Index: src/fluid_synth.c =================================================================== --- src/fluid_synth.c (revision 162) +++ src/fluid_synth.c (arbetskopia) @@ -331,6 +331,70 @@ } /*************************************************************** + * FLUID SAMPLE TIMERS + * Timers that use written audio data as timing reference + */ +struct _fluid_sample_timer_t +{ + fluid_sample_timer_t* next; /* Single linked list of timers */ + unsigned long starttick; + fluid_timer_callback_t callback; + void* data; + int isfinished; +}; + +/* + * fluid_sample_timer_process - called when synth->ticks is updated + */ +void fluid_sample_timer_process(fluid_synth_t* synth) +{ + fluid_sample_timer_t* st; + for (st=synth->sample_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_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data) +{ + fluid_sample_timer_t* result = FLUID_NEW(fluid_sample_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->sample_timers; + synth->sample_timers = result; + return result; +} + +int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer) +{ + fluid_sample_timer_t** ptr = &synth->sample_timers; + while (*ptr) { + if (*ptr == timer) { + *ptr = timer->next; + FLUID_FREE(timer); + return FLUID_OK; + } + ptr = &((*ptr)->next); + } + FLUID_LOG(FLUID_ERR,"delete_fluid_sample_timer failed, no timer found"); + return FLUID_FAILED; +} + + +/*************************************************************** * * FLUID SYNTH */ @@ -2029,6 +2093,10 @@ /* fluid_mutex_unlock(synth->busy); /\* Allow other threads to touch the synth *\/ */ + fluid_sample_timer_process(synth); + + fluid_check_fpe("fluid_sample_timer_process"); + return 0; } Index: src/fluid_synth.h =================================================================== --- src/fluid_synth.h (revision 162) +++ src/fluid_synth.h (arbetskopia) @@ -81,7 +81,6 @@ int offset; }; - /* * fluid_synth_t */ @@ -144,6 +143,8 @@ * Note: This simple scheme does -not- provide 100 % protection against * thread problems, for example from MIDI thread and shell thread */ + fluid_sample_timer_t* sample_timers; /* List of timers triggered after a block has been processed */ + #ifdef LADSPA fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */ #endif @@ -208,6 +209,10 @@ 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); + +fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data); +int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer); + /* * misc */ Index: src/fluidsynth_priv.h =================================================================== --- src/fluidsynth_priv.h (revision 162) +++ src/fluidsynth_priv.h (arbetskopia) @@ -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_sample_timer_t fluid_sample_timer_t; /*************************************************************** * Index: src/fluid_midi.c =================================================================== --- src/fluid_midi.c (revision 162) +++ src/fluid_midi.c (arbetskopia) @@ -1120,6 +1120,7 @@ fluid_player_t* new_fluid_player(fluid_synth_t* synth) { int i; + char* timing_source; fluid_player_t* player; player = FLUID_NEW(fluid_player_t); if (player == NULL) { @@ -1133,13 +1134,22 @@ player->track[i] = NULL; } player->synth = synth; - player->timer = NULL; + player->system_timer = NULL; + player->sample_timer = NULL; player->playlist = NULL; player->current_file = NULL; player->division = 0; player->send_program_change = 1; player->miditempo = 480000; player->deltatime = 4.0; + + player->use_system_timer = 0; + if (fluid_settings_getstr(synth->settings, "player.timing-source", &timing_source) != 0) { + if (strcmp(timing_source, "system") == 0) { + player->use_system_timer = 1; + } + } + return player; } @@ -1159,6 +1169,17 @@ return FLUID_OK; } +/** + * Registers settings related to the MIDI player + */ +void 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", "system", 0, NULL, NULL); +} + + int fluid_player_reset(fluid_player_t* player) { int i; @@ -1327,10 +1348,20 @@ player->status = FLUID_PLAYER_PLAYING; - player->timer = new_fluid_timer((int) player->deltatime, fluid_player_callback, + if (player->use_system_timer) { + player->system_timer = new_fluid_timer((int) player->deltatime, fluid_player_callback, (void*) player, 1, 0); - if (player->timer == NULL) { - return FLUID_FAILED; + if (player->system_timer == NULL) { + return FLUID_FAILED; + } + } else { + player->sample_timer = new_fluid_sample_timer(player->synth, fluid_player_callback, + (void*) player); + + if (player->sample_timer == NULL) { + return FLUID_FAILED; + } + fluid_player_callback(player, 0); /* Process the first events before the first block */ } return FLUID_OK; } @@ -1342,14 +1373,19 @@ */ int fluid_player_stop(fluid_player_t* player) { - if (player->timer != NULL) { - delete_fluid_timer(player->timer); + if (player->system_timer != NULL) { + delete_fluid_timer(player->system_timer); } + if (player->sample_timer != NULL) { + delete_fluid_sample_timer(player->synth, player->sample_timer); + } player->status = FLUID_PLAYER_DONE; - player->timer = NULL; + player->sample_timer = NULL; + player->system_timer = NULL; return FLUID_OK; } + /* FIXME - Looping seems to not actually be implemented? */ /** @@ -1403,7 +1439,21 @@ */ int fluid_player_join(fluid_player_t* player) { - return player->timer? fluid_timer_join(player->timer) : FLUID_OK; + if (player->system_timer) { + return fluid_timer_join(player->system_timer); + } else if (player->sample_timer) { + /* Busy-wait loop, since there's no thread to wait for... */ + while (player->status == FLUID_PLAYER_PLAYING) { +#if defined(WIN32) + Sleep(10); +#elif defined(MACOS9) + /* FIXME: How do we sleep in Macos9? */ +#else + usleep(10000); +#endif + } + } + return FLUID_OK; } /************************************************************************ Index: src/fluid_midi.h =================================================================== --- src/fluid_midi.h (revision 162) +++ src/fluid_midi.h (arbetskopia) @@ -249,10 +249,12 @@ int ntracks; fluid_track_t *track[MAX_NUMBER_OF_TRACKS]; fluid_synth_t* synth; - fluid_timer_t* timer; + fluid_timer_t* system_timer; + fluid_sample_timer_t* sample_timer; fluid_list_t* playlist; char* current_file; char send_program_change; /* should we ignore the program changes? */ + char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */ int start_ticks; /* the number of tempo ticks passed at the last tempo change */ int cur_ticks; /* the number of tempo ticks passed */ int begin_msec; /* the time (msec) of the beginning of the file */ @@ -270,7 +272,9 @@ int fluid_player_reset(fluid_player_t* player); int fluid_player_load(fluid_player_t* player, char *filename); +void fluid_player_settings(fluid_settings_t* settings); + /* * fluid_midi_file */
_______________________________________________ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev