d3d10/tests: Add a test for effect compilation containing empty buffers.
[wine.git] / dlls / xactengine3_7 / xact_dll.c
blobcf6733106cedf4286b07cacbbcb4dbf289a372af
1 /*
2 * Copyright (c) 2018 Ethan Lee for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <FACT.h>
22 #define COBJMACROS
23 #include "objbase.h"
25 #if XACT3_VER < 0x0300
26 #include "xact2wb.h"
27 #include "initguid.h"
28 #include "xact.h"
29 #else
30 #include "xact3wb.h"
31 #include "xaudio2.h"
32 #include "initguid.h"
33 #include "xact3.h"
34 #endif
35 #include "wine/debug.h"
36 #include "wine/rbtree.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
40 #if XACT3_VER < 0x0300
41 #define IID_IXACT3Engine IID_IXACTEngine
42 #define IXACT3Cue IXACTCue
43 #define IXACT3CueVtbl IXACTCueVtbl
44 #define IXACT3Engine IXACTEngine
45 #define IXACT3EngineVtbl IXACTEngineVtbl
46 #define IXACT3Engine_QueryInterface IXACTEngine_QueryInterface
47 #define IXACT3SoundBank IXACTSoundBank
48 #define IXACT3SoundBankVtbl IXACTSoundBankVtbl
49 #define IXACT3Wave IXACTWave
50 #define IXACT3WaveVtbl IXACTWaveVtbl
51 #define IXACT3WaveBank IXACTWaveBank
52 #define IXACT3WaveBankVtbl IXACTWaveBankVtbl
53 #endif
55 #define XACTNOTIFICATIONTYPE_MAX 19 /* XACTNOTIFICATIONTYPE_WAVEBANKSTREAMING_INVALIDCONTENT + 1 */
57 struct wrapper_lookup
59 struct wine_rb_entry entry;
60 void *fact;
61 void *xact;
64 typedef struct _XACT3EngineImpl {
65 IXACT3Engine IXACT3Engine_iface;
67 FACTAudioEngine *fact_engine;
69 XACT_READFILE_CALLBACK pReadFile;
70 XACT_GETOVERLAPPEDRESULT_CALLBACK pGetOverlappedResult;
71 XACT_NOTIFICATION_CALLBACK notification_callback;
73 void *contexts[XACTNOTIFICATIONTYPE_MAX];
74 struct wine_rb_tree wrapper_lookup;
75 CRITICAL_SECTION wrapper_lookup_cs;
76 } XACT3EngineImpl;
78 static int wrapper_lookup_compare(const void *key, const struct wine_rb_entry *entry)
80 struct wrapper_lookup *lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry);
82 return (key > lookup->fact) - (key < lookup->fact);
85 static void wrapper_lookup_destroy(struct wine_rb_entry *entry, void *context)
87 struct wrapper_lookup *lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry);
89 HeapFree(GetProcessHeap(), 0, lookup);
92 static void wrapper_remove_entry(XACT3EngineImpl *engine, void *key)
94 struct wrapper_lookup *lookup;
95 struct wine_rb_entry *entry;
97 EnterCriticalSection(&engine->wrapper_lookup_cs);
99 entry = wine_rb_get(&engine->wrapper_lookup, key);
100 if (!entry)
102 LeaveCriticalSection(&engine->wrapper_lookup_cs);
104 WARN("cannot find key in wrapper lookup\n");
106 else
108 wine_rb_remove(&engine->wrapper_lookup, entry);
110 LeaveCriticalSection(&engine->wrapper_lookup_cs);
112 lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry);
113 HeapFree(GetProcessHeap(), 0, lookup);
117 static HRESULT wrapper_add_entry(XACT3EngineImpl *engine, void *fact, void *xact)
119 struct wrapper_lookup *lookup;
120 UINT ret;
122 lookup = HeapAlloc(GetProcessHeap(), 0, sizeof(*lookup));
123 if (!lookup)
125 ERR("Failed to allocate wrapper_lookup!\n");
126 return E_OUTOFMEMORY;
128 lookup->fact = fact;
129 lookup->xact = xact;
131 EnterCriticalSection(&engine->wrapper_lookup_cs);
132 ret = wine_rb_put(&engine->wrapper_lookup, lookup->fact, &lookup->entry);
133 LeaveCriticalSection(&engine->wrapper_lookup_cs);
135 if (ret)
137 WARN("wrapper_lookup already present in the tree??\n");
138 HeapFree(GetProcessHeap(), 0, lookup);
141 return S_OK;
144 /* Must be protected by engine->wrapper_lookup_cs */
145 static void* wrapper_find_entry(XACT3EngineImpl *engine, void *faudio)
147 struct wrapper_lookup *lookup;
148 struct wine_rb_entry *entry;
150 entry = wine_rb_get(&engine->wrapper_lookup, faudio);
151 if (entry)
153 lookup = WINE_RB_ENTRY_VALUE(entry, struct wrapper_lookup, entry);
154 return lookup->xact;
157 WARN("cannot find interface in wrapper lookup\n");
158 return NULL;
161 typedef struct _XACT3CueImpl {
162 IXACT3Cue IXACT3Cue_iface;
163 FACTCue *fact_cue;
164 XACT3EngineImpl *engine;
165 } XACT3CueImpl;
167 static inline XACT3CueImpl *impl_from_IXACT3Cue(IXACT3Cue *iface)
169 return CONTAINING_RECORD(iface, XACT3CueImpl, IXACT3Cue_iface);
172 static HRESULT WINAPI IXACT3CueImpl_Play(IXACT3Cue *iface)
174 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
176 TRACE("(%p)\n", iface);
178 return FACTCue_Play(This->fact_cue);
181 static HRESULT WINAPI IXACT3CueImpl_Stop(IXACT3Cue *iface, DWORD dwFlags)
183 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
185 TRACE("(%p)->(%lu)\n", iface, dwFlags);
187 return FACTCue_Stop(This->fact_cue, dwFlags);
190 static HRESULT WINAPI IXACT3CueImpl_GetState(IXACT3Cue *iface, DWORD *pdwState)
192 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
194 TRACE("(%p)->(%p)\n", iface, pdwState);
196 return FACTCue_GetState(This->fact_cue, (uint32_t *)pdwState);
199 static HRESULT WINAPI IXACT3CueImpl_Destroy(IXACT3Cue *iface)
201 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
202 UINT ret;
204 TRACE("(%p)\n", iface);
206 ret = FACTCue_Destroy(This->fact_cue);
207 if (ret != 0)
208 WARN("FACTCue_Destroy returned %d\n", ret);
209 wrapper_remove_entry(This->engine, This->fact_cue);
210 HeapFree(GetProcessHeap(), 0, This);
211 return S_OK;
214 #if XACT3_VER < 0x0300
216 static HRESULT WINAPI IXACT3CueImpl_GetChannelMap(IXACT3Cue *iface,
217 XACTCHANNELMAP *map, DWORD size, DWORD *needed_size)
219 FIXME("(%p)->(%p, %lu, %p)\n", iface, map, size, needed_size);
221 return E_NOTIMPL;
224 static HRESULT WINAPI IXACT3CueImpl_SetChannelMap(IXACT3Cue *iface, XACTCHANNELMAP *map)
226 FIXME("(%p)->(%p)\n", iface, map);
228 return E_NOTIMPL;
231 static HRESULT WINAPI IXACT3CueImpl_GetChannelVolume(IXACT3Cue *iface, XACTCHANNELVOLUME *volume)
233 FIXME("(%p)->(%p)\n", iface, volume);
235 return E_NOTIMPL;
238 static HRESULT WINAPI IXACT3CueImpl_SetChannelVolume(IXACT3Cue *iface, XACTCHANNELVOLUME *volume)
240 FIXME("(%p)->(%p)\n", iface, volume);
242 return E_NOTIMPL;
245 #endif
247 static HRESULT WINAPI IXACT3CueImpl_SetMatrixCoefficients(IXACT3Cue *iface,
248 UINT32 uSrcChannelCount, UINT32 uDstChannelCount,
249 float *pMatrixCoefficients)
251 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
253 TRACE("(%p)->(%u, %u, %p)\n", iface, uSrcChannelCount, uDstChannelCount,
254 pMatrixCoefficients);
256 return FACTCue_SetMatrixCoefficients(This->fact_cue, uSrcChannelCount,
257 uDstChannelCount, pMatrixCoefficients);
260 static XACTVARIABLEINDEX WINAPI IXACT3CueImpl_GetVariableIndex(IXACT3Cue *iface,
261 PCSTR szFriendlyName)
263 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
265 TRACE("(%p)->(%s)\n", iface, szFriendlyName);
267 return FACTCue_GetVariableIndex(This->fact_cue, szFriendlyName);
270 static HRESULT WINAPI IXACT3CueImpl_SetVariable(IXACT3Cue *iface,
271 XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE nValue)
273 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
275 TRACE("(%p)->(%u, %f)\n", iface, nIndex, nValue);
277 return FACTCue_SetVariable(This->fact_cue, nIndex, nValue);
280 static HRESULT WINAPI IXACT3CueImpl_GetVariable(IXACT3Cue *iface,
281 XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE *nValue)
283 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
285 TRACE("(%p)->(%u, %p)\n", iface, nIndex, nValue);
287 return FACTCue_GetVariable(This->fact_cue, nIndex, nValue);
290 static HRESULT WINAPI IXACT3CueImpl_Pause(IXACT3Cue *iface, BOOL fPause)
292 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
294 TRACE("(%p)->(%u)\n", iface, fPause);
296 return FACTCue_Pause(This->fact_cue, fPause);
299 #if XACT3_VER >= 0x0205
300 static HRESULT WINAPI IXACT3CueImpl_GetProperties(IXACT3Cue *iface,
301 XACT_CUE_INSTANCE_PROPERTIES **ppProperties)
303 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
304 FACTCueInstanceProperties *fProps;
305 HRESULT hr;
307 TRACE("(%p)->(%p)\n", iface, ppProperties);
309 hr = FACTCue_GetProperties(This->fact_cue, &fProps);
310 if(FAILED(hr))
311 return hr;
313 *ppProperties = (XACT_CUE_INSTANCE_PROPERTIES*) fProps;
314 return hr;
316 #endif
318 #if XACT3_VER >= 0x0305
319 static HRESULT WINAPI IXACT3CueImpl_SetOutputVoices(IXACT3Cue *iface,
320 const XAUDIO2_VOICE_SENDS *pSendList)
322 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
323 FIXME("(%p)->(%p): stub!\n", This, pSendList);
324 return S_OK;
327 static HRESULT WINAPI IXACT3CueImpl_SetOutputVoiceMatrix(IXACT3Cue *iface,
328 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
329 UINT32 DestinationChannels, const float *pLevelMatrix)
331 XACT3CueImpl *This = impl_from_IXACT3Cue(iface);
332 FIXME("(%p)->(%p %u %u %p): stub!\n", This, pDestinationVoice, SourceChannels,
333 DestinationChannels, pLevelMatrix);
334 return S_OK;
336 #endif
338 static const IXACT3CueVtbl XACT3Cue_Vtbl =
340 IXACT3CueImpl_Play,
341 IXACT3CueImpl_Stop,
342 IXACT3CueImpl_GetState,
343 IXACT3CueImpl_Destroy,
344 #if XACT3_VER < 0x0300
345 IXACT3CueImpl_GetChannelMap,
346 IXACT3CueImpl_SetChannelMap,
347 IXACT3CueImpl_GetChannelVolume,
348 IXACT3CueImpl_SetChannelVolume,
349 #endif
350 IXACT3CueImpl_SetMatrixCoefficients,
351 IXACT3CueImpl_GetVariableIndex,
352 IXACT3CueImpl_SetVariable,
353 IXACT3CueImpl_GetVariable,
354 IXACT3CueImpl_Pause,
355 #if XACT3_VER >= 0x0205
356 IXACT3CueImpl_GetProperties,
357 #endif
358 #if XACT3_VER >= 0x0305
359 IXACT3CueImpl_SetOutputVoices,
360 IXACT3CueImpl_SetOutputVoiceMatrix
361 #endif
364 typedef struct _XACT3SoundBankImpl {
365 IXACT3SoundBank IXACT3SoundBank_iface;
367 FACTSoundBank *fact_soundbank;
368 XACT3EngineImpl *engine;
369 } XACT3SoundBankImpl;
371 static inline XACT3SoundBankImpl *impl_from_IXACT3SoundBank(IXACT3SoundBank *iface)
373 return CONTAINING_RECORD(iface, XACT3SoundBankImpl, IXACT3SoundBank_iface);
376 static XACTINDEX WINAPI IXACT3SoundBankImpl_GetCueIndex(IXACT3SoundBank *iface,
377 PCSTR szFriendlyName)
379 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
381 TRACE("(%p)->(%s)\n", This, szFriendlyName);
383 return FACTSoundBank_GetCueIndex(This->fact_soundbank, szFriendlyName);
386 #if XACT3_VER >= 0x0205
387 static HRESULT WINAPI IXACT3SoundBankImpl_GetNumCues(IXACT3SoundBank *iface,
388 XACTINDEX *pnNumCues)
390 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
392 TRACE("(%p)->(%p)\n", This, pnNumCues);
394 return FACTSoundBank_GetNumCues(This->fact_soundbank, pnNumCues);
397 static HRESULT WINAPI IXACT3SoundBankImpl_GetCueProperties(IXACT3SoundBank *iface,
398 XACTINDEX nCueIndex, XACT_CUE_PROPERTIES *pProperties)
400 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
402 TRACE("(%p)->(%u, %p)\n", This, nCueIndex, pProperties);
404 return FACTSoundBank_GetCueProperties(This->fact_soundbank, nCueIndex,
405 (FACTCueProperties*) pProperties);
407 #endif
409 static HRESULT WINAPI IXACT3SoundBankImpl_Prepare(IXACT3SoundBank *iface,
410 XACTINDEX nCueIndex, DWORD dwFlags, XACTTIME timeOffset,
411 IXACT3Cue** ppCue)
413 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
414 XACT3CueImpl *cue;
415 FACTCue *fcue;
416 UINT ret;
417 HRESULT hr;
419 TRACE("(%p)->(%u, 0x%lx, %lu, %p)\n", This, nCueIndex, dwFlags, timeOffset,
420 ppCue);
422 ret = FACTSoundBank_Prepare(This->fact_soundbank, nCueIndex, dwFlags,
423 timeOffset, &fcue);
424 if(ret != 0)
426 ERR("Failed to CreateCue: %d\n", ret);
427 return E_FAIL;
430 cue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cue));
431 if (!cue)
433 FACTCue_Destroy(fcue);
434 ERR("Failed to allocate XACT3CueImpl!\n");
435 return E_OUTOFMEMORY;
438 hr = wrapper_add_entry(This->engine, fcue, &cue->IXACT3Cue_iface);
439 if (FAILED(hr))
441 FACTCue_Destroy(fcue);
442 HeapFree(GetProcessHeap(), 0, cue);
443 return hr;
446 cue->IXACT3Cue_iface.lpVtbl = &XACT3Cue_Vtbl;
447 cue->fact_cue = fcue;
448 cue->engine = This->engine;
449 *ppCue = &cue->IXACT3Cue_iface;
451 TRACE("Created Cue: %p\n", cue);
453 return S_OK;
456 static HRESULT WINAPI IXACT3SoundBankImpl_Play(IXACT3SoundBank *iface,
457 XACTINDEX nCueIndex, DWORD dwFlags, XACTTIME timeOffset,
458 IXACT3Cue** ppCue)
460 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
461 XACT3CueImpl *cue;
462 FACTCue *fcue;
463 HRESULT hr;
465 TRACE("(%p)->(%u, 0x%lx, %lu, %p)\n", This, nCueIndex, dwFlags, timeOffset,
466 ppCue);
468 /* If the application doesn't want a handle, don't generate one at all.
469 * Let the engine handle that memory instead.
470 * -flibit
472 if (ppCue == NULL){
473 hr = FACTSoundBank_Play(This->fact_soundbank, nCueIndex, dwFlags,
474 timeOffset, NULL);
475 }else{
476 hr = FACTSoundBank_Play(This->fact_soundbank, nCueIndex, dwFlags,
477 timeOffset, &fcue);
478 if(FAILED(hr))
479 return hr;
481 cue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cue));
482 if (!cue)
484 FACTCue_Destroy(fcue);
485 ERR("Failed to allocate XACT3CueImpl!\n");
486 return E_OUTOFMEMORY;
489 hr = wrapper_add_entry(This->engine, fcue, &cue->IXACT3Cue_iface);
490 if (FAILED(hr))
492 FACTCue_Destroy(fcue);
493 HeapFree(GetProcessHeap(), 0, cue);
494 return hr;
497 cue->IXACT3Cue_iface.lpVtbl = &XACT3Cue_Vtbl;
498 cue->fact_cue = fcue;
499 cue->engine = This->engine;
500 *ppCue = &cue->IXACT3Cue_iface;
503 return hr;
506 static HRESULT WINAPI IXACT3SoundBankImpl_Stop(IXACT3SoundBank *iface,
507 XACTINDEX nCueIndex, DWORD dwFlags)
509 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
511 TRACE("(%p)->(%lu)\n", This, dwFlags);
513 return FACTSoundBank_Stop(This->fact_soundbank, nCueIndex, dwFlags);
516 static HRESULT WINAPI IXACT3SoundBankImpl_Destroy(IXACT3SoundBank *iface)
518 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
519 HRESULT hr;
521 TRACE("(%p)\n", This);
523 hr = FACTSoundBank_Destroy(This->fact_soundbank);
525 wrapper_remove_entry(This->engine, This->fact_soundbank);
526 HeapFree(GetProcessHeap(), 0, This);
527 return hr;
530 static HRESULT WINAPI IXACT3SoundBankImpl_GetState(IXACT3SoundBank *iface,
531 DWORD *pdwState)
533 XACT3SoundBankImpl *This = impl_from_IXACT3SoundBank(iface);
535 TRACE("(%p)->(%p)\n", This, pdwState);
537 return FACTSoundBank_GetState(This->fact_soundbank, (uint32_t *)pdwState);
540 static const IXACT3SoundBankVtbl XACT3SoundBank_Vtbl =
542 IXACT3SoundBankImpl_GetCueIndex,
543 #if XACT3_VER >= 0x0205
544 IXACT3SoundBankImpl_GetNumCues,
545 IXACT3SoundBankImpl_GetCueProperties,
546 #endif
547 IXACT3SoundBankImpl_Prepare,
548 IXACT3SoundBankImpl_Play,
549 IXACT3SoundBankImpl_Stop,
550 IXACT3SoundBankImpl_Destroy,
551 IXACT3SoundBankImpl_GetState
554 #if XACT3_VER >= 0x0205
556 typedef struct _XACT3WaveImpl {
557 IXACT3Wave IXACT3Wave_iface;
559 FACTWave *fact_wave;
560 XACT3EngineImpl *engine;
561 } XACT3WaveImpl;
563 static inline XACT3WaveImpl *impl_from_IXACT3Wave(IXACT3Wave *iface)
565 return CONTAINING_RECORD(iface, XACT3WaveImpl, IXACT3Wave_iface);
568 static HRESULT WINAPI IXACT3WaveImpl_Destroy(IXACT3Wave *iface)
570 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
571 HRESULT hr;
573 TRACE("(%p)\n", This);
575 hr = FACTWave_Destroy(This->fact_wave);
576 wrapper_remove_entry(This->engine, This->fact_wave);
577 HeapFree(GetProcessHeap(), 0, This);
578 return hr;
581 static HRESULT WINAPI IXACT3WaveImpl_Play(IXACT3Wave *iface)
583 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
585 TRACE("(%p)\n", This);
587 return FACTWave_Play(This->fact_wave);
590 static HRESULT WINAPI IXACT3WaveImpl_Stop(IXACT3Wave *iface, DWORD dwFlags)
592 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
594 TRACE("(%p)->(0x%lx)\n", This, dwFlags);
596 return FACTWave_Stop(This->fact_wave, dwFlags);
599 static HRESULT WINAPI IXACT3WaveImpl_Pause(IXACT3Wave *iface, BOOL fPause)
601 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
603 TRACE("(%p)->(%u)\n", This, fPause);
605 return FACTWave_Pause(This->fact_wave, fPause);
608 static HRESULT WINAPI IXACT3WaveImpl_GetState(IXACT3Wave *iface, DWORD *pdwState)
610 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
612 TRACE("(%p)->(%p)\n", This, pdwState);
614 return FACTWave_GetState(This->fact_wave, (uint32_t *)pdwState);
617 static HRESULT WINAPI IXACT3WaveImpl_SetPitch(IXACT3Wave *iface, XACTPITCH pitch)
619 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
621 TRACE("(%p)->(%d)\n", This, pitch);
623 return FACTWave_SetPitch(This->fact_wave, pitch);
626 static HRESULT WINAPI IXACT3WaveImpl_SetVolume(IXACT3Wave *iface, XACTVOLUME volume)
628 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
630 TRACE("(%p)->(%f)\n", This, volume);
632 return FACTWave_SetVolume(This->fact_wave, volume);
635 static HRESULT WINAPI IXACT3WaveImpl_SetMatrixCoefficients(IXACT3Wave *iface,
636 UINT32 uSrcChannelCount, UINT32 uDstChannelCount,
637 float *pMatrixCoefficients)
639 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
641 TRACE("(%p)->(%u, %u, %p)\n", This, uSrcChannelCount, uDstChannelCount,
642 pMatrixCoefficients);
644 return FACTWave_SetMatrixCoefficients(This->fact_wave, uSrcChannelCount,
645 uDstChannelCount, pMatrixCoefficients);
648 static HRESULT WINAPI IXACT3WaveImpl_GetProperties(IXACT3Wave *iface,
649 XACT_WAVE_INSTANCE_PROPERTIES *pProperties)
651 XACT3WaveImpl *This = impl_from_IXACT3Wave(iface);
653 TRACE("(%p)->(%p)\n", This, pProperties);
655 return FACTWave_GetProperties(This->fact_wave,
656 (FACTWaveInstanceProperties*) pProperties);
659 static const IXACT3WaveVtbl XACT3Wave_Vtbl =
661 IXACT3WaveImpl_Destroy,
662 IXACT3WaveImpl_Play,
663 IXACT3WaveImpl_Stop,
664 IXACT3WaveImpl_Pause,
665 IXACT3WaveImpl_GetState,
666 IXACT3WaveImpl_SetPitch,
667 IXACT3WaveImpl_SetVolume,
668 IXACT3WaveImpl_SetMatrixCoefficients,
669 IXACT3WaveImpl_GetProperties
672 #endif
674 typedef struct _XACT3WaveBankImpl {
675 IXACT3WaveBank IXACT3WaveBank_iface;
677 FACTWaveBank *fact_wavebank;
678 struct _XACT3EngineImpl *engine;
679 } XACT3WaveBankImpl;
681 static inline XACT3WaveBankImpl *impl_from_IXACT3WaveBank(IXACT3WaveBank *iface)
683 return CONTAINING_RECORD(iface, XACT3WaveBankImpl, IXACT3WaveBank_iface);
686 static HRESULT WINAPI IXACT3WaveBankImpl_Destroy(IXACT3WaveBank *iface)
688 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
689 HRESULT hr;
691 TRACE("(%p)\n", This);
693 hr = FACTWaveBank_Destroy(This->fact_wavebank);
695 wrapper_remove_entry(This->engine, This->fact_wavebank);
697 HeapFree(GetProcessHeap(), 0, This);
698 return hr;
701 #if XACT3_VER >= 0x0205
703 static HRESULT WINAPI IXACT3WaveBankImpl_GetNumWaves(IXACT3WaveBank *iface,
704 XACTINDEX *pnNumWaves)
706 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
708 TRACE("(%p)->(%p)\n", This, pnNumWaves);
710 return FACTWaveBank_GetNumWaves(This->fact_wavebank, pnNumWaves);
713 static XACTINDEX WINAPI IXACT3WaveBankImpl_GetWaveIndex(IXACT3WaveBank *iface,
714 PCSTR szFriendlyName)
716 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
718 TRACE("(%p)->(%s)\n", This, szFriendlyName);
720 return FACTWaveBank_GetWaveIndex(This->fact_wavebank, szFriendlyName);
723 static HRESULT WINAPI IXACT3WaveBankImpl_GetWaveProperties(IXACT3WaveBank *iface,
724 XACTINDEX nWaveIndex, XACT_WAVE_PROPERTIES *pWaveProperties)
726 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
728 TRACE("(%p)->(%u, %p)\n", This, nWaveIndex, pWaveProperties);
730 return FACTWaveBank_GetWaveProperties(This->fact_wavebank, nWaveIndex,
731 (FACTWaveProperties*) pWaveProperties);
734 static HRESULT WINAPI IXACT3WaveBankImpl_Prepare(IXACT3WaveBank *iface,
735 XACTINDEX nWaveIndex, DWORD dwFlags, DWORD dwPlayOffset,
736 XACTLOOPCOUNT nLoopCount, IXACT3Wave** ppWave)
738 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
739 XACT3WaveImpl *wave;
740 FACTWave *fwave;
741 UINT ret;
742 HRESULT hr;
744 TRACE("(%p)->(0x%x, %lu, 0x%lx, %u, %p)\n", This, nWaveIndex, dwFlags,
745 dwPlayOffset, nLoopCount, ppWave);
747 ret = FACTWaveBank_Prepare(This->fact_wavebank, nWaveIndex, dwFlags,
748 dwPlayOffset, nLoopCount, &fwave);
749 if(ret != 0)
751 ERR("Failed to CreateWave: %d\n", ret);
752 return E_FAIL;
755 wave = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wave));
756 if (!wave)
758 FACTWave_Destroy(fwave);
759 ERR("Failed to allocate XACT3WaveImpl!\n");
760 return E_OUTOFMEMORY;
763 hr = wrapper_add_entry(This->engine, fwave, &wave->IXACT3Wave_iface);
764 if (FAILED(hr))
766 FACTWave_Destroy(fwave);
767 HeapFree(GetProcessHeap(), 0, wave);
768 return hr;
771 wave->IXACT3Wave_iface.lpVtbl = &XACT3Wave_Vtbl;
772 wave->fact_wave = fwave;
773 wave->engine = This->engine;
774 *ppWave = &wave->IXACT3Wave_iface;
776 TRACE("Created Wave: %p\n", wave);
778 return S_OK;
781 static HRESULT WINAPI IXACT3WaveBankImpl_Play(IXACT3WaveBank *iface,
782 XACTINDEX nWaveIndex, DWORD dwFlags, DWORD dwPlayOffset,
783 XACTLOOPCOUNT nLoopCount, IXACT3Wave** ppWave)
785 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
786 XACT3WaveImpl *wave;
787 FACTWave *fwave;
788 HRESULT hr;
790 TRACE("(%p)->(0x%x, %lu, 0x%lx, %u, %p)\n", This, nWaveIndex, dwFlags, dwPlayOffset,
791 nLoopCount, ppWave);
793 /* If the application doesn't want a handle, don't generate one at all.
794 * Let the engine handle that memory instead.
795 * -flibit
797 if (ppWave == NULL){
798 hr = FACTWaveBank_Play(This->fact_wavebank, nWaveIndex, dwFlags,
799 dwPlayOffset, nLoopCount, NULL);
800 }else{
801 hr = FACTWaveBank_Play(This->fact_wavebank, nWaveIndex, dwFlags,
802 dwPlayOffset, nLoopCount, &fwave);
803 if(FAILED(hr))
804 return hr;
806 wave = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wave));
807 if (!wave)
809 FACTWave_Destroy(fwave);
810 ERR("Failed to allocate XACT3WaveImpl!\n");
811 return E_OUTOFMEMORY;
814 hr = wrapper_add_entry(This->engine, fwave, &wave->IXACT3Wave_iface);
815 if (FAILED(hr))
817 FACTWave_Destroy(fwave);
818 HeapFree(GetProcessHeap(), 0, wave);
819 return hr;
822 wave->IXACT3Wave_iface.lpVtbl = &XACT3Wave_Vtbl;
823 wave->fact_wave = fwave;
824 wave->engine = This->engine;
825 *ppWave = &wave->IXACT3Wave_iface;
828 return hr;
831 static HRESULT WINAPI IXACT3WaveBankImpl_Stop(IXACT3WaveBank *iface,
832 XACTINDEX nWaveIndex, DWORD dwFlags)
834 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
836 TRACE("(%p)->(%u, %lu)\n", This, nWaveIndex, dwFlags);
838 return FACTWaveBank_Stop(This->fact_wavebank, nWaveIndex, dwFlags);
841 #endif
843 static HRESULT WINAPI IXACT3WaveBankImpl_GetState(IXACT3WaveBank *iface,
844 DWORD *pdwState)
846 XACT3WaveBankImpl *This = impl_from_IXACT3WaveBank(iface);
848 TRACE("(%p)->(%p)\n", This, pdwState);
850 return FACTWaveBank_GetState(This->fact_wavebank, (uint32_t *)pdwState);
853 static const IXACT3WaveBankVtbl XACT3WaveBank_Vtbl =
855 IXACT3WaveBankImpl_Destroy,
856 #if XACT3_VER >= 0x0205
857 IXACT3WaveBankImpl_GetNumWaves,
858 IXACT3WaveBankImpl_GetWaveIndex,
859 IXACT3WaveBankImpl_GetWaveProperties,
860 IXACT3WaveBankImpl_Prepare,
861 IXACT3WaveBankImpl_Play,
862 IXACT3WaveBankImpl_Stop,
863 #endif
864 IXACT3WaveBankImpl_GetState
867 typedef struct wrap_readfile_struct {
868 XACT3EngineImpl *engine;
869 HANDLE file;
870 } wrap_readfile_struct;
872 static int32_t FACTCALL wrap_readfile(
873 void* hFile,
874 void* lpBuffer,
875 uint32_t nNumberOfBytesRead,
876 uint32_t *lpNumberOfBytesRead,
877 FACTOverlapped *lpOverlapped)
879 wrap_readfile_struct *wrap = (wrap_readfile_struct*) hFile;
880 return wrap->engine->pReadFile(wrap->file, lpBuffer, nNumberOfBytesRead,
881 (DWORD *)lpNumberOfBytesRead, (LPOVERLAPPED)lpOverlapped);
884 static int32_t FACTCALL wrap_getoverlappedresult(
885 void* hFile,
886 FACTOverlapped *lpOverlapped,
887 uint32_t *lpNumberOfBytesTransferred,
888 int32_t bWait)
890 wrap_readfile_struct *wrap = (wrap_readfile_struct*) hFile;
891 return wrap->engine->pGetOverlappedResult(wrap->file, (LPOVERLAPPED)lpOverlapped,
892 (DWORD *)lpNumberOfBytesTransferred, bWait);
895 static inline XACT3EngineImpl *impl_from_IXACT3Engine(IXACT3Engine *iface)
897 return CONTAINING_RECORD(iface, XACT3EngineImpl, IXACT3Engine_iface);
900 static HRESULT WINAPI IXACT3EngineImpl_QueryInterface(IXACT3Engine *iface,
901 REFIID riid, void **ppvObject)
903 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
905 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
907 if(IsEqualGUID(riid, &IID_IUnknown) ||
908 IsEqualGUID(riid, &IID_IXACT3Engine)){
909 *ppvObject = &This->IXACT3Engine_iface;
911 else
912 *ppvObject = NULL;
914 if (*ppvObject){
915 IUnknown_AddRef((IUnknown*)*ppvObject);
916 return S_OK;
919 FIXME("(%p)->(%s,%p), not found\n", This, debugstr_guid(riid), ppvObject);
921 return E_NOINTERFACE;
924 static ULONG WINAPI IXACT3EngineImpl_AddRef(IXACT3Engine *iface)
926 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
927 ULONG ref = FACTAudioEngine_AddRef(This->fact_engine);
928 TRACE("(%p)->(): Refcount now %lu\n", This, ref);
929 return ref;
932 static ULONG WINAPI IXACT3EngineImpl_Release(IXACT3Engine *iface)
934 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
935 ULONG ref = FACTAudioEngine_Release(This->fact_engine);
937 TRACE("(%p)->(): Refcount now %lu\n", This, ref);
939 if (!ref)
941 DeleteCriticalSection(&This->wrapper_lookup_cs);
942 wine_rb_destroy(&This->wrapper_lookup, wrapper_lookup_destroy, NULL);
943 HeapFree(GetProcessHeap(), 0, This);
945 return ref;
948 static HRESULT WINAPI IXACT3EngineImpl_GetRendererCount(IXACT3Engine *iface,
949 XACTINDEX *pnRendererCount)
951 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
953 TRACE("(%p)->(%p)\n", This, pnRendererCount);
955 return FACTAudioEngine_GetRendererCount(This->fact_engine, pnRendererCount);
958 static HRESULT WINAPI IXACT3EngineImpl_GetRendererDetails(IXACT3Engine *iface,
959 XACTINDEX nRendererIndex, XACT_RENDERER_DETAILS *pRendererDetails)
961 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
963 TRACE("(%p)->(%d, %p)\n", This, nRendererIndex, pRendererDetails);
965 return FACTAudioEngine_GetRendererDetails(This->fact_engine,
966 nRendererIndex, (FACTRendererDetails*) pRendererDetails);
969 #if XACT3_VER >= 0x0205
971 static HRESULT WINAPI IXACT3EngineImpl_GetFinalMixFormat(IXACT3Engine *iface,
972 WAVEFORMATEXTENSIBLE *pFinalMixFormat)
974 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
976 TRACE("(%p)->(%p)\n", This, pFinalMixFormat);
978 return FACTAudioEngine_GetFinalMixFormat(This->fact_engine,
979 (FAudioWaveFormatExtensible*) pFinalMixFormat);
982 #endif
984 static XACTNOTIFICATIONTYPE xact_notification_type_from_fact(uint8_t type)
986 /* we can't use a switch statement, because the constants are static const
987 * variables, and some compilers can't deal with that */
988 #define X(a) if (type == FACTNOTIFICATIONTYPE_##a) return XACTNOTIFICATIONTYPE_##a
989 X(CUEPREPARED);
990 X(CUEPLAY);
991 X(CUESTOP);
992 X(CUEDESTROYED);
993 X(MARKER);
994 X(SOUNDBANKDESTROYED);
995 X(WAVEBANKDESTROYED);
996 X(LOCALVARIABLECHANGED);
997 X(GLOBALVARIABLECHANGED);
998 X(GUICONNECTED);
999 X(GUIDISCONNECTED);
1000 X(WAVEPLAY);
1001 X(WAVESTOP);
1002 X(WAVEBANKPREPARED);
1003 X(WAVEBANKSTREAMING_INVALIDCONTENT);
1004 #if XACT3_VER >= 0x0205
1005 X(WAVEPREPARED);
1006 X(WAVELOOPED);
1007 X(WAVEDESTROYED);
1008 #endif
1009 #undef X
1011 FIXME("unknown type %#x\n", type);
1012 return 0;
1015 static void FACTCALL fact_notification_cb(const FACTNotification *notification)
1017 XACT3EngineImpl *engine = (XACT3EngineImpl *)notification->pvContext;
1018 XACT_NOTIFICATION xnotification;
1020 TRACE("notification %d, context %p\n", notification->type, notification->pvContext);
1022 /* Older versions of FAudio don't pass through the context */
1023 if (!engine)
1025 WARN("Notification context is NULL\n");
1026 return;
1029 xnotification.type = xact_notification_type_from_fact(notification->type);
1030 xnotification.timeStamp = notification->timeStamp;
1031 xnotification.pvContext = engine->contexts[notification->type];
1033 EnterCriticalSection(&engine->wrapper_lookup_cs);
1034 if (notification->type == XACTNOTIFICATIONTYPE_WAVEBANKPREPARED
1035 || notification->type == XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED)
1037 xnotification.waveBank.pWaveBank = wrapper_find_entry(engine, notification->waveBank.pWaveBank);
1039 else if(notification->type == XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED)
1041 xnotification.soundBank.pSoundBank = wrapper_find_entry(engine, notification->soundBank.pSoundBank);
1043 else if (notification->type == XACTNOTIFICATIONTYPE_WAVESTOP
1044 #if XACT3_VER >= 0x0205
1045 || notification->type == XACTNOTIFICATIONTYPE_WAVEDESTROYED
1046 || notification->type == XACTNOTIFICATIONTYPE_WAVELOOPED
1047 || notification->type == XACTNOTIFICATIONTYPE_WAVEPLAY
1048 || notification->type == XACTNOTIFICATIONTYPE_WAVEPREPARED)
1049 #else
1051 #endif
1053 xnotification.wave.cueIndex = notification->wave.cueIndex;
1054 xnotification.wave.pCue = wrapper_find_entry(engine, notification->wave.pCue);
1055 xnotification.wave.pSoundBank = wrapper_find_entry(engine, notification->wave.pSoundBank);
1056 #if XACT3_VER >= 0x0205
1057 xnotification.wave.pWave = wrapper_find_entry(engine, notification->wave.pWave);
1058 #endif
1059 xnotification.wave.pWaveBank = wrapper_find_entry(engine, notification->wave.pWaveBank);
1061 else if (notification->type == XACTNOTIFICATIONTYPE_CUEPLAY ||
1062 notification->type == XACTNOTIFICATIONTYPE_CUEPREPARED ||
1063 notification->type == XACTNOTIFICATIONTYPE_CUESTOP ||
1064 notification->type == XACTNOTIFICATIONTYPE_CUEDESTROYED)
1066 xnotification.cue.pCue = wrapper_find_entry(engine, notification->cue.pCue);
1067 xnotification.cue.cueIndex = notification->cue.cueIndex;
1068 xnotification.cue.pSoundBank = wrapper_find_entry(engine, notification->cue.pSoundBank);
1070 else
1072 LeaveCriticalSection(&engine->wrapper_lookup_cs);
1073 FIXME("Unsupported callback type %d\n", notification->type);
1074 return;
1076 LeaveCriticalSection(&engine->wrapper_lookup_cs);
1078 engine->notification_callback(&xnotification);
1081 static HRESULT WINAPI IXACT3EngineImpl_Initialize(IXACT3Engine *iface,
1082 const XACT_RUNTIME_PARAMETERS *pParams)
1084 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1085 FACTRuntimeParameters params;
1086 UINT ret;
1088 TRACE("(%p)->(%p)\n", This, pParams);
1090 memset(&params, 0, sizeof(FACTRuntimeParameters));
1091 /* Explicitly copy to the FAudio structure as the packing is wrong under 64 bits */
1092 params.lookAheadTime = pParams->lookAheadTime;
1093 params.pGlobalSettingsBuffer = pParams->pGlobalSettingsBuffer;
1094 params.globalSettingsBufferSize = pParams->globalSettingsBufferSize;
1095 params.globalSettingsFlags = pParams->globalSettingsFlags;
1096 params.globalSettingsAllocAttributes = pParams->globalSettingsAllocAttributes;
1097 params.pRendererID = (int16_t*)pParams->pRendererID;
1098 params.pXAudio2 = NULL;
1099 params.pMasteringVoice = NULL;
1101 #if XACT3_VER >= 0x0300
1102 /* FIXME: pXAudio2 and pMasteringVoice are pointers to
1103 * IXAudio2/IXAudio2MasteringVoice objects. FACT wants pointers to
1104 * FAudio/FAudioMasteringVoice objects. In Wine's XAudio2 implementation, we
1105 * actually have them available, but only if you access their internal data.
1106 * For now we can just force these pointers to NULL, as XACT simply
1107 * generates its own engine and endpoint in that situation. These parameters
1108 * are mostly an optimization for games with multiple XACT3Engines that want
1109 * a single engine running everything.
1110 * -flibit
1112 if (pParams->pXAudio2 != NULL){
1113 FIXME("pXAudio2 parameter not supported!\n");
1115 if (pParams->pMasteringVoice != NULL){
1116 FIXME("pMasteringVoice parameter not supported!\n");
1119 #endif
1121 /* Force Windows I/O, do NOT use the FACT default! */
1122 This->pReadFile = (XACT_READFILE_CALLBACK)
1123 pParams->fileIOCallbacks.readFileCallback;
1124 This->pGetOverlappedResult = (XACT_GETOVERLAPPEDRESULT_CALLBACK)
1125 pParams->fileIOCallbacks.getOverlappedResultCallback;
1126 if (This->pReadFile == NULL)
1127 This->pReadFile = (XACT_READFILE_CALLBACK) ReadFile;
1128 if (This->pGetOverlappedResult == NULL)
1129 This->pGetOverlappedResult = (XACT_GETOVERLAPPEDRESULT_CALLBACK)
1130 GetOverlappedResult;
1131 params.fileIOCallbacks.readFileCallback = wrap_readfile;
1132 params.fileIOCallbacks.getOverlappedResultCallback = wrap_getoverlappedresult;
1133 params.fnNotificationCallback = fact_notification_cb;
1135 This->notification_callback = (XACT_NOTIFICATION_CALLBACK)pParams->fnNotificationCallback;
1137 ret = FACTAudioEngine_Initialize(This->fact_engine, &params);
1138 if (ret != 0)
1139 WARN("FACTAudioEngine_Initialize returned %d\n", ret);
1141 return !ret ? S_OK : E_FAIL;
1144 static HRESULT WINAPI IXACT3EngineImpl_ShutDown(IXACT3Engine *iface)
1146 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1148 TRACE("(%p)\n", This);
1150 return FACTAudioEngine_ShutDown(This->fact_engine);
1153 static HRESULT WINAPI IXACT3EngineImpl_DoWork(IXACT3Engine *iface)
1155 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1157 TRACE("(%p)\n", This);
1159 return FACTAudioEngine_DoWork(This->fact_engine);
1162 static HRESULT WINAPI IXACT3EngineImpl_CreateSoundBank(IXACT3Engine *iface,
1163 const void* pvBuffer, DWORD dwSize, DWORD dwFlags,
1164 DWORD dwAllocAttributes, IXACT3SoundBank **ppSoundBank)
1166 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1167 XACT3SoundBankImpl *sb;
1168 FACTSoundBank *fsb;
1169 UINT ret;
1170 HRESULT hr;
1172 TRACE("(%p)->(%p, %lu, 0x%lx, 0x%lx, %p)\n", This, pvBuffer, dwSize, dwFlags,
1173 dwAllocAttributes, ppSoundBank);
1175 ret = FACTAudioEngine_CreateSoundBank(This->fact_engine, pvBuffer, dwSize,
1176 dwFlags, dwAllocAttributes, &fsb);
1177 if(ret != 0)
1179 ERR("Failed to CreateSoundBank: %d\n", ret);
1180 return E_FAIL;
1183 sb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sb));
1184 if (!sb)
1186 FACTSoundBank_Destroy(fsb);
1187 ERR("Failed to allocate XACT3SoundBankImpl!\n");
1188 return E_OUTOFMEMORY;
1191 hr = wrapper_add_entry(This, fsb, &sb->IXACT3SoundBank_iface);
1192 if (FAILED(hr))
1194 FACTSoundBank_Destroy(fsb);
1195 HeapFree(GetProcessHeap(), 0, sb);
1196 return hr;
1199 sb->IXACT3SoundBank_iface.lpVtbl = &XACT3SoundBank_Vtbl;
1200 sb->fact_soundbank = fsb;
1201 sb->engine = This;
1202 *ppSoundBank = &sb->IXACT3SoundBank_iface;
1204 TRACE("Created SoundBank: %p\n", sb);
1206 return S_OK;
1209 static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *iface,
1210 const void* pvBuffer, DWORD dwSize, DWORD dwFlags,
1211 DWORD dwAllocAttributes, IXACT3WaveBank **ppWaveBank)
1213 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1214 XACT3WaveBankImpl *wb;
1215 FACTWaveBank *fwb;
1216 HRESULT hr;
1217 UINT ret;
1219 TRACE("(%p)->(%p, %lu, 0x%lx, 0x%lx, %p)\n", This, pvBuffer, dwSize, dwFlags,
1220 dwAllocAttributes, ppWaveBank);
1222 ret = FACTAudioEngine_CreateInMemoryWaveBank(This->fact_engine, pvBuffer,
1223 dwSize, dwFlags, dwAllocAttributes, &fwb);
1224 if(ret != 0)
1226 ERR("Failed to CreateWaveBank: %d\n", ret);
1227 return E_FAIL;
1230 wb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wb));
1231 if (!wb)
1233 FACTWaveBank_Destroy(fwb);
1234 ERR("Failed to allocate XACT3WaveBankImpl!\n");
1235 return E_OUTOFMEMORY;
1238 hr = wrapper_add_entry(This, fwb, &wb->IXACT3WaveBank_iface);
1239 if (FAILED(hr))
1241 FACTWaveBank_Destroy(fwb);
1242 HeapFree(GetProcessHeap(), 0, wb);
1243 return hr;
1246 wb->IXACT3WaveBank_iface.lpVtbl = &XACT3WaveBank_Vtbl;
1247 wb->fact_wavebank = fwb;
1248 wb->engine = This;
1249 *ppWaveBank = &wb->IXACT3WaveBank_iface;
1251 TRACE("Created in-memory WaveBank: %p\n", wb);
1253 return S_OK;
1256 static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *iface,
1257 const XACT_WAVEBANK_STREAMING_PARAMETERS *pParms,
1258 IXACT3WaveBank **ppWaveBank)
1260 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1261 FACTStreamingParameters fakeParms;
1262 wrap_readfile_struct *fake;
1263 XACT3WaveBankImpl *wb;
1264 FACTWaveBank *fwb;
1265 UINT ret;
1266 HRESULT hr;
1268 TRACE("(%p)->(%p, %p)\n", This, pParms, ppWaveBank);
1270 /* We have to wrap the file to fix up the callbacks! */
1271 fake = (wrap_readfile_struct*) CoTaskMemAlloc(
1272 sizeof(wrap_readfile_struct));
1273 fake->engine = This;
1274 fake->file = pParms->file;
1275 fakeParms.file = fake;
1276 fakeParms.flags = pParms->flags;
1277 fakeParms.offset = pParms->offset;
1278 fakeParms.packetSize = pParms->packetSize;
1280 ret = FACTAudioEngine_CreateStreamingWaveBank(This->fact_engine, &fakeParms,
1281 &fwb);
1282 if(ret != 0)
1284 ERR("Failed to CreateWaveBank: %d\n", ret);
1285 return E_FAIL;
1288 wb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wb));
1289 if (!wb)
1291 FACTWaveBank_Destroy(fwb);
1292 ERR("Failed to allocate XACT3WaveBankImpl!\n");
1293 return E_OUTOFMEMORY;
1296 hr = wrapper_add_entry(This, fwb, &wb->IXACT3WaveBank_iface);
1297 if (FAILED(hr))
1299 FACTWaveBank_Destroy(fwb);
1300 HeapFree(GetProcessHeap(), 0, wb);
1301 return hr;
1304 wb->IXACT3WaveBank_iface.lpVtbl = &XACT3WaveBank_Vtbl;
1305 wb->fact_wavebank = fwb;
1306 wb->engine = This;
1307 *ppWaveBank = &wb->IXACT3WaveBank_iface;
1309 TRACE("Created streaming WaveBank: %p\n", wb);
1311 return S_OK;
1314 #if XACT3_VER >= 0x0205
1316 static HRESULT WINAPI IXACT3EngineImpl_PrepareInMemoryWave(IXACT3Engine *iface,
1317 DWORD dwFlags, WAVEBANKENTRY entry, DWORD *pdwSeekTable,
1318 BYTE *pbWaveData, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount,
1319 IXACT3Wave **ppWave)
1321 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1322 FIXME("(%p): stub!\n", This);
1323 return E_NOTIMPL;
1326 static HRESULT WINAPI IXACT3EngineImpl_PrepareStreamingWave(IXACT3Engine *iface,
1327 DWORD dwFlags, WAVEBANKENTRY entry,
1328 XACT_STREAMING_PARAMETERS streamingParams, DWORD dwAlignment,
1329 DWORD *pdwSeekTable, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount,
1330 IXACT3Wave **ppWave)
1332 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1333 FIXME("(%p): stub!\n", This);
1334 return E_NOTIMPL;
1337 static HRESULT WINAPI IXACT3EngineImpl_PrepareWave(IXACT3Engine *iface,
1338 DWORD dwFlags, PCSTR szWavePath, WORD wStreamingPacketSize,
1339 DWORD dwAlignment, DWORD dwPlayOffset, XACTLOOPCOUNT nLoopCount,
1340 IXACT3Wave **ppWave)
1342 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1343 XACT3WaveImpl *wave;
1344 FACTWave *fwave = NULL;
1345 UINT ret;
1346 HRESULT hr;
1348 TRACE("(%p)->(0x%08lx, %s, %d, %ld, %ld, %d, %p)\n", This, dwFlags, debugstr_a(szWavePath),
1349 wStreamingPacketSize, dwAlignment, dwPlayOffset, nLoopCount, ppWave);
1351 ret = FACTAudioEngine_PrepareWave(This->fact_engine, dwFlags, szWavePath, wStreamingPacketSize,
1352 dwAlignment, dwPlayOffset, nLoopCount, &fwave);
1353 if(ret != 0 || !fwave)
1355 ERR("Failed to CreateWave: %d (%p)\n", ret, fwave);
1356 return E_FAIL;
1359 wave = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wave));
1360 if (!wave)
1362 FACTWave_Destroy(fwave);
1363 return E_OUTOFMEMORY;
1366 hr = wrapper_add_entry(This, fwave, &wave->IXACT3Wave_iface);
1367 if (FAILED(hr))
1369 FACTWave_Destroy(fwave);
1370 HeapFree(GetProcessHeap(), 0, wave);
1371 return hr;
1374 wave->IXACT3Wave_iface.lpVtbl = &XACT3Wave_Vtbl;
1375 wave->fact_wave = fwave;
1376 wave->engine = This;
1377 *ppWave = &wave->IXACT3Wave_iface;
1379 TRACE("Created Wave: %p\n", wave);
1381 return S_OK;
1384 #endif
1386 enum {
1387 NOTIFY_SoundBank = 0x01,
1388 NOTIFY_WaveBank = 0x02,
1389 NOTIFY_Cue = 0x04,
1390 NOTIFY_Wave = 0x08,
1391 NOTIFY_cueIndex = 0x10,
1392 NOTIFY_waveIndex = 0x20
1395 /* these constants don't have the same values across xactengine versions */
1396 static uint8_t fact_notification_type_from_xact(XACTNOTIFICATIONTYPE type)
1398 /* we can't use a switch statement, because the constants are static const
1399 * variables, and some compilers can't deal with that */
1400 #define X(a) if (type == XACTNOTIFICATIONTYPE_##a) return FACTNOTIFICATIONTYPE_##a
1401 X(CUEPREPARED);
1402 X(CUEPLAY);
1403 X(CUESTOP);
1404 X(CUEDESTROYED);
1405 X(MARKER);
1406 X(SOUNDBANKDESTROYED);
1407 X(WAVEBANKDESTROYED);
1408 X(LOCALVARIABLECHANGED);
1409 X(GLOBALVARIABLECHANGED);
1410 X(GUICONNECTED);
1411 X(GUIDISCONNECTED);
1412 X(WAVEPLAY);
1413 X(WAVESTOP);
1414 X(WAVEBANKPREPARED);
1415 X(WAVEBANKSTREAMING_INVALIDCONTENT);
1416 #if XACT3_VER >= 0x0205
1417 X(WAVEPREPARED);
1418 X(WAVELOOPED);
1419 X(WAVEDESTROYED);
1420 #endif
1421 #undef X
1423 FIXME("unknown type %#x\n", type);
1424 return 0;
1427 static inline void unwrap_notificationdesc(FACTNotificationDescription *fd,
1428 const XACT_NOTIFICATION_DESCRIPTION *xd)
1430 DWORD flags = 0;
1432 TRACE("Type %d\n", xd->type);
1434 memset(fd, 0, sizeof(*fd));
1436 fd->type = fact_notification_type_from_xact(xd->type);
1438 /* we can't use a switch statement, because the constants are static const
1439 * variables, and some compilers can't deal with that */
1441 /* Supports SoundBank, Cue index, Cue instance */
1442 if (fd->type == FACTNOTIFICATIONTYPE_CUEPREPARED || fd->type == FACTNOTIFICATIONTYPE_CUEPLAY ||
1443 fd->type == FACTNOTIFICATIONTYPE_CUESTOP || fd->type == FACTNOTIFICATIONTYPE_CUEDESTROYED ||
1444 fd->type == FACTNOTIFICATIONTYPE_MARKER || fd->type == FACTNOTIFICATIONTYPE_LOCALVARIABLECHANGED)
1446 flags = NOTIFY_SoundBank | NOTIFY_cueIndex | NOTIFY_Cue;
1448 /* Supports WaveBank */
1449 else if (fd->type == FACTNOTIFICATIONTYPE_WAVEBANKDESTROYED || fd->type == FACTNOTIFICATIONTYPE_WAVEBANKPREPARED ||
1450 fd->type == FACTNOTIFICATIONTYPE_WAVEBANKSTREAMING_INVALIDCONTENT)
1452 flags = NOTIFY_WaveBank;
1454 /* Supports NOTIFY_SoundBank */
1455 else if (fd->type == FACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED)
1457 flags = NOTIFY_SoundBank;
1459 /* Supports SoundBank, SoundBank, Cue index, Cue instance, WaveBank, Wave instance */
1460 else if (fd->type == FACTNOTIFICATIONTYPE_WAVEPLAY || fd->type == FACTNOTIFICATIONTYPE_WAVESTOP ||
1461 fd->type == FACTNOTIFICATIONTYPE_WAVELOOPED)
1463 flags = NOTIFY_SoundBank | NOTIFY_cueIndex | NOTIFY_Cue | NOTIFY_WaveBank | NOTIFY_Wave;
1465 /* Supports WaveBank, Wave index, Wave instance */
1466 else if (fd->type == FACTNOTIFICATIONTYPE_WAVEPREPARED || fd->type == FACTNOTIFICATIONTYPE_WAVEDESTROYED)
1468 flags = NOTIFY_WaveBank | NOTIFY_waveIndex | NOTIFY_Wave;
1471 /* We have to unwrap the FACT object first! */
1472 fd->flags = xd->flags;
1473 if (flags & NOTIFY_cueIndex)
1474 fd->cueIndex = xd->cueIndex;
1475 #if XACT3_VER >= 0x0205
1476 if (flags & NOTIFY_waveIndex)
1477 fd->waveIndex = xd->waveIndex;
1478 #endif
1480 if (flags & NOTIFY_Cue && xd->pCue != NULL)
1482 XACT3CueImpl *cue = impl_from_IXACT3Cue(xd->pCue);
1483 if (cue)
1484 fd->pCue = cue->fact_cue;
1487 if (flags & NOTIFY_SoundBank && xd->pSoundBank != NULL)
1489 XACT3SoundBankImpl *sound = impl_from_IXACT3SoundBank(xd->pSoundBank);
1490 if (sound)
1491 fd->pSoundBank = sound->fact_soundbank;
1494 if (flags & NOTIFY_WaveBank && xd->pWaveBank != NULL)
1496 XACT3WaveBankImpl *bank = impl_from_IXACT3WaveBank(xd->pWaveBank);
1497 if (bank)
1498 fd->pWaveBank = bank->fact_wavebank;
1501 #if XACT3_VER >= 0x0205
1502 if (flags & NOTIFY_Wave && xd->pWave != NULL)
1504 XACT3WaveImpl *wave = impl_from_IXACT3Wave(xd->pWave);
1505 if (wave)
1506 fd->pWave = wave->fact_wave;
1508 #endif
1511 static HRESULT WINAPI IXACT3EngineImpl_RegisterNotification(IXACT3Engine *iface,
1512 const XACT_NOTIFICATION_DESCRIPTION *pNotificationDesc)
1514 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1515 FACTNotificationDescription fdesc;
1517 TRACE("(%p)->(%p)\n", This, pNotificationDesc);
1519 if (pNotificationDesc->type < XACTNOTIFICATIONTYPE_CUEPREPARED ||
1520 pNotificationDesc->type > XACTNOTIFICATIONTYPE_WAVEBANKSTREAMING_INVALIDCONTENT)
1521 return E_INVALIDARG;
1523 unwrap_notificationdesc(&fdesc, pNotificationDesc);
1524 This->contexts[pNotificationDesc->type] = pNotificationDesc->pvContext;
1525 fdesc.pvContext = This;
1526 return FACTAudioEngine_RegisterNotification(This->fact_engine, &fdesc);
1529 static HRESULT WINAPI IXACT3EngineImpl_UnRegisterNotification(IXACT3Engine *iface,
1530 const XACT_NOTIFICATION_DESCRIPTION *pNotificationDesc)
1532 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1533 FACTNotificationDescription fdesc;
1535 TRACE("(%p)->(%p)\n", This, pNotificationDesc);
1537 if (pNotificationDesc->type < XACTNOTIFICATIONTYPE_CUEPREPARED ||
1538 pNotificationDesc->type > XACTNOTIFICATIONTYPE_WAVEBANKSTREAMING_INVALIDCONTENT)
1539 return S_OK;
1541 unwrap_notificationdesc(&fdesc, pNotificationDesc);
1542 fdesc.pvContext = This;
1543 return FACTAudioEngine_UnRegisterNotification(This->fact_engine, &fdesc);
1546 static XACTCATEGORY WINAPI IXACT3EngineImpl_GetCategory(IXACT3Engine *iface,
1547 PCSTR szFriendlyName)
1549 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1551 TRACE("(%p)->(%s)\n", This, szFriendlyName);
1553 return FACTAudioEngine_GetCategory(This->fact_engine, szFriendlyName);
1556 static HRESULT WINAPI IXACT3EngineImpl_Stop(IXACT3Engine *iface,
1557 XACTCATEGORY nCategory, DWORD dwFlags)
1559 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1561 TRACE("(%p)->(%u, 0x%lx)\n", This, nCategory, dwFlags);
1563 return FACTAudioEngine_Stop(This->fact_engine, nCategory, dwFlags);
1566 static HRESULT WINAPI IXACT3EngineImpl_SetVolume(IXACT3Engine *iface,
1567 XACTCATEGORY nCategory, XACTVOLUME nVolume)
1569 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1571 TRACE("(%p)->(%u, %f)\n", This, nCategory, nVolume);
1573 return FACTAudioEngine_SetVolume(This->fact_engine, nCategory, nVolume);
1576 static HRESULT WINAPI IXACT3EngineImpl_Pause(IXACT3Engine *iface,
1577 XACTCATEGORY nCategory, BOOL fPause)
1579 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1581 TRACE("(%p)->(%u, %u)\n", This, nCategory, fPause);
1583 return FACTAudioEngine_Pause(This->fact_engine, nCategory, fPause);
1586 static XACTVARIABLEINDEX WINAPI IXACT3EngineImpl_GetGlobalVariableIndex(
1587 IXACT3Engine *iface, PCSTR szFriendlyName)
1589 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1591 TRACE("(%p)->(%s)\n", This, szFriendlyName);
1593 return FACTAudioEngine_GetGlobalVariableIndex(This->fact_engine,
1594 szFriendlyName);
1597 static HRESULT WINAPI IXACT3EngineImpl_SetGlobalVariable(IXACT3Engine *iface,
1598 XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE nValue)
1600 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1602 TRACE("(%p)->(%u, %f)\n", This, nIndex, nValue);
1604 return FACTAudioEngine_SetGlobalVariable(This->fact_engine, nIndex, nValue);
1607 static HRESULT WINAPI IXACT3EngineImpl_GetGlobalVariable(IXACT3Engine *iface,
1608 XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE *nValue)
1610 XACT3EngineImpl *This = impl_from_IXACT3Engine(iface);
1612 TRACE("(%p)->(%u, %p)\n", This, nIndex, nValue);
1614 return FACTAudioEngine_GetGlobalVariable(This->fact_engine, nIndex, nValue);
1617 static const IXACT3EngineVtbl XACT3Engine_Vtbl =
1619 IXACT3EngineImpl_QueryInterface,
1620 IXACT3EngineImpl_AddRef,
1621 IXACT3EngineImpl_Release,
1622 IXACT3EngineImpl_GetRendererCount,
1623 IXACT3EngineImpl_GetRendererDetails,
1624 #if XACT3_VER >= 0x0205
1625 IXACT3EngineImpl_GetFinalMixFormat,
1626 #endif
1627 IXACT3EngineImpl_Initialize,
1628 IXACT3EngineImpl_ShutDown,
1629 IXACT3EngineImpl_DoWork,
1630 IXACT3EngineImpl_CreateSoundBank,
1631 IXACT3EngineImpl_CreateInMemoryWaveBank,
1632 IXACT3EngineImpl_CreateStreamingWaveBank,
1633 #if XACT3_VER >= 0x0205
1634 IXACT3EngineImpl_PrepareWave,
1635 IXACT3EngineImpl_PrepareInMemoryWave,
1636 IXACT3EngineImpl_PrepareStreamingWave,
1637 #endif
1638 IXACT3EngineImpl_RegisterNotification,
1639 IXACT3EngineImpl_UnRegisterNotification,
1640 IXACT3EngineImpl_GetCategory,
1641 IXACT3EngineImpl_Stop,
1642 IXACT3EngineImpl_SetVolume,
1643 IXACT3EngineImpl_Pause,
1644 IXACT3EngineImpl_GetGlobalVariableIndex,
1645 IXACT3EngineImpl_SetGlobalVariable,
1646 IXACT3EngineImpl_GetGlobalVariable
1649 void* XACT_Internal_Malloc(size_t size)
1651 return CoTaskMemAlloc(size);
1654 void XACT_Internal_Free(void* ptr)
1656 return CoTaskMemFree(ptr);
1659 void* XACT_Internal_Realloc(void* ptr, size_t size)
1661 return CoTaskMemRealloc(ptr, size);
1664 static HRESULT WINAPI XACT3CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1666 if(IsEqualGUID(riid, &IID_IUnknown) ||
1667 IsEqualGUID(riid, &IID_IClassFactory))
1669 *ppobj = iface;
1670 return S_OK;
1673 *ppobj = NULL;
1674 WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
1675 return E_NOINTERFACE;
1678 static ULONG WINAPI XACT3CF_AddRef(IClassFactory *iface)
1680 return 2;
1683 static ULONG WINAPI XACT3CF_Release(IClassFactory *iface)
1685 return 1;
1688 static HRESULT WINAPI XACT3CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
1689 REFIID riid, void **ppobj)
1691 HRESULT hr;
1692 XACT3EngineImpl *object;
1694 TRACE("(%p)->(%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid), ppobj);
1696 *ppobj = NULL;
1698 if(pOuter)
1699 return CLASS_E_NOAGGREGATION;
1701 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1702 if(!object)
1703 return E_OUTOFMEMORY;
1705 object->IXACT3Engine_iface.lpVtbl = &XACT3Engine_Vtbl;
1707 FACTCreateEngineWithCustomAllocatorEXT(
1709 &object->fact_engine,
1710 XACT_Internal_Malloc,
1711 XACT_Internal_Free,
1712 XACT_Internal_Realloc
1715 hr = IXACT3Engine_QueryInterface(&object->IXACT3Engine_iface, riid, ppobj);
1716 if(FAILED(hr)){
1717 HeapFree(GetProcessHeap(), 0, object);
1718 return hr;
1721 wine_rb_init(&object->wrapper_lookup, wrapper_lookup_compare);
1722 InitializeCriticalSection(&object->wrapper_lookup_cs);
1724 return hr;
1727 static HRESULT WINAPI XACT3CF_LockServer(IClassFactory *iface, BOOL dolock)
1729 TRACE("(%p)->(%d): stub!\n", iface, dolock);
1730 return S_OK;
1733 static const IClassFactoryVtbl XACT3CF_Vtbl =
1735 XACT3CF_QueryInterface,
1736 XACT3CF_AddRef,
1737 XACT3CF_Release,
1738 XACT3CF_CreateInstance,
1739 XACT3CF_LockServer
1742 static IClassFactory XACTFactory = { &XACT3CF_Vtbl };
1744 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
1746 TRACE("(%p, %ld, %p)\n", hinstDLL, reason, pReserved);
1748 switch (reason)
1750 case DLL_PROCESS_ATTACH:
1751 DisableThreadLibraryCalls( hinstDLL );
1752 TRACE("Using FAudio version %d\n", FAudioLinkedVersion() );
1753 break;
1755 return TRUE;
1758 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
1760 if (IsEqualGUID(rclsid, &CLSID_XACTEngine))
1762 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1763 return IClassFactory_QueryInterface(&XACTFactory, riid, ppv);
1766 FIXME("Unknown class %s\n", debugstr_guid(rclsid));
1767 return CLASS_E_CLASSNOTAVAILABLE;