Skip to content

Commit

Permalink
Workaround for jack sample rate mismatch
Browse files Browse the repository at this point in the history
During 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
synth.sample-rate setting, a regression was introduced in
5fbddce 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.
  • Loading branch information
derselbst committed Jan 17, 2020
1 parent e19652d commit 3ae29e7
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 13 deletions.
10 changes: 7 additions & 3 deletions src/drivers/fluid_adriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -331,8 +333,10 @@ new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
* @return The new audio driver instance.
*
* 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.
* audio is sent to audio driver. It is the responsibility of the callback
* \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().
*
Expand Down
1 change: 1 addition & 0 deletions src/drivers/fluid_adriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 25 additions & 10 deletions src/drivers/fluid_jack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -493,15 +492,17 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien

if((unsigned long)sample_rate != jack_srate)
{
fluid_synth_t* synth;
if(fluid_jack_obtain_synth(settings, &synth) != FLUID_OK)
{
FLUID_LOG(FLUID_ERR, "jack driver: Unable to obtain the synth. This is a programming error, please report to upstream.");
goto error_recovery;
}
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);
}

/* 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(dev->data);
" (synth.sample-rate=%lu, jackd=%lu)", (unsigned long)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 */
fluid_synth_process_event_queue(synth);
}

return FLUID_OK;
Expand Down Expand Up @@ -865,7 +866,7 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings,
}

return (fluid_midi_driver_t *)dev;

error_recovery:
delete_fluid_jack_midi_driver((fluid_midi_driver_t *)dev);
return NULL;
Expand All @@ -887,4 +888,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 */
34 changes: 34 additions & 0 deletions src/utils/fluid_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
2 changes: 2 additions & 0 deletions src/utils/fluid_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 27 additions & 0 deletions test/test_jack_obtaining_synth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

#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);
#endif
return EXIT_SUCCESS;
}

0 comments on commit 3ae29e7

Please sign in to comment.