From 0d627c7c0b8aef4ece3d166d4036cf2e622dbd3f Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 16 Apr 2021 18:21:36 +0800 Subject: [PATCH 1/2] wasapi: use device period size in shared mode. --- src/drivers/fluid_wasapi.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/drivers/fluid_wasapi.c b/src/drivers/fluid_wasapi.c index 8eebe349..ab469090 100644 --- a/src/drivers/fluid_wasapi.c +++ b/src/drivers/fluid_wasapi.c @@ -89,8 +89,15 @@ static const IID _IID_IAudioRenderClient = * audio.periods still determines the buffer size, but has no direct impact on * the latency (at least according to Microsoft). The valid range for * audio.period-size may vary depending on the driver and sample rate. + * - In shared mode, audio.period-size is completely ignored. Instead, a value + * provided by the audio driver is used. In theory this means the latency in + * shared mode is out of fluidsynth's control, but you may still increase + * audio.periods for a larger buffer to fix buffer underruns in case there + * are any. * - The sample rate and sample format of fluidsynth must be supported by the - * audio device in exclusive mode. Otherwise driver creation will fail. + * audio device in exclusive mode. Otherwise driver creation will fail. Use + * `fluidsynth ---query-audio-devices` to find out the modes supported by + * the soundcards installed on the system. * - In shared mode, if the sample rate of the synth doesn't match what is * configured in the 'advanced' tab of the audio device properties dialog, * Windows will automatically resample the output (obviously). Windows @@ -331,7 +338,7 @@ void fluid_wasapi_audio_driver_settings(fluid_settings_t *settings) static DWORD WINAPI fluid_wasapi_audio_run(void *p) { fluid_wasapi_audio_driver_t *dev = (fluid_wasapi_audio_driver_t *)p; - DWORD time_to_sleep = dev->buffer_duration * 1000 / 2; + DWORD time_to_sleep; UINT32 pos; DWORD len; void *channels_out[2]; @@ -349,11 +356,6 @@ static DWORD WINAPI fluid_wasapi_audio_run(void *p) int needs_com_uninit = FALSE; int i; - if(time_to_sleep < 1) - { - time_to_sleep = 1; - } - /* Clear format structure */ ZeroMemory(&wfx, sizeof(WAVEFORMATEXTENSIBLE)); @@ -417,9 +419,19 @@ static DWORD WINAPI fluid_wasapi_audio_run(void *p) } else { + fluid_long_long_t defp; share_mode = AUDCLNT_SHAREMODE_SHARED; FLUID_LOG(FLUID_DBG, "wasapi: using shared mode."); dev->periods_reftime = 0; + + //use default period size of the device + if(SUCCEEDED(IAudioClient_GetDevicePeriod(dev->aucl, &defp, NULL))) + { + dev->period_size = (int)(defp / 1e7 * dev->sample_rate); + dev->buffer_duration = dev->periods * dev->period_size / dev->sample_rate; + dev->buffer_duration_reftime = (fluid_long_long_t)(dev->buffer_duration * 1e7 + .5); + FLUID_LOG(FLUID_DBG, "wasapi: using device period size: %d", dev->period_size); + } } ret = IAudioClient_IsFormatSupported(dev->aucl, share_mode, (const WAVEFORMATEX *)&wfx, (WAVEFORMATEX **)&rwfx); @@ -486,6 +498,11 @@ static DWORD WINAPI fluid_wasapi_audio_run(void *p) FLUID_LOG(FLUID_DBG, "wasapi: requested %d frames of buffers, got %u.", dev->periods * dev->period_size, dev->nframes); dev->buffer_duration = dev->nframes / dev->sample_rate; + time_to_sleep = dev->buffer_duration * 1000 / 2; + if(time_to_sleep < 1) + { + time_to_sleep = 1; + } dev->drybuf = FLUID_ARRAY(float *, dev->audio_channels * 2); @@ -779,7 +796,7 @@ static void fluid_wasapi_finddev_callback(IMMDevice *dev, void *data) { fluid_wasapi_finddev_data_t *d = (fluid_wasapi_finddev_data_t *)data; int nsz; - char *name; + char *name = NULL; wchar_t *id = NULL; IPropertyStore *prop = NULL; PROPVARIANT var; From 5eff4e592e95a0ff34a9de8a5228c080f8e12e36 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 16 Apr 2021 18:34:11 +0800 Subject: [PATCH 2/2] wasapi: correctly render effects if no custom audio processing is used. I couldn't find a conceivable use case for calling `new_fluid_audio_driver2` with `fluid_synth_process` as its callback in client code... So I took the lazy route. If custom audio processing is indeed used, nothing would be changed by this patch. It still gets no effects buffer (like the vast majority of other drivers). --- src/drivers/fluid_wasapi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/drivers/fluid_wasapi.c b/src/drivers/fluid_wasapi.c index ab469090..e3826f11 100644 --- a/src/drivers/fluid_wasapi.c +++ b/src/drivers/fluid_wasapi.c @@ -635,6 +635,8 @@ static int fluid_wasapi_write_processed_channels(void *data, int len, fluid_wasapi_audio_driver_t *drv = (fluid_wasapi_audio_driver_t *) data; float *optr[FLUID_WASAPI_MAX_OUTPUTS * 2]; int16_t *ioptr[FLUID_WASAPI_MAX_OUTPUTS * 2]; + int efx_nch = 0; + float **efx_buf = NULL; for(ch = 0; ch < drv->channels_count; ++ch) { @@ -643,7 +645,12 @@ static int fluid_wasapi_write_processed_channels(void *data, int len, ioptr[ch] = (int16_t *)channels_out[ch] + channels_off[ch]; } - ret = drv->func(drv->user_pointer, len, 0, NULL, drv->channels_count, drv->drybuf); + if(drv->func == (fluid_audio_func_t)fluid_synth_process) + { + efx_nch = drv->channels_count; + efx_buf = drv->drybuf; + } + ret = drv->func(drv->user_pointer, len, efx_nch, efx_buf, drv->channels_count, drv->drybuf); for(ch = 0; ch < drv->channels_count; ++ch) {