Merge branch '2.0.x' into master

This commit is contained in:
derselbst 2019-08-19 16:39:36 +02:00
commit 1e7a5f594d
8 changed files with 153 additions and 167 deletions

View file

@ -29,7 +29,7 @@ set ( PACKAGE "fluidsynth" )
# FluidSynth package version
set ( FLUIDSYNTH_VERSION_MAJOR 2 )
set ( FLUIDSYNTH_VERSION_MINOR 0 )
set ( FLUIDSYNTH_VERSION_MICRO 5 )
set ( FLUIDSYNTH_VERSION_MICRO 6 )
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
@ -44,7 +44,7 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
# This is not exactly the same algorithm as the libtool one, but the results are the same.
set ( LIB_VERSION_CURRENT 2 )
set ( LIB_VERSION_AGE 1 )
set ( LIB_VERSION_REVISION 2 )
set ( LIB_VERSION_REVISION 3 )
set ( LIB_VERSION_INFO
"${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" )

View file

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = libfluidsynth
PROJECT_NUMBER = 2.0.5
PROJECT_NUMBER = 2.0.6
OUTPUT_DIRECTORY = api
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View file

@ -8,8 +8,8 @@
\author David Henningsson
\author Tom Moebert
\author Copyright © 2003-2019 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
\version Revision 2.0.5
\date 2019-04-17
\version Revision 2.0.6
\date 2019-08-17
All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@ -21,6 +21,7 @@ All the source code examples in this document are in the public domain; you can
- \ref Disclaimer
- \ref Introduction
- \ref NewIn2_0_6
- \ref NewIn2_0_5
- \ref NewIn2_0_3
- \ref NewIn2_0_2
@ -63,6 +64,10 @@ What is FluidSynth?
- FluidSynth is open source, in active development. For more details, take a look at http://www.fluidsynth.org
\section NewIn2_0_6 Whats new in 2.0.6?
- the MIDI player did not emit any audio when calling fluid_player_play() after fluid_player_stop()
\section NewIn2_0_5 Whats new in 2.0.5?
- fluid_synth_process() omitted audio samples when called with arbitrary sample counts that were not a multiple of fluid_synth_get_internal_bufsize()
@ -75,7 +80,6 @@ What is FluidSynth?
- fluid_midi_event_get_text()
- fluid_midi_event_get_lyrics()
\section NewIn2_0_2 Whats new in 2.0.2?
- fluid_synth_error() has been deprecated, use fluid_set_log_function() to interfere log messages

View file

@ -293,8 +293,14 @@ find_fluid_audio_driver(fluid_settings_t *settings)
* @param synth Synthesizer instance for which the audio driver is created for.
* @return The new audio driver instance.
*
* Creates a new audio driver for a given 'synth' instance with a defined set
* of configuration 'settings'.
* Creates a new audio driver for a given \p synth instance with a defined set
* of configuration \p settings.
*
* @note As soon as an audio driver is created, the \p synth starts rendering audio.
* This means that all necessary sound-setup should be completed after this point,
* thus of all object types in use (synth, midi player, sequencer, etc.) the audio
* driver should always be the last one to be created and the first one to be deleted!
* Also refer to the order of object creation in the code examples.
*/
fluid_audio_driver_t *
new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
@ -326,9 +332,15 @@ new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
*
* Like new_fluid_audio_driver() but allows for custom audio processing before
* audio is sent to audio driver. It is the responsibility of the callback
* 'func' to render the audio into the buffers.
* \p func to render the audio into the buffers.
*
* NOTE: Not as efficient as new_fluid_audio_driver().
* @note Not as efficient as new_fluid_audio_driver().
*
* @note As soon as an audio driver is created, the \p synth starts rendering audio.
* This means that all necessary sound-setup should be completed after this point,
* thus of all object types in use (synth, midi player, sequencer, etc.) the audio
* driver should always be the last one to be created and the first one to be deleted!
* Also refer to the order of object creation in the code examples.
*/
fluid_audio_driver_t *
new_fluid_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)

View file

