mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-19 06:02:03 +00:00
Fix waveout driver crash (#759)
This PR addresses issue https://github.com/FluidSynth/fluidsynth/issues/758. It ensures that the `internal buffer size` used by waveout device driver and the `extra buffers size` required by fluid_synth_process() are both coherent (i.e they should be of same size). To ensure this, both kind of buffers are now dependent of`audio.period` and `audio.period-size settings`.
This commit is contained in:
parent
c7878dec74
commit
8322d95425
1 changed files with 33 additions and 21 deletions
|
@ -33,12 +33,9 @@
|
|||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
|
||||
/* Number of buffers in the chain */
|
||||
/* Number of driver buffers in the chain */
|
||||
#define NB_SOUND_BUFFERS 4
|
||||
|
||||
/* Milliseconds of a single sound buffer */
|
||||
#define MS_BUFFER_LENGTH 20
|
||||
|
||||
/**
|
||||
* The driver handle multiple channels.
|
||||
* Actually the number maximum of channels is limited to 2 * WAVEOUT_MAX_STEREO_CHANNELS.
|
||||
|
@ -93,7 +90,7 @@ typedef struct
|
|||
HWAVEOUT hWaveOut;
|
||||
WAVEHDR waveHeader[NB_SOUND_BUFFERS];
|
||||
|
||||
int sample_size;
|
||||
int periods; /* numbers of internal driver buffers */
|
||||
int num_frames;
|
||||
|
||||
HANDLE hThread;
|
||||
|
@ -255,11 +252,14 @@ void fluid_waveout_audio_driver_settings(fluid_settings_t *settings)
|
|||
*
|
||||
* @param setting. The settings the driver looks for:
|
||||
* "synth.sample-rate", the sample rate.
|
||||
* "synth.audio-channels", the number of internal mixer stereo buffer.
|
||||
* "audio.periods",the number of buffers.
|
||||
* "audio.period-size",the size of one buffer.
|
||||
* "audio.sample-format",the sample format, 16bits or float.
|
||||
*
|
||||
* @param synth, fluidsynth synth instance to associate to the driver.
|
||||
*
|
||||
* Note: The number of internal mixer buffer is indicated by synth->audio_channels.
|
||||
* Note: The number of internal mixer stereo buffer is indicated by "synth.audio-channels".
|
||||
* If the audio device cannot handle the format or do not have enough channels,
|
||||
* the driver fails and return NULL.
|
||||
*/
|
||||
|
@ -292,6 +292,13 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
fluid_settings_getint(settings, "synth.audio-channels", &audio_channels);
|
||||
|
||||
if(periods > NB_SOUND_BUFFERS)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO, "audio.periods %d exceeds internal limit %d",
|
||||
periods, NB_SOUND_BUFFERS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clear format structure */
|
||||
ZeroMemory(&wfx, sizeof(WAVEFORMATEXTENSIBLE));
|
||||
|
||||
|
@ -339,7 +346,6 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
wfx.Format.nBlockAlign = sample_size * wfx.Format.nChannels;
|
||||
wfx.Format.nSamplesPerSec = frequency;
|
||||
wfx.Format.nAvgBytesPerSec = frequency * wfx.Format.nBlockAlign;
|
||||
|
||||
/* WAVEFORMATEXTENSIBLE extension is used only when channels number
|
||||
is above 2.
|
||||
When channels number is below 2, only WAVEFORMATEX structure
|
||||
|
@ -355,14 +361,13 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
wfx.dwChannelMask = channel_mask_speakers[audio_channels - 1];
|
||||
}
|
||||
|
||||
/* Calculate the length of a single buffer */
|
||||
lenBuffer = (MS_BUFFER_LENGTH * wfx.Format.nAvgBytesPerSec + 999) / 1000;
|
||||
/* Round to 8-bytes size */
|
||||
lenBuffer = (lenBuffer + 7) & ~7;
|
||||
/* allocate the internal waveout buffers:
|
||||
The length of a single buffer in bytes is dependant of period_size.
|
||||
*/
|
||||
lenBuffer = wfx.Format.nBlockAlign * period_size;
|
||||
/* create and clear the driver data */
|
||||
dev = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(fluid_waveout_audio_driver_t) + lenBuffer * NB_SOUND_BUFFERS);
|
||||
|
||||
sizeof(fluid_waveout_audio_driver_t) + lenBuffer * periods);
|
||||
if(dev == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
|
@ -375,10 +380,10 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
|
||||
/* Save copy of other variables */
|
||||
dev->write_ptr = write_ptr;
|
||||
dev->sample_size = sample_size;
|
||||
|
||||
/* Calculate the number of frames in a block */
|
||||
dev->num_frames = lenBuffer / wfx.Format.nBlockAlign;
|
||||
/* number of frames in a buffer */
|
||||
dev->num_frames = period_size;
|
||||
/* number of buffers */
|
||||
dev->periods = periods;
|
||||
dev->channels_count = wfx.Format.nChannels;
|
||||
|
||||
/* Set default device to use */
|
||||
|
@ -386,6 +391,12 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
|
||||
if(func)
|
||||
{
|
||||
/* allocate extra buffer used by fluid_waveout_write_processed_channels().
|
||||
These buffers are buffer adaptation between the rendering
|
||||
API fluid_synth_process() and the waveout internal buffers
|
||||
Note: the size (in bytes) of these extra buffer (drybuf[]) must be the
|
||||
same that the size of internal waveout buffers.
|
||||
*/
|
||||
dev->drybuf = FLUID_ARRAY(float*, audio_channels * 2);
|
||||
if(dev->drybuf == NULL)
|
||||
{
|
||||
|
@ -396,7 +407,8 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
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);
|
||||
/* The length of a single buffer drybuf[i] is dependant of period_size */
|
||||
dev->drybuf[i] = FLUID_ARRAY(float, period_size);
|
||||
if(dev->drybuf[i] == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
|
@ -486,7 +498,7 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
ptrBuffer = (LPSTR)(dev + 1);
|
||||
|
||||
/* Setup the sample buffers */
|
||||
for(i = 0; i < NB_SOUND_BUFFERS; i++)
|
||||
for(i = 0; i < periods; i++)
|
||||
{
|
||||
/* Clear the sample buffer */
|
||||
memset(ptrBuffer, 0, lenBuffer);
|
||||
|
@ -505,7 +517,7 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
|
|||
}
|
||||
|
||||
/* Play the sample buffers */
|
||||
for(i = 0; i < NB_SOUND_BUFFERS; i++)
|
||||
for(i = 0; i < periods; i++)
|
||||
{
|
||||
waveOutWrite(dev->hWaveOut, &dev->waveHeader[i], sizeof(WAVEHDR));
|
||||
}
|
||||
|
@ -530,7 +542,7 @@ void delete_fluid_waveout_audio_driver(fluid_audio_driver_t *d)
|
|||
/* release all the allocated resources */
|
||||
if(dev->hWaveOut != NULL)
|
||||
{
|
||||
dev->nQuit = NB_SOUND_BUFFERS;
|
||||
dev->nQuit = dev->periods;
|
||||
WaitForSingleObject(dev->hQuit, INFINITE);
|
||||
|
||||
waveOutClose(dev->hWaveOut);
|
||||
|
|
Loading…
Reference in a new issue