From 41c65022c1946c8f1bc877e038dcaf2b058ffcc5 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 2 Jun 2024 22:03:55 +0200 Subject: [PATCH] faudio: Import upstream release 24.06. --- libs/faudio/include/FAudio.h | 2 +- libs/faudio/src/FACT_internal.c | 14 +- libs/faudio/src/FAudioFX_reverb.c | 2 +- libs/faudio/src/FAudio_internal.c | 68 +++++++- libs/faudio/src/FAudio_internal.h | 2 + libs/faudio/src/FAudio_platform_win32.c | 220 ++++++++++++++++++++---- libs/faudio/src/stb_vorbis.h | 2 +- 7 files changed, 266 insertions(+), 44 deletions(-) diff --git a/libs/faudio/include/FAudio.h b/libs/faudio/include/FAudio.h index afe81424d12..ec2c3bfeac4 100644 --- a/libs/faudio/include/FAudio.h +++ b/libs/faudio/include/FAudio.h @@ -494,7 +494,7 @@ extern FAudioGUID DATAFORMAT_SUBTYPE_IEEE_FLOAT; #define FAUDIO_ABI_VERSION 0 #define FAUDIO_MAJOR_VERSION 24 -#define FAUDIO_MINOR_VERSION 5 +#define FAUDIO_MINOR_VERSION 6 #define FAUDIO_PATCH_VERSION 0 #define FAUDIO_COMPILED_VERSION ( \ diff --git a/libs/faudio/src/FACT_internal.c b/libs/faudio/src/FACT_internal.c index 0f0e4f968d9..a18f37a578d 100644 --- a/libs/faudio/src/FACT_internal.c +++ b/libs/faudio/src/FACT_internal.c @@ -85,7 +85,7 @@ static inline float FACT_INTERNAL_CalculateFilterFrequency( * * -@Woflox */ - float freq = 2 * FAudio_sin( + float freq = 2.0f * FAudio_sinf( F3DAUDIO_PI * FAudio_min(desiredFrequency / sampleRate, 0.5f) ); @@ -1027,21 +1027,21 @@ float FACT_INTERNAL_CalculateRPC( } else if (rpc->points[i].type == 1) /* Fast */ { - result += maxY * (1.0f - FAudio_pow(1.0f - FAudio_pow(deltaXNormalized, 1.0f / 1.5f), 1.5f)); + result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_powf(deltaXNormalized, 1.0f / 1.5f), 1.5f)); } else if (rpc->points[i].type == 2) /* Slow */ { - result += maxY * (1.0f - FAudio_pow(1.0f - FAudio_pow(deltaXNormalized, 1.5f), 1.0f / 1.5f)); + result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_powf(deltaXNormalized, 1.5f), 1.0f / 1.5f)); } else if (rpc->points[i].type == 3) /* SinCos */ { if (maxY > 0.0f) { - result += maxY * (1.0f - FAudio_pow(1.0f - FAudio_sqrtf(deltaXNormalized), 2.0f)); + result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_sqrtf(deltaXNormalized), 2.0f)); } else { - result += maxY * (1.0f - FAudio_sqrtf(1.0f - FAudio_pow(deltaXNormalized, 2.0f))); + result += maxY * (1.0f - FAudio_sqrtf(1.0f - FAudio_powf(deltaXNormalized, 2.0f))); } } else @@ -2066,8 +2066,8 @@ uint32_t FACT_INTERNAL_ParseAudioEngine( rpcOffset, dspPresetOffset, dspParameterOffset; - uint16_t blob1Count, blob2Count; - uint8_t version, tool; + uint16_t blob1Count, blob2Count, tool; + uint8_t version; uint8_t se; uint32_t magic; size_t memsize; diff --git a/libs/faudio/src/FAudioFX_reverb.c b/libs/faudio/src/FAudioFX_reverb.c index eaf12d8ab44..219495e7916 100644 --- a/libs/faudio/src/FAudioFX_reverb.c +++ b/libs/faudio/src/FAudioFX_reverb.c @@ -183,7 +183,7 @@ static inline void DspBiQuad_Change( float q, float gain ) { - const float TWOPI = 6.283185307179586476925286766559005; + const float TWOPI = (float)6.283185307179586476925286766559005; float theta_c = (TWOPI * frequency) / (float) filter->sampleRate; float mu = DbGainToFactor(gain); float beta = (type == DSP_BIQUAD_LOWSHELVING) ? diff --git a/libs/faudio/src/FAudio_internal.c b/libs/faudio/src/FAudio_internal.c index a20e003db3c..37609ae8886 100644 --- a/libs/faudio/src/FAudio_internal.c +++ b/libs/faudio/src/FAudio_internal.c @@ -383,6 +383,12 @@ static void FAudio_INTERNAL_DecodeBuffers( if ( voice->src.callback != NULL && voice->src.callback->OnBufferStart != NULL ) { + FAudio_PlatformUnlockMutex(voice->src.bufferLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock) + + FAudio_PlatformUnlockMutex(voice->sendLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock) + FAudio_PlatformUnlockMutex(voice->audio->sourceLock); LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock) @@ -393,6 +399,12 @@ static void FAudio_INTERNAL_DecodeBuffers( FAudio_PlatformLockMutex(voice->audio->sourceLock); LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + + FAudio_PlatformLockMutex(voice->sendLock); + LOG_MUTEX_LOCK(voice->audio, voice->sendLock) + + FAudio_PlatformLockMutex(voice->src.bufferLock); + LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock) } } @@ -442,6 +454,12 @@ static void FAudio_INTERNAL_DecodeBuffers( if ( voice->src.callback != NULL && voice->src.callback->OnLoopEnd != NULL ) { + FAudio_PlatformUnlockMutex(voice->src.bufferLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock) + + FAudio_PlatformUnlockMutex(voice->sendLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock) + FAudio_PlatformUnlockMutex(voice->audio->sourceLock); LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock) @@ -452,6 +470,12 @@ static void FAudio_INTERNAL_DecodeBuffers( FAudio_PlatformLockMutex(voice->audio->sourceLock); LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + + FAudio_PlatformLockMutex(voice->sendLock); + LOG_MUTEX_LOCK(voice->audio, voice->sendLock) + + FAudio_PlatformLockMutex(voice->src.bufferLock); + LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock) } } else @@ -504,6 +528,12 @@ static void FAudio_INTERNAL_DecodeBuffers( /* Callbacks */ if (voice->src.callback != NULL) { + FAudio_PlatformUnlockMutex(voice->src.bufferLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock) + + FAudio_PlatformUnlockMutex(voice->sendLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock) + FAudio_PlatformUnlockMutex(voice->audio->sourceLock); LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock) @@ -522,6 +552,15 @@ static void FAudio_INTERNAL_DecodeBuffers( ); } + FAudio_PlatformLockMutex(voice->audio->sourceLock); + LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + + FAudio_PlatformLockMutex(voice->sendLock); + LOG_MUTEX_LOCK(voice->audio, voice->sendLock) + + FAudio_PlatformLockMutex(voice->src.bufferLock); + LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock) + /* One last chance at redemption */ if (buffer == NULL && voice->src.bufferList != NULL) { @@ -531,14 +570,29 @@ static void FAudio_INTERNAL_DecodeBuffers( if (buffer != NULL && voice->src.callback->OnBufferStart != NULL) { + FAudio_PlatformUnlockMutex(voice->src.bufferLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock) + + FAudio_PlatformUnlockMutex(voice->sendLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock) + + FAudio_PlatformUnlockMutex(voice->audio->sourceLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock) + voice->src.callback->OnBufferStart( voice->src.callback, buffer->pContext ); - } - FAudio_PlatformLockMutex(voice->audio->sourceLock); - LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + FAudio_PlatformLockMutex(voice->audio->sourceLock); + LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + + FAudio_PlatformLockMutex(voice->sendLock); + LOG_MUTEX_LOCK(voice->audio, voice->sendLock) + + FAudio_PlatformLockMutex(voice->src.bufferLock); + LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock) + } } voice->audio->pFree(toDelete); @@ -631,7 +685,7 @@ static inline void FAudio_INTERNAL_FilterVoice( filterState[ci][FAudioHighPassFilter] = samples[j * numChannels + ci] - filterState[ci][FAudioLowPassFilter] - (filter->OneOverQ * filterState[ci][FAudioBandPassFilter]); filterState[ci][FAudioBandPassFilter] = (filter->Frequency * filterState[ci][FAudioHighPassFilter]) + filterState[ci][FAudioBandPassFilter]; filterState[ci][FAudioNotchFilter] = filterState[ci][FAudioHighPassFilter] + filterState[ci][FAudioLowPassFilter]; - samples[j * numChannels + ci] = filterState[ci][filter->Type] * filter->WetDryMix + samples[j * numChannels + ci] * (1.0 - filter->WetDryMix); + samples[j * numChannels + ci] = filterState[ci][filter->Type] * filter->WetDryMix + samples[j * numChannels + ci] * (1.0f - filter->WetDryMix); } LOG_FUNC_EXIT(audio) @@ -1250,6 +1304,9 @@ static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice *voice) if (voice->src.callback != NULL && voice->src.callback->OnBufferEnd != NULL) { + FAudio_PlatformUnlockMutex(voice->src.bufferLock); + LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock) + FAudio_PlatformUnlockMutex(voice->audio->sourceLock); LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock) @@ -1260,6 +1317,9 @@ static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice *voice) FAudio_PlatformLockMutex(voice->audio->sourceLock); LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock) + + FAudio_PlatformLockMutex(voice->src.bufferLock); + LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock) } voice->audio->pFree(entry); } diff --git a/libs/faudio/src/FAudio_internal.h b/libs/faudio/src/FAudio_internal.h index 6c7623d82ca..2bf7a38e372 100644 --- a/libs/faudio/src/FAudio_internal.h +++ b/libs/faudio/src/FAudio_internal.h @@ -57,6 +57,7 @@ #define FAudio_strlcpy(ptr1, ptr2, size) lstrcpynA(ptr1, ptr2, size) #define FAudio_pow(x, y) pow(x, y) +#define FAudio_powf(x, y) powf(x, y) #define FAudio_log(x) log(x) #define FAudio_log10(x) log10(x) #define FAudio_sin(x) sin(x) @@ -138,6 +139,7 @@ extern void FAudio_Log(char const *msg); #define FAudio_strlcpy(ptr1, ptr2, size) SDL_strlcpy(ptr1, ptr2, size) #define FAudio_pow(x, y) SDL_pow(x, y) +#define FAudio_powf(x, y) SDL_powf(x, y) #define FAudio_log(x) SDL_log(x) #define FAudio_log10(x) SDL_log10(x) #define FAudio_sin(x) SDL_sin(x) diff --git a/libs/faudio/src/FAudio_platform_win32.c b/libs/faudio/src/FAudio_platform_win32.c index 5de6536a39b..d5ebbfc14cc 100644 --- a/libs/faudio/src/FAudio_platform_win32.c +++ b/libs/faudio/src/FAudio_platform_win32.c @@ -41,6 +41,7 @@ #include #include #include +#include DEFINE_GUID(CLSID_CWMADecMediaObject, 0x2eeb4adf, 0x4578, 0x4d10, 0xbc, 0xa7, 0xbb, 0x95, 0x5f, 0x56, 0x32, 0x0a); DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, FAUDIO_FORMAT_XMAUDIO2); @@ -180,6 +181,11 @@ static DWORD WINAPI FAudio_AudioClientThread(void *user) while (WaitForMultipleObjects(2, args->events, FALSE, INFINITE) == WAIT_OBJECT_0) { hr = IAudioClient_GetCurrentPadding(args->client, &padding); + if (hr == AUDCLNT_E_DEVICE_INVALIDATED) + { + /* Device was removed, just exit */ + break; + } FAudio_assert(!FAILED(hr) && "Failed to get IAudioClient current padding!"); hr = FAudio_FillAudioClientBuffer(args, render_client, frames, padding); @@ -194,6 +200,141 @@ static DWORD WINAPI FAudio_AudioClientThread(void *user) return 0; } +/* Sets `defaultDeviceIndex` to the default audio device index in + * `deviceCollection`. + * On failure, `defaultDeviceIndex` is not modified and the latest error is + * returned. */ +static HRESULT FAudio_DefaultDeviceIndex( + IMMDeviceCollection *deviceCollection, + uint32_t* defaultDeviceIndex +) { + IMMDevice *device; + HRESULT hr; + uint32_t i, count; + WCHAR *default_guid; + WCHAR *device_guid; + + /* Open the default device and get its GUID. */ + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint( + device_enumerator, + eRender, + eConsole, + &device + ); + if (FAILED(hr)) + { + return hr; + } + hr = IMMDevice_GetId(device, &default_guid); + if (FAILED(hr)) + { + IMMDevice_Release(device); + return hr; + } + + /* Free the default device. */ + IMMDevice_Release(device); + + hr = IMMDeviceCollection_GetCount(deviceCollection, &count); + if (FAILED(hr)) + { + CoTaskMemFree(default_guid); + return hr; + } + + for (i = 0; i < count; i += 1) + { + /* Open the device and get its GUID. */ + hr = IMMDeviceCollection_Item(deviceCollection, i, &device); + if (FAILED(hr)) { + CoTaskMemFree(default_guid); + return hr; + } + hr = IMMDevice_GetId(device, &device_guid); + if (FAILED(hr)) + { + CoTaskMemFree(default_guid); + IMMDevice_Release(device); + return hr; + } + + if (lstrcmpW(default_guid, device_guid) == 0) + { + /* Device found. */ + CoTaskMemFree(default_guid); + CoTaskMemFree(device_guid); + IMMDevice_Release(device); + *defaultDeviceIndex = i; + return S_OK; + } + + CoTaskMemFree(device_guid); + IMMDevice_Release(device); + } + + /* This should probably never happen. Just in case, set + * `defaultDeviceIndex` to 0 and return S_OK. */ + CoTaskMemFree(default_guid); + *defaultDeviceIndex = 0; + return S_OK; +} + +/* Open `device`, corresponding to `deviceIndex`. `deviceIndex` 0 always + * corresponds to the default device. XAudio reorders the devices so that the + * default device is always at index 0, so we mimick this behavior here by + * swapping the devices at indexes 0 and `defaultDeviceIndex`. + */ +static HRESULT FAudio_OpenDevice(uint32_t deviceIndex, IMMDevice **device) +{ + IMMDeviceCollection *deviceCollection; + HRESULT hr; + uint32_t defaultDeviceIndex; + uint32_t actualIndex; + + *device = NULL; + + hr = IMMDeviceEnumerator_EnumAudioEndpoints( + device_enumerator, + eRender, + DEVICE_STATE_ACTIVE, + &deviceCollection + ); + if (FAILED(hr)) + { + return hr; + } + + /* Get the default device index. */ + hr = FAudio_DefaultDeviceIndex(deviceCollection, &defaultDeviceIndex); + if (FAILED(hr)) + { + IMMDeviceCollection_Release(deviceCollection); + return hr; + } + + if (deviceIndex == 0) { + /* Default device. */ + actualIndex = defaultDeviceIndex; + } else if (deviceIndex == defaultDeviceIndex) { + /* Open the device at index 0 instead of the "correct" one. */ + actualIndex = 0; + } else { + /* Otherwise, just open the device. */ + actualIndex = deviceIndex; + + } + hr = IMMDeviceCollection_Item(deviceCollection, actualIndex, device); + if (FAILED(hr)) + { + IMMDeviceCollection_Release(deviceCollection); + return hr; + } + + IMMDeviceCollection_Release(deviceCollection); + + return hr; +} + void FAudio_PlatformInit( FAudio *audio, uint32_t flags, @@ -223,7 +364,6 @@ void FAudio_PlatformInit( FAudio_PlatformAddRef(); *platformDevice = NULL; - if (deviceIndex > 0) return; args = FAudio_malloc(sizeof(*args)); FAudio_assert(!!args && "Failed to allocate FAudio thread args!"); @@ -257,13 +397,8 @@ void FAudio_PlatformInit( data->stopEvent = CreateEventW(NULL, FALSE, FALSE, NULL); FAudio_assert(!!data->stopEvent && "Failed to create FAudio thread stop event!"); - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint( - device_enumerator, - eRender, - eConsole, - &device - ); - FAudio_assert(!FAILED(hr) && "Failed to get default audio endpoint!"); + hr = FAudio_OpenDevice(deviceIndex, &device); + FAudio_assert(!FAILED(hr) && "Failed to get audio device!"); hr = IMMDevice_Activate( device, @@ -394,29 +529,35 @@ void FAudio_PlatformRelease() uint32_t FAudio_PlatformGetDeviceCount(void) { - IMMDevice *device; + IMMDeviceCollection *device_collection; uint32_t count; HRESULT hr; FAudio_PlatformAddRef(); - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint( + + hr = IMMDeviceEnumerator_EnumAudioEndpoints( device_enumerator, eRender, - eConsole, - &device + DEVICE_STATE_ACTIVE, + &device_collection ); - - if (hr == E_NOTFOUND) { + if (FAILED(hr)) { FAudio_PlatformRelease(); return 0; } - FAudio_assert(!FAILED(hr) && "Failed to get default audio endpoint!"); + hr = IMMDeviceCollection_GetCount(device_collection, &count); + if (FAILED(hr)) { + IMMDeviceCollection_Release(device_collection); + FAudio_PlatformRelease(); + return 0; + } + + IMMDeviceCollection_Release(device_collection); - IMMDevice_Release(device); FAudio_PlatformRelease(); - return 1; + return count; } uint32_t FAudio_PlatformGetDeviceDetails( @@ -427,31 +568,50 @@ uint32_t FAudio_PlatformGetDeviceDetails( WAVEFORMATEXTENSIBLE *ext; IAudioClient *client; IMMDevice *device; + IPropertyStore* properties; + PROPVARIANT deviceName; + uint32_t count = 0; uint32_t ret = 0; HRESULT hr; WCHAR *str; GUID sub; FAudio_memset(details, 0, sizeof(FAudioDeviceDetails)); - if (index > 0) return FAUDIO_E_INVALID_CALL; FAudio_PlatformAddRef(); - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint( - device_enumerator, - eRender, - eConsole, - &device - ); - FAudio_assert(!FAILED(hr) && "Failed to get default audio endpoint!"); + count = FAudio_PlatformGetDeviceCount(); + if (index >= count) + { + FAudio_PlatformRelease(); + return FAUDIO_E_INVALID_CALL; + } - details->Role = FAudioGlobalDefaultDevice; + hr = FAudio_OpenDevice(index, &device); + FAudio_assert(!FAILED(hr) && "Failed to get audio endpoint!"); + if (index == 0) + { + details->Role = FAudioGlobalDefaultDevice; + } + else + { + details->Role = FAudioNotDefaultDevice; + } + + /* Set the Device Display Name */ + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &properties); + FAudio_assert(!FAILED(hr) && "Failed to open device property store!"); + hr = IPropertyStore_GetValue(properties, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &deviceName); + FAudio_assert(!FAILED(hr) && "Failed to get audio device friendly name!"); + lstrcpynW((LPWSTR)details->DisplayName, deviceName.pwszVal, ARRAYSIZE(details->DisplayName) - 1); + PropVariantClear(&deviceName); + IPropertyStore_Release(properties); + + /* Set the Device ID */ hr = IMMDevice_GetId(device, &str); FAudio_assert(!FAILED(hr) && "Failed to get audio endpoint id!"); - - lstrcpynW((WCHAR *)details->DeviceID, str, ARRAYSIZE(details->DeviceID) - 1); - lstrcpynW((WCHAR *)details->DisplayName, str, ARRAYSIZE(details->DisplayName) - 1); + lstrcpynW((LPWSTR)details->DeviceID, str, ARRAYSIZE(details->DeviceID) - 1); CoTaskMemFree(str); hr = IMMDevice_Activate( @@ -1053,7 +1213,7 @@ FAUDIOAPI uint32_t XNA_GetSongEnded() return 1; } FAudioSourceVoice_GetState(songVoice, &state, 0); - return state.BuffersQueued == 0; + return state.BuffersQueued == 0 && state.SamplesPlayed == 0; } FAUDIOAPI void XNA_EnableVisualization(uint32_t enable) diff --git a/libs/faudio/src/stb_vorbis.h b/libs/faudio/src/stb_vorbis.h index 3a6e009ba5a..bba90fe477e 100644 --- a/libs/faudio/src/stb_vorbis.h +++ b/libs/faudio/src/stb_vorbis.h @@ -1382,7 +1382,7 @@ static void skip(vorb *z, int n) } #ifndef STB_VORBIS_NO_STDIO { - long x = ftell(z->f); + int64_t x = ftell(z->f); fseek(z->f, x+n, SEEK_SET); } #endif