@ -55,7 +55,7 @@ int option_help = 0; /* set to 1 if "-o help" is specified */
/* Process a command line option -o setting=value, for example: -o synth.polyhony=16 */
void process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
int process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
{
char *val;
int hints;
@ -74,13 +74,13 @@ void process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
if(FLUID_STRCMP(optarg, "help") == 0)
{
option_help = 1;
return;
return FLUID_OK;
}
if(FLUID_STRCMP(optarg, "") == 0)
{
fprintf(stderr, "Invalid -o option (name part is empty)\n");
return;
return FLUID_FAILED;
}
switch(fluid_settings_get_type(settings, optarg))
@ -89,7 +89,7 @@ void process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
if(fluid_settings_setnum(settings, optarg, atof(val)) != FLUID_OK)
{
fprintf(stderr, "Failed to set floating point parameter '%s'\n", optarg);
exit(1);
return FLUID_FAILED;
}
break;
@ -117,7 +117,7 @@ void process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
if(fluid_settings_setint(settings, optarg, ival) != FLUID_OK)
{
fprintf(stderr, "Failed to set integer parameter '%s'\n", optarg);
exit(1);
return FLUID_FAILED;
}
break;
@ -126,15 +126,17 @@ void process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
if(fluid_settings_setstr(settings, optarg, val) != FLUID_OK)
{
fprintf(stderr, "Failed to set string parameter '%s'\n", optarg);
exit(1);
return FLUID_FAILED;
}
break;
default:
fprintf(stderr, "Setting parameter '%s' not found\n", optarg);
exit(1);
return FLUID_FAILED;
}
return FLUID_OK;
}
static void
@ -341,6 +343,7 @@ static int is_dls(const char *fname)
int main(int argc, char **argv)
{
fluid_settings_t *settings;
int result = -1;
int arg1 = 1;
char buf[512];
int c, i;
@ -349,7 +352,6 @@ int main(int argc, char **argv)
int midi_in = 1;
fluid_player_t *player = NULL;
fluid_midi_router_t *router = NULL;
//fluid_sequencer_t* sequencer = NULL;
fluid_midi_driver_t *mdriver = NULL;
fluid_audio_driver_t *adriver = NULL;
fluid_synth_t *synth = NULL;
@ -458,7 +460,7 @@ int main(int argc, char **argv)
{
printf("Option -%c requires an argument\n", c);
print_usage();
exit(0);
goto cleanup;
}
else
{
@ -468,7 +470,7 @@ int main(int argc, char **argv)
{
printf("Expected argument to option -%c found switch instead\n", c);
print_usage();
exit(0);
goto cleanup;
}
}
}
@ -500,7 +502,8 @@ int main(int argc, char **argv)
{
printf("-a options (audio driver):\n ");
show_settings_str_options(settings, "audio.driver");
exit(0);
result = 0;
goto cleanup;
}
else
{
@ -542,7 +545,8 @@ int main(int argc, char **argv)
printf("\nNOTE: No libsndfile support!\n"
"cpu: Use CPU native byte order\n");
#endif
exit(0);
result = 0;
goto cleanup;
}
else
{
@ -571,6 +575,8 @@ int main(int argc, char **argv)
case 'h':
print_welcome();
print_help(settings);
result = 0;
goto cleanup;
break;
case 'i':
@ -601,7 +607,8 @@ int main(int argc, char **argv)
{
printf("-m options (MIDI driver):\n ");
show_settings_str_options(settings, "midi.driver");
exit(0);
result = 0;
goto cleanup;
}
else
{
@ -627,7 +634,8 @@ int main(int argc, char **argv)
#else
printf("\nNOTE: No libsndfile support!\n");
#endif
exit(0);
result = 0;
goto cleanup;
}
else
{
@ -637,7 +645,10 @@ int main(int argc, char **argv)
break;
case 'o':
process_o_cmd_line_option(settings, optarg);
if(process_o_cmd_line_option(settings, optarg) != FLUID_OK)
{
goto cleanup;
}
break;
case 'p' :
@ -692,7 +703,8 @@ int main(int argc, char **argv)
#else
printf("\nNOTE: No libsndfile support!\n");
#endif
exit(0);
result = 0;
goto cleanup;
}
else
{
@ -704,7 +716,8 @@ int main(int argc, char **argv)
case 'V':
print_welcome();
print_configure();
exit(0);
result = 0;
goto cleanup;
break;
case 'v':
@ -719,7 +732,7 @@ int main(int argc, char **argv)
case '?':
printf("Unknown option %c\n", optopt);
print_usage();
exit(0);
goto cleanup;
break;
default:
@ -730,7 +743,7 @@ int main(int argc, char **argv)
default:
printf("Unknown switch '%c'\n", c);
print_usage();
exit(0);
goto cleanup;
break;
#endif
} /* end of switch statement */
@ -751,7 +764,8 @@ int main(int argc, char **argv)
{
printf("FluidSynth settings:\n");
fluid_settings_foreach(settings, settings, settings_foreach_func);
exit(0);
result = 0;
goto cleanup;
}
#ifdef WIN32
@ -801,7 +815,7 @@ int main(int argc, char **argv)
if(synth == NULL)
{
fprintf(stderr, "Failed to create the synthesizer\n");
exit(-1);
goto cleanup;
}
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
@ -820,18 +834,6 @@ int main(int argc, char **argv)
}
}
/* start the synthesis thread */
if(!fast_render)
{
adriver = new_fluid_audio_driver(settings, synth);
if(adriver == NULL)
{
fprintf(stderr, "Failed to create the audio driver\n");
goto cleanup;
}
}
router = new_fluid_midi_router(
settings,
dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event,
@ -850,7 +852,6 @@ int main(int argc, char **argv)
/* In dump mode, text output is generated for events going into and out of the router.
* The example dump functions are put into the chain before and after the router..
*/
//sequencer = new_fluid_sequencer2(0);
mdriver = new_fluid_midi_driver(
settings,
dump ? fluid_midi_dump_prerouter : fluid_midi_router_handle_midi_event,
@ -869,7 +870,6 @@ int main(int argc, char **argv)
{
if((argv[i][0] != '-') && fluid_is_midifile(argv[i]))
{
if(player == NULL)
{
player = new_fluid_player(synth);
@ -973,21 +973,6 @@ int main(int argc, char **argv)
#endif
/* run the shell */
if(interactive)
{
printf("Type 'help' for help topics.\n\n");
/* In dump mode we set the prompt to "". The UI cannot easily
* handle lines, which don't end with CR. Changing the prompt
* cannot be done through a command, because the current shell
* does not handle empty arguments. The ordinary case is dump ==
* 0.
*/
fluid_settings_setstr(settings, "shell.prompt", dump ? "" : "> ");
fluid_usershell(settings, cmd_handler); /* this is a synchronous shell */
}
/* fast rendering audio file, if requested */
if(fast_render)
{
@ -1011,6 +996,33 @@ int main(int argc, char **argv)
fast_render_loop(settings, synth, player);
}
else /* start the synthesis thread */
{
adriver = new_fluid_audio_driver(settings, synth);
if(adriver == NULL)
{
fprintf(stderr, "Failed to create the audio driver\n");
goto cleanup;
}
/* run the shell */
if(interactive)
{
printf("Type 'help' for help topics.\n\n");
/* In dump mode we set the prompt to "". The UI cannot easily
* handle lines, which don't end with CR. Changing the prompt
* cannot be done through a command, because the current shell
* does not handle empty arguments. The ordinary case is dump ==
* 0.
*/
fluid_settings_setstr(settings, "shell.prompt", dump ? "" : "> ");
fluid_usershell(settings, cmd_handler); /* this is a synchronous shell */
}
}
result = 0;
cleanup:
@ -1050,40 +1062,16 @@ cleanup:
/* if no audio driver and sample timers are used, nothing makes the player advance */
fluid_player_join(player);
}
delete_fluid_player(player);
}
if(mdriver)
{
delete_fluid_midi_driver(mdriver);
}
delete_fluid_audio_driver(adriver);
delete_fluid_player(player);
delete_fluid_midi_driver(mdriver);
delete_fluid_midi_router(router);
delete_fluid_synth(synth);
delete_fluid_settings(settings);
if(router)
{
delete_fluid_midi_router(router);
}
/*if (sequencer) {
delete_fluid_sequencer(sequencer);
}*/
if(adriver)
{
delete_fluid_audio_driver(adriver);
}
if(synth)
{
delete_fluid_synth(synth);
}
if(settings)
{
delete_fluid_settings(settings);
}
return 0;
return result;
}
/*
@ -1094,7 +1082,6 @@ print_usage()
{
fprintf(stderr, "Usage: fluidsynth [options] [soundfonts]\n");
fprintf(stderr, "Try -h for help.\n");
exit(0);
}
void
@ -1205,8 +1192,4 @@ print_help(fluid_settings_t *settings)
{
FLUID_FREE(midi_options);
}
delete_fluid_settings(settings);
exit(0);
}

View file

@ -48,7 +48,7 @@ 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,
static void fluid_track_send_events(fluid_track_t *track,
fluid_synth_t *synth,
fluid_player_t *player,
unsigned int ticks);
@ -1552,13 +1552,12 @@ fluid_track_reset(fluid_track_t *track)
/*
* fluid_track_send_events
*/
int
void
fluid_track_send_events(fluid_track_t *track,
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;
@ -1579,7 +1578,7 @@ fluid_track_send_events(fluid_track_t *track,
if(event == NULL)
{
return status;
return;
}
/* printf("track=%02d\tticks=%05u\ttrack=%05u\tdtime=%05u\tnext=%05u\n", */
@ -1591,7 +1590,7 @@ fluid_track_send_events(fluid_track_t *track,
if(track->ticks + event->dtime > ticks)
{
return status;
return;
}
track->ticks += event->dtime;
@ -1619,8 +1618,6 @@ fluid_track_send_events(fluid_track_t *track,
fluid_track_next_event(track);
}
return status;
}
/******************************************************
@ -1678,6 +1675,26 @@ new_fluid_player(fluid_synth_t *synth)
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");
if(player->use_system_timer)
{
player->system_timer = new_fluid_timer((int) player->deltatime,
fluid_player_callback, player, TRUE, FALSE, TRUE);
if(player->system_timer == NULL)
{
goto err;
}
}
else
{
player->sample_timer = new_fluid_sample_timer(player->synth,
fluid_player_callback, player);
if(player->sample_timer == NULL)
{
goto err;
}
}
fluid_settings_getint(synth->settings, "player.reset-synth", &i);
fluid_player_handle_reset_synth(player, NULL, i);
@ -1686,11 +1703,16 @@ new_fluid_player(fluid_synth_t *synth)
fluid_player_handle_reset_synth, player);
return player;
err:
delete_fluid_player(player);
return NULL;
}
/**
* Delete a MIDI player instance.
* @param player MIDI player instance
* @warning Do not call while the \p synth renders audio, i.e. an audio driver is running or any other synthesizer thread calls fluid_synth_process() or fluid_synth_nwrite_float() or fluid_synth_write_*() !
*/
void
delete_fluid_player(fluid_player_t *player)
@ -1703,6 +1725,9 @@ delete_fluid_player(fluid_player_t *player)
fluid_player_stop(player);
fluid_player_reset(player);
delete_fluid_timer(player->system_timer);
delete_fluid_sample_timer(player->synth, player->sample_timer);
while(player->playlist != NULL)
{
q = player->playlist->next;
@ -2030,6 +2055,11 @@ fluid_player_callback(void *data, unsigned int msec)
loadnextfile = player->currentfile == NULL ? 1 : 0;
if(player->status == FLUID_PLAYER_DONE)
{
fluid_synth_all_notes_off(synth, -1);
return 1;
}
do
{
if(loadnextfile)
@ -2058,12 +2088,7 @@ fluid_player_callback(void *data, unsigned int msec)
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)
{
/* */
}
fluid_track_send_events(player->track[i], synth, player, player->cur_ticks);
}
}
@ -2098,63 +2123,33 @@ 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 ||
player->playlist == NULL)
{
return FLUID_OK;
}
if(player->playlist == NULL)
if(!player->use_system_timer)
{
return FLUID_OK;
fluid_sample_timer_reset(player->synth, player->sample_timer);
}
player->status = FLUID_PLAYER_PLAYING;
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)
{
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;
}
}
return FLUID_OK;
}
/**
* Stops a MIDI player.
* Pauses the MIDI playback.
*
* It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose.
* @param player MIDI player instance
* @return Always returns #FLUID_OK
*/
int
fluid_player_stop(fluid_player_t *player)
{
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->sample_timer = NULL;
player->system_timer = NULL;
fluid_player_seek(player, fluid_player_get_current_tick(player));
return FLUID_OK;
}
@ -2240,26 +2235,17 @@ int fluid_player_set_bpm(fluid_player_t *player, int bpm)
}
/**
* Wait for a MIDI player to terminate (when done playing).
* Wait for a MIDI player until the playback has been stopped.
* @param player MIDI player instance
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @return Always #FLUID_OK
*/
int
fluid_player_join(fluid_player_t *player)
{
if(player->system_timer)
while(player->status != FLUID_PLAYER_DONE)
{
return fluid_timer_join(player->system_timer);
fluid_msleep(10);
}
else if(player->sample_timer)
{
/* Busy-wait loop, since there's no thread to wait for... */
while(player->status != FLUID_PLAYER_DONE)
{
fluid_msleep(10);
}
}
return FLUID_OK;
}

