Workaround for jack sample rate mismatch (#607)

During the creation of a jack audio driver, it is checked whether the sample-rate of the settings object matches jack's rate. If not, it was adjusted previously via fluid_synth_set_sample_rate(). Due to the deprecation of that function and removal of real-time capability of the synth.sample-rate setting, a regression was introduced in 5fbddcecc3 causing the synth's sample-rate to be not updated.

This workaround obtains the synth via the settings instance and for now calls the deprecated sample-rate set function.
This commit is contained in:
Tom M 2020-01-19 15:36:15 +01:00 committed by GitHub
parent ba71d6ad9e
commit 3610372ae5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 13 deletions

View file

@ -294,7 +294,9 @@ find_fluid_audio_driver(fluid_settings_t *settings)
* @return The new audio driver instance.
*
* Creates a new audio driver for a given \p synth instance with a defined set
* of configuration \p settings.
* of configuration \p settings. The \p settings instance must be the same that
* you have passed to new_fluid_synth() when creating the \p synth instance.
* Otherwise the behaviour is undefined.
*
* @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,
@ -332,7 +334,9 @@ 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
* \p func to render the audio into the buffers.
* \p func to render the audio into the buffers. If \p func uses a fluid_synth_t \p synth,
* the \p settings instance must be the same that you have passed to new_fluid_synth()
* when creating the \p synth instance. Otherwise the behaviour is undefined.
*
* @note Not as efficient as new_fluid_audio_driver().
*

View file

@ -119,6 +119,7 @@ fluid_audio_driver_t *new_fluid_jack_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_jack_audio_driver(fluid_audio_driver_t *p);
void fluid_jack_audio_driver_settings(fluid_settings_t *settings);
int fluid_jack_obtain_synth(fluid_settings_t *settings, fluid_synth_t **synth);
#endif
#if SNDMAN_SUPPORT

View file

@ -484,7 +484,6 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
}
}
/* Adjust sample rate to match JACK's */
jack_srate = jack_get_sample_rate(client);
FLUID_LOG(FLUID_DBG, "Jack engine sample rate: %lu", jack_srate);
@ -492,16 +491,22 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
if((unsigned long)sample_rate != jack_srate)
{
fluid_synth_t* synth;
if(fluid_jack_obtain_synth(settings, &synth) == FLUID_OK)
{
FLUID_LOG(FLUID_INFO, "Jack sample rate mismatch, adjusting."
" (synth.sample-rate=%lu, jackd=%lu)", (unsigned long)sample_rate, jack_srate);
fluid_settings_setnum(settings, "synth.sample-rate", jack_srate);
}
fluid_synth_set_sample_rate(synth, jack_srate);
/* Changing sample rate is non RT, so make sure we process it and/or other things now */
if(dev->callback == NULL)
fluid_synth_process_event_queue(synth);
}
else
{
fluid_synth_process_event_queue(dev->data);
FLUID_LOG(FLUID_WARN, "Jack sample rate mismatch (synth.sample-rate=%lu, jackd=%lu)"
" impossible to adjust, because the settings object provided to new_fluid_audio_driver2() was not used to create a synth."
, (unsigned long)sample_rate, jack_srate);
}
}
return FLUID_OK;
@ -887,4 +892,18 @@ delete_fluid_jack_midi_driver(fluid_midi_driver_t *p)
FLUID_FREE(dev);
}
int fluid_jack_obtain_synth(fluid_settings_t *settings, fluid_synth_t **synth)
{
void *data;
if(!fluid_settings_is_realtime(settings, "synth.gain") ||
(data = fluid_settings_get_user_data(settings, "synth.gain")) == NULL)
{
return FLUID_FAILED;
}
*synth = data;
return FLUID_OK;
}
#endif /* JACK_SUPPORT */

View file

@ -791,6 +791,40 @@ int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
return FLUID_OK;
}
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name)
{
fluid_setting_node_t *node;
void* retval = NULL;
fluid_return_val_if_fail(settings != NULL, NULL);
fluid_return_val_if_fail(name != NULL, NULL);
fluid_return_val_if_fail(name[0] != '\0', NULL);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_NUM_TYPE)
{
fluid_num_setting_t *setting = &node->num;
retval = setting->data;
}
else if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
retval = setting->data;
}
else if(node->type == FLUID_INT_TYPE)
{
fluid_int_setting_t *setting = &node->i;
retval = setting->data;
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the type of the setting with the given name
*

View file

@ -52,4 +52,6 @@ int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name);
#endif /* _FLUID_SETTINGS_H */

View file

@ -19,6 +19,7 @@ ADD_FLUID_TEST(test_synth_process)
ADD_FLUID_TEST(test_ct2hz)
ADD_FLUID_TEST(test_seq_event_queue_sort)
ADD_FLUID_TEST(test_seq_scale)
ADD_FLUID_TEST(test_jack_obtaining_synth)
# if ( LIBSNDFILE_HASVORBIS )
# ADD_FLUID_TEST(test_sf3_sfont_loading)

View file

@ -0,0 +1,34 @@
#include "test.h"
#include "fluidsynth.h"
#include "fluid_adriver.h"
// The jack driver may need the synth instance to adjust the sample-rate in case it mismatches with
// the sample-rate of the jack driver. However, new_fluid_audio_driver2() does not receive a synth pointer.
// Thus looking up the synth instance must be done via the settings object.
int main(void)
{
#if JACK_SUPPORT
fluid_synth_t *obtained_synth;
fluid_synth_t *expected_synth;
fluid_settings_t *settings = new_fluid_settings();
TEST_ASSERT(settings != NULL);
expected_synth = new_fluid_synth(settings);
TEST_ASSERT(expected_synth != NULL);
TEST_SUCCESS(fluid_jack_obtain_synth(settings, &obtained_synth));
TEST_ASSERT(obtained_synth == expected_synth);
delete_fluid_synth(obtained_synth);
delete_fluid_settings(settings);
obtained_synth = expected_synth = NULL;
settings = new_fluid_settings();
TEST_ASSERT(settings != NULL);
TEST_ASSERT(fluid_jack_obtain_synth(settings, &obtained_synth) == FLUID_FAILED);
delete_fluid_settings(settings);
#endif
return EXIT_SUCCESS;
}