diff --git a/configure b/configure index 166c260a6ec..bed9eab3673 100755 --- a/configure +++ b/configure @@ -16630,6 +16630,7 @@ then enable_x3daudio1_5=${enable_x3daudio1_5:-no} enable_x3daudio1_6=${enable_x3daudio1_6:-no} enable_x3daudio1_7=${enable_x3daudio1_7:-no} + enable_xactengine3_7=${enable_xactengine3_7:-no} enable_xapofx1_1=${enable_xapofx1_1:-no} enable_xapofx1_2=${enable_xapofx1_2:-no} enable_xapofx1_3=${enable_xapofx1_3:-no} diff --git a/configure.ac b/configure.ac index 6f5aa8da200..29ff38f169b 100644 --- a/configure.ac +++ b/configure.ac @@ -1958,6 +1958,7 @@ then enable_x3daudio1_5=${enable_x3daudio1_5:-no} enable_x3daudio1_6=${enable_x3daudio1_6:-no} enable_x3daudio1_7=${enable_x3daudio1_7:-no} + enable_xactengine3_7=${enable_xactengine3_7:-no} enable_xapofx1_1=${enable_xapofx1_1:-no} enable_xapofx1_2=${enable_xapofx1_2:-no} enable_xapofx1_3=${enable_xapofx1_3:-no} diff --git a/dlls/xactengine3_7/Makefile.in b/dlls/xactengine3_7/Makefile.in index f92aad6680e..6fce27d1628 100644 --- a/dlls/xactengine3_7/Makefile.in +++ b/dlls/xactengine3_7/Makefile.in @@ -1,4 +1,7 @@ MODULE = xactengine3_7.dll +IMPORTS = ole32 uuid +EXTRALIBS = $(FAUDIO_LIBS) +EXTRAINCL = $(FAUDIO_CFLAGS) C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c index ffabc3829f4..3a14db74608 100644 --- a/dlls/xactengine3_7/xact_dll.c +++ b/dlls/xactengine3_7/xact_dll.c @@ -19,7 +19,12 @@ #include "config.h" #include +#include +#define NONAMELESSUNION +#define COBJMACROS + +#include "initguid.h" #include "xact3.h" #include "rpcproxy.h" #include "xact_classes.h" @@ -29,6 +34,457 @@ WINE_DEFAULT_DEBUG_CHANNEL(xact3); static HINSTANCE instance; +typedef struct _XACT3EngineImpl { + IXACT3Engine IXACT3Engine_iface; + + FACTAudioEngine *fact_engine; + + XACT_READFILE_CALLBACK pReadFile; + XACT_GETOVERLAPPEDRESULT_CALLBACK pGetOverlappedResult; +} XACT3EngineImpl; + +typedef struct wrap_readfile_struct { + XACT3EngineImpl *engine; + HANDLE file; +} wrap_readfile_struct; + +static int32_t FACTCALL wrap_readfile( + void* hFile, + void* lpBuffer, + uint32_t nNumberOfBytesRead, + uint32_t *lpNumberOfBytesRead, + FACTOverlapped *lpOverlapped) +{ + wrap_readfile_struct *wrap = (wrap_readfile_struct*) hFile; + return wrap->engine->pReadFile(wrap->file, lpBuffer, nNumberOfBytesRead, + lpNumberOfBytesRead, (LPOVERLAPPED)lpOverlapped); +} + +static int32_t FACTCALL wrap_getoverlappedresult( + void* hFile, + FACTOverlapped *lpOverlapped, + uint32_t *lpNumberOfBytesTransferred, + int32_t bWait) +{ + wrap_readfile_struct *wrap = (wrap_readfile_struct*) hFile; + return wrap->engine->pGetOverlappedResult(wrap->file, (LPOVERLAPPED)lpOverlapped, + lpNumberOfBytesTransferred, bWait); +} + +static inline XACT3EngineImpl *impl_from_IXACT3Engine(IXACT3Engine *iface) +{ + return CONTAINING_RECORD(iface, XACT3EngineImpl, IXACT3Engine_iface); +} + +static HRESULT WINAPI IXACT3EngineImpl_QueryInterface(IXACT3Engine *iface, + REFIID riid, void **ppvObject) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + if(IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IXACT3Engine)){ + *ppvObject = &This->IXACT3Engine_iface; + } + else + *ppvObject = NULL; + + if (*ppvObject){ + IUnknown_AddRef((IUnknown*)*ppvObject); + return S_OK; + } + + FIXME("(%p)->(%s,%p), not found\n", This, debugstr_guid(riid), ppvObject); + + return E_NOINTERFACE; +} + +static ULONG WINAPI IXACT3EngineImpl_AddRef(IXACT3Engine *iface) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + ULONG ref = FACTAudioEngine_AddRef(This->fact_engine); + TRACE("(%p)->(): Refcount now %u\n", This, ref); + return ref; +} + +static ULONG WINAPI IXACT3EngineImpl_Release(IXACT3Engine *iface) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + ULONG ref = FACTAudioEngine_Release(This->fact_engine); + + TRACE("(%p)->(): Refcount now %u\n", This, ref); + + if (!ref) + HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +static HRESULT WINAPI IXACT3EngineImpl_GetRendererCount(IXACT3Engine *iface, + XACTINDEX *pnRendererCount) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%p)\n", This, pnRendererCount); + + return FACTAudioEngine_GetRendererCount(This->fact_engine, pnRendererCount); +} + +static HRESULT WINAPI IXACT3EngineImpl_GetRendererDetails(IXACT3Engine *iface, + XACTINDEX nRendererIndex, XACT_RENDERER_DETAILS *pRendererDetails) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%d, %p)\n", This, nRendererIndex, pRendererDetails); + + return FACTAudioEngine_GetRendererDetails(This->fact_engine, + nRendererIndex, (FACTRendererDetails*) pRendererDetails); +} + +static HRESULT WINAPI IXACT3EngineImpl_GetFinalMixFormat(IXACT3Engine *iface, + WAVEFORMATEXTENSIBLE *pFinalMixFormat) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%p)\n", This, pFinalMixFormat); + + return FACTAudioEngine_GetFinalMixFormat(This->fact_engine, + (FAudioWaveFormatExtensible*) pFinalMixFormat); +} + +static HRESULT WINAPI IXACT3EngineImpl_Initialize(IXACT3Engine *iface, + const XACT_RUNTIME_PARAMETERS *pParams) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FACTRuntimeParameters params; + + TRACE("(%p)->(%p)\n", This, pParams); + + memcpy(¶ms, pParams, sizeof(FACTRuntimeParameters)); + + /* FIXME: pXAudio2 and pMasteringVoice are pointers to + * IXAudio2/IXAudio2MasteringVoice objects. FACT wants pointers to + * FAudio/FAudioMasteringVoice objects. In Wine's XAudio2 implementation, we + * actually have them available, but only if you access their internal data. + * For now we can just force these pointers to NULL, as XACT simply + * generates its own engine and endpoint in that situation. These parameters + * are mostly an optimization for games with multiple XACT3Engines that want + * a single engine running everything. + * -flibit + */ + if (pParams->pXAudio2 != NULL){ + FIXME("pXAudio2 parameter not supported! Falling back to NULL\n"); + params.pXAudio2 = NULL; + + if (pParams->pMasteringVoice != NULL){ + FIXME("pXAudio2 parameter not supported! Falling back to NULL\n"); + params.pMasteringVoice = NULL; + } + } + + /* Force Windows I/O, do NOT use the FACT default! */ + This->pReadFile = (XACT_READFILE_CALLBACK) + pParams->fileIOCallbacks.readFileCallback; + This->pGetOverlappedResult = (XACT_GETOVERLAPPEDRESULT_CALLBACK) + pParams->fileIOCallbacks.getOverlappedResultCallback; + if (This->pReadFile == NULL) + This->pReadFile = (XACT_READFILE_CALLBACK) ReadFile; + if (This->pGetOverlappedResult == NULL) + This->pGetOverlappedResult = (XACT_GETOVERLAPPEDRESULT_CALLBACK) + GetOverlappedResult; + params.fileIOCallbacks.readFileCallback = wrap_readfile; + params.fileIOCallbacks.getOverlappedResultCallback = wrap_getoverlappedresult; + + return FACTAudioEngine_Initialize(This->fact_engine, ¶ms); +} + +static HRESULT WINAPI IXACT3EngineImpl_ShutDown(IXACT3Engine *iface) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)\n", This); + + return FACTAudioEngine_ShutDown(This->fact_engine); +} + +static HRESULT WINAPI IXACT3EngineImpl_DoWork(IXACT3Engine *iface) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)\n", This); + + return FACTAudioEngine_DoWork(This->fact_engine); +} + +static HRESULT WINAPI IXACT3EngineImpl_CreateSoundBank(IXACT3Engine *iface, + const void* pvBuffer, DWORD dwSize, DWORD dwFlags, + DWORD dwAllocAttributes, IXACT3SoundBank **ppSoundBank) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p)->(%p, %u, 0x%x, 0x%x, %p): stub!\n", This, pvBuffer, dwSize, dwFlags, + dwAllocAttributes, ppSoundBank); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *iface, + const void* pvBuffer, DWORD dwSize, DWORD dwFlags, + DWORD dwAllocAttributes, IXACT3WaveBank **ppWaveBank) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p)->(%p, %u, 0x%x, 0x%x, %p): stub!\n", This, pvBuffer, dwSize, dwFlags, + dwAllocAttributes, ppWaveBank); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *iface, + const XACT_STREAMING_PARAMETERS *pParms, + IXACT3WaveBank **ppWaveBank) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p)->(%p, %p): stub!\n", This, pParms, ppWaveBank); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_PrepareInMemoryWave(IXACT3Engine *iface, + DWORD dwFlags, WAVEBANKENTRY entry, DWORD *pdwSeekTable, + BYTE *pbWaveData, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount, + IXACT3Wave **ppWave) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p): stub!\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_PrepareStreamingWave(IXACT3Engine *iface, + DWORD dwFlags, WAVEBANKENTRY entry, + XACT_STREAMING_PARAMETERS streamingParams, DWORD dwAlignment, + DWORD *pdwSeekTable, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount, + IXACT3Wave **ppWave) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p): stub!\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_PrepareWave(IXACT3Engine *iface, + DWORD dwFlags, PCSTR szWavePath, WORD wStreamingPacketSize, + DWORD dwAlignment, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount, + IXACT3Wave **ppWave) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + FIXME("(%p): stub!\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_RegisterNotification(IXACT3Engine *iface, + const XACT_NOTIFICATION_DESCRIPTION *pNotificationDesc) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + FIXME("(%p)->(%p): stub!\n", This, pNotificationDesc); + return E_NOTIMPL; +} + +static HRESULT WINAPI IXACT3EngineImpl_UnRegisterNotification(IXACT3Engine *iface, + const XACT_NOTIFICATION_DESCRIPTION *pNotificationDesc) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + FIXME("(%p)->(%p): stub!\n", This, pNotificationDesc); + return E_NOTIMPL; +} + +static XACTCATEGORY WINAPI IXACT3EngineImpl_GetCategory(IXACT3Engine *iface, + PCSTR szFriendlyName) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%s)\n", This, szFriendlyName); + + return FACTAudioEngine_GetCategory(This->fact_engine, szFriendlyName); +} + +static HRESULT WINAPI IXACT3EngineImpl_Stop(IXACT3Engine *iface, + XACTCATEGORY nCategory, DWORD dwFlags) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%u, 0x%x)\n", This, nCategory, dwFlags); + + return FACTAudioEngine_Stop(This->fact_engine, nCategory, dwFlags); +} + +static HRESULT WINAPI IXACT3EngineImpl_SetVolume(IXACT3Engine *iface, + XACTCATEGORY nCategory, XACTVOLUME nVolume) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%u, %f)\n", This, nCategory, nVolume); + + return FACTAudioEngine_SetVolume(This->fact_engine, nCategory, nVolume); +} + +static HRESULT WINAPI IXACT3EngineImpl_Pause(IXACT3Engine *iface, + XACTCATEGORY nCategory, BOOL fPause) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%u, %u)\n", This, nCategory, fPause); + + return FACTAudioEngine_Pause(This->fact_engine, nCategory, fPause); +} + +static XACTVARIABLEINDEX WINAPI IXACT3EngineImpl_GetGlobalVariableIndex( + IXACT3Engine *iface, PCSTR szFriendlyName) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%s)\n", This, szFriendlyName); + + return FACTAudioEngine_GetGlobalVariableIndex(This->fact_engine, + szFriendlyName); +} + +static HRESULT WINAPI IXACT3EngineImpl_SetGlobalVariable(IXACT3Engine *iface, + XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE nValue) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%u, %f)\n", This, nIndex, nValue); + + return FACTAudioEngine_SetGlobalVariable(This->fact_engine, nIndex, nValue); +} + +static HRESULT WINAPI IXACT3EngineImpl_GetGlobalVariable(IXACT3Engine *iface, + XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE *nValue) +{ + XACT3EngineImpl *This = impl_from_IXACT3Engine(iface); + + TRACE("(%p)->(%u, %p)\n", This, nIndex, nValue); + + return FACTAudioEngine_GetGlobalVariable(This->fact_engine, nIndex, nValue); +} + +static const IXACT3EngineVtbl XACT3Engine_Vtbl = +{ + IXACT3EngineImpl_QueryInterface, + IXACT3EngineImpl_AddRef, + IXACT3EngineImpl_Release, + IXACT3EngineImpl_GetRendererCount, + IXACT3EngineImpl_GetRendererDetails, + IXACT3EngineImpl_GetFinalMixFormat, + IXACT3EngineImpl_Initialize, + IXACT3EngineImpl_ShutDown, + IXACT3EngineImpl_DoWork, + IXACT3EngineImpl_CreateSoundBank, + IXACT3EngineImpl_CreateInMemoryWaveBank, + IXACT3EngineImpl_CreateStreamingWaveBank, + IXACT3EngineImpl_PrepareWave, + IXACT3EngineImpl_PrepareInMemoryWave, + IXACT3EngineImpl_PrepareStreamingWave, + IXACT3EngineImpl_RegisterNotification, + IXACT3EngineImpl_UnRegisterNotification, + IXACT3EngineImpl_GetCategory, + IXACT3EngineImpl_Stop, + IXACT3EngineImpl_SetVolume, + IXACT3EngineImpl_Pause, + IXACT3EngineImpl_GetGlobalVariableIndex, + IXACT3EngineImpl_SetGlobalVariable, + IXACT3EngineImpl_GetGlobalVariable +}; + +void* XACT_Internal_Malloc(size_t size) +{ + return CoTaskMemAlloc(size); +} + +void XACT_Internal_Free(void* ptr) +{ + return CoTaskMemFree(ptr); +} + +void* XACT_Internal_Realloc(void* ptr, size_t size) +{ + return CoTaskMemRealloc(ptr, size); +} + +static HRESULT WINAPI XACT3CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IClassFactory)) + { + *ppobj = iface; + return S_OK; + } + + *ppobj = NULL; + WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI XACT3CF_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI XACT3CF_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI XACT3CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter, + REFIID riid, void **ppobj) +{ + HRESULT hr; + XACT3EngineImpl *object; + + TRACE("(%p)->(%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid), ppobj); + + *ppobj = NULL; + + if(pOuter) + return CLASS_E_NOAGGREGATION; + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if(!object) + return E_OUTOFMEMORY; + + object->IXACT3Engine_iface.lpVtbl = &XACT3Engine_Vtbl; + + FACTCreateEngineWithCustomAllocatorEXT( + 0, + &object->fact_engine, + XACT_Internal_Malloc, + XACT_Internal_Free, + XACT_Internal_Realloc + ); + + hr = IXACT3Engine_QueryInterface(&object->IXACT3Engine_iface, riid, ppobj); + if(FAILED(hr)){ + HeapFree(GetProcessHeap(), 0, object); + return hr; + } + + return hr; +} + +static HRESULT WINAPI XACT3CF_LockServer(IClassFactory *iface, BOOL dolock) +{ + TRACE("(%p)->(%d): stub!\n", iface, dolock); + return S_OK; +} + +static const IClassFactoryVtbl XACT3CF_Vtbl = +{ + XACT3CF_QueryInterface, + XACT3CF_AddRef, + XACT3CF_Release, + XACT3CF_CreateInstance, + XACT3CF_LockServer +}; + +static IClassFactory XACTFactory = { &XACT3CF_Vtbl }; + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved) { TRACE("(%p, %d, %p)\n", hinstDLL, reason, pReserved); @@ -50,8 +506,13 @@ HRESULT WINAPI DllCanUnloadNow(void) HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) { - FIXME("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + if (IsEqualGUID(rclsid, &CLSID_XACTEngine37)) + { + TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return IClassFactory_QueryInterface(&XACTFactory, riid, ppv); + } + FIXME("Unknown class %s\n", debugstr_guid(rclsid)); return CLASS_E_CLASSNOTAVAILABLE; }