mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-27 22:43:36 +00:00
Various fixes to dsound driver (#435)
- fluid_dsound_audio_run() and fluid_win32_error() are now static functions. - WAVEFORMATEX is not required by DirectSound during the playback. We do not need it anymore after calling ::SetFormat(), so allocating this structure dynamically inside driver structure is useless. - Implemented support for float sample type. - Uses an event object for handling the end of thread, it allows to combine the quit event with the later wait in milliseconds in a single block. - Calculates the amount of milliseconds to sleep rather than sleeping always for one millisecond. - Fix an error into a FLUID_LOG() call. - Fix handle leak of the thread, now it is correctly closed with CloseHandle(). - ExitThread() is a nonsense in that position, since the thread is already exiting. - Fix error when compiling with WSDK 8.1, by defining NOBITMAP, in case NOGDI macro added somewhere
This commit is contained in:
parent
923f5f3544
commit
6f8a574e36
1 changed files with 81 additions and 44 deletions
|
@ -30,9 +30,12 @@
|
|||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter);
|
||||
#define NOBITMAP
|
||||
#include <mmreg.h>
|
||||
|
||||
char *fluid_win32_error(HRESULT hr);
|
||||
static DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter);
|
||||
|
||||
static char *fluid_win32_error(HRESULT hr);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -40,12 +43,12 @@ typedef struct
|
|||
LPDIRECTSOUND direct_sound;
|
||||
LPDIRECTSOUNDBUFFER prim_buffer;
|
||||
LPDIRECTSOUNDBUFFER sec_buffer;
|
||||
WAVEFORMATEX *format;
|
||||
HANDLE thread;
|
||||
DWORD threadID;
|
||||
fluid_synth_t *synth;
|
||||
fluid_audio_callback_t write;
|
||||
int cont;
|
||||
HANDLE quit_ev;
|
||||
int bytes_per_second;
|
||||
DWORD buffer_byte_size;
|
||||
DWORD queue_byte_size;
|
||||
DWORD frame_size;
|
||||
|
@ -109,6 +112,7 @@ new_fluid_dsound_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
double sample_rate;
|
||||
int periods, period_size;
|
||||
fluid_dsound_devsel_t devsel;
|
||||
WAVEFORMATEX format;
|
||||
|
||||
/* create and clear the driver data */
|
||||
dev = FLUID_NEW(fluid_dsound_audio_driver_t);
|
||||
|
@ -121,42 +125,49 @@ new_fluid_dsound_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_dsound_audio_driver_t));
|
||||
dev->synth = synth;
|
||||
dev->cont = 1;
|
||||
|
||||
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
|
||||
fluid_settings_getint(settings, "audio.periods", &periods);
|
||||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
|
||||
/* Clear the buffer format */
|
||||
ZeroMemory(&format, sizeof(WAVEFORMATEX));
|
||||
|
||||
/* check the format */
|
||||
if(!fluid_settings_str_equal(settings, "audio.sample-format", "16bits"))
|
||||
if(fluid_settings_str_equal(settings, "audio.sample-format", "float"))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Selected 32 bit sample format");
|
||||
|
||||
dev->frame_size = 2 * sizeof(float);
|
||||
dev->write = fluid_synth_write_float;
|
||||
|
||||
format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
}
|
||||
else if(fluid_settings_str_equal(settings, "audio.sample-format", "16bits"))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Selected 16 bit sample format");
|
||||
|
||||
dev->frame_size = 2 * sizeof(short);
|
||||
dev->write = fluid_synth_write_s16;
|
||||
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
}
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Unhandled sample format");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->frame_size = 2 * sizeof(short);
|
||||
dev->buffer_byte_size = period_size * dev->frame_size;
|
||||
dev->queue_byte_size = periods * dev->buffer_byte_size;
|
||||
dev->write = fluid_synth_write_s16;
|
||||
dev->bytes_per_second = sample_rate * dev->frame_size;
|
||||
|
||||
/* create and initialize the buffer format */
|
||||
dev->format = (WAVEFORMATEX *) FLUID_MALLOC(sizeof(WAVEFORMATEX));
|
||||
|
||||
if(dev->format == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
ZeroMemory(dev->format, sizeof(WAVEFORMATEX));
|
||||
|
||||
dev->format->wFormatTag = WAVE_FORMAT_PCM;
|
||||
dev->format->nChannels = 2;
|
||||
dev->format->wBitsPerSample = 16;
|
||||
dev->format->nSamplesPerSec = (DWORD) sample_rate;
|
||||
dev->format->nBlockAlign = (WORD) dev->frame_size;
|
||||
dev->format->nAvgBytesPerSec = dev->format->nSamplesPerSec * dev->frame_size;
|
||||
dev->format->cbSize = 0;
|
||||
/* Finish to initialize the buffer format */
|
||||
format.nChannels = 2;
|
||||
format.wBitsPerSample = dev->frame_size * 4;
|
||||
format.nSamplesPerSec = (DWORD) sample_rate;
|
||||
format.nBlockAlign = (WORD) dev->frame_size;
|
||||
format.nAvgBytesPerSec = dev->bytes_per_second;
|
||||
|
||||
devsel.devGUID = NULL;
|
||||
|
||||
|
@ -220,11 +231,11 @@ new_fluid_dsound_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
|
||||
/* set the primary sound buffer to this format. if it fails, just
|
||||
print a warning. */
|
||||
hr = IDirectSoundBuffer_SetFormat(dev->prim_buffer, dev->format);
|
||||
hr = IDirectSoundBuffer_SetFormat(dev->prim_buffer, &format);
|
||||
|
||||
if(hr != DS_OK)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Can't set format of primary sound buffer", fluid_win32_error(hr));
|
||||
FLUID_LOG(FLUID_WARN, "Can't set format of primary sound buffer: %s", fluid_win32_error(hr));
|
||||
}
|
||||
|
||||
/* initialize the buffer description */
|
||||
|
@ -232,9 +243,8 @@ new_fluid_dsound_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
ZeroMemory(&desc, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
|
||||
desc.lpwfxFormat = dev->format;
|
||||
desc.lpwfxFormat = &format;
|
||||
desc.dwBufferBytes = dev->queue_byte_size;
|
||||
desc.dwReserved = 0;
|
||||
|
||||
if(caps.dwFreeHwMixingStreamingBuffers > 0)
|
||||
{
|
||||
|
@ -267,9 +277,16 @@ new_fluid_dsound_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
/* Unlock */
|
||||
IDirectSoundBuffer_Unlock(dev->sec_buffer, buf1, bytes1, 0, 0);
|
||||
|
||||
/* Create object to signal thread exit */
|
||||
dev->quit_ev = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if(dev->quit_ev == NULL)
|
||||
{
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
/* start the audio thread */
|
||||
dev->thread = CreateThread(NULL, 0, &fluid_dsound_audio_run, (LPVOID) dev, 0, &dev->threadID);
|
||||
dev->thread = CreateThread(NULL, 0, fluid_dsound_audio_run, (LPVOID) dev, 0, &dev->threadID);
|
||||
|
||||
if(dev->thread == NULL)
|
||||
{
|
||||
|
@ -289,23 +306,30 @@ void delete_fluid_dsound_audio_driver(fluid_audio_driver_t *d)
|
|||
fluid_dsound_audio_driver_t *dev = (fluid_dsound_audio_driver_t *) d;
|
||||
fluid_return_if_fail(dev != NULL);
|
||||
|
||||
/* tell the audio thread to stop its loop */
|
||||
dev->cont = 0;
|
||||
|
||||
/* wait till the audio thread exits */
|
||||
if(dev->thread != 0)
|
||||
if(dev->thread != NULL)
|
||||
{
|
||||
/* tell the audio thread to stop its loop */
|
||||
SetEvent(dev->quit_ev);
|
||||
|
||||
if(WaitForSingleObject(dev->thread, 2000) != WAIT_OBJECT_0)
|
||||
{
|
||||
/* on error kill the thread mercilessly */
|
||||
FLUID_LOG(FLUID_DBG, "Couldn't join the audio thread. killing it.");
|
||||
TerminateThread(dev->thread, 0);
|
||||
}
|
||||
|
||||
/* Release the thread object */
|
||||
CloseHandle(dev->thread);
|
||||
}
|
||||
|
||||
/* release all the allocated ressources */
|
||||
/* Release the event object */
|
||||
if(dev->quit_ev != NULL)
|
||||
{
|
||||
CloseHandle(dev->quit_ev);
|
||||
}
|
||||
|
||||
FLUID_FREE(dev->format);
|
||||
/* release all the allocated resources */
|
||||
|
||||
if(dev->sec_buffer != NULL)
|
||||
{
|
||||
|
@ -326,13 +350,14 @@ void delete_fluid_dsound_audio_driver(fluid_audio_driver_t *d)
|
|||
FLUID_FREE(dev);
|
||||
}
|
||||
|
||||
DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter)
|
||||
static DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter)
|
||||
{
|
||||
fluid_dsound_audio_driver_t *dev = (fluid_dsound_audio_driver_t *) lpParameter;
|
||||
short *buf1, *buf2;
|
||||
DWORD bytes1, bytes2;
|
||||
DWORD cur_position, frames, play_position, write_position, bytes;
|
||||
HRESULT res;
|
||||
int ms;
|
||||
|
||||
cur_position = 0;
|
||||
|
||||
|
@ -341,9 +366,8 @@ DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter)
|
|||
|
||||
IDirectSoundBuffer_Play(dev->sec_buffer, 0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
while(dev->cont)
|
||||
for(;;)
|
||||
{
|
||||
|
||||
IDirectSoundBuffer_GetCurrentPosition(dev->sec_buffer, &play_position, &write_position);
|
||||
|
||||
if(cur_position <= play_position)
|
||||
|
@ -395,19 +419,32 @@ DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter)
|
|||
cur_position -= dev->queue_byte_size;
|
||||
}
|
||||
|
||||
/* 1 ms of wait */
|
||||
ms = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sleep(1);
|
||||
/* Calculate how many milliseconds to sleep (minus 1 for safety) */
|
||||
ms = (dev->buffer_byte_size - bytes) * 1000 / dev->bytes_per_second - 1;
|
||||
|
||||
if(ms < 1)
|
||||
{
|
||||
ms = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0; /* never reached */
|
||||
/* Wait quit event or timeout */
|
||||
if(WaitForSingleObject(dev->quit_ev, ms) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *fluid_win32_error(HRESULT hr)
|
||||
static char *fluid_win32_error(HRESULT hr)
|
||||
{
|
||||
char *s = "Don't know why";
|
||||
|
||||
|
|
Loading…
Reference in a new issue