"The King of Fighters '98 Ultimate Match Final Edition" depends on this behavior. At least, the build I have is; it seems other builds are not.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
-- v7: xactengine3_7: Forward wave bank notifications to the application. faudio: Import upstream commit e3c444e4f819d2364a6adb0ae73b1d01185b1e93. xactengine3_7/tests: Test notifications when loading a wave bank.
From: Giovanni Mascellani gmascellani@codeweavers.com
"The King of Fighters '98 Ultimate Match Final Edition" depends on this behavior. At least, the build I have is; it seems other builds are not.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/xactengine3_7/tests/xact3.c | 171 +++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+)
diff --git a/dlls/xactengine3_7/tests/xact3.c b/dlls/xactengine3_7/tests/xact3.c index 623a1c97db8..1b27eb9aa19 100644 --- a/dlls/xactengine3_7/tests/xact3.c +++ b/dlls/xactengine3_7/tests/xact3.c @@ -28,6 +28,7 @@
#include "initguid.h" #include "xact3.h" +#include "xact3wb.h"
DEFINE_GUID(IID_IXACT3Engine30, 0x9e33f661, 0x2d07, 0x43ec, 0x97, 0x04, 0xbb, 0xcb, 0x71, 0xa5, 0x49, 0x72); DEFINE_GUID(IID_IXACT3Engine31, 0xe72c1b9a, 0xd717, 0x41c0, 0x81, 0xa6, 0x50, 0xeb, 0x56, 0xe8, 0x06, 0x49); @@ -90,11 +91,181 @@ static void test_interfaces(void) } }
+static WCHAR *gen_xwb_file(void) +{ + static const WAVEBANKENTRY entry = + { + .Format = + { + .wFormatTag = WAVEBANKMINIFORMAT_TAG_ADPCM, + .nChannels = 2, + .nSamplesPerSec = 22051, + .wBlockAlign = 48, + }, + }; + static const WAVEBANKDATA bank_data = + { + .dwFlags = WAVEBANK_TYPE_STREAMING, + .dwEntryCount = 1, + .szBankName = "test", + .dwEntryMetaDataElementSize = sizeof(entry), + .dwEntryNameElementSize = WAVEBANK_ENTRYNAME_LENGTH, + .dwAlignment = 0x800, + }; + static const WAVEBANKHEADER header = + { + .dwSignature = WAVEBANK_HEADER_SIGNATURE, + .dwVersion = XACT_CONTENT_VERSION, + .dwHeaderVersion = WAVEBANK_HEADER_VERSION, + .Segments = + { + [WAVEBANK_SEGIDX_BANKDATA] = + { + .dwOffset = sizeof(header), + .dwLength = sizeof(bank_data), + }, + [WAVEBANK_SEGIDX_ENTRYMETADATA] = + { + .dwOffset = sizeof(header) + sizeof(bank_data), + .dwLength = sizeof(entry), + }, + }, + }; + static WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + + GetTempPathW(ARRAY_SIZE(path), path); + lstrcatW(path, L"test.xwb"); + + file = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Cannot create file %s, error %ld\n", + wine_dbgstr_w(path), GetLastError()); + + WriteFile(file, &header, sizeof(header), &written, NULL); + ok(written == sizeof(header), "Cannot write header\n"); + + WriteFile(file, &bank_data, sizeof(bank_data), &written, NULL); + ok(written == sizeof(bank_data), "Cannot write bank data\n"); + + WriteFile(file, &entry, sizeof(entry), &written, NULL); + ok(written == sizeof(entry), "Cannot write entry\n"); + + CloseHandle(file); + + return path; +} + +struct notification_cb_data +{ + XACTNOTIFICATIONTYPE type; + IXACT3WaveBank *wave_bank; + BOOL received; + DWORD thread_id; +}; + +static void WINAPI notification_cb(const XACT_NOTIFICATION *notification) +{ + struct notification_cb_data *data = notification->pvContext; + DWORD thread_id = GetCurrentThreadId(); + + data->received = TRUE; + ok(notification->type == data->type, + "Unexpected notification type %u\n", notification->type); + ok(notification->waveBank.pWaveBank == data->wave_bank, "Unexpected wave bank %p instead of %p\n", + notification->waveBank.pWaveBank, data->wave_bank); + ok(thread_id == data->thread_id, "Unexpected thread id %#lx instead of %#lx\n", thread_id, data->thread_id); +} + +static void test_notifications(void) +{ + struct notification_cb_data prepared_data = { 0 }, destroyed_data = { 0 }; + XACT_NOTIFICATION_DESCRIPTION notification_desc = { 0 }; + XACT_STREAMING_PARAMETERS streaming_params = { 0 }; + XACT_RUNTIME_PARAMETERS params = { 0 }; + IXACT3Engine *engine; + WCHAR *filename; + unsigned int i; + HANDLE file; + DWORD state; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_XACTEngine, NULL, CLSCTX_INPROC_SERVER, &IID_IXACT3Engine, (void **)&engine); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* Win 10 v1507 */, "Cannot create engine, hr %#lx\n", hr); + + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("XACT not supported\n"); + return; + } + + params.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT; + params.fnNotificationCallback = notification_cb; + + hr = IXACT3Engine_Initialize(engine, ¶ms); + ok(hr == S_OK, "Cannot initialize engine, hr %#lx\n", hr); + + prepared_data.type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED; + prepared_data.thread_id = GetCurrentThreadId(); + notification_desc.type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED; + notification_desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; + notification_desc.pvContext = &prepared_data; + hr = IXACT3Engine_RegisterNotification(engine, ¬ification_desc); + ok(hr == S_OK, "Cannot register notification, hr %#lx\n", hr); + + destroyed_data.type = XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED; + destroyed_data.thread_id = GetCurrentThreadId(); + notification_desc.type = XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED; + notification_desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; + notification_desc.pvContext = NULL; + hr = IXACT3Engine_RegisterNotification(engine, ¬ification_desc); + ok(hr == S_OK, "Cannot register notification, hr %#lx\n", hr); + + /* Registering again overrides pvContext, but each notification + * class has its own pvContext. */ + notification_desc.pvContext = &destroyed_data; + hr = IXACT3Engine_RegisterNotification(engine, ¬ification_desc); + ok(hr == S_OK, "Cannot register notification, hr %#lx\n", hr); + + filename = gen_xwb_file(); + + file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + ok(file != INVALID_HANDLE_VALUE, "Cannot open file\n"); + + streaming_params.file = file; + streaming_params.packetSize = 0x800; + hr = IXACT3Engine_CreateStreamingWaveBank(engine, &streaming_params, &prepared_data.wave_bank); + ok(hr == S_OK, "Cannot create a streaming wave bank, hr %#lx\n", hr); + destroyed_data.wave_bank = prepared_data.wave_bank; + + for (i = 0; i < 10 && !prepared_data.received; i++) + { + IXACT3Engine_DoWork(engine); + Sleep(1); + } + + hr = IXACT3WaveBank_GetState(prepared_data.wave_bank, &state); + ok(hr == S_OK, "Cannot query wave bank state, hr %#lx\n", hr); + ok(state == XACT_WAVEBANKSTATE_PREPARED, "Wave bank is not in prepared state, but in %#lx\n", state); + + todo_wine ok(prepared_data.received, "The 'wave bank prepared' notification was never received\n"); + ok(!destroyed_data.received, "The 'wave bank destroyed' notification was received too early\n"); + + IXACT3WaveBank_Destroy(prepared_data.wave_bank); + todo_wine ok(destroyed_data.received, "The 'wave bank destroyed' notification was never received\n"); + + CloseHandle(file); + IXACT3Engine_Release(engine); + + DeleteFileW(filename); +} + START_TEST(xact3) { CoInitialize(NULL);
test_interfaces(); + test_notifications();
CoUninitialize(); }
From: Giovanni Mascellani gmascellani@codeweavers.com
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- libs/faudio/include/FAudio.h | 2 +- libs/faudio/src/FACT.c | 36 ++++++++- libs/faudio/src/FACT_internal.h | 1 + libs/faudio/src/FAudioFX_reverb.c | 99 ++++++++++++++----------- libs/faudio/src/FAudio_internal_simd.c | 8 +- libs/faudio/src/FAudio_platform_win32.c | 4 + 6 files changed, 97 insertions(+), 53 deletions(-)
diff --git a/libs/faudio/include/FAudio.h b/libs/faudio/include/FAudio.h index 0368d93eaac..f9dce8dfc16 100644 --- a/libs/faudio/include/FAudio.h +++ b/libs/faudio/include/FAudio.h @@ -485,7 +485,7 @@ extern FAudioGUID DATAFORMAT_SUBTYPE_IEEE_FLOAT;
#define FAUDIO_ABI_VERSION 0 #define FAUDIO_MAJOR_VERSION 22 -#define FAUDIO_MINOR_VERSION 6 +#define FAUDIO_MINOR_VERSION 7 #define FAUDIO_PATCH_VERSION 0
#define FAUDIO_COMPILED_VERSION ( \ diff --git a/libs/faudio/src/FACT.c b/libs/faudio/src/FACT.c index c3596ec2d48..f7b3a64bb8e 100644 --- a/libs/faudio/src/FACT.c +++ b/libs/faudio/src/FACT.c @@ -433,9 +433,17 @@ uint32_t FACTAudioEngine_DoWork(FACTAudioEngine *pEngine) uint8_t i; FACTCue *cue; LinkedList *list; + FACTNotification *note;
FAudio_PlatformLockMutex(pEngine->apiLock);
+ while (pEngine->wb_notifications_list) + { + note = (FACTNotification*) pEngine->wb_notifications_list->entry; + pEngine->notificationCallback(note); + LinkedList_RemoveEntry(&pEngine->wb_notifications_list, note, pEngine->apiLock, pEngine->pFree); + } + list = pEngine->sbList; while (list != NULL) { @@ -495,6 +503,7 @@ uint32_t FACTAudioEngine_CreateInMemoryWaveBank( uint32_t dwAllocAttributes, FACTWaveBank **ppWaveBank ) { + FACTNotification *note; uint32_t retval; FAudio_PlatformLockMutex(pEngine->apiLock); retval = FACT_INTERNAL_ParseWaveBank( @@ -507,6 +516,14 @@ uint32_t FACTAudioEngine_CreateInMemoryWaveBank( 0, ppWaveBank ); + if (pEngine->notifications & NOTIFY_WAVEBANKPREPARED) + { + note = (FACTNotification*) pEngine->pMalloc(sizeof(FACTNotification)); + note->type = FACTNOTIFICATIONTYPE_WAVEBANKPREPARED; + note->waveBank.pWaveBank = *ppWaveBank; + note->pvContext = pEngine->wb_context; + LinkedList_AddEntry(&pEngine->wb_notifications_list, note, pEngine->apiLock, pEngine->pMalloc); + } FAudio_PlatformUnlockMutex(pEngine->apiLock); return retval; } @@ -516,6 +533,7 @@ uint32_t FACTAudioEngine_CreateStreamingWaveBank( const FACTStreamingParameters *pParms, FACTWaveBank **ppWaveBank ) { + FACTNotification *note; uint32_t retval, packetSize; FAudio_PlatformLockMutex(pEngine->apiLock); if ( pEngine->pReadFile == FACT_INTERNAL_DefaultReadFile && @@ -538,6 +556,14 @@ uint32_t FACTAudioEngine_CreateStreamingWaveBank( 1, ppWaveBank ); + if (pEngine->notifications & NOTIFY_WAVEBANKPREPARED) + { + note = (FACTNotification*) pEngine->pMalloc(sizeof(FACTNotification)); + note->type = FACTNOTIFICATIONTYPE_WAVEBANKPREPARED; + note->waveBank.pWaveBank = *ppWaveBank; + note->pvContext = pEngine->wb_context; + LinkedList_AddEntry(&pEngine->wb_notifications_list, note, pEngine->apiLock, pEngine->pMalloc); + } FAudio_PlatformUnlockMutex(pEngine->apiLock); return retval; } @@ -2175,11 +2201,13 @@ uint32_t FACTWave_Stop(FACTWave *pWave, uint32_t dwFlags) { FACTNotification note; note.type = FACTNOTIFICATIONTYPE_WAVESTOP; + note.wave.cueIndex = pWave->parentCue->index; + note.wave.pCue = pWave->parentCue; + note.wave.pSoundBank = pWave->parentCue->parentBank; note.wave.pWave = pWave; - if (pWave->parentBank->parentEngine->notifications & NOTIFY_WAVESTOP) - { - note.pvContext = pWave->parentBank->parentEngine->wave_context; - } + note.wave.pWaveBank = pWave->parentBank; + note.pvContext = pWave->parentBank->parentEngine->wave_context; + pWave->parentBank->parentEngine->notificationCallback(¬e); }
diff --git a/libs/faudio/src/FACT_internal.h b/libs/faudio/src/FACT_internal.h index 8d46953be7b..97d09e56c66 100644 --- a/libs/faudio/src/FACT_internal.h +++ b/libs/faudio/src/FACT_internal.h @@ -440,6 +440,7 @@ struct FACTAudioEngine void *sb_context; void *wb_context; void *wave_context; + LinkedList *wb_notifications_list;
/* Settings handle */ void *settings; diff --git a/libs/faudio/src/FAudioFX_reverb.c b/libs/faudio/src/FAudioFX_reverb.c index 8219afd139a..b357b772ec6 100644 --- a/libs/faudio/src/FAudioFX_reverb.c +++ b/libs/faudio/src/FAudioFX_reverb.c @@ -1015,35 +1015,35 @@ static inline float DspReverb_INTERNAL_Process_2_to_2( size_t sample_count ) { const float *in_end = samples_in + sample_count; - float in, in_ratio, early, late[2]; + float in, early, late[2]; float squared_sum = 0;
while (samples_in < in_end) { /* Input - Combine 2 channels into 1 */ in = (samples_in[0] + samples_in[1]) / 2.0f; - in_ratio = in * reverb->dry_ratio; - samples_in += 2;
/* Early Reflections */ early = DspReverb_INTERNAL_ProcessEarly(reverb, in);
/* Reverberation with Wet/Dry Mix */ - late[0] = DspReverb_INTERNAL_ProcessChannel( + late[0] = (DspReverb_INTERNAL_ProcessChannel( reverb, &reverb->channel[0], early - ); + ) * reverb->wet_ratio) + samples_in[0] * reverb->dry_ratio; late[1] = (DspReverb_INTERNAL_ProcessChannel( reverb, &reverb->channel[1], early - ) * reverb->wet_ratio) + in_ratio; + ) * reverb->wet_ratio) + samples_in[1] * reverb->dry_ratio; squared_sum += (late[0] * late[0]) + (late[1] * late[1]);
/* Output */ *samples_out++ = late[0]; *samples_out++ = late[1]; + + samples_in += 2; }
return squared_sum; @@ -1407,6 +1407,22 @@ uint32_t FAudioFXReverb_LockForProcess( fapo->base.pMalloc );
+ /* Initialize the effect to a default setting */ + if (fapo->apiVersion == 9) + { + DspReverb_SetParameters9( + &fapo->reverb, + (FAudioFXReverbParameters9*) fapo->base.m_pParameterBlocks + ); + } + else + { + DspReverb_SetParameters( + &fapo->reverb, + (FAudioFXReverbParameters*) fapo->base.m_pParameterBlocks + ); + } + /* Call parent to do basic validation */ return FAPOBase_LockForProcess( &fapo->base, @@ -1487,6 +1503,24 @@ void FAudioFXReverb_Process( FAudioFXReverbParameters *params; uint8_t update_params = FAPOBase_ParametersChanged(&fapo->base); float total; + + params = (FAudioFXReverbParameters*) FAPOBase_BeginProcess(&fapo->base); + + /* Update parameters before doing anything else */ + if (update_params) + { + if (fapo->apiVersion == 9) + { + DspReverb_SetParameters9( + &fapo->reverb, + (FAudioFXReverbParameters9*) params + ); + } + else + { + DspReverb_SetParameters(&fapo->reverb, params); + } + } /* Handle disabled filter */ if (IsEnabled == 0) @@ -1503,6 +1537,7 @@ void FAudioFXReverb_Process( ); }
+ FAPOBase_EndProcess(&fapo->base); return; } @@ -1516,24 +1551,6 @@ void FAudioFXReverb_Process( ); }
- params = (FAudioFXReverbParameters*) FAPOBase_BeginProcess(&fapo->base); - - /* Update parameters */ - if (update_params) - { - if (fapo->apiVersion == 9) - { - DspReverb_SetParameters9( - &fapo->reverb, - (FAudioFXReverbParameters9*) params - ); - } - else - { - DspReverb_SetParameters(&fapo->reverb, params); - } - } - /* Run reverb effect */ #define PROCESS(pin, pout) \ DspReverb_INTERNAL_Process_##pin##_to_##pout( \ @@ -1666,16 +1683,6 @@ uint32_t FAudioCreateReverbWithCustomAllocatorEXT( sizeof(FAudioFXReverbParameters) * 3 ); result->apiVersion = 7; - #define INITPARAMS(offset) \ - FAudio_memcpy( \ - params + sizeof(FAudioFXReverbParameters) * offset, \ - &fxdefault, \ - sizeof(FAudioFXReverbParameters) \ - ); - INITPARAMS(0) - INITPARAMS(1) - INITPARAMS(2) - #undef INITPARAMS
/* Initialize... */ FAudio_memcpy( @@ -1711,6 +1718,13 @@ uint32_t FAudioCreateReverbWithCustomAllocatorEXT( result->base.Destructor = FAudioFXReverb_Free; #undef ASSIGN_VT
+ /* Prepare the default parameters */ + result->base.base.Initialize( + result, + &fxdefault, + sizeof(FAudioFXReverbParameters) + ); + /* Finally. */ *ppApo = &result->base.base; return 0; @@ -1839,16 +1853,6 @@ uint32_t FAudioCreateReverb9WithCustomAllocatorEXT( sizeof(FAudioFXReverbParameters9) * 3 ); result->apiVersion = 9; - #define INITPARAMS(offset) \ - FAudio_memcpy( \ - params + sizeof(FAudioFXReverbParameters9) * offset, \ - &fxdefault, \ - sizeof(FAudioFXReverbParameters9) \ - ); - INITPARAMS(0) - INITPARAMS(1) - INITPARAMS(2) - #undef INITPARAMS
/* Initialize... */ FAudio_memcpy( @@ -1884,6 +1888,13 @@ uint32_t FAudioCreateReverb9WithCustomAllocatorEXT( result->base.Destructor = FAudioFXReverb_Free; #undef ASSIGN_VT
+ /* Prepare the default parameters */ + result->base.base.Initialize( + result, + &fxdefault, + sizeof(FAudioFXReverbParameters9) + ); + /* Finally. */ *ppApo = &result->base.base; return 0; diff --git a/libs/faudio/src/FAudio_internal_simd.c b/libs/faudio/src/FAudio_internal_simd.c index 344a918719c..e2b192c82af 100644 --- a/libs/faudio/src/FAudio_internal_simd.c +++ b/libs/faudio/src/FAudio_internal_simd.c @@ -285,10 +285,10 @@ void FAudio_INTERNAL_Convert_U8_To_F32_NEON( const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); /* convert top 8 bytes to 8 uint16 */ const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); /* convert bottom 8 bytes to 8 uint16 */ /* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */ - vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128)); - vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128)); - vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128)); - vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128)); + vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128)); + vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128)); + vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128)); + vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128)); i -= 16; mmsrc -= 16; dst -= 16; }
diff --git a/libs/faudio/src/FAudio_platform_win32.c b/libs/faudio/src/FAudio_platform_win32.c index 9edb2b21bff..29944edcfed 100644 --- a/libs/faudio/src/FAudio_platform_win32.c +++ b/libs/faudio/src/FAudio_platform_win32.c @@ -501,6 +501,10 @@ uint32_t FAudio_PlatformGetDeviceDetails( sizeof(GUID) ); } + else + { + details->OutputFormat.dwChannelMask = GetMask(format->nChannels); + }
CoTaskMemFree(format);
From: Giovanni Mascellani gmascellani@codeweavers.com
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/xactengine3_7/tests/xact3.c | 5 +- dlls/xactengine3_7/xact_dll.c | 201 +++++++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 14 deletions(-)
diff --git a/dlls/xactengine3_7/tests/xact3.c b/dlls/xactengine3_7/tests/xact3.c index 1b27eb9aa19..5daa18ca81b 100644 --- a/dlls/xactengine3_7/tests/xact3.c +++ b/dlls/xactengine3_7/tests/xact3.c @@ -172,6 +172,7 @@ static void WINAPI notification_cb(const XACT_NOTIFICATION *notification) data->received = TRUE; ok(notification->type == data->type, "Unexpected notification type %u\n", notification->type); + todo_wine_if(notification->type == XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED) ok(notification->waveBank.pWaveBank == data->wave_bank, "Unexpected wave bank %p instead of %p\n", notification->waveBank.pWaveBank, data->wave_bank); ok(thread_id == data->thread_id, "Unexpected thread id %#lx instead of %#lx\n", thread_id, data->thread_id); @@ -248,11 +249,11 @@ static void test_notifications(void) ok(hr == S_OK, "Cannot query wave bank state, hr %#lx\n", hr); ok(state == XACT_WAVEBANKSTATE_PREPARED, "Wave bank is not in prepared state, but in %#lx\n", state);
- todo_wine ok(prepared_data.received, "The 'wave bank prepared' notification was never received\n"); + ok(prepared_data.received, "The 'wave bank prepared' notification was never received\n"); ok(!destroyed_data.received, "The 'wave bank destroyed' notification was received too early\n");
IXACT3WaveBank_Destroy(prepared_data.wave_bank); - todo_wine ok(destroyed_data.received, "The 'wave bank destroyed' notification was never received\n"); + ok(destroyed_data.received, "The 'wave bank destroyed' notification was never received\n");
CloseHandle(file); IXACT3Engine_Release(engine); diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c index 98c3cf8f076..f7be480656d 100644 --- a/dlls/xactengine3_7/xact_dll.c +++ b/dlls/xactengine3_7/xact_dll.c @@ -34,6 +34,7 @@ #include "xact3.h" #endif #include "wine/debug.h" +#include "wine/rbtree.h"
WINE_DEFAULT_DEBUG_CHANNEL(xact3);
@@ -52,6 +53,42 @@ WINE_DEFAULT_DEBUG_CHANNEL(xact3); #define IXACT3WaveBankVtbl IXACTWaveBankVtbl #endif
+struct wrapper_lookup +{ + struct wine_rb_entry entry; + void *fact; + void *xact; +}; + +static int wrapper_lookup_compare(const void *key, const struct wine_rb_entry *entry) +{ + struct wrapper_lookup *lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry); + + return (key > lookup->fact) - (key < lookup->fact); +} + +static void wrapper_lookup_destroy(struct wine_rb_entry *entry, void *context) +{ + struct wrapper_lookup *lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry); + + HeapFree(GetProcessHeap(), 0, lookup); +} + +typedef struct _XACT3EngineImpl { + IXACT3Engine IXACT3Engine_iface; + + FACTAudioEngine *fact_engine; + + XACT_READFILE_CALLBACK pReadFile; + XACT_GETOVERLAPPEDRESULT_CALLBACK pGetOverlappedResult; + XACT_NOTIFICATION_CALLBACK notification_callback; + + void *wb_prepared_context; + void *wb_destroyed_context; + struct wine_rb_tree wb_wrapper_lookup; + CRITICAL_SECTION wb_wrapper_lookup_cs; +} XACT3EngineImpl; + typedef struct _XACT3CueImpl { IXACT3Cue IXACT3Cue_iface; FACTCue *fact_cue; @@ -543,6 +580,7 @@ typedef struct _XACT3WaveBankImpl { IXACT3WaveBank IXACT3WaveBank_iface;
FACTWaveBank *fact_wavebank; + struct _XACT3EngineImpl *engine; } XACT3WaveBankImpl;
static inline XACT3WaveBankImpl *impl_from_IXACT3WaveBank(IXACT3WaveBank *iface) @@ -553,10 +591,32 @@ static inline XACT3WaveBankImpl *impl_from_IXACT3WaveBank(IXACT3WaveBank *iface) static HRESULT WINAPI IXACT3WaveBankImpl_Destroy(IXACT3WaveBank *iface) { XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface); + struct wrapper_lookup *lookup; + struct wine_rb_entry *entry; HRESULT hr;
TRACE("(%p)\n", This);
+ EnterCriticalSection(&This->engine->wb_wrapper_lookup_cs); + + entry = wine_rb_get(&This->engine->wb_wrapper_lookup, This->fact_wavebank); + + if (!entry) + { + LeaveCriticalSection(&This->engine->wb_wrapper_lookup_cs); + + WARN("cannot find wave bank in wrapper lookup\n"); + } + else + { + wine_rb_remove(&This->engine->wb_wrapper_lookup, entry); + + LeaveCriticalSection(&This->engine->wb_wrapper_lookup_cs); + + lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry); + HeapFree(GetProcessHeap(), 0, lookup); + } + hr = FACTWaveBank_Destroy(This->fact_wavebank); HeapFree(GetProcessHeap(), 0, This); return hr; @@ -709,16 +769,6 @@ static const IXACT3WaveBankVtbl XACT3WaveBank_Vtbl = IXACT3WaveBankImpl_GetState };
-typedef struct _XACT3EngineImpl { - IXACT3Engine IXACT3Engine_iface; - - FACTAudioEngine *fact_engine; - - XACT_READFILE_CALLBACK pReadFile; - XACT_GETOVERLAPPEDRESULT_CALLBACK pGetOverlappedResult; - XACT_NOTIFICATION_CALLBACK notification_callback; -} XACT3EngineImpl; - typedef struct wrap_readfile_struct { XACT3EngineImpl *engine; HANDLE file; @@ -792,7 +842,11 @@ static ULONG WINAPI IXACT3EngineImpl_Release(IXACT3Engine *iface) TRACE("(%p)->(): Refcount now %lu\n", This, ref);
if (!ref) + { + DeleteCriticalSection(&This->wb_wrapper_lookup_cs); + wine_rb_destroy(&This->wb_wrapper_lookup, wrapper_lookup_destroy, NULL); HeapFree(GetProcessHeap(), 0, This); + } return ref; }
@@ -832,9 +886,45 @@ static HRESULT WINAPI IXACT3EngineImpl_GetFinalMixFormat(IXACT3Engine *iface,
#endif
+static XACTNOTIFICATIONTYPE xact_notification_type_from_fact(uint8_t type) +{ + /* we can't use a switch statement, because the constants are static const + * variables, and some compilers can't deal with that */ +#define X(a) if (type == FACTNOTIFICATIONTYPE_##a) return XACTNOTIFICATIONTYPE_##a + X(CUEPREPARED); + X(CUEPLAY); + X(CUESTOP); + X(CUEDESTROYED); + X(MARKER); + X(SOUNDBANKDESTROYED); + X(WAVEBANKDESTROYED); + X(LOCALVARIABLECHANGED); + X(GLOBALVARIABLECHANGED); + X(GUICONNECTED); + X(GUIDISCONNECTED); + X(WAVEPLAY); + X(WAVESTOP); + X(WAVEBANKPREPARED); + X(WAVEBANKSTREAMING_INVALIDCONTENT); +#if XACT3_VER >= 0x0205 + X(WAVEPREPARED); + X(WAVELOOPED); + X(WAVEDESTROYED); +#endif +#undef X + + FIXME("unknown type %#x\n", type); + return 0; +} + static void FACTCALL fact_notification_cb(const FACTNotification *notification) { XACT3EngineImpl *engine = (XACT3EngineImpl *)notification->pvContext; + XACT_NOTIFICATION xnotification; + struct wrapper_lookup *lookup; + struct wine_rb_entry *entry; + + TRACE("notification %p\n", notification->pvContext);
/* Older versions of FAudio don't pass through the context */ if (!engine) @@ -843,7 +933,37 @@ static void FACTCALL fact_notification_cb(const FACTNotification *notification) return; }
- FIXME("Unsupported callback type %d\n", notification->type); + xnotification.type = xact_notification_type_from_fact(notification->type); + xnotification.timeStamp = notification->timeStamp; + + if (notification->type == XACTNOTIFICATIONTYPE_WAVEBANKPREPARED + || notification->type == XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED) + { + EnterCriticalSection(&engine->wb_wrapper_lookup_cs); + entry = wine_rb_get(&engine->wb_wrapper_lookup, notification->waveBank.pWaveBank); + if (!entry) + { + WARN("cannot find wave bank in wrapper lookup\n"); + xnotification.waveBank.pWaveBank = NULL; + } + else + { + lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry); + xnotification.waveBank.pWaveBank = lookup->xact; + } + LeaveCriticalSection(&engine->wb_wrapper_lookup_cs); + if (notification->type == XACTNOTIFICATIONTYPE_WAVEBANKPREPARED) + xnotification.pvContext = engine->wb_prepared_context; + else + xnotification.pvContext = engine->wb_destroyed_context; + } + else + { + FIXME("Unsupported callback type %d\n", notification->type); + return; + } + + engine->notification_callback(&xnotification); }
static HRESULT WINAPI IXACT3EngineImpl_Initialize(IXACT3Engine *iface, @@ -969,6 +1089,7 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *ifac DWORD dwAllocAttributes, IXACT3WaveBank **ppWaveBank) { XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + struct wrapper_lookup *lookup; XACT3WaveBankImpl *wb; FACTWaveBank *fwb; UINT ret; @@ -992,8 +1113,32 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *ifac return E_OUTOFMEMORY; }
+ lookup = HeapAlloc(GetProcessHeap(), 0, sizeof(*lookup)); + if (!lookup) + { + FACTWaveBank_Destroy(fwb); + HeapFree(GetProcessHeap(), 0, wb); + ERR("Failed to allocate wrapper_lookup!\n"); + return E_OUTOFMEMORY; + } + lookup->fact = fwb; + lookup->xact = &wb->IXACT3WaveBank_iface; + + EnterCriticalSection(&This->wb_wrapper_lookup_cs); + + ret = wine_rb_put(&This->wb_wrapper_lookup, lookup->fact, &lookup->entry); + + LeaveCriticalSection(&This->wb_wrapper_lookup_cs); + + if (ret) + { + WARN("wrapper_lookup already present in the tree??\n"); + HeapFree(GetProcessHeap(), 0, lookup); + } + wb->IXACT3WaveBank_iface.lpVtbl = &XACT3WaveBank_Vtbl; wb->fact_wavebank = fwb; + wb->engine = This; *ppWaveBank = &wb->IXACT3WaveBank_iface;
TRACE("Created in-memory WaveBank: %p\n", wb); @@ -1007,6 +1152,7 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *ifa { XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); FACTStreamingParameters fakeParms; + struct wrapper_lookup *lookup; wrap_readfile_struct *fake; XACT3WaveBankImpl *wb; FACTWaveBank *fwb; @@ -1040,8 +1186,32 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *ifa return E_OUTOFMEMORY; }
+ lookup = HeapAlloc(GetProcessHeap(), 0, sizeof(*lookup)); + if (!lookup) + { + FACTWaveBank_Destroy(fwb); + HeapFree(GetProcessHeap(), 0, wb); + ERR("Failed to allocate wrapper_lookup!\n"); + return E_OUTOFMEMORY; + } + lookup->fact = fwb; + lookup->xact = &wb->IXACT3WaveBank_iface; + + EnterCriticalSection(&This->wb_wrapper_lookup_cs); + + ret = wine_rb_put(&This->wb_wrapper_lookup, lookup->fact, &lookup->entry); + + LeaveCriticalSection(&This->wb_wrapper_lookup_cs); + + if (ret) + { + WARN("wrapper_lookup already present in the tree??\n"); + HeapFree(GetProcessHeap(), 0, lookup); + } + wb->IXACT3WaveBank_iface.lpVtbl = &XACT3WaveBank_Vtbl; wb->fact_wavebank = fwb; + wb->engine = This; *ppWaveBank = &wb->IXACT3WaveBank_iface;
TRACE("Created streaming WaveBank: %p\n", wb); @@ -1198,7 +1368,6 @@ static inline void unwrap_notificationdesc(FACTNotificationDescription *fd,
/* We have to unwrap the FACT object first! */ fd->flags = xd->flags; - fd->pvContext = xd->pvContext; if (flags & NOTIFY_cueIndex) fd->cueIndex = xd->cueIndex; #if XACT3_VER >= 0x0205 @@ -1245,6 +1414,11 @@ static HRESULT WINAPI IXACT3EngineImpl_RegisterNotification(IXACT3Engine *iface,
TRACE("(%p)->(%p)\n", This, pNotificationDesc);
+ if (pNotificationDesc->type == XACTNOTIFICATIONTYPE_WAVEBANKPREPARED) + This->wb_prepared_context = pNotificationDesc->pvContext; + else if (pNotificationDesc->type == XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED) + This->wb_destroyed_context = pNotificationDesc->pvContext; + unwrap_notificationdesc(&fdesc, pNotificationDesc); fdesc.pvContext = This; return FACTAudioEngine_RegisterNotification(This->fact_engine, &fdesc); @@ -1438,6 +1612,9 @@ static HRESULT WINAPI XACT3CF_CreateInstance(IClassFactory *iface, IUnknown *pOu return hr; }
+ wine_rb_init(&object->wb_wrapper_lookup, wrapper_lookup_compare); + InitializeCriticalSection(&object->wb_wrapper_lookup_cs); + return hr; }