View file

@ -500,16 +500,13 @@ struct _fluid_sample_timer_t
*/
static void fluid_sample_timer_process(fluid_synth_t *synth)
{
fluid_sample_timer_t *st, *stnext;
fluid_sample_timer_t *st;
long msec;
int cont;
unsigned int ticks = fluid_synth_get_ticks(synth);
for(st = synth->sample_timers; st; st = stnext)
for(st = synth->sample_timers; st; st = st->next)
{
/* st may be freed in the callback below. cache it's successor now to avoid use after free */
stnext = st->next;
if(st->isfinished)
{
continue;
@ -535,7 +532,7 @@ fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_c
return NULL;
}
result->starttick = fluid_synth_get_ticks(synth);
fluid_sample_timer_reset(synth, result);
result->isfinished = 0;
result->data = data;
result->callback = callback;
@ -565,6 +562,10 @@ void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer
}
}
void fluid_sample_timer_reset(fluid_synth_t *synth, fluid_sample_timer_t *timer)
{
timer->starttick = fluid_synth_get_ticks(synth);
}
/***************************************************************
*

View file

@ -205,7 +205,7 @@ int fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double le
fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data);
void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer);
void fluid_sample_timer_reset(fluid_synth_t *synth, fluid_sample_timer_t *timer);
void fluid_synth_process_event_queue(fluid_synth_t *synth);