From 64121229ea37a0cda772e998e93349d3b506aa1d Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Wed, 20 Jan 2021 19:30:03 +0800 Subject: [PATCH] Add support for multiple stereo outputs when callbacks are used. --- src/drivers/fluid_dsound.c | 64 ++++++++++++++++++++++++------------- src/drivers/fluid_waveout.c | 60 ++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/drivers/fluid_dsound.c b/src/drivers/fluid_dsound.c index ab922bc9..00cb791e 100644 --- a/src/drivers/fluid_dsound.c +++ b/src/drivers/fluid_dsound.c @@ -93,8 +93,7 @@ typedef struct /* callback called by the task for audio rendering in dsound buffers */ fluid_audio_channels_callback_t write; HANDLE quit_ev; /* Event object to request the audio task to stop */ - float *lbuf; - float *rbuf; + float **drybuf; int bytes_per_second; /* number of bytes per second */ DWORD buffer_byte_size; /* size of one buffer in bytes */ @@ -200,6 +199,7 @@ new_fluid_dsound_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t fu double sample_rate; int periods, period_size; int audio_channels; + int i; fluid_dsound_devsel_t devsel; WAVEFORMATEXTENSIBLE format; @@ -224,6 +224,9 @@ new_fluid_dsound_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t fu /* Clear format structure*/ ZeroMemory(&format, sizeof(WAVEFORMATEXTENSIBLE)); + /* Set this early so that if buffer allocation failed we can free the memory */ + dev->channels_count = audio_channels * 2; + /* check the format */ if(!func) { @@ -262,13 +265,22 @@ new_fluid_dsound_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t fu format.Format.wBitsPerSample = 8 * sizeof(float); format.SubFormat = guid_float; format.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - dev->lbuf = FLUID_ARRAY(float, periods * period_size); - dev->rbuf = FLUID_ARRAY(float, periods * period_size); - if (dev->lbuf == NULL || dev->rbuf == NULL) + dev->drybuf = FLUID_ARRAY(float*, audio_channels * 2); + if(dev->drybuf == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); goto error_recovery; } + FLUID_MEMSET(dev->drybuf, 0, sizeof(float*) * audio_channels * 2); + for(i = 0; i < audio_channels * 2; ++i) + { + dev->drybuf[i] = FLUID_ARRAY(float, periods * period_size); + if(dev->drybuf[i] == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + } } /* Finish to initialize the format structure */ @@ -305,7 +317,6 @@ new_fluid_dsound_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t fu dev->buffer_byte_size = period_size * dev->frame_size; dev->queue_byte_size = periods * dev->buffer_byte_size; dev->bytes_per_second = format.Format.nAvgBytesPerSec; - dev->channels_count = format.Format.nChannels; devsel.devGUID = NULL; @@ -452,6 +463,8 @@ error_recovery: void delete_fluid_dsound_audio_driver(fluid_audio_driver_t *d) { + int i; + fluid_dsound_audio_driver_t *dev = (fluid_dsound_audio_driver_t *) d; fluid_return_if_fail(dev != NULL); @@ -506,8 +519,15 @@ void delete_fluid_dsound_audio_driver(fluid_audio_driver_t *d) IDirectSound_Release(dev->direct_sound); } - FLUID_FREE(dev->lbuf); - FLUID_FREE(dev->rbuf); + if(dev->func) + { + for(i = 0; i < dev->channels_count; ++i) + { + FLUID_FREE(dev->drybuf[i]); + } + } + + FLUID_FREE(dev->drybuf); FLUID_FREE(dev); } @@ -689,23 +709,23 @@ static int fluid_dsound_write_processed_channels(fluid_synth_t *data, int len, void *channels_out[], int channels_off[], int channels_incr[]) { - int i; + int i, ch; int ret; fluid_dsound_audio_driver_t *drv = (fluid_dsound_audio_driver_t*) data; - float *out[2] = {drv->lbuf, drv->rbuf}; - float *lptr; - float *rptr; - FLUID_MEMSET(drv->lbuf, 0, len * sizeof(float)); - FLUID_MEMSET(drv->rbuf, 0, len * sizeof(float)); - ret = drv->func(drv->synth, len, 0, NULL, 2, out); - lptr = (float*)channels_out[0] + channels_off[0]; - rptr = (float*)channels_out[1] + channels_off[1]; - for (i = 0; i < len; ++i) + float *optr[DSOUND_MAX_STEREO_CHANNELS * 2]; + for(ch = 0; ch < drv->channels_count; ++ch) { - *lptr = drv->lbuf[i]; - *rptr = drv->rbuf[i]; - lptr += channels_incr[0]; - rptr += channels_incr[1]; + FLUID_MEMSET(drv->drybuf[ch], 0, len * sizeof(float)); + optr[ch] = (float*)channels_out[ch] + channels_off[ch]; + } + ret = drv->func(drv->synth, len, 0, NULL, drv->channels_count, drv->drybuf); + for(ch = 0; ch < drv->channels_count; ++ch) + { + for(i = 0; i < len; ++i) + { + *optr[ch] = drv->drybuf[ch][i]; + optr[ch] += channels_incr[ch]; + } } return ret; } diff --git a/src/drivers/fluid_waveout.c b/src/drivers/fluid_waveout.c index a6672fee..1c212196 100644 --- a/src/drivers/fluid_waveout.c +++ b/src/drivers/fluid_waveout.c @@ -88,8 +88,7 @@ typedef struct void *synth; fluid_audio_func_t func; fluid_audio_channels_callback_t write_ptr; - float *lbuf; - float *rbuf; + float **drybuf; HWAVEOUT hWaveOut; WAVEHDR waveHeader[NB_SOUND_BUFFERS]; @@ -387,14 +386,24 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f if(func) { - dev->lbuf = FLUID_ARRAY(float, periods * period_size); - dev->rbuf = FLUID_ARRAY(float, periods * period_size); - if (dev->lbuf == NULL || dev->rbuf == NULL) + dev->drybuf = FLUID_ARRAY(float*, audio_channels * 2); + if(dev->drybuf == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); delete_fluid_waveout_audio_driver(&dev->driver); return NULL; } + FLUID_MEMSET(dev->drybuf, 0, sizeof(float*) * audio_channels * 2); + for(i = 0; i < audio_channels * 2; ++i) + { + dev->drybuf[i] = FLUID_ARRAY(float, periods * period_size); + if(dev->drybuf[i] == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + delete_fluid_waveout_audio_driver(&dev->driver); + return NULL; + } + } } /* get the selected device name. if none is specified, use default device. */ @@ -513,6 +522,8 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f void delete_fluid_waveout_audio_driver(fluid_audio_driver_t *d) { + int i; + fluid_waveout_audio_driver_t *dev = (fluid_waveout_audio_driver_t *) d; fluid_return_if_fail(dev != NULL); @@ -538,8 +549,15 @@ void delete_fluid_waveout_audio_driver(fluid_audio_driver_t *d) CloseHandle(dev->hQuit); } - FLUID_FREE(dev->lbuf); - FLUID_FREE(dev->rbuf); + if(dev->func) + { + for(i = 0; i < dev->channels_count; ++i) + { + FLUID_FREE(dev->drybuf[i]); + } + } + + FLUID_FREE(dev->drybuf); HeapFree(GetProcessHeap(), 0, dev); } @@ -549,23 +567,23 @@ static int fluid_waveout_write_processed_channels(fluid_synth_t *data, int len, void *channels_out[], int channels_off[], int channels_incr[]) { - int i; + int i, ch; int ret; fluid_waveout_audio_driver_t *drv = (fluid_waveout_audio_driver_t*) data; - float *out[2] = {drv->lbuf, drv->rbuf}; - float *lptr; - float *rptr; - FLUID_MEMSET(drv->lbuf, 0, len * sizeof(float)); - FLUID_MEMSET(drv->rbuf, 0, len * sizeof(float)); - ret = drv->func(drv->synth, len, 0, NULL, 2, out); - lptr = (float*)channels_out[0] + channels_off[0]; - rptr = (float*)channels_out[1] + channels_off[1]; - for (i = 0; i < len; ++i) + float *optr[WAVEOUT_MAX_STEREO_CHANNELS * 2]; + for(ch = 0; ch < drv->channels_count; ++ch) { - *lptr = drv->lbuf[i]; - *rptr = drv->rbuf[i]; - lptr += channels_incr[0]; - rptr += channels_incr[1]; + FLUID_MEMSET(drv->drybuf[ch], 0, len * sizeof(float)); + optr[ch] = (float*)channels_out[ch] + channels_off[ch]; + } + ret = drv->func(drv->synth, len, 0, NULL, drv->channels_count, drv->drybuf); + for(ch = 0; ch < drv->channels_count; ++ch) + { + for(i = 0; i < len; ++i) + { + *optr[ch] = drv->drybuf[ch][i]; + optr[ch] += channels_incr[ch]; + } } return ret; }