mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-31 21:50:37 +00:00
Merge branch '2.1.x' into master
This commit is contained in:
commit
e04cd572cb
16 changed files with 488 additions and 29 deletions
|
@ -194,8 +194,8 @@ jobs:
|
||||||
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
||||||
pkg-config --list-all
|
pkg-config --list-all
|
||||||
mkdir build && cd build || exit -1
|
mkdir build && cd build || exit -1
|
||||||
cmake -Werror=dev -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) $(CMAKE_FLAGS) -Denable-readline=0 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 .. || exit -1
|
cmake -Werror=dev -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) $(CMAKE_FLAGS) -Denable-readline=0 -Denable-floats=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 .. || exit -1
|
||||||
mingw32-make.exe all || exit -1
|
mingw32-make.exe -j4 all || exit -1
|
||||||
displayName: 'Compile fluidsynth'
|
displayName: 'Compile fluidsynth'
|
||||||
- script: |
|
- script: |
|
||||||
@ECHO ON
|
@ECHO ON
|
||||||
|
@ -204,14 +204,14 @@ jobs:
|
||||||
set PATH=%PATH:C:\Program Files\Git\bin;=%
|
set PATH=%PATH:C:\Program Files\Git\bin;=%
|
||||||
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
||||||
cd build || exit -1
|
cd build || exit -1
|
||||||
mingw32-make.exe check || exit -1
|
mingw32-make.exe -j4 check || exit -1
|
||||||
displayName: 'Execute Unittests'
|
displayName: 'Execute Unittests'
|
||||||
continueOnError: 'true'
|
continueOnError: 'true'
|
||||||
- script: |
|
- script: |
|
||||||
@ECHO ON
|
@ECHO ON
|
||||||
cd build
|
cd build
|
||||||
mingw32-make.exe install || exit -1
|
mingw32-make.exe install || exit -1
|
||||||
xcopy test $(Build.ArtifactStagingDirectory)\bin /s
|
REM xcopy test $(Build.ArtifactStagingDirectory)\bin /s
|
||||||
del $(Build.ArtifactStagingDirectory)\bin\concrt*.dll
|
del $(Build.ArtifactStagingDirectory)\bin\concrt*.dll
|
||||||
del $(Build.ArtifactStagingDirectory)\bin\vcruntime*.dll
|
del $(Build.ArtifactStagingDirectory)\bin\vcruntime*.dll
|
||||||
del $(Build.ArtifactStagingDirectory)\bin\msvcp*.dll
|
del $(Build.ArtifactStagingDirectory)\bin\msvcp*.dll
|
||||||
|
|
|
@ -29,7 +29,7 @@ set ( PACKAGE "fluidsynth" )
|
||||||
# FluidSynth package version
|
# FluidSynth package version
|
||||||
set ( FLUIDSYNTH_VERSION_MAJOR 2 )
|
set ( FLUIDSYNTH_VERSION_MAJOR 2 )
|
||||||
set ( FLUIDSYNTH_VERSION_MINOR 1 )
|
set ( FLUIDSYNTH_VERSION_MINOR 1 )
|
||||||
set ( FLUIDSYNTH_VERSION_MICRO 5 )
|
set ( FLUIDSYNTH_VERSION_MICRO 6 )
|
||||||
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
|
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
|
||||||
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
|
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
\author Josh Green
|
\author Josh Green
|
||||||
\author David Henningsson
|
\author David Henningsson
|
||||||
\author Tom Moebert
|
\author Tom Moebert
|
||||||
\author Copyright © 2003-2020 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
|
\author Copyright © 2003-2021 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
|
||||||
\version Revision 2.1.5
|
\version Revision 2.1.6
|
||||||
\date 2020-09-06
|
\date 2021-01-02
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
.\" along with this program; see the file LICENSE. If not, write to
|
.\" along with this program; see the file LICENSE. If not, write to
|
||||||
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
.\"
|
.\"
|
||||||
.TH FluidSynth 1 "Feb 16, 2020"
|
.TH FluidSynth 1 "Jan 1, 2021"
|
||||||
.\" Please update the above date whenever this man page is modified.
|
.\" Please update the above date whenever this man page is modified.
|
||||||
.\"
|
.\"
|
||||||
.\" Some roff macros, for reference:
|
.\" Some roff macros, for reference:
|
||||||
|
|
|
@ -1115,7 +1115,7 @@ void
|
||||||
print_welcome()
|
print_welcome()
|
||||||
{
|
{
|
||||||
printf("FluidSynth runtime version %s\n"
|
printf("FluidSynth runtime version %s\n"
|
||||||
"Copyright (C) 2000-2020 Peter Hanappe and others.\n"
|
"Copyright (C) 2000-2021 Peter Hanappe and others.\n"
|
||||||
"Distributed under the LGPL license.\n"
|
"Distributed under the LGPL license.\n"
|
||||||
"SoundFont(R) is a registered trademark of Creative Technology Ltd.\n\n",
|
"SoundFont(R) is a registered trademark of Creative Technology Ltd.\n\n",
|
||||||
fluid_version_str());
|
fluid_version_str());
|
||||||
|
|
|
@ -1718,6 +1718,9 @@ delete_fluid_player(fluid_player_t *player)
|
||||||
|
|
||||||
fluid_return_if_fail(player != NULL);
|
fluid_return_if_fail(player != NULL);
|
||||||
|
|
||||||
|
fluid_settings_callback_int(player->synth->settings, "player.reset-synth",
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
fluid_player_stop(player);
|
fluid_player_stop(player);
|
||||||
fluid_player_reset(player);
|
fluid_player_reset(player);
|
||||||
|
|
||||||
|
|
|
@ -606,10 +606,15 @@ static FLUID_INLINE unsigned int fluid_synth_get_min_note_length_LOCAL(fluid_syn
|
||||||
* @param settings Configuration parameters to use (used directly).
|
* @param settings Configuration parameters to use (used directly).
|
||||||
* @return New FluidSynth instance or NULL on error
|
* @return New FluidSynth instance or NULL on error
|
||||||
*
|
*
|
||||||
* @note The @p settings parameter is used directly and should freed after
|
* @note The @p settings parameter is used directly, but the synth does not take ownership of it.
|
||||||
* the synth has been deleted. Further note that you may modify FluidSettings of the
|
* Hence, the caller is responsible for freeing it, when no longer needed.
|
||||||
|
* Further note that you may modify FluidSettings of the
|
||||||
* @p settings instance. However, only those FluidSettings marked as 'realtime' will
|
* @p settings instance. However, only those FluidSettings marked as 'realtime' will
|
||||||
* affect the synth immediately. See the \ref fluidsettings for more details.
|
* affect the synth immediately. See the \ref fluidsettings for more details.
|
||||||
|
*
|
||||||
|
* @warning The @p settings object should only be used by a single synth at a time. I.e. creating
|
||||||
|
* multiple synth instances with a single @p settings object causes undefined behavior. Once the
|
||||||
|
* "single synth" has been deleted, you may use the @p settings object again for another synth.
|
||||||
*/
|
*/
|
||||||
fluid_synth_t *
|
fluid_synth_t *
|
||||||
new_fluid_synth(fluid_settings_t *settings)
|
new_fluid_synth(fluid_settings_t *settings)
|
||||||
|
@ -1018,6 +1023,50 @@ delete_fluid_synth(fluid_synth_t *synth)
|
||||||
|
|
||||||
fluid_profiling_print();
|
fluid_profiling_print();
|
||||||
|
|
||||||
|
/* unregister all real-time settings callback, to avoid a use-after-free when changing those settings after
|
||||||
|
* this synth has been deleted*/
|
||||||
|
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.gain",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_int(synth->settings, "synth.polyphony",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_int(synth->settings, "synth.device-id",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.percussion",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.sustained",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.released",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.age",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.volume",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.overflow.important",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_str(synth->settings, "synth.overflow.important-channels",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.reverb.room-size",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.reverb.damp",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.reverb.width",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.reverb.level",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_int(synth->settings, "synth.reverb.active",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_int(synth->settings, "synth.chorus.active",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_int(synth->settings, "synth.chorus.nr",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.chorus.level",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.chorus.depth",
|
||||||
|
NULL, NULL);
|
||||||
|
fluid_settings_callback_num(synth->settings, "synth.chorus.speed",
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
/* turn off all voices, needed to unload SoundFont data */
|
/* turn off all voices, needed to unload SoundFont data */
|
||||||
if(synth->voice != NULL)
|
if(synth->voice != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1030,6 +1079,12 @@ delete_fluid_synth(fluid_synth_t *synth)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WARNING: A this point we must ensure that the reference counter
|
||||||
|
of any soundfont sample owned by any rvoice belonging to the voice
|
||||||
|
are correctly decremented. This is the contrary part to
|
||||||
|
to fluid_voice_init() where the sample's reference counter is
|
||||||
|
incremented.
|
||||||
|
*/
|
||||||
fluid_voice_unlock_rvoice(voice);
|
fluid_voice_unlock_rvoice(voice);
|
||||||
fluid_voice_overflow_rvoice_finished(voice);
|
fluid_voice_overflow_rvoice_finished(voice);
|
||||||
|
|
||||||
|
@ -1082,6 +1137,18 @@ delete_fluid_synth(fluid_synth_t *synth)
|
||||||
|
|
||||||
delete_fluid_list(synth->loaders);
|
delete_fluid_list(synth->loaders);
|
||||||
|
|
||||||
|
/* wait for and delete all the lazy sfont unloading timers */
|
||||||
|
|
||||||
|
for(list = synth->fonts_to_be_unloaded; list; list = fluid_list_next(list))
|
||||||
|
{
|
||||||
|
fluid_timer_t* timer = fluid_list_get(list);
|
||||||
|
// explicitly join to wait for the unload really to happen
|
||||||
|
fluid_timer_join(timer);
|
||||||
|
// delete_fluid_timer alone would stop the timer, even if it had not unloaded the soundfont yet
|
||||||
|
delete_fluid_timer(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_fluid_list(synth->fonts_to_be_unloaded);
|
||||||
|
|
||||||
if(synth->channel != NULL)
|
if(synth->channel != NULL)
|
||||||
{
|
{
|
||||||
|
@ -4653,7 +4720,21 @@ fluid_synth_check_finished_voices(fluid_synth_t *synth)
|
||||||
}
|
}
|
||||||
else if(synth->voice[j]->overflow_rvoice == fv)
|
else if(synth->voice[j]->overflow_rvoice == fv)
|
||||||
{
|
{
|
||||||
|
/* Unlock the overflow_rvoice of the voice.
|
||||||
|
Decrement the reference count of the sample owned by this
|
||||||
|
rvoice.
|
||||||
|
*/
|
||||||
fluid_voice_overflow_rvoice_finished(synth->voice[j]);
|
fluid_voice_overflow_rvoice_finished(synth->voice[j]);
|
||||||
|
|
||||||
|
/* Decrement synth active voice count. Must not be incorporated
|
||||||
|
in fluid_voice_overflow_rvoice_finished() because
|
||||||
|
fluid_voice_overflow_rvoice_finished() is called also
|
||||||
|
at synth destruction and in this case the variable should be
|
||||||
|
accessed via voice->channel->synth->active_voice_count.
|
||||||
|
And for certain voices which are not playing, the field
|
||||||
|
voice->channel is NULL.
|
||||||
|
*/
|
||||||
|
synth->active_voice_count--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5161,11 +5242,25 @@ fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unload a SoundFont.
|
* Schedule a SoundFont for unloading.
|
||||||
|
*
|
||||||
|
* If the SoundFont isn't used anymore by any playing voices, it will be unloaded immediately.
|
||||||
|
*
|
||||||
|
* If any samples of the given SoundFont are still required by active voices,
|
||||||
|
* the SoundFont will be unloaded in a lazy manner, once those voices have finished synthesizing.
|
||||||
|
* If you call delete_fluid_synth(), all voices will be destroyed and the SoundFont
|
||||||
|
* will be unloaded in any case.
|
||||||
|
* Once this function returned, fluid_synth_sfcount() and similar functions will behave as if
|
||||||
|
* the SoundFont has already been unloaded, even though the lazy-unloading is still pending.
|
||||||
|
*
|
||||||
|
* @note This lazy-unloading mechanism was broken between FluidSynth 1.1.4 and 2.1.5 . As a
|
||||||
|
* consequence, SoundFonts scheduled for lazy-unloading may be never freed under certain
|
||||||
|
* conditions. Calling delete_fluid_synth() does not recover this situation either.
|
||||||
|
*
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @param id ID of SoundFont to unload
|
* @param id ID of SoundFont to unload
|
||||||
* @param reset_presets TRUE to re-assign presets for all MIDI channels
|
* @param reset_presets TRUE to re-assign presets for all MIDI channels
|
||||||
* @return #FLUID_OK on success, #FLUID_FAILED on error
|
* @return #FLUID_OK if the given @p id was found, #FLUID_FAILED otherwise.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets)
|
fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets)
|
||||||
|
@ -5226,7 +5321,8 @@ fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont)
|
||||||
} /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
|
} /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_fluid_timer(100, fluid_synth_sfunload_callback, sfont, TRUE, TRUE, FALSE);
|
fluid_timer_t* timer = new_fluid_timer(100, fluid_synth_sfunload_callback, sfont, TRUE, FALSE, FALSE);
|
||||||
|
synth->fonts_to_be_unloaded = fluid_list_prepend(synth->fonts_to_be_unloaded, timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ struct _fluid_synth_t
|
||||||
fluid_list_t *loaders; /**< the SoundFont loaders */
|
fluid_list_t *loaders; /**< the SoundFont loaders */
|
||||||
fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
||||||
int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
|
int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
|
||||||
|
fluid_list_t *fonts_to_be_unloaded; /**< list of timers that try to unload a soundfont */
|
||||||
|
|
||||||
float gain; /**< master gain */
|
float gain; /**< master gain */
|
||||||
fluid_channel_t **channel; /**< the channels */
|
fluid_channel_t **channel; /**< the channels */
|
||||||
|
|
|
@ -174,6 +174,7 @@ static void fluid_voice_swap_rvoice(fluid_voice_t *voice)
|
||||||
voice->can_access_rvoice = voice->can_access_overflow_rvoice;
|
voice->can_access_rvoice = voice->can_access_overflow_rvoice;
|
||||||
voice->overflow_rvoice = rtemp;
|
voice->overflow_rvoice = rtemp;
|
||||||
voice->can_access_overflow_rvoice = ctemp;
|
voice->can_access_overflow_rvoice = ctemp;
|
||||||
|
voice->overflow_sample = voice->sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fluid_voice_initialize_rvoice(fluid_voice_t *voice, fluid_real_t output_rate)
|
static void fluid_voice_initialize_rvoice(fluid_voice_t *voice, fluid_real_t output_rate)
|
||||||
|
@ -242,6 +243,7 @@ new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate)
|
||||||
voice->eventhandler = handler;
|
voice->eventhandler = handler;
|
||||||
voice->channel = NULL;
|
voice->channel = NULL;
|
||||||
voice->sample = NULL;
|
voice->sample = NULL;
|
||||||
|
voice->overflow_sample = NULL;
|
||||||
voice->output_rate = output_rate;
|
voice->output_rate = output_rate;
|
||||||
|
|
||||||
/* Initialize both the rvoice and overflow_rvoice */
|
/* Initialize both the rvoice and overflow_rvoice */
|
||||||
|
@ -321,12 +323,13 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
|
||||||
voice->has_noteoff = 0;
|
voice->has_noteoff = 0;
|
||||||
UPDATE_RVOICE0(fluid_rvoice_reset);
|
UPDATE_RVOICE0(fluid_rvoice_reset);
|
||||||
|
|
||||||
/* Increment the reference count of the sample to prevent the
|
/*
|
||||||
unloading of the soundfont while this voice is playing,
|
We increment the reference count of the sample to indicate that this
|
||||||
once for us and once for the rvoice. */
|
sample is about to be owned by the rvoice. This will prevent the
|
||||||
|
unloading of the soundfont while this rvoice is playing.
|
||||||
|
*/
|
||||||
fluid_sample_incr_ref(sample);
|
fluid_sample_incr_ref(sample);
|
||||||
fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample);
|
fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample);
|
||||||
fluid_sample_incr_ref(sample);
|
|
||||||
voice->sample = sample;
|
voice->sample = sample;
|
||||||
|
|
||||||
i = fluid_channel_get_interp_method(channel);
|
i = fluid_channel_get_interp_method(channel);
|
||||||
|
@ -1413,12 +1416,20 @@ fluid_voice_kill_excl(fluid_voice_t *voice)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by fluid_synth when the overflow rvoice can be reclaimed.
|
* Unlock the overflow rvoice of the voice.
|
||||||
|
* Decrement the reference count of the sample owned by this rvoice.
|
||||||
|
*
|
||||||
|
* Called by fluid_synth when the overflow rvoice has finished by itself.
|
||||||
|
* Must be called also explicitly at synth destruction to ensure that
|
||||||
|
* the soundfont be unloaded successfully.
|
||||||
*/
|
*/
|
||||||
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice)
|
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice)
|
||||||
{
|
{
|
||||||
voice->can_access_overflow_rvoice = 1;
|
voice->can_access_overflow_rvoice = 1;
|
||||||
fluid_voice_sample_unref(&voice->overflow_rvoice->dsp.sample);
|
|
||||||
|
/* Decrement the reference count of the sample to indicate
|
||||||
|
that this sample isn't owned by the rvoice anymore */
|
||||||
|
fluid_voice_sample_unref(&voice->overflow_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1446,17 +1457,14 @@ fluid_voice_stop(fluid_voice_t *voice)
|
||||||
|
|
||||||
voice->chan = NO_CHANNEL;
|
voice->chan = NO_CHANNEL;
|
||||||
|
|
||||||
if(voice->can_access_rvoice)
|
/* Decrement the reference count of the sample, to indicate
|
||||||
{
|
that this sample isn't owned by the rvoice anymore.
|
||||||
fluid_voice_sample_unref(&voice->rvoice->dsp.sample);
|
*/
|
||||||
}
|
fluid_voice_sample_unref(&voice->sample);
|
||||||
|
|
||||||
voice->status = FLUID_VOICE_OFF;
|
voice->status = FLUID_VOICE_OFF;
|
||||||
voice->has_noteoff = 1;
|
voice->has_noteoff = 1;
|
||||||
|
|
||||||
/* Decrement the reference count of the sample. */
|
|
||||||
fluid_voice_sample_unref(&voice->sample);
|
|
||||||
|
|
||||||
/* Decrement voice count */
|
/* Decrement voice count */
|
||||||
voice->channel->synth->active_voice_count--;
|
voice->channel->synth->active_voice_count--;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct _fluid_voice_t
|
||||||
fluid_rvoice_eventhandler_t *eventhandler;
|
fluid_rvoice_eventhandler_t *eventhandler;
|
||||||
fluid_zone_range_t *zone_range; /* instrument zone range*/
|
fluid_zone_range_t *zone_range; /* instrument zone range*/
|
||||||
fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
|
fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
|
||||||
|
fluid_sample_t *overflow_sample; /* Pointer to sample (dupe in overflow_rvoice) */
|
||||||
|
|
||||||
unsigned int start_time;
|
unsigned int start_time;
|
||||||
int mod_count;
|
int mod_count;
|
||||||
|
|
|
@ -909,6 +909,10 @@ fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hint
|
||||||
* @param settings a settings object
|
* @param settings a settings object
|
||||||
* @param name a setting's name
|
* @param name a setting's name
|
||||||
* @return TRUE if the setting is changeable in real-time, FALSE otherwise
|
* @return TRUE if the setting is changeable in real-time, FALSE otherwise
|
||||||
|
*
|
||||||
|
* @note Before using this function, make sure the @p settings object has already been used to create
|
||||||
|
* a synthesizer, a MIDI driver, an audio driver, a MIDI player, or a command handler (depending on
|
||||||
|
* which settings you want to query).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
|
fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
|
||||||
|
|
|
@ -60,6 +60,10 @@ typedef struct
|
||||||
struct _fluid_timer_t
|
struct _fluid_timer_t
|
||||||
{
|
{
|
||||||
long msec;
|
long msec;
|
||||||
|
|
||||||
|
// Pointer to a function to be executed by the timer.
|
||||||
|
// This field is set to NULL once the timer is finished to indicate completion.
|
||||||
|
// This allows for timed waits, rather than waiting forever as fluid_timer_join() does.
|
||||||
fluid_timer_callback_t callback;
|
fluid_timer_callback_t callback;
|
||||||
void *data;
|
void *data;
|
||||||
fluid_thread_t *thread;
|
fluid_thread_t *thread;
|
||||||
|
@ -1160,6 +1164,7 @@ fluid_timer_run(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
||||||
|
timer->callback = NULL;
|
||||||
|
|
||||||
if(timer->auto_destroy)
|
if(timer->auto_destroy)
|
||||||
{
|
{
|
||||||
|
@ -1253,6 +1258,19 @@ fluid_timer_join(fluid_timer_t *timer)
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fluid_timer_is_running(const fluid_timer_t *timer)
|
||||||
|
{
|
||||||
|
// for unit test usage only
|
||||||
|
return timer->callback != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
long fluid_timer_get_interval(const fluid_timer_t * timer)
|
||||||
|
{
|
||||||
|
// for unit test usage only
|
||||||
|
return timer->msec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
|
|
|
@ -235,6 +235,8 @@ fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback,
|
||||||
void delete_fluid_timer(fluid_timer_t *timer);
|
void delete_fluid_timer(fluid_timer_t *timer);
|
||||||
int fluid_timer_join(fluid_timer_t *timer);
|
int fluid_timer_join(fluid_timer_t *timer);
|
||||||
int fluid_timer_stop(fluid_timer_t *timer);
|
int fluid_timer_stop(fluid_timer_t *timer);
|
||||||
|
int fluid_timer_is_running(const fluid_timer_t *timer);
|
||||||
|
long fluid_timer_get_interval(const fluid_timer_t * timer);
|
||||||
|
|
||||||
// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)
|
// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)
|
||||||
#define NEW_GLIB_THREAD_API GLIB_CHECK_VERSION(2,32,0)
|
#define NEW_GLIB_THREAD_API GLIB_CHECK_VERSION(2,32,0)
|
||||||
|
|
|
@ -13,6 +13,7 @@ ADD_FLUID_TEST(test_sample_rate_change)
|
||||||
ADD_FLUID_TEST(test_preset_sample_loading)
|
ADD_FLUID_TEST(test_preset_sample_loading)
|
||||||
ADD_FLUID_TEST(test_preset_pinning)
|
ADD_FLUID_TEST(test_preset_pinning)
|
||||||
ADD_FLUID_TEST(test_bug_635)
|
ADD_FLUID_TEST(test_bug_635)
|
||||||
|
ADD_FLUID_TEST(test_settings_unregister_callback)
|
||||||
ADD_FLUID_TEST(test_pointer_alignment)
|
ADD_FLUID_TEST(test_pointer_alignment)
|
||||||
ADD_FLUID_TEST(test_seqbind_unregister)
|
ADD_FLUID_TEST(test_seqbind_unregister)
|
||||||
ADD_FLUID_TEST(test_synth_chorus_reverb)
|
ADD_FLUID_TEST(test_synth_chorus_reverb)
|
||||||
|
@ -20,6 +21,7 @@ ADD_FLUID_TEST(test_snprintf)
|
||||||
ADD_FLUID_TEST(test_synth_process)
|
ADD_FLUID_TEST(test_synth_process)
|
||||||
ADD_FLUID_TEST(test_ct2hz)
|
ADD_FLUID_TEST(test_ct2hz)
|
||||||
ADD_FLUID_TEST(test_sample_validate)
|
ADD_FLUID_TEST(test_sample_validate)
|
||||||
|
ADD_FLUID_TEST(test_sfont_unloading)
|
||||||
ADD_FLUID_TEST(test_seq_event_queue_sort)
|
ADD_FLUID_TEST(test_seq_event_queue_sort)
|
||||||
ADD_FLUID_TEST(test_seq_scale)
|
ADD_FLUID_TEST(test_seq_scale)
|
||||||
ADD_FLUID_TEST(test_seq_evt_order)
|
ADD_FLUID_TEST(test_seq_evt_order)
|
||||||
|
|
95
test/test_settings_unregister_callback.c
Normal file
95
test/test_settings_unregister_callback.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
#include "fluidsynth.h"
|
||||||
|
#include "fluidsynth_priv.h"
|
||||||
|
#include "fluid_synth.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static fluid_list_t* realtime_int_settings = NULL;
|
||||||
|
static fluid_list_t* realtime_str_settings = NULL;
|
||||||
|
static fluid_list_t* realtime_num_settings = NULL;
|
||||||
|
|
||||||
|
void iter_func (void *data, const char *name, int type)
|
||||||
|
{
|
||||||
|
if(fluid_settings_is_realtime(data, name))
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case FLUID_INT_TYPE:
|
||||||
|
realtime_int_settings = fluid_list_prepend(realtime_int_settings, FLUID_STRDUP(name));
|
||||||
|
break;
|
||||||
|
case FLUID_STR_TYPE:
|
||||||
|
realtime_str_settings = fluid_list_prepend(realtime_str_settings, FLUID_STRDUP(name));
|
||||||
|
break;
|
||||||
|
case FLUID_NUM_TYPE:
|
||||||
|
realtime_num_settings = fluid_list_prepend(realtime_num_settings, FLUID_STRDUP(name));
|
||||||
|
break;
|
||||||
|
case FLUID_SET_TYPE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TEST_ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this test should make sure that sample rate changed are handled correctly
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
fluid_list_t* list;
|
||||||
|
fluid_player_t* player;
|
||||||
|
fluid_synth_t *synth;
|
||||||
|
fluid_settings_t *settings = new_fluid_settings();
|
||||||
|
TEST_ASSERT(settings != NULL);
|
||||||
|
|
||||||
|
synth = new_fluid_synth(settings);
|
||||||
|
TEST_ASSERT(synth != NULL);
|
||||||
|
|
||||||
|
player = new_fluid_player(synth);
|
||||||
|
TEST_ASSERT(player != NULL);
|
||||||
|
|
||||||
|
// see which of the objects above has registered a realtime setting
|
||||||
|
fluid_settings_foreach(settings, settings, iter_func);
|
||||||
|
|
||||||
|
// delete the objects
|
||||||
|
delete_fluid_player(player);
|
||||||
|
delete_fluid_synth(synth);
|
||||||
|
|
||||||
|
// and now, start making changes to those realtime settings
|
||||||
|
// Anything below fluidsynth 2.1.5 will crash
|
||||||
|
|
||||||
|
for(list = realtime_int_settings; list; list = fluid_list_next(list))
|
||||||
|
{
|
||||||
|
int min, max;
|
||||||
|
char* name = fluid_list_get(list);
|
||||||
|
TEST_SUCCESS(fluid_settings_getint_range(settings, name, &min, &max));
|
||||||
|
TEST_SUCCESS(fluid_settings_setint(settings, name, min));
|
||||||
|
FLUID_FREE(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_fluid_list(realtime_int_settings);
|
||||||
|
|
||||||
|
for(list = realtime_num_settings; list; list = fluid_list_next(list))
|
||||||
|
{
|
||||||
|
double min, max;
|
||||||
|
char* name = fluid_list_get(list);
|
||||||
|
TEST_SUCCESS(fluid_settings_getnum_range(settings, name, &min, &max));
|
||||||
|
TEST_SUCCESS(fluid_settings_setnum(settings, name, min));
|
||||||
|
FLUID_FREE(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_fluid_list(realtime_num_settings);
|
||||||
|
|
||||||
|
|
||||||
|
for(list = realtime_str_settings; list; list = fluid_list_next(list))
|
||||||
|
{
|
||||||
|
char* name = fluid_list_get(list);
|
||||||
|
TEST_SUCCESS(fluid_settings_setstr(settings, name, "ABCDEFG"));
|
||||||
|
FLUID_FREE(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_fluid_list(realtime_str_settings);
|
||||||
|
|
||||||
|
delete_fluid_settings(settings);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
229
test/test_sfont_unloading.c
Normal file
229
test/test_sfont_unloading.c
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
#include "fluidsynth.h"
|
||||||
|
#include "synth/fluid_synth.h"
|
||||||
|
#include "utils/fluid_sys.h"
|
||||||
|
|
||||||
|
void wait_and_free(fluid_synth_t* synth, int id, const char* calling_func)
|
||||||
|
{
|
||||||
|
fluid_list_t *list, *list_orig;
|
||||||
|
list_orig = list = synth->fonts_to_be_unloaded;
|
||||||
|
synth->fonts_to_be_unloaded = NULL;
|
||||||
|
delete_fluid_synth(synth);
|
||||||
|
|
||||||
|
for(; list; list = fluid_list_next(list))
|
||||||
|
{
|
||||||
|
fluid_timer_t* timer = fluid_list_get(list);
|
||||||
|
FLUID_LOG(FLUID_INFO, "%s(): Start waiting for soundfont %d to unload", calling_func, id);
|
||||||
|
if(fluid_timer_is_running(timer))
|
||||||
|
{
|
||||||
|
/* timer still running, wait a bit*/
|
||||||
|
fluid_msleep(50 * fluid_timer_get_interval(timer));
|
||||||
|
TEST_ASSERT(!fluid_timer_is_running(timer));
|
||||||
|
}
|
||||||
|
delete_fluid_timer(timer);
|
||||||
|
FLUID_LOG(FLUID_INFO, "%s(): End waiting for soundfont %d to unload", calling_func, id);
|
||||||
|
}
|
||||||
|
delete_fluid_list(list_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_without_rendering(fluid_settings_t* settings)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
fluid_synth_t *synth = new_fluid_synth(settings);
|
||||||
|
TEST_ASSERT(synth != NULL);
|
||||||
|
|
||||||
|
TEST_ASSERT(fluid_is_soundfont(TEST_SOUNDFONT) == TRUE);
|
||||||
|
|
||||||
|
// load a sfont to synth
|
||||||
|
TEST_SUCCESS(id = fluid_synth_sfload(synth, TEST_SOUNDFONT, 1));
|
||||||
|
// one sfont loaded
|
||||||
|
TEST_ASSERT(fluid_synth_sfcount(synth) == 1);
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteon(synth, 0, 60, 127));
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_sfunload(synth, id, 1));
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteoff(synth, 0, 60));
|
||||||
|
|
||||||
|
// there must be one font scheduled for lazy unloading
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
|
||||||
|
wait_and_free(synth, id, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this should work fine after applying JJCs fix a4ac56502fec5f0c20a60187d965c94ba1dc81c2
|
||||||
|
static void test_after_polyphony_exceeded(fluid_settings_t* settings)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
fluid_synth_t *synth = new_fluid_synth(settings);
|
||||||
|
TEST_ASSERT(synth != NULL);
|
||||||
|
|
||||||
|
TEST_ASSERT(fluid_is_soundfont(TEST_SOUNDFONT) == TRUE);
|
||||||
|
|
||||||
|
// load a sfont to synth
|
||||||
|
TEST_SUCCESS(id = fluid_synth_sfload(synth, TEST_SOUNDFONT, 1));
|
||||||
|
// one sfont loaded
|
||||||
|
TEST_ASSERT(fluid_synth_sfcount(synth) == 1);
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteon(synth, 0, 60, 127));
|
||||||
|
FLUID_LOG(FLUID_INFO, "test_after_polyphony_exceeded(): note on C4, voice count=%d",
|
||||||
|
fluid_synth_get_active_voice_count(synth));
|
||||||
|
|
||||||
|
// need to render a bit to make synth->ticks_since_start advance, to make the previous voice "killable"
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, 2048, 0, NULL, 0, NULL));
|
||||||
|
|
||||||
|
// polyphony exceeded - killing the killable voice from above
|
||||||
|
TEST_SUCCESS(fluid_synth_noteon(synth, 0, 61, 127));
|
||||||
|
|
||||||
|
// need to render again, to make the synth thread assign rvoice->dsp.sample, so that sample_unref() later really unrefs
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, 2048, 0, NULL, 0, NULL));
|
||||||
|
FLUID_LOG(FLUID_INFO, "test_after_polyphony_exceeded(): note on C#4, voice count=%d",
|
||||||
|
fluid_synth_get_active_voice_count(synth));
|
||||||
|
|
||||||
|
FLUID_LOG(FLUID_INFO, "test_after_polyphony_exceeded(): unload sounfont");
|
||||||
|
TEST_SUCCESS(fluid_synth_sfunload(synth, id, 1));
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteoff(synth, 0, 61));
|
||||||
|
|
||||||
|
// need to render yet again, to make the synth thread release the rvoice so it can be reclaimed by
|
||||||
|
// fluid_synth_check_finished_voices()
|
||||||
|
// need to render may more samples this time, so the voice makes it pass the release phase...
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, 204800, 0, NULL, 0, NULL));
|
||||||
|
|
||||||
|
// make any API call to execute fluid_synth_check_finished_voices()
|
||||||
|
FLUID_LOG(FLUID_INFO, "test_after_polyphony_exceeded(): note off C#4, voice count=%d",
|
||||||
|
fluid_synth_get_active_voice_count(synth));
|
||||||
|
|
||||||
|
// there must be one font scheduled for lazy unloading
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
|
||||||
|
wait_and_free(synth, id, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_default_polyphony(fluid_settings_t* settings, int with_rendering)
|
||||||
|
{
|
||||||
|
enum { BUFSIZE = 128 };
|
||||||
|
fluid_voice_t* buf[BUFSIZE];
|
||||||
|
|
||||||
|
int id;
|
||||||
|
fluid_synth_t *synth = new_fluid_synth(settings);
|
||||||
|
TEST_ASSERT(synth != NULL);
|
||||||
|
|
||||||
|
TEST_ASSERT(fluid_is_soundfont(TEST_SOUNDFONT) == TRUE);
|
||||||
|
|
||||||
|
// load a sfont to synth
|
||||||
|
TEST_SUCCESS(id = fluid_synth_sfload(synth, TEST_SOUNDFONT, 1));
|
||||||
|
// one sfont loaded
|
||||||
|
TEST_ASSERT(fluid_synth_sfcount(synth) == 1);
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteon(synth, 0, 60, 127));
|
||||||
|
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, fluid_synth_get_internal_bufsize(synth), 0, NULL, 0, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_noteon(synth, 0, 61, 127));
|
||||||
|
|
||||||
|
fluid_synth_get_voicelist(synth, buf, BUFSIZE, -1);
|
||||||
|
|
||||||
|
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 4);
|
||||||
|
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
// make the synth thread assign rvoice->dsp.sample
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, 2 * fluid_synth_get_internal_bufsize(synth), 0, NULL, 0, NULL));
|
||||||
|
|
||||||
|
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded == NULL);
|
||||||
|
|
||||||
|
TEST_SUCCESS(fluid_synth_sfunload(synth, id, 1));
|
||||||
|
|
||||||
|
// now, there must be one font scheduled for lazy unloading
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
TEST_ASSERT(fluid_timer_is_running(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
|
||||||
|
// noteoff the second note and render something
|
||||||
|
TEST_SUCCESS(fluid_synth_noteoff(synth, 0, 61));
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, fluid_synth_get_internal_bufsize(synth), 0, NULL, 0, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
// still 4 because key 61 is playing in release phase now
|
||||||
|
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 4);
|
||||||
|
// must be still running
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
TEST_ASSERT(fluid_timer_is_running(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
|
||||||
|
// noteoff the first note and render something
|
||||||
|
TEST_SUCCESS(fluid_synth_noteoff(synth, 0, 60));
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, fluid_synth_get_internal_bufsize(synth), 0, NULL, 0, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
// still 4 because keys 60 + 61 are playing in release phase now
|
||||||
|
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 4);
|
||||||
|
// must be still running
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
TEST_ASSERT(fluid_timer_is_running(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
// render enough, to make the synth thread release the rvoice so it can be reclaimed by
|
||||||
|
// fluid_synth_check_finished_voices()
|
||||||
|
TEST_SUCCESS(fluid_synth_process(synth, 2048000, 0, NULL, 0, NULL));
|
||||||
|
|
||||||
|
// this API call should reclaim the rvoices and call fluid_voice_stop()
|
||||||
|
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT(synth->fonts_to_be_unloaded != NULL);
|
||||||
|
if(with_rendering)
|
||||||
|
{
|
||||||
|
// We want to see that the timer thread unloads the soundfont before we call delete_fluid_synth().
|
||||||
|
// Wait to give the timer thread a chance to unload and finish.
|
||||||
|
fluid_msleep(10 * fluid_timer_get_interval(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
TEST_ASSERT(!fluid_timer_is_running(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TEST_ASSERT(fluid_timer_is_running(fluid_list_get(synth->fonts_to_be_unloaded)));
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_and_free(synth, id, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this tests the soundfont loading API of the synth.
|
||||||
|
// might be expanded to test the soundfont loader as well...
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
fluid_settings_t *settings = new_fluid_settings();
|
||||||
|
TEST_ASSERT(settings != NULL);
|
||||||
|
|
||||||
|
FLUID_LOG(FLUID_INFO, "Begin test_default_polyphony() with rendering");
|
||||||
|
test_default_polyphony(settings, TRUE);
|
||||||
|
FLUID_LOG(FLUID_INFO, "End test_default_polyphony()\n");
|
||||||
|
|
||||||
|
FLUID_LOG(FLUID_INFO, "Begin test_default_polyphony() without rendering");
|
||||||
|
test_default_polyphony(settings, FALSE);
|
||||||
|
FLUID_LOG(FLUID_INFO, "End test_default_polyphony()\n");
|
||||||
|
|
||||||
|
fluid_settings_setint(settings, "synth.polyphony", 2);
|
||||||
|
|
||||||
|
FLUID_LOG(FLUID_INFO, "Begin test_after_polyphony_exceeded()");
|
||||||
|
test_after_polyphony_exceeded(settings);
|
||||||
|
FLUID_LOG(FLUID_INFO, "End test_after_polyphony_exceeded()\n");
|
||||||
|
|
||||||
|
FLUID_LOG(FLUID_INFO, "Begin test_without_rendering()");
|
||||||
|
test_without_rendering(settings);
|
||||||
|
FLUID_LOG(FLUID_INFO, "End test_without_rendering()");
|
||||||
|
|
||||||
|
delete_fluid_settings(settings);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
Reference in a new issue