1 #include "xaudio2.h"
2 #include "XAPO.h"
3 
4 #include <FAPOBase.h>
5 
6 ///////////////////////////////////////////////////////////////////////////////
7 //
8 // IXAudio2VoiceCallback
9 //
10 
11 struct FAudioVoiceCppCallback
12 {
13 	FAudioVoiceCallback callbacks;
14 	IXAudio2VoiceCallback *com;
15 };
16 
OnBufferEnd(FAudioVoiceCallback * callback,void * pBufferContext)17 static void FAUDIOCALL OnBufferEnd(FAudioVoiceCallback *callback, void *pBufferContext)
18 {
19 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnBufferEnd(pBufferContext);
20 }
21 
OnBufferStart(FAudioVoiceCallback * callback,void * pBufferContext)22 static void FAUDIOCALL OnBufferStart(FAudioVoiceCallback *callback, void *pBufferContext)
23 {
24 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnBufferStart(pBufferContext);
25 }
26 
OnLoopEnd(FAudioVoiceCallback * callback,void * pBufferContext)27 static void FAUDIOCALL OnLoopEnd(FAudioVoiceCallback *callback, void *pBufferContext)
28 {
29 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnLoopEnd(pBufferContext);
30 }
31 
OnStreamEnd(FAudioVoiceCallback * callback)32 static void FAUDIOCALL OnStreamEnd(FAudioVoiceCallback *callback)
33 {
34 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnStreamEnd();
35 }
36 
OnVoiceError(FAudioVoiceCallback * callback,void * pBufferContext,uint32_t Error)37 static void FAUDIOCALL OnVoiceError(
38 	FAudioVoiceCallback *callback,
39 	void *pBufferContext,
40 	uint32_t Error
41 ) {
42 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceError(pBufferContext, Error);
43 }
44 
OnVoiceProcessingPassEnd(FAudioVoiceCallback * callback)45 static void FAUDIOCALL OnVoiceProcessingPassEnd(FAudioVoiceCallback *callback)
46 {
47 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassEnd();
48 }
49 
OnVoiceProcessingPassStart(FAudioVoiceCallback * callback,uint32_t BytesRequired)50 static void FAUDIOCALL OnVoiceProcessingPassStart(
51 	FAudioVoiceCallback *callback,
52 	uint32_t BytesRequired
53 ) {
54 #if XAUDIO2_VERSION >= 1
55 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassStart(
56 		BytesRequired);
57 #else
58 	reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassStart();
59 #endif // XAUDIO2_VERSION >= 1
60 }
61 
wrap_voice_callback(IXAudio2VoiceCallback * com_interface)62 FAudioVoiceCppCallback *wrap_voice_callback(IXAudio2VoiceCallback *com_interface)
63 {
64 	if (com_interface == NULL)
65 	{
66 		return NULL;
67 	}
68 
69 	FAudioVoiceCppCallback *cb = new FAudioVoiceCppCallback();
70 	cb->callbacks.OnBufferEnd = OnBufferEnd;
71 	cb->callbacks.OnBufferStart = OnBufferStart;
72 	cb->callbacks.OnLoopEnd = OnLoopEnd;
73 	cb->callbacks.OnStreamEnd = OnStreamEnd;
74 	cb->callbacks.OnVoiceError = OnVoiceError;
75 	cb->callbacks.OnVoiceProcessingPassEnd = OnVoiceProcessingPassEnd;
76 	cb->callbacks.OnVoiceProcessingPassStart = OnVoiceProcessingPassStart;
77 	cb->com = com_interface;
78 
79 	return cb;
80 }
81 
82 ///////////////////////////////////////////////////////////////////////////////
83 //
84 // IXAudio2EngineCallback
85 //
86 
87 struct FAudioCppEngineCallback
88 {
89 	FAudioEngineCallback callbacks;
90 	IXAudio2EngineCallback *com;
91 
92 	FAudioCppEngineCallback *next;
93 };
94 
OnCriticalError(FAudioEngineCallback * callback,uint32_t Error)95 static void FAUDIOCALL OnCriticalError(FAudioEngineCallback *callback, uint32_t Error)
96 {
97 	reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnCriticalError(Error);
98 }
99 
OnProcessingPassEnd(FAudioEngineCallback * callback)100 static void FAUDIOCALL OnProcessingPassEnd(FAudioEngineCallback *callback)
101 {
102 	reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnProcessingPassEnd();
103 }
104 
OnProcessingPassStart(FAudioEngineCallback * callback)105 static void FAUDIOCALL OnProcessingPassStart(FAudioEngineCallback *callback)
106 {
107 	reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnProcessingPassStart();
108 }
109 
wrap_engine_callback(IXAudio2EngineCallback * com_interface)110 static FAudioCppEngineCallback *wrap_engine_callback(IXAudio2EngineCallback *com_interface)
111 {
112 	if (com_interface == NULL)
113 	{
114 		return NULL;
115 	}
116 
117 	FAudioCppEngineCallback *cb = new FAudioCppEngineCallback();
118 	cb->callbacks.OnCriticalError = OnCriticalError;
119 	cb->callbacks.OnProcessingPassEnd = OnProcessingPassEnd;
120 	cb->callbacks.OnProcessingPassStart = OnProcessingPassStart;
121 	cb->com = com_interface;
122 	cb->next = NULL;
123 
124 	return cb;
125 }
126 
find_and_remove_engine_callback(FAudioCppEngineCallback * list,IXAudio2EngineCallback * com)127 static FAudioCppEngineCallback *find_and_remove_engine_callback(
128 	FAudioCppEngineCallback *list,
129 	IXAudio2EngineCallback *com
130 ) {
131 	FAudioCppEngineCallback *last = list;
132 
133 	for (FAudioCppEngineCallback *it = list->next; it != NULL; it = it->next)
134 	{
135 		if (it->com == com)
136 		{
137 			last->next = it->next;
138 			return it;
139 		}
140 
141 		last = it;
142 	}
143 
144 	return NULL;
145 }
146 
147 ///////////////////////////////////////////////////////////////////////////////
148 //
149 // XAUDIO2_VOICE_SENDS / XAUDIO2_SEND_DESCRIPTOR => FAudio
150 //
151 
unwrap_voice_sends(const XAUDIO2_VOICE_SENDS * x_sends)152 static FAudioVoiceSends *unwrap_voice_sends(const XAUDIO2_VOICE_SENDS *x_sends)
153 {
154 	if (x_sends == NULL)
155 	{
156 		return NULL;
157 	}
158 
159 	FAudioVoiceSends *f_sends = new FAudioVoiceSends;
160 	f_sends->SendCount = x_sends->SendCount;
161 	f_sends->pSends = new FAudioSendDescriptor[f_sends->SendCount];
162 
163 	for (uint32_t i = 0; i < f_sends->SendCount; ++i)
164 	{
165 #if XAUDIO2_VERSION >= 4
166 		f_sends->pSends[i].Flags = x_sends->pSends[i].Flags;
167 		f_sends->pSends[i].pOutputVoice = x_sends->pSends[i].pOutputVoice->faudio_voice;
168 #else
169 		f_sends->pSends[i].Flags = 0;
170 		f_sends->pSends[i].pOutputVoice = x_sends->pSends[i]->faudio_voice;
171 #endif // XAUDIO2_VERSION >= 4
172 	}
173 
174 	return f_sends;
175 }
176 
free_voice_sends(FAudioVoiceSends * f_sends)177 static void free_voice_sends(FAudioVoiceSends *f_sends)
178 {
179 	if (f_sends != NULL)
180 	{
181 		delete[] f_sends->pSends;
182 		delete f_sends;
183 	}
184 }
185 
186 ///////////////////////////////////////////////////////////////////////////////
187 //
188 // XAUDIO2_EFFECT_CHAIN / XAUDIO2_EFFECT_DESCRIPTOR => FAudio
189 //
190 
191 struct FAPOCppBase
192 {
193 	FAPO fapo;
194 	IXAPO *xapo;
195 	IXAPOParameters *xapo_params;
196 	LONG refcount;
197 };
198 
AddRef(void * fapo)199 static int32_t FAPOCALL AddRef(void *fapo)
200 {
201 	FAPOCppBase *base = reinterpret_cast<FAPOCppBase *>(fapo);
202 	return ++base->refcount;
203 }
204 
Release(void * fapo)205 static int32_t FAPOCALL Release(void *fapo)
206 {
207 	FAPOCppBase *base = reinterpret_cast<FAPOCppBase *>(fapo);
208 	IXAPO *xapo = base->xapo;
209 	LONG ref = --base->refcount;
210 	if (ref == 0)
211 	{
212 		xapo->Release();
213 		if (base->xapo_params != NULL)
214 		{
215 			base->xapo_params->Release();
216 		}
217 		delete base;
218 	}
219 	return ref;
220 }
221 
GetRegistrationProperties(void * fapo,FAPORegistrationProperties ** ppRegistrationProperties)222 static uint32_t FAPOCALL GetRegistrationProperties(
223 	void *fapo,
224 	FAPORegistrationProperties **ppRegistrationProperties)
225 {
226 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
227 	return xapo->GetRegistrationProperties(ppRegistrationProperties);
228 }
229 
IsInputFormatSupported(void * fapo,const FAudioWaveFormatEx * pOutputFormat,const FAudioWaveFormatEx * pRequestedInputFormat,FAudioWaveFormatEx ** ppSupportedInputFormat)230 static uint32_t FAPOCALL IsInputFormatSupported(
231 	void *fapo,
232 	const FAudioWaveFormatEx *pOutputFormat,
233 	const FAudioWaveFormatEx *pRequestedInputFormat,
234 	FAudioWaveFormatEx **ppSupportedInputFormat
235 ) {
236 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
237 	return xapo->IsInputFormatSupported(
238 		pOutputFormat,
239 		pRequestedInputFormat,
240 		ppSupportedInputFormat);
241 }
242 
IsOutputFormatSupported(void * fapo,const FAudioWaveFormatEx * pInputFormat,const FAudioWaveFormatEx * pRequestedOutputFormat,FAudioWaveFormatEx ** ppSupportedOutputFormat)243 static uint32_t FAPOCALL IsOutputFormatSupported(
244 	void *fapo,
245 	const FAudioWaveFormatEx *pInputFormat,
246 	const FAudioWaveFormatEx *pRequestedOutputFormat,
247 	FAudioWaveFormatEx **ppSupportedOutputFormat
248 ) {
249 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
250 	return xapo->IsOutputFormatSupported(
251 		pInputFormat,
252 		pRequestedOutputFormat,
253 		ppSupportedOutputFormat);
254 }
255 
Initialize(void * fapo,const void * pData,uint32_t DataByteSize)256 static uint32_t FAPOCALL Initialize(void *fapo, const void *pData, uint32_t DataByteSize)
257 {
258 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
259 	return xapo->Initialize(pData, DataByteSize);
260 }
261 
Reset(void * fapo)262 static void FAPOCALL Reset(void *fapo)
263 {
264 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
265 	xapo->Reset();
266 }
267 
LockForProcess(void * fapo,uint32_t InputLockedParameterCount,const FAPOLockForProcessBufferParameters * pInputLockedParameters,uint32_t OutputLockedParameterCount,const FAPOLockForProcessBufferParameters * pOutputLockedParameters)268 static uint32_t FAPOCALL LockForProcess(
269 	void *fapo,
270 	uint32_t InputLockedParameterCount,
271 	const FAPOLockForProcessBufferParameters *pInputLockedParameters,
272 	uint32_t OutputLockedParameterCount,
273 	const FAPOLockForProcessBufferParameters *pOutputLockedParameters
274 ) {
275 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
276 	return xapo->LockForProcess(
277 		InputLockedParameterCount,
278 		pInputLockedParameters,
279 		OutputLockedParameterCount,
280 		pOutputLockedParameters);
281 }
282 
UnlockForProcess(void * fapo)283 static void FAPOCALL UnlockForProcess(void *fapo)
284 {
285 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
286 	xapo->UnlockForProcess();
287 }
288 
Process(void * fapo,uint32_t InputProcessParameterCount,const FAPOProcessBufferParameters * pInputProcessParameters,uint32_t OutputProcessParameterCount,FAPOProcessBufferParameters * pOutputProcessParameters,int32_t IsEnabled)289 static void FAPOCALL Process(
290 	void *fapo,
291 	uint32_t InputProcessParameterCount,
292 	const FAPOProcessBufferParameters *pInputProcessParameters,
293 	uint32_t OutputProcessParameterCount,
294 	FAPOProcessBufferParameters *pOutputProcessParameters,
295 	int32_t IsEnabled
296 ) {
297 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
298 	xapo->Process(
299 		InputProcessParameterCount,
300 		pInputProcessParameters,
301 		OutputProcessParameterCount,
302 		pOutputProcessParameters,
303 		IsEnabled);
304 }
305 
CalcInputFrames(void * fapo,uint32_t OutputFrameCount)306 static uint32_t FAPOCALL CalcInputFrames(void *fapo, uint32_t OutputFrameCount)
307 {
308 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
309 	return xapo->CalcInputFrames(OutputFrameCount);
310 }
311 
CalcOutputFrames(void * fapo,uint32_t InputFrameCount)312 static uint32_t FAPOCALL CalcOutputFrames(void *fapo, uint32_t InputFrameCount)
313 {
314 	IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
315 	return xapo->CalcOutputFrames(InputFrameCount);
316 }
317 
SetParameters(void * fapoParameters,const void * pParameters,uint32_t ParameterByteSize)318 static void FAPOCALL SetParameters(
319 	void *fapoParameters,
320 	const void *pParameters,
321 	uint32_t ParameterByteSize
322 ) {
323 	IXAPOParameters *xapo_params = reinterpret_cast<FAPOCppBase *>(fapoParameters)->xapo_params;
324 	return xapo_params->SetParameters(pParameters, ParameterByteSize);
325 }
326 
GetParameters(void * fapoParameters,void * pParameters,uint32_t ParameterByteSize)327 static void FAPOCALL GetParameters(void *fapoParameters, void *pParameters, uint32_t ParameterByteSize)
328 {
329 	IXAPOParameters *xapo_params = reinterpret_cast<FAPOCppBase *>(fapoParameters)->xapo_params;
330 	return xapo_params->GetParameters(pParameters, ParameterByteSize);
331 }
332 
wrap_xapo_effect(IUnknown * xapo)333 static FAPO *wrap_xapo_effect(IUnknown *xapo)
334 {
335 	if (xapo == NULL)
336 	{
337 		return NULL;
338 	}
339 
340 	// FIXME: assumes that all effects are derived from CXAPOParametersBase
341 	FAPOCppBase *f_effect = new FAPOCppBase;
342 	f_effect->refcount = 1;
343 	xapo->QueryInterface(IID_IXAPO, (void **)&f_effect->xapo);
344 	xapo->QueryInterface(IID_IXAPOParameters, (void **)&f_effect->xapo_params);
345 
346 	f_effect->fapo.AddRef = AddRef;
347 	f_effect->fapo.Release = Release;
348 	f_effect->fapo.GetRegistrationProperties = GetRegistrationProperties;
349 	f_effect->fapo.IsInputFormatSupported = IsInputFormatSupported;
350 	f_effect->fapo.IsOutputFormatSupported = IsOutputFormatSupported;
351 	f_effect->fapo.Initialize = Initialize;
352 	f_effect->fapo.Reset = Reset;
353 	f_effect->fapo.LockForProcess = LockForProcess;
354 	f_effect->fapo.UnlockForProcess = UnlockForProcess;
355 	f_effect->fapo.Process = Process;
356 	f_effect->fapo.CalcInputFrames = CalcInputFrames;
357 	f_effect->fapo.CalcOutputFrames = CalcOutputFrames;
358 	f_effect->fapo.GetParameters = GetParameters;
359 	f_effect->fapo.SetParameters = SetParameters;
360 
361 	return &f_effect->fapo;
362 }
363 
wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN * x_chain)364 static FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *x_chain)
365 {
366 	if (x_chain == NULL)
367 	{
368 		return NULL;
369 	}
370 
371 	FAudioEffectChain *f_chain = new FAudioEffectChain;
372 	f_chain->EffectCount = x_chain->EffectCount;
373 	f_chain->pEffectDescriptors = new FAudioEffectDescriptor[f_chain->EffectCount];
374 
375 	for (uint32_t i = 0; i < f_chain->EffectCount; ++i)
376 	{
377 		f_chain->pEffectDescriptors[i].InitialState = x_chain->pEffectDescriptors[i].InitialState;
378 		f_chain->pEffectDescriptors[i].OutputChannels =
379 			x_chain->pEffectDescriptors[i].OutputChannels;
380 		f_chain->pEffectDescriptors[i].pEffect =
381 			wrap_xapo_effect(x_chain->pEffectDescriptors[i].pEffect);
382 	}
383 
384 	return f_chain;
385 }
386 
free_effect_chain(FAudioEffectChain * f_chain)387 static void free_effect_chain(FAudioEffectChain *f_chain)
388 {
389 	if (f_chain != NULL)
390 	{
391 		delete[] f_chain->pEffectDescriptors;
392 		delete f_chain;
393 	}
394 }
395 
396 ///////////////////////////////////////////////////////////////////////////////
397 //
398 // IXAudio2SourceVoice implementation
399 //
400 
401 class XAudio2SourceVoiceImpl : public IXAudio2SourceVoice
402 {
403 public:
XAudio2SourceVoiceImpl(FAudio * faudio,const WAVEFORMATEX * pSourceFormat,UINT32 Flags,float MaxFrequencyRatio,IXAudio2VoiceCallback * pCallback,const XAUDIO2_VOICE_SENDS * pSendList,const XAUDIO2_EFFECT_CHAIN * pEffectChain)404 	XAudio2SourceVoiceImpl(
405 		FAudio *faudio,
406 		const WAVEFORMATEX *pSourceFormat,
407 		UINT32 Flags,
408 		float MaxFrequencyRatio,
409 		IXAudio2VoiceCallback *pCallback,
410 		const XAUDIO2_VOICE_SENDS *pSendList,
411 		const XAUDIO2_EFFECT_CHAIN *pEffectChain)
412 	{
413 		voice_callback = wrap_voice_callback(pCallback);
414 		voice_sends = unwrap_voice_sends(pSendList);
415 		effect_chain = wrap_effect_chain(pEffectChain);
416 		FAudio_CreateSourceVoice(
417 			faudio,
418 			&faudio_voice,
419 			pSourceFormat,
420 			Flags,
421 			MaxFrequencyRatio,
422 			reinterpret_cast<FAudioVoiceCallback *>(voice_callback),
423 			voice_sends,
424 			effect_chain);
425 	}
426 
427 	// IXAudio2Voice
GetVoiceDetails(XAUDIO2_VOICE_DETAILS * pVoiceDetails)428 	COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
429 	{
430 #if XAUDIO2_VERSION > 7
431 		FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
432 #else
433 		FAudioVoiceDetails fDetails;
434 		FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
435 		pVoiceDetails->CreationFlags = fDetails.CreationFlags;
436 		pVoiceDetails->InputChannels = fDetails.InputChannels;
437 		pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
438 #endif // XAUDIO2_VERSION <= 7
439 	}
440 
SetOutputVoices(const XAUDIO2_VOICE_SENDS * pSendList)441 	COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
442 	{
443 		free_voice_sends(voice_sends);
444 		voice_sends = unwrap_voice_sends(pSendList);
445 		return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
446 	}
447 
SetEffectChain(const XAUDIO2_EFFECT_CHAIN * pEffectChain)448 	COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
449 	{
450 		free_effect_chain(effect_chain);
451 		effect_chain = wrap_effect_chain(pEffectChain);
452 		return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
453 	}
454 
EnableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)455 	COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
456 	{
457 		return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
458 	}
459 
DisableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)460 	COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
461 	{
462 		return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
463 	}
464 
GetEffectState(UINT32 EffectIndex,BOOL * pEnabled)465 	COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
466 	{
467 		FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
468 	}
469 
SetEffectParameters(UINT32 EffectIndex,const void * pParameters,UINT32 ParametersByteSize,UINT32 OperationSet=FAUDIO_COMMIT_NOW)470 	COM_METHOD(HRESULT) SetEffectParameters(
471 		UINT32 EffectIndex,
472 		const void *pParameters,
473 		UINT32 ParametersByteSize,
474 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
475 	) {
476 		return FAudioVoice_SetEffectParameters(
477 			faudio_voice,
478 			EffectIndex,
479 			pParameters,
480 			ParametersByteSize,
481 			OperationSet);
482 	}
483 
GetEffectParameters(UINT32 EffectIndex,void * pParameters,UINT32 ParametersByteSize)484 	COM_METHOD(HRESULT) GetEffectParameters(
485 		UINT32 EffectIndex,
486 		void *pParameters,
487 		UINT32 ParametersByteSize)
488 	{
489 		return FAudioVoice_GetEffectParameters(
490 			faudio_voice,
491 			EffectIndex,
492 			pParameters,
493 			ParametersByteSize);
494 	}
495 
SetFilterParameters(const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)496 	COM_METHOD(HRESULT) SetFilterParameters(
497 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
498 		UINT32 OperationSet = FAUDIO_COMMIT_NOW)
499 	{
500 		return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
501 	}
502 
GetFilterParameters(XAUDIO2_FILTER_PARAMETERS * pParameters)503 	COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
504 	{
505 		FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
506 	}
507 
508 #if XAUDIO2_VERSION >= 4
SetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)509 	COM_METHOD(HRESULT) SetOutputFilterParameters(
510 		IXAudio2Voice *pDestinationVoice,
511 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
512 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
513 	) {
514 		return FAudioVoice_SetOutputFilterParameters(
515 			faudio_voice,
516 			((XAudio2SourceVoiceImpl *)pDestinationVoice)->faudio_voice,
517 			pParameters,
518 			OperationSet);
519 	}
520 
GetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,XAUDIO2_FILTER_PARAMETERS * pParameters)521 	COM_METHOD(void) GetOutputFilterParameters(
522 		IXAudio2Voice *pDestinationVoice,
523 		XAUDIO2_FILTER_PARAMETERS *pParameters
524 	) {
525 		FAudioVoice_GetOutputFilterParameters(
526 			faudio_voice,
527 			((XAudio2SourceVoiceImpl *)pDestinationVoice)->faudio_voice,
528 			pParameters);
529 	}
530 #endif // XAUDIO2_VERSION >= 4
531 
SetVolume(float Volume,UINT32 OperationSet=FAUDIO_COMMIT_NOW)532 	COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
533 	{
534 		return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
535 	}
536 
GetVolume(float * pVolume)537 	COM_METHOD(void) GetVolume(float *pVolume)
538 	{
539 		FAudioVoice_GetVolume(faudio_voice, pVolume);
540 	}
541 
SetChannelVolumes(UINT32 Channels,const float * pVolumes,UINT32 OperationSet=FAUDIO_COMMIT_NOW)542 	COM_METHOD(HRESULT) SetChannelVolumes(
543 		UINT32 Channels,
544 		const float *pVolumes,
545 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
546 	) {
547 		return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
548 	}
549 
GetChannelVolumes(UINT32 Channels,float * pVolumes)550 	COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
551 	{
552 		FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
553 	}
554 
SetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,const float * pLevelMatrix,UINT32 OperationSet=FAUDIO_COMMIT_NOW)555 	COM_METHOD(HRESULT) SetOutputMatrix(
556 		IXAudio2Voice *pDestinationVoice,
557 		UINT32 SourceChannels,
558 		UINT32 DestinationChannels,
559 		const float *pLevelMatrix,
560 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
561 	) {
562 		FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
563 		return FAudioVoice_SetOutputMatrix(
564 			faudio_voice, dest, SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
565 	}
566 
567 #if XAUDIO2_VERSION >= 1
GetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,float * pLevelMatrix)568 	COM_METHOD(void) GetOutputMatrix(
569 #else
570 	COM_METHOD(HRESULT) GetOutputMatrix(
571 #endif
572 		IXAudio2Voice *pDestinationVoice,
573 		UINT32 SourceChannels,
574 		UINT32 DestinationChannels,
575 		float *pLevelMatrix
576 	) {
577 		FAudioVoice_GetOutputMatrix(
578 			faudio_voice,
579 			pDestinationVoice->faudio_voice,
580 			SourceChannels,
581 			DestinationChannels,
582 			pLevelMatrix);
583 #if XAUDIO2_VERSION < 1
584 		return S_OK;
585 #endif // XAUDIO2_VERSION < 1
586 	}
587 
DestroyVoice()588 	COM_METHOD(void) DestroyVoice()
589 	{
590 		FAudioVoice_DestroyVoice(faudio_voice);
591 		// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
592 		if (voice_callback)
593 		{
594 			delete voice_callback;
595 		}
596 		free_voice_sends(voice_sends);
597 		free_effect_chain(effect_chain);
598 		delete this;
599 	}
600 
601 	// IXAudio2SourceVoice
Start(UINT32 Flags=0,UINT32 OperationSet=FAUDIO_COMMIT_NOW)602 	COM_METHOD(HRESULT) Start(UINT32 Flags = 0, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
603 	{
604 		return FAudioSourceVoice_Start(faudio_voice, Flags, OperationSet);
605 	}
606 
Stop(UINT32 Flags=0,UINT32 OperationSet=FAUDIO_COMMIT_NOW)607 	COM_METHOD(HRESULT) Stop(UINT32 Flags = 0, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
608 	{
609 		return FAudioSourceVoice_Stop(faudio_voice, Flags, OperationSet);
610 	}
611 
SubmitSourceBuffer(const XAUDIO2_BUFFER * pBuffer,const XAUDIO2_BUFFER_WMA * pBufferWMA=NULL)612 	COM_METHOD(HRESULT) SubmitSourceBuffer(
613 		const XAUDIO2_BUFFER *pBuffer,
614 		const XAUDIO2_BUFFER_WMA *pBufferWMA = NULL)
615 	{
616 		return FAudioSourceVoice_SubmitSourceBuffer(faudio_voice, pBuffer, pBufferWMA);
617 	}
618 
FlushSourceBuffers()619 	COM_METHOD(HRESULT) FlushSourceBuffers()
620 	{
621 		return FAudioSourceVoice_FlushSourceBuffers(faudio_voice);
622 	}
623 
Discontinuity()624 	COM_METHOD(HRESULT) Discontinuity()
625 	{
626 		return FAudioSourceVoice_Discontinuity(faudio_voice);
627 	}
628 
ExitLoop(UINT32 OperationSet=FAUDIO_COMMIT_NOW)629 	COM_METHOD(HRESULT) ExitLoop(UINT32 OperationSet = FAUDIO_COMMIT_NOW)
630 	{
631 		return FAudioSourceVoice_ExitLoop(faudio_voice, OperationSet);
632 	}
633 
634 #if (XAUDIO2_VERSION <= 7)
GetState(XAUDIO2_VOICE_STATE * pVoiceState)635 	COM_METHOD(void) GetState(XAUDIO2_VOICE_STATE *pVoiceState)
636 #else
637 	COM_METHOD(void) GetState(XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags = 0)
638 #endif
639 	{
640 #if (XAUDIO2_VERSION <= 7)
641 		FAudioSourceVoice_GetState(faudio_voice, pVoiceState, 0);
642 #else
643 		FAudioSourceVoice_GetState(faudio_voice, pVoiceState, Flags);
644 #endif
645 	}
646 
SetFrequencyRatio(float Ratio,UINT32 OperationSet=FAUDIO_COMMIT_NOW)647 	COM_METHOD(HRESULT) SetFrequencyRatio(float Ratio, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
648 	{
649 		return FAudioSourceVoice_SetFrequencyRatio(faudio_voice, Ratio, OperationSet);
650 	}
651 
GetFrequencyRatio(float * pRatio)652 	COM_METHOD(void) GetFrequencyRatio(float *pRatio)
653 	{
654 		FAudioSourceVoice_GetFrequencyRatio(faudio_voice, pRatio);
655 	}
656 
657 #if XAUDIO2_VERSION >= 4
SetSourceSampleRate(UINT32 NewSourceSampleRate)658 	COM_METHOD(HRESULT) SetSourceSampleRate(UINT32 NewSourceSampleRate)
659 	{
660 		return FAudioSourceVoice_SetSourceSampleRate(faudio_voice, NewSourceSampleRate);
661 	}
662 #endif // XAUDIO2_VERSION >= 4
663 
664 private:
665 	FAudioVoiceCppCallback *voice_callback;
666 	FAudioVoiceSends *voice_sends;
667 	FAudioEffectChain *effect_chain;
668 };
669 
670 ///////////////////////////////////////////////////////////////////////////////
671 //
672 // IXAudio2SubmixVoice implementation
673 //
674 
675 class XAudio2SubmixVoiceImpl : public IXAudio2SubmixVoice
676 {
677 public:
XAudio2SubmixVoiceImpl(FAudio * faudio,UINT32 InputChannels,UINT32 InputSampleRate,UINT32 Flags,UINT32 ProcessingStage,const XAUDIO2_VOICE_SENDS * pSendList,const XAUDIO2_EFFECT_CHAIN * pEffectChain)678 	XAudio2SubmixVoiceImpl(
679 		FAudio *faudio,
680 		UINT32 InputChannels,
681 		UINT32 InputSampleRate,
682 		UINT32 Flags,
683 		UINT32 ProcessingStage,
684 		const XAUDIO2_VOICE_SENDS *pSendList,
685 		const XAUDIO2_EFFECT_CHAIN *pEffectChain
686 	) {
687 		voice_sends = unwrap_voice_sends(pSendList);
688 		effect_chain = wrap_effect_chain(pEffectChain);
689 		FAudio_CreateSubmixVoice(
690 			faudio,
691 			&faudio_voice,
692 			InputChannels,
693 			InputSampleRate,
694 			Flags,
695 			ProcessingStage,
696 			voice_sends,
697 			effect_chain);
698 	}
699 
700 	// IXAudio2Voice
GetVoiceDetails(XAUDIO2_VOICE_DETAILS * pVoiceDetails)701 	COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
702 	{
703 #if XAUDIO2_VERSION > 7
704 		FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
705 #else
706 		FAudioVoiceDetails fDetails;
707 		FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
708 		pVoiceDetails->CreationFlags = fDetails.CreationFlags;
709 		pVoiceDetails->InputChannels = fDetails.InputChannels;
710 		pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
711 #endif // XAUDIO2_VERSION <= 7
712 	}
713 
SetOutputVoices(const XAUDIO2_VOICE_SENDS * pSendList)714 	COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
715 	{
716 		free_voice_sends(voice_sends);
717 		voice_sends = unwrap_voice_sends(pSendList);
718 		return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
719 	}
720 
SetEffectChain(const XAUDIO2_EFFECT_CHAIN * pEffectChain)721 	COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
722 	{
723 		free_effect_chain(effect_chain);
724 		effect_chain = wrap_effect_chain(pEffectChain);
725 		return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
726 	}
727 
EnableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)728 	COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
729 	{
730 		return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
731 	}
732 
DisableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)733 	COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
734 	{
735 		return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
736 	}
737 
GetEffectState(UINT32 EffectIndex,BOOL * pEnabled)738 	COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
739 	{
740 		FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
741 	}
742 
SetEffectParameters(UINT32 EffectIndex,const void * pParameters,UINT32 ParametersByteSize,UINT32 OperationSet=FAUDIO_COMMIT_NOW)743 	COM_METHOD(HRESULT) SetEffectParameters(
744 		UINT32 EffectIndex,
745 		const void *pParameters,
746 		UINT32 ParametersByteSize,
747 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
748 	) {
749 		return FAudioVoice_SetEffectParameters(
750 			faudio_voice,
751 			EffectIndex,
752 			pParameters,
753 			ParametersByteSize,
754 			OperationSet);
755 	}
756 
GetEffectParameters(UINT32 EffectIndex,void * pParameters,UINT32 ParametersByteSize)757 	COM_METHOD(HRESULT) GetEffectParameters(
758 		UINT32 EffectIndex,
759 		void *pParameters,
760 		UINT32 ParametersByteSize
761 	) {
762 		return FAudioVoice_GetEffectParameters(
763 			faudio_voice,
764 			EffectIndex,
765 			pParameters,
766 			ParametersByteSize);
767 	}
768 
SetFilterParameters(const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)769 	COM_METHOD(HRESULT) SetFilterParameters(
770 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
771 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
772 	) {
773 		return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
774 	}
775 
GetFilterParameters(XAUDIO2_FILTER_PARAMETERS * pParameters)776 	COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
777 	{
778 		FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
779 	}
780 
781 #if XAUDIO2_VERSION >= 4
SetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)782 	COM_METHOD(HRESULT) SetOutputFilterParameters(
783 		IXAudio2Voice *pDestinationVoice,
784 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
785 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
786 	) {
787 		return FAudioVoice_SetOutputFilterParameters(
788 			faudio_voice,
789 			((XAudio2SubmixVoiceImpl *)pDestinationVoice)->faudio_voice,
790 			pParameters,
791 			OperationSet);
792 	}
793 
GetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,XAUDIO2_FILTER_PARAMETERS * pParameters)794 	COM_METHOD(void) GetOutputFilterParameters(
795 		IXAudio2Voice *pDestinationVoice,
796 		XAUDIO2_FILTER_PARAMETERS *pParameters
797 	) {
798 		FAudioVoice_GetOutputFilterParameters(
799 			faudio_voice, ((XAudio2SubmixVoiceImpl *)pDestinationVoice)->faudio_voice, pParameters);
800 	}
801 #endif // XAUDIO2_VERSION >= 4
802 
SetVolume(float Volume,UINT32 OperationSet=FAUDIO_COMMIT_NOW)803 	COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
804 	{
805 		return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
806 	}
807 
GetVolume(float * pVolume)808 	COM_METHOD(void) GetVolume(float *pVolume)
809 	{
810 		FAudioVoice_GetVolume(faudio_voice, pVolume);
811 	}
812 
SetChannelVolumes(UINT32 Channels,const float * pVolumes,UINT32 OperationSet=FAUDIO_COMMIT_NOW)813 	COM_METHOD(HRESULT) SetChannelVolumes(
814 		UINT32 Channels,
815 		const float *pVolumes,
816 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
817 	) {
818 		return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
819 	}
820 
GetChannelVolumes(UINT32 Channels,float * pVolumes)821 	COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
822 	{
823 		FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
824 	}
825 
SetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,const float * pLevelMatrix,UINT32 OperationSet=FAUDIO_COMMIT_NOW)826 	COM_METHOD(HRESULT) SetOutputMatrix(
827 		IXAudio2Voice *pDestinationVoice,
828 		UINT32 SourceChannels,
829 		UINT32 DestinationChannels,
830 		const float *pLevelMatrix,
831 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
832 	) {
833 		FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
834 		return FAudioVoice_SetOutputMatrix(
835 			faudio_voice,
836 			dest,
837 			SourceChannels,
838 			DestinationChannels,
839 			pLevelMatrix,
840 			OperationSet);
841 	}
842 
843 #if XAUDIO2_VERSION >= 1
GetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,float * pLevelMatrix)844 	COM_METHOD(void) GetOutputMatrix(
845 #else
846 	COM_METHOD(HRESULT) GetOutputMatrix(
847 #endif
848 		IXAudio2Voice *pDestinationVoice,
849 		UINT32 SourceChannels,
850 		UINT32 DestinationChannels,
851 		float *pLevelMatrix
852 	) {
853 		FAudioVoice_GetOutputMatrix(
854 			faudio_voice,
855 			pDestinationVoice->faudio_voice,
856 			SourceChannels,
857 			DestinationChannels,
858 			pLevelMatrix);
859 #if XAUDIO2_VERSION < 1
860 		return S_OK;
861 #endif // XAUDIO2_VERSION < 1
862 	}
863 
DestroyVoice()864 	COM_METHOD(void) DestroyVoice()
865 	{
866 		FAudioVoice_DestroyVoice(faudio_voice);
867 		// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
868 		free_voice_sends(voice_sends);
869 		free_effect_chain(effect_chain);
870 		delete this;
871 	}
872 
873 private:
874 	FAudioVoiceSends *voice_sends;
875 	FAudioEffectChain *effect_chain;
876 };
877 
878 ///////////////////////////////////////////////////////////////////////////////
879 //
880 // IXAudio2MasteringVoice implementation
881 //
882 
883 #if (XAUDIO2_VERSION >= 8)
884 uint32_t device_index_from_device_id(FAudio *faudio, LPCWSTR deviceId);
885 #endif // (XAUDIO2_VERSION >= 8)
886 
887 class XAudio2MasteringVoiceImpl : public IXAudio2MasteringVoice
888 {
889 public:
890 #if (XAUDIO2_VERSION <= 7)
XAudio2MasteringVoiceImpl(FAudio * faudio,UINT32 InputChannels,UINT32 InputSampleRate,UINT32 Flags,UINT32 DeviceIndex,const XAUDIO2_EFFECT_CHAIN * pEffectChain)891 	XAudio2MasteringVoiceImpl(
892 		FAudio *faudio,
893 		UINT32 InputChannels,
894 		UINT32 InputSampleRate,
895 		UINT32 Flags,
896 		UINT32 DeviceIndex,
897 		const XAUDIO2_EFFECT_CHAIN *pEffectChain
898 	) {
899 		voice_sends = NULL;
900 		effect_chain = wrap_effect_chain(pEffectChain);
901 		FAudio_CreateMasteringVoice(
902 			faudio,
903 			&faudio_voice,
904 			InputChannels,
905 			InputSampleRate,
906 			Flags,
907 			DeviceIndex,
908 			effect_chain);
909 	}
910 #else
911 	XAudio2MasteringVoiceImpl(
912 		FAudio *faudio,
913 		UINT32 InputChannels,
914 		UINT32 InputSampleRate,
915 		UINT32 Flags,
916 		LPCWSTR szDeviceId,
917 		const XAUDIO2_EFFECT_CHAIN *pEffectChain,
918 		int StreamCategory
919 	) {
920 		uint32_t device_index = 0;
921 
922 		if (szDeviceId != NULL)
923 		{
924 			device_index = device_index_from_device_id(faudio, szDeviceId);
925 		}
926 
927 		voice_sends = NULL;
928 		effect_chain = wrap_effect_chain(pEffectChain);
929 		FAudio_CreateMasteringVoice(
930 			faudio,
931 			&faudio_voice,
932 			InputChannels,
933 			InputSampleRate,
934 			Flags,
935 			device_index,
936 			effect_chain);
937 	}
938 #endif
939 
940 	// IXAudio2Voice
GetVoiceDetails(XAUDIO2_VOICE_DETAILS * pVoiceDetails)941 	COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
942 	{
943 #if XAUDIO2_VERSION > 7
944 		FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
945 #else
946 		FAudioVoiceDetails fDetails;
947 		FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
948 		pVoiceDetails->CreationFlags = fDetails.CreationFlags;
949 		pVoiceDetails->InputChannels = fDetails.InputChannels;
950 		pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
951 #endif // XAUDIO2_VERSION <= 7
952 	}
953 
SetOutputVoices(const XAUDIO2_VOICE_SENDS * pSendList)954 	COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
955 	{
956 		free_voice_sends(voice_sends);
957 		voice_sends = unwrap_voice_sends(pSendList);
958 		return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
959 	}
960 
SetEffectChain(const XAUDIO2_EFFECT_CHAIN * pEffectChain)961 	COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
962 	{
963 		free_effect_chain(effect_chain);
964 		effect_chain = wrap_effect_chain(pEffectChain);
965 		return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
966 	}
967 
EnableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)968 	COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
969 	{
970 		return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
971 	}
972 
DisableEffect(UINT32 EffectIndex,UINT32 OperationSet=FAUDIO_COMMIT_NOW)973 	COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
974 	{
975 		return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
976 	}
977 
GetEffectState(UINT32 EffectIndex,BOOL * pEnabled)978 	COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
979 	{
980 		FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
981 	}
982 
SetEffectParameters(UINT32 EffectIndex,const void * pParameters,UINT32 ParametersByteSize,UINT32 OperationSet=FAUDIO_COMMIT_NOW)983 	COM_METHOD(HRESULT) SetEffectParameters(
984 		UINT32 EffectIndex,
985 		const void *pParameters,
986 		UINT32 ParametersByteSize,
987 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
988 	) {
989 		return FAudioVoice_SetEffectParameters(
990 			faudio_voice,
991 			EffectIndex,
992 			pParameters,
993 			ParametersByteSize,
994 			OperationSet);
995 	}
996 
GetEffectParameters(UINT32 EffectIndex,void * pParameters,UINT32 ParametersByteSize)997 	COM_METHOD(HRESULT) GetEffectParameters(
998 		UINT32 EffectIndex,
999 		void *pParameters,
1000 		UINT32 ParametersByteSize
1001 	) {
1002 		return FAudioVoice_GetEffectParameters(
1003 			faudio_voice,
1004 			EffectIndex,
1005 			pParameters,
1006 			ParametersByteSize);
1007 	}
1008 
SetFilterParameters(const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)1009 	COM_METHOD(HRESULT) SetFilterParameters(
1010 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
1011 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
1012 	) {
1013 		return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
1014 	}
1015 
GetFilterParameters(XAUDIO2_FILTER_PARAMETERS * pParameters)1016 	COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
1017 	{
1018 		FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
1019 	}
1020 
1021 #if XAUDIO2_VERSION >= 4
SetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,const XAUDIO2_FILTER_PARAMETERS * pParameters,UINT32 OperationSet=FAUDIO_COMMIT_NOW)1022 	COM_METHOD(HRESULT) SetOutputFilterParameters(
1023 		IXAudio2Voice *pDestinationVoice,
1024 		const XAUDIO2_FILTER_PARAMETERS *pParameters,
1025 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
1026 	) {
1027 		return FAudioVoice_SetOutputFilterParameters(
1028 			faudio_voice,
1029 			((XAudio2MasteringVoiceImpl *)pDestinationVoice)->faudio_voice,
1030 			pParameters,
1031 			OperationSet);
1032 	}
1033 
GetOutputFilterParameters(IXAudio2Voice * pDestinationVoice,XAUDIO2_FILTER_PARAMETERS * pParameters)1034 	COM_METHOD(void) GetOutputFilterParameters(
1035 		IXAudio2Voice *pDestinationVoice,
1036 		XAUDIO2_FILTER_PARAMETERS *pParameters
1037 	) {
1038 		FAudioVoice_GetOutputFilterParameters(
1039 			faudio_voice,
1040 			((XAudio2MasteringVoiceImpl *)pDestinationVoice)->faudio_voice,
1041 			pParameters);
1042 	}
1043 #endif // XAUDIO2_VERSION >= 4
1044 
SetVolume(float Volume,UINT32 OperationSet=FAUDIO_COMMIT_NOW)1045 	COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
1046 	{
1047 		return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
1048 	}
1049 
GetVolume(float * pVolume)1050 	COM_METHOD(void) GetVolume(float *pVolume)
1051 	{
1052 		FAudioVoice_GetVolume(faudio_voice, pVolume);
1053 	}
1054 
SetChannelVolumes(UINT32 Channels,const float * pVolumes,UINT32 OperationSet=FAUDIO_COMMIT_NOW)1055 	COM_METHOD(HRESULT) SetChannelVolumes(
1056 		UINT32 Channels,
1057 		const float *pVolumes,
1058 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
1059 	) {
1060 		return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
1061 	}
1062 
GetChannelVolumes(UINT32 Channels,float * pVolumes)1063 	COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
1064 	{
1065 		FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
1066 	}
1067 
SetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,const float * pLevelMatrix,UINT32 OperationSet=FAUDIO_COMMIT_NOW)1068 	COM_METHOD(HRESULT) SetOutputMatrix(
1069 		IXAudio2Voice *pDestinationVoice,
1070 		UINT32 SourceChannels,
1071 		UINT32 DestinationChannels,
1072 		const float *pLevelMatrix,
1073 		UINT32 OperationSet = FAUDIO_COMMIT_NOW
1074 	) {
1075 		FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
1076 		return FAudioVoice_SetOutputMatrix(
1077 			faudio_voice,
1078 			dest,
1079 			SourceChannels,
1080 			DestinationChannels,
1081 			pLevelMatrix,
1082 			OperationSet);
1083 	}
1084 
1085 #if XAUDIO2_VERSION >= 1
GetOutputMatrix(IXAudio2Voice * pDestinationVoice,UINT32 SourceChannels,UINT32 DestinationChannels,float * pLevelMatrix)1086 	COM_METHOD(void) GetOutputMatrix(
1087 #else
1088 	COM_METHOD(HRESULT) GetOutputMatrix(
1089 #endif
1090 		IXAudio2Voice *pDestinationVoice,
1091 		UINT32 SourceChannels,
1092 		UINT32 DestinationChannels,
1093 		float *pLevelMatrix
1094 	) {
1095 		FAudioVoice_GetOutputMatrix(
1096 			faudio_voice,
1097 			pDestinationVoice->faudio_voice,
1098 			SourceChannels,
1099 			DestinationChannels,
1100 			pLevelMatrix);
1101 #if XAUDIO2_VERSION < 1
1102 		return S_OK;
1103 #endif // XAUDIO2_VERSION < 1
1104 	}
1105 
DestroyVoice()1106 	COM_METHOD(void) DestroyVoice()
1107 	{
1108 		FAudioVoice_DestroyVoice(faudio_voice);
1109 		// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
1110 		free_voice_sends(voice_sends);
1111 		free_effect_chain(effect_chain);
1112 		delete this;
1113 	}
1114 
1115 	// IXAudio2MasteringVoice
1116 #if XAUDIO2_VERSION >= 8
GetChannelMask(uint32_t * pChannelmask)1117 	COM_METHOD(HRESULT) GetChannelMask(uint32_t *pChannelmask)
1118 	{
1119 		return FAudioMasteringVoice_GetChannelMask(faudio_voice, pChannelmask);
1120 	}
1121 #endif
1122 
1123 private:
1124 	FAudioVoiceSends *voice_sends;
1125 	FAudioEffectChain *effect_chain;
1126 };
1127 
1128 ///////////////////////////////////////////////////////////////////////////////
1129 //
1130 // IXAudio2 implementation
1131 //
1132 
XAudio2_INTERNAL_Malloc(size_t size)1133 void* CDECL XAudio2_INTERNAL_Malloc(size_t size)
1134 {
1135 	return CoTaskMemAlloc(size);
1136 }
XAudio2_INTERNAL_Free(void * ptr)1137 void CDECL XAudio2_INTERNAL_Free(void* ptr)
1138 {
1139 	CoTaskMemFree(ptr);
1140 }
XAudio2_INTERNAL_Realloc(void * ptr,size_t size)1141 void* CDECL XAudio2_INTERNAL_Realloc(void* ptr, size_t size)
1142 {
1143 	return CoTaskMemRealloc(ptr, size);
1144 }
1145 
1146 class XAudio2Impl : public IXAudio2
1147 {
1148 public:
XAudio2Impl()1149 	XAudio2Impl()
1150 	{
1151 		callback_list.com = NULL;
1152 		callback_list.next = NULL;
1153 		FAudioCOMConstructWithCustomAllocatorEXT(
1154 			&faudio,
1155 			XAUDIO2_VERSION,
1156 			XAudio2_INTERNAL_Malloc,
1157 			XAudio2_INTERNAL_Free,
1158 			XAudio2_INTERNAL_Realloc
1159 		);
1160 	}
1161 
XAudio2Impl(UINT32 Flags,XAUDIO2_PROCESSOR XAudio2Processor)1162 	XAudio2Impl(UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor)
1163 	{
1164 		callback_list.com = NULL;
1165 		callback_list.next = NULL;
1166 		FAudioCreateWithCustomAllocatorEXT(
1167 			&faudio,
1168 			Flags,
1169 			XAudio2Processor,
1170 			XAudio2_INTERNAL_Malloc,
1171 			XAudio2_INTERNAL_Free,
1172 			XAudio2_INTERNAL_Realloc
1173 		);
1174 	}
1175 
QueryInterface(REFIID riid,void ** ppvInterface)1176 	COM_METHOD(HRESULT) QueryInterface(REFIID riid, void **ppvInterface)
1177 	{
1178 		if (guid_equals(riid, IID_IXAudio2))
1179 		{
1180 			*ppvInterface = static_cast<IXAudio2 *>(this);
1181 		}
1182 		else if (guid_equals(riid, IID_IUnknown))
1183 		{
1184 			*ppvInterface = static_cast<IUnknown *>(this);
1185 		}
1186 		else
1187 		{
1188 			*ppvInterface = NULL;
1189 			return E_NOINTERFACE;
1190 		}
1191 
1192 		reinterpret_cast<IUnknown *>(*ppvInterface)->AddRef();
1193 
1194 		return S_OK;
1195 	}
1196 
AddRef()1197 	COM_METHOD(ULONG) AddRef()
1198 	{
1199 		return FAudio_AddRef(faudio);
1200 	}
1201 
Release()1202 	COM_METHOD(ULONG) Release()
1203 	{
1204 		ULONG refcount = FAudio_Release(faudio);
1205 		if (refcount == 0)
1206 		{
1207 			delete this;
1208 		}
1209 		return 1;
1210 	}
1211 
1212 #if (XAUDIO2_VERSION <= 7)
GetDeviceCount(UINT32 * pCount)1213 	COM_METHOD(HRESULT) GetDeviceCount(UINT32 *pCount)
1214 	{
1215 		return FAudio_GetDeviceCount(faudio, pCount);
1216 	}
1217 
GetDeviceDetails(UINT32 Index,XAUDIO2_DEVICE_DETAILS * pDeviceDetails)1218 	COM_METHOD(HRESULT) GetDeviceDetails(UINT32 Index, XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
1219 	{
1220 		return FAudio_GetDeviceDetails(faudio, Index, pDeviceDetails);
1221 	}
1222 
Initialize(UINT32 Flags=0,XAUDIO2_PROCESSOR XAudio2Processor=FAUDIO_DEFAULT_PROCESSOR)1223 	COM_METHOD(HRESULT) Initialize(
1224 		UINT32 Flags = 0,
1225 		XAUDIO2_PROCESSOR XAudio2Processor = FAUDIO_DEFAULT_PROCESSOR
1226 	) {
1227 		return FAudio_Initialize(faudio, Flags, XAudio2Processor);
1228 	}
1229 #endif // XAUDIO2_VERSION <= 7
1230 
RegisterForCallbacks(IXAudio2EngineCallback * pCallback)1231 	COM_METHOD(HRESULT) RegisterForCallbacks(IXAudio2EngineCallback *pCallback)
1232 	{
1233 		FAudioCppEngineCallback *cb = wrap_engine_callback(pCallback);
1234 		cb->next = callback_list.next;
1235 		callback_list.next = cb;
1236 
1237 		return FAudio_RegisterForCallbacks(faudio, reinterpret_cast<FAudioEngineCallback *>(cb));
1238 	}
1239 
UnregisterForCallbacks(IXAudio2EngineCallback * pCallback)1240 	COM_METHOD(void) UnregisterForCallbacks(IXAudio2EngineCallback *pCallback)
1241 	{
1242 		FAudioCppEngineCallback *cb = find_and_remove_engine_callback(&callback_list, pCallback);
1243 
1244 		if (cb == NULL)
1245 		{
1246 			return;
1247 		}
1248 
1249 		FAudio_UnregisterForCallbacks(faudio, reinterpret_cast<FAudioEngineCallback *>(cb));
1250 		delete cb;
1251 	}
1252 
CreateSourceVoice(IXAudio2SourceVoice ** ppSourceVoice,const WAVEFORMATEX * pSourceFormat,UINT32 Flags=0,float MaxFrequencyRatio=FAUDIO_DEFAULT_FREQ_RATIO,IXAudio2VoiceCallback * pCallback=NULL,const XAUDIO2_VOICE_SENDS * pSendList=NULL,const XAUDIO2_EFFECT_CHAIN * pEffectChain=NULL)1253 	COM_METHOD(HRESULT) CreateSourceVoice(
1254 		IXAudio2SourceVoice **ppSourceVoice,
1255 		const WAVEFORMATEX *pSourceFormat,
1256 		UINT32 Flags = 0,
1257 		float MaxFrequencyRatio = FAUDIO_DEFAULT_FREQ_RATIO,
1258 		IXAudio2VoiceCallback *pCallback = NULL,
1259 		const XAUDIO2_VOICE_SENDS *pSendList = NULL,
1260 		const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL
1261 	) {
1262 		*ppSourceVoice = new XAudio2SourceVoiceImpl(
1263 			faudio, pSourceFormat, Flags, MaxFrequencyRatio, pCallback, pSendList, pEffectChain);
1264 		return S_OK;
1265 	}
1266 
CreateSubmixVoice(IXAudio2SubmixVoice ** ppSubmixVoice,UINT32 InputChannels,UINT32 InputSampleRate,UINT32 Flags=0,UINT32 ProcessingStage=0,const XAUDIO2_VOICE_SENDS * pSendList=NULL,const XAUDIO2_EFFECT_CHAIN * pEffectChain=NULL)1267 	COM_METHOD(HRESULT) CreateSubmixVoice(
1268 		IXAudio2SubmixVoice **ppSubmixVoice,
1269 		UINT32 InputChannels,
1270 		UINT32 InputSampleRate,
1271 		UINT32 Flags = 0,
1272 		UINT32 ProcessingStage = 0,
1273 		const XAUDIO2_VOICE_SENDS *pSendList = NULL,
1274 		const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL
1275 	) {
1276 		*ppSubmixVoice = new XAudio2SubmixVoiceImpl(
1277 			faudio,
1278 			InputChannels,
1279 			InputSampleRate,
1280 			Flags,
1281 			ProcessingStage,
1282 			pSendList,
1283 			pEffectChain);
1284 		return S_OK;
1285 	}
1286 
1287 #if (XAUDIO2_VERSION <= 7)
CreateMasteringVoice(IXAudio2MasteringVoice ** ppMasteringVoice,UINT32 InputChannels=FAUDIO_DEFAULT_CHANNELS,UINT32 InputSampleRate=FAUDIO_DEFAULT_SAMPLERATE,UINT32 Flags=0,UINT32 DeviceIndex=0,const XAUDIO2_EFFECT_CHAIN * pEffectChain=NULL)1288 	COM_METHOD(HRESULT) CreateMasteringVoice(
1289 		IXAudio2MasteringVoice **ppMasteringVoice,
1290 		UINT32 InputChannels = FAUDIO_DEFAULT_CHANNELS,
1291 		UINT32 InputSampleRate = FAUDIO_DEFAULT_SAMPLERATE,
1292 		UINT32 Flags = 0,
1293 		UINT32 DeviceIndex = 0,
1294 		const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL
1295 	) {
1296 		*ppMasteringVoice = new XAudio2MasteringVoiceImpl(
1297 			faudio, InputChannels, InputSampleRate, Flags, DeviceIndex, pEffectChain);
1298 		return S_OK;
1299 	}
1300 #else
CreateMasteringVoice(IXAudio2MasteringVoice ** ppMasteringVoice,UINT32 InputChannels=FAUDIO_DEFAULT_CHANNELS,UINT32 InputSampleRate=FAUDIO_DEFAULT_SAMPLERATE,UINT32 Flags=0,LPCWSTR szDeviceId=NULL,const XAUDIO2_EFFECT_CHAIN * pEffectChain=NULL,int StreamCategory=6)1301 	COM_METHOD(HRESULT) CreateMasteringVoice(
1302 		IXAudio2MasteringVoice **ppMasteringVoice,
1303 		UINT32 InputChannels = FAUDIO_DEFAULT_CHANNELS,
1304 		UINT32 InputSampleRate = FAUDIO_DEFAULT_SAMPLERATE,
1305 		UINT32 Flags = 0,
1306 		LPCWSTR szDeviceId = NULL,
1307 		const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL,
1308 		int StreamCategory = 6
1309 	) {
1310 		*ppMasteringVoice = new XAudio2MasteringVoiceImpl(
1311 			faudio,
1312 			InputChannels,
1313 			InputSampleRate,
1314 			Flags,
1315 			szDeviceId,
1316 			pEffectChain,
1317 			StreamCategory);
1318 		return S_OK;
1319 	}
1320 #endif
1321 
StartEngine()1322 	COM_METHOD(HRESULT) StartEngine()
1323 	{
1324 		return FAudio_StartEngine(faudio);
1325 	}
1326 
StopEngine()1327 	COM_METHOD(void) StopEngine()
1328 	{
1329 		FAudio_StopEngine(faudio);
1330 	}
1331 
CommitChanges(UINT32 OperationSet)1332 	COM_METHOD(HRESULT) CommitChanges(UINT32 OperationSet)
1333 	{
1334 		return FAudio_CommitOperationSet(faudio, OperationSet);
1335 	}
1336 
GetPerformanceData(XAUDIO2_PERFORMANCE_DATA * pPerfData)1337 	COM_METHOD(void) GetPerformanceData(XAUDIO2_PERFORMANCE_DATA *pPerfData)
1338 	{
1339 #if XAUDIO2_VERSION >= 3
1340 		FAudio_GetPerformanceData(faudio, pPerfData);
1341 #else
1342 		FAudioPerformanceData fPerfData;
1343 		FAudio_GetPerformanceData(faudio, &fPerfData);
1344 
1345 		pPerfData->AudioCyclesSinceLastQuery = fPerfData.AudioCyclesSinceLastQuery;
1346 		pPerfData->TotalCyclesSinceLastQuery = fPerfData.TotalCyclesSinceLastQuery;
1347 		pPerfData->MinimumCyclesPerQuantum = fPerfData.MinimumCyclesPerQuantum;
1348 		pPerfData->MaximumCyclesPerQuantum = fPerfData.MaximumCyclesPerQuantum;
1349 		pPerfData->MemoryUsageInBytes = fPerfData.MemoryUsageInBytes;
1350 		pPerfData->CurrentLatencyInSamples = fPerfData.CurrentLatencyInSamples;
1351 		pPerfData->GlitchesSinceEngineStarted = fPerfData.GlitchesSinceEngineStarted;
1352 		pPerfData->ActiveSourceVoiceCount = fPerfData.ActiveSourceVoiceCount;
1353 		pPerfData->TotalSourceVoiceCount = fPerfData.TotalSourceVoiceCount;
1354 		pPerfData->ActiveSubmixVoiceCount = fPerfData.ActiveSubmixVoiceCount;
1355 		pPerfData->TotalSubmixVoiceCount = fPerfData.ActiveSubmixVoiceCount;
1356 		pPerfData->ActiveXmaSourceVoices = fPerfData.ActiveXmaSourceVoices;
1357 		pPerfData->ActiveXmaStreams = fPerfData.ActiveXmaStreams;
1358 #endif // XAUDIO2_VERSION >= 3
1359 	}
1360 
1361 	COM_METHOD(void)
SetDebugConfiguration(XAUDIO2_DEBUG_CONFIGURATION * pDebugConfiguration,void * pReserved=NULL)1362 	SetDebugConfiguration(
1363 		XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
1364 		void *pReserved = NULL
1365 	) {
1366 		FAudio_SetDebugConfiguration(
1367 			faudio,
1368 			pDebugConfiguration,
1369 			pReserved);
1370 	}
1371 
1372 private:
1373 	FAudio *faudio;
1374 	FAudioCppEngineCallback callback_list;
1375 };
1376 
1377 ///////////////////////////////////////////////////////////////////////////////
1378 //
1379 // Create function
1380 //
1381 
CreateXAudio2Internal()1382 void *CreateXAudio2Internal()
1383 {
1384 	return new XAudio2Impl();
1385 }
1386 
1387 #if XAUDIO2_VERSION >= 8
1388 
XAudio2Create(IXAudio2 ** ppXAudio2,UINT32 Flags,XAUDIO2_PROCESSOR XAudio2Processor)1389 extern "C" FAUDIOCPP_API XAudio2Create(IXAudio2 **ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor)
1390 {
1391 	// FAudio only accepts one processor
1392 	*ppXAudio2 = new XAudio2Impl(Flags, FAUDIO_DEFAULT_PROCESSOR);
1393 	return S_OK;
1394 }
1395 
1396 #endif // XAUDIO2_VERSION >= 8
1397