Show More
Commit Description:
Add timers for Simulation and various engines...
Commit Description:
Add timers for Simulation and various engines Starting to add additional timers for different stages of the process of updating in order to get more insight into what is slowing it down. The update takes 9ms, which is much longer than it used to. Engine-specific timers are coming later.
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/cpp/xaudio2.cpp
1396 lines | 36.3 KiB | text/x-c | CppLexer
Early working version (including all dependencies, lol).
r0 #include "xaudio2.h"
#include "XAPO.h"
#include <FAPOBase.h>
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2VoiceCallback
//
struct FAudioVoiceCppCallback
{
FAudioVoiceCallback callbacks;
IXAudio2VoiceCallback *com;
};
static void FAUDIOCALL OnBufferEnd(FAudioVoiceCallback *callback, void *pBufferContext)
{
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnBufferEnd(pBufferContext);
}
static void FAUDIOCALL OnBufferStart(FAudioVoiceCallback *callback, void *pBufferContext)
{
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnBufferStart(pBufferContext);
}
static void FAUDIOCALL OnLoopEnd(FAudioVoiceCallback *callback, void *pBufferContext)
{
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnLoopEnd(pBufferContext);
}
static void FAUDIOCALL OnStreamEnd(FAudioVoiceCallback *callback)
{
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnStreamEnd();
}
static void FAUDIOCALL OnVoiceError(
FAudioVoiceCallback *callback,
void *pBufferContext,
uint32_t Error
) {
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceError(pBufferContext, Error);
}
static void FAUDIOCALL OnVoiceProcessingPassEnd(FAudioVoiceCallback *callback)
{
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassEnd();
}
static void FAUDIOCALL OnVoiceProcessingPassStart(
FAudioVoiceCallback *callback,
uint32_t BytesRequired
) {
#if XAUDIO2_VERSION >= 1
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassStart(
BytesRequired);
#else
reinterpret_cast<FAudioVoiceCppCallback *>(callback)->com->OnVoiceProcessingPassStart();
#endif // XAUDIO2_VERSION >= 1
}
FAudioVoiceCppCallback *wrap_voice_callback(IXAudio2VoiceCallback *com_interface)
{
if (com_interface == NULL)
{
return NULL;
}
FAudioVoiceCppCallback *cb = new FAudioVoiceCppCallback();
cb->callbacks.OnBufferEnd = OnBufferEnd;
cb->callbacks.OnBufferStart = OnBufferStart;
cb->callbacks.OnLoopEnd = OnLoopEnd;
cb->callbacks.OnStreamEnd = OnStreamEnd;
cb->callbacks.OnVoiceError = OnVoiceError;
cb->callbacks.OnVoiceProcessingPassEnd = OnVoiceProcessingPassEnd;
cb->callbacks.OnVoiceProcessingPassStart = OnVoiceProcessingPassStart;
cb->com = com_interface;
return cb;
}
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2EngineCallback
//
struct FAudioCppEngineCallback
{
FAudioEngineCallback callbacks;
IXAudio2EngineCallback *com;
FAudioCppEngineCallback *next;
};
static void FAUDIOCALL OnCriticalError(FAudioEngineCallback *callback, uint32_t Error)
{
reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnCriticalError(Error);
}
static void FAUDIOCALL OnProcessingPassEnd(FAudioEngineCallback *callback)
{
reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnProcessingPassEnd();
}
static void FAUDIOCALL OnProcessingPassStart(FAudioEngineCallback *callback)
{
reinterpret_cast<FAudioCppEngineCallback *>(callback)->com->OnProcessingPassStart();
}
static FAudioCppEngineCallback *wrap_engine_callback(IXAudio2EngineCallback *com_interface)
{
if (com_interface == NULL)
{
return NULL;
}
FAudioCppEngineCallback *cb = new FAudioCppEngineCallback();
cb->callbacks.OnCriticalError = OnCriticalError;
cb->callbacks.OnProcessingPassEnd = OnProcessingPassEnd;
cb->callbacks.OnProcessingPassStart = OnProcessingPassStart;
cb->com = com_interface;
cb->next = NULL;
return cb;
}
static FAudioCppEngineCallback *find_and_remove_engine_callback(
FAudioCppEngineCallback *list,
IXAudio2EngineCallback *com
) {
FAudioCppEngineCallback *last = list;
for (FAudioCppEngineCallback *it = list->next; it != NULL; it = it->next)
{
if (it->com == com)
{
last->next = it->next;
return it;
}
last = it;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
//
// XAUDIO2_VOICE_SENDS / XAUDIO2_SEND_DESCRIPTOR => FAudio
//
static FAudioVoiceSends *unwrap_voice_sends(const XAUDIO2_VOICE_SENDS *x_sends)
{
if (x_sends == NULL)
{
return NULL;
}
FAudioVoiceSends *f_sends = new FAudioVoiceSends;
f_sends->SendCount = x_sends->SendCount;
f_sends->pSends = new FAudioSendDescriptor[f_sends->SendCount];
for (uint32_t i = 0; i < f_sends->SendCount; ++i)
{
#if XAUDIO2_VERSION >= 4
f_sends->pSends[i].Flags = x_sends->pSends[i].Flags;
f_sends->pSends[i].pOutputVoice = x_sends->pSends[i].pOutputVoice->faudio_voice;
#else
f_sends->pSends[i].Flags = 0;
f_sends->pSends[i].pOutputVoice = x_sends->pSends[i]->faudio_voice;
#endif // XAUDIO2_VERSION >= 4
}
return f_sends;
}
static void free_voice_sends(FAudioVoiceSends *f_sends)
{
if (f_sends != NULL)
{
delete[] f_sends->pSends;
delete f_sends;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// XAUDIO2_EFFECT_CHAIN / XAUDIO2_EFFECT_DESCRIPTOR => FAudio
//
struct FAPOCppBase
{
FAPO fapo;
IXAPO *xapo;
IXAPOParameters *xapo_params;
LONG refcount;
};
static int32_t FAPOCALL AddRef(void *fapo)
{
FAPOCppBase *base = reinterpret_cast<FAPOCppBase *>(fapo);
return ++base->refcount;
}
static int32_t FAPOCALL Release(void *fapo)
{
FAPOCppBase *base = reinterpret_cast<FAPOCppBase *>(fapo);
IXAPO *xapo = base->xapo;
LONG ref = --base->refcount;
if (ref == 0)
{
xapo->Release();
if (base->xapo_params != NULL)
{
base->xapo_params->Release();
}
delete base;
}
return ref;
}
static uint32_t FAPOCALL GetRegistrationProperties(
void *fapo,
FAPORegistrationProperties **ppRegistrationProperties)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->GetRegistrationProperties(ppRegistrationProperties);
}
static uint32_t FAPOCALL IsInputFormatSupported(
void *fapo,
const FAudioWaveFormatEx *pOutputFormat,
const FAudioWaveFormatEx *pRequestedInputFormat,
FAudioWaveFormatEx **ppSupportedInputFormat
) {
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->IsInputFormatSupported(
pOutputFormat,
pRequestedInputFormat,
ppSupportedInputFormat);
}
static uint32_t FAPOCALL IsOutputFormatSupported(
void *fapo,
const FAudioWaveFormatEx *pInputFormat,
const FAudioWaveFormatEx *pRequestedOutputFormat,
FAudioWaveFormatEx **ppSupportedOutputFormat
) {
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->IsOutputFormatSupported(
pInputFormat,
pRequestedOutputFormat,
ppSupportedOutputFormat);
}
static uint32_t FAPOCALL Initialize(void *fapo, const void *pData, uint32_t DataByteSize)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->Initialize(pData, DataByteSize);
}
static void FAPOCALL Reset(void *fapo)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
xapo->Reset();
}
static uint32_t FAPOCALL LockForProcess(
void *fapo,
uint32_t InputLockedParameterCount,
const FAPOLockForProcessBufferParameters *pInputLockedParameters,
uint32_t OutputLockedParameterCount,
const FAPOLockForProcessBufferParameters *pOutputLockedParameters
) {
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->LockForProcess(
InputLockedParameterCount,
pInputLockedParameters,
OutputLockedParameterCount,
pOutputLockedParameters);
}
static void FAPOCALL UnlockForProcess(void *fapo)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
xapo->UnlockForProcess();
}
static void FAPOCALL Process(
void *fapo,
uint32_t InputProcessParameterCount,
const FAPOProcessBufferParameters *pInputProcessParameters,
uint32_t OutputProcessParameterCount,
FAPOProcessBufferParameters *pOutputProcessParameters,
int32_t IsEnabled
) {
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
xapo->Process(
InputProcessParameterCount,
pInputProcessParameters,
OutputProcessParameterCount,
pOutputProcessParameters,
IsEnabled);
}
static uint32_t FAPOCALL CalcInputFrames(void *fapo, uint32_t OutputFrameCount)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->CalcInputFrames(OutputFrameCount);
}
static uint32_t FAPOCALL CalcOutputFrames(void *fapo, uint32_t InputFrameCount)
{
IXAPO *xapo = reinterpret_cast<FAPOCppBase *>(fapo)->xapo;
return xapo->CalcOutputFrames(InputFrameCount);
}
static void FAPOCALL SetParameters(
void *fapoParameters,
const void *pParameters,
uint32_t ParameterByteSize
) {
IXAPOParameters *xapo_params = reinterpret_cast<FAPOCppBase *>(fapoParameters)->xapo_params;
return xapo_params->SetParameters(pParameters, ParameterByteSize);
}
static void FAPOCALL GetParameters(void *fapoParameters, void *pParameters, uint32_t ParameterByteSize)
{
IXAPOParameters *xapo_params = reinterpret_cast<FAPOCppBase *>(fapoParameters)->xapo_params;
return xapo_params->GetParameters(pParameters, ParameterByteSize);
}
static FAPO *wrap_xapo_effect(IUnknown *xapo)
{
if (xapo == NULL)
{
return NULL;
}
// FIXME: assumes that all effects are derived from CXAPOParametersBase
FAPOCppBase *f_effect = new FAPOCppBase;
f_effect->refcount = 1;
xapo->QueryInterface(IID_IXAPO, (void **)&f_effect->xapo);
xapo->QueryInterface(IID_IXAPOParameters, (void **)&f_effect->xapo_params);
f_effect->fapo.AddRef = AddRef;
f_effect->fapo.Release = Release;
f_effect->fapo.GetRegistrationProperties = GetRegistrationProperties;
f_effect->fapo.IsInputFormatSupported = IsInputFormatSupported;
f_effect->fapo.IsOutputFormatSupported = IsOutputFormatSupported;
f_effect->fapo.Initialize = Initialize;
f_effect->fapo.Reset = Reset;
f_effect->fapo.LockForProcess = LockForProcess;
f_effect->fapo.UnlockForProcess = UnlockForProcess;
f_effect->fapo.Process = Process;
f_effect->fapo.CalcInputFrames = CalcInputFrames;
f_effect->fapo.CalcOutputFrames = CalcOutputFrames;
f_effect->fapo.GetParameters = GetParameters;
f_effect->fapo.SetParameters = SetParameters;
return &f_effect->fapo;
}
static FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *x_chain)
{
if (x_chain == NULL)
{
return NULL;
}
FAudioEffectChain *f_chain = new FAudioEffectChain;
f_chain->EffectCount = x_chain->EffectCount;
f_chain->pEffectDescriptors = new FAudioEffectDescriptor[f_chain->EffectCount];
for (uint32_t i = 0; i < f_chain->EffectCount; ++i)
{
f_chain->pEffectDescriptors[i].InitialState = x_chain->pEffectDescriptors[i].InitialState;
f_chain->pEffectDescriptors[i].OutputChannels =
x_chain->pEffectDescriptors[i].OutputChannel;
f_chain->pEffectDescriptors[i].pEffect =
wrap_xapo_effect(x_chain->pEffectDescriptors[i].pEffect);
}
return f_chain;
}
static void free_effect_chain(FAudioEffectChain *f_chain)
{
if (f_chain != NULL)
{
delete[] f_chain->pEffectDescriptors;
delete f_chain;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2SourceVoice implementation
//
class XAudio2SourceVoiceImpl : public IXAudio2SourceVoice
{
public:
XAudio2SourceVoiceImpl(
FAudio *faudio,
const WAVEFORMATEX *pSourceFormat,
UINT32 Flags,
float MaxFrequencyRatio,
IXAudio2VoiceCallback *pCallback,
const XAUDIO2_VOICE_SENDS *pSendList,
const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
voice_callback = wrap_voice_callback(pCallback);
voice_sends = unwrap_voice_sends(pSendList);
effect_chain = wrap_effect_chain(pEffectChain);
FAudio_CreateSourceVoice(
faudio,
&faudio_voice,
pSourceFormat,
Flags,
MaxFrequencyRatio,
reinterpret_cast<FAudioVoiceCallback *>(voice_callback),
voice_sends,
effect_chain);
}
// IXAudio2Voice
COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
#if XAUDIO2_VERSION > 7
FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
#else
FAudioVoiceDetails fDetails;
FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
pVoiceDetails->CreationFlags = fDetails.CreationFlags;
pVoiceDetails->InputChannels = fDetails.InputChannels;
pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
#endif // XAUDIO2_VERSION <= 7
}
COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
{
free_voice_sends(voice_sends);
voice_sends = unwrap_voice_sends(pSendList);
return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
}
COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
free_effect_chain(effect_chain);
effect_chain = wrap_effect_chain(pEffectChain);
return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
}
COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
{
FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
}
COM_METHOD(HRESULT) SetEffectParameters(
UINT32 EffectIndex,
const void *pParameters,
UINT32 ParametersByteSize,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize,
OperationSet);
}
COM_METHOD(HRESULT) GetEffectParameters(
UINT32 EffectIndex,
void *pParameters,
UINT32 ParametersByteSize)
{
return FAudioVoice_GetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize);
}
COM_METHOD(HRESULT) SetFilterParameters(
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
}
COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
{
FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
}
#if XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetOutputFilterParameters(
faudio_voice,
((XAudio2SourceVoiceImpl *)pDestinationVoice)->faudio_voice,
pParameters,
OperationSet);
}
COM_METHOD(void) GetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters
) {
FAudioVoice_GetOutputFilterParameters(
faudio_voice,
((XAudio2SourceVoiceImpl *)pDestinationVoice)->faudio_voice,
pParameters);
}
#endif // XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
}
COM_METHOD(void) GetVolume(float *pVolume)
{
FAudioVoice_GetVolume(faudio_voice, pVolume);
}
COM_METHOD(HRESULT) SetChannelVolumes(
UINT32 Channels,
const float *pVolumes,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
}
COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
{
FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
}
COM_METHOD(HRESULT) SetOutputMatrix(
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
const float *pLevelMatrix,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
return FAudioVoice_SetOutputMatrix(
faudio_voice, dest, SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
}
#if XAUDIO2_VERSION >= 1
COM_METHOD(void) GetOutputMatrix(
#else
COM_METHOD(HRESULT) GetOutputMatrix(
#endif
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
float *pLevelMatrix
) {
FAudioVoice_GetOutputMatrix(
faudio_voice,
pDestinationVoice->faudio_voice,
SourceChannels,
DestinationChannels,
pLevelMatrix);
#if XAUDIO2_VERSION < 1
return S_OK;
#endif // XAUDIO2_VERSION < 1
}
COM_METHOD(void) DestroyVoice()
{
FAudioVoice_DestroyVoice(faudio_voice);
// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
if (voice_callback)
{
delete voice_callback;
}
free_voice_sends(voice_sends);
free_effect_chain(effect_chain);
delete this;
}
// IXAudio2SourceVoice
COM_METHOD(HRESULT) Start(UINT32 Flags = 0, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioSourceVoice_Start(faudio_voice, Flags, OperationSet);
}
COM_METHOD(HRESULT) Stop(UINT32 Flags = 0, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioSourceVoice_Stop(faudio_voice, Flags, OperationSet);
}
COM_METHOD(HRESULT) SubmitSourceBuffer(
const XAUDIO2_BUFFER *pBuffer,
const XAUDIO2_BUFFER_WMA *pBufferWMA = NULL)
{
return FAudioSourceVoice_SubmitSourceBuffer(faudio_voice, pBuffer, pBufferWMA);
}
COM_METHOD(HRESULT) FlushSourceBuffers()
{
return FAudioSourceVoice_FlushSourceBuffers(faudio_voice);
}
COM_METHOD(HRESULT) Discontinuity()
{
return FAudioSourceVoice_Discontinuity(faudio_voice);
}
COM_METHOD(HRESULT) ExitLoop(UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioSourceVoice_ExitLoop(faudio_voice, OperationSet);
}
#if (XAUDIO2_VERSION <= 7)
COM_METHOD(void) GetState(XAUDIO2_VOICE_STATE *pVoiceState)
#else
COM_METHOD(void) GetState(XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags = 0)
#endif
{
#if (XAUDIO2_VERSION <= 7)
FAudioSourceVoice_GetState(faudio_voice, pVoiceState, 0);
#else
FAudioSourceVoice_GetState(faudio_voice, pVoiceState, Flags);
#endif
}
COM_METHOD(HRESULT) SetFrequencyRatio(float Ratio, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioSourceVoice_SetFrequencyRatio(faudio_voice, Ratio, OperationSet);
}
COM_METHOD(void) GetFrequencyRatio(float *pRatio)
{
FAudioSourceVoice_GetFrequencyRatio(faudio_voice, pRatio);
}
#if XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetSourceSampleRate(UINT32 NewSourceSampleRate)
{
return FAudioSourceVoice_SetSourceSampleRate(faudio_voice, NewSourceSampleRate);
}
#endif // XAUDIO2_VERSION >= 4
private:
FAudioVoiceCppCallback *voice_callback;
FAudioVoiceSends *voice_sends;
FAudioEffectChain *effect_chain;
};
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2SubmixVoice implementation
//
class XAudio2SubmixVoiceImpl : public IXAudio2SubmixVoice
{
public:
XAudio2SubmixVoiceImpl(
FAudio *faudio,
UINT32 InputChannels,
UINT32 InputSampleRate,
UINT32 Flags,
UINT32 ProcessingStage,
const XAUDIO2_VOICE_SENDS *pSendList,
const XAUDIO2_EFFECT_CHAIN *pEffectChain
) {
voice_sends = unwrap_voice_sends(pSendList);
effect_chain = wrap_effect_chain(pEffectChain);
FAudio_CreateSubmixVoice(
faudio,
&faudio_voice,
InputChannels,
InputSampleRate,
Flags,
ProcessingStage,
voice_sends,
effect_chain);
}
// IXAudio2Voice
COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
#if XAUDIO2_VERSION > 7
FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
#else
FAudioVoiceDetails fDetails;
FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
pVoiceDetails->CreationFlags = fDetails.CreationFlags;
pVoiceDetails->InputChannels = fDetails.InputChannels;
pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
#endif // XAUDIO2_VERSION <= 7
}
COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
{
free_voice_sends(voice_sends);
voice_sends = unwrap_voice_sends(pSendList);
return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
}
COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
free_effect_chain(effect_chain);
effect_chain = wrap_effect_chain(pEffectChain);
return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
}
COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
{
FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
}
COM_METHOD(HRESULT) SetEffectParameters(
UINT32 EffectIndex,
const void *pParameters,
UINT32 ParametersByteSize,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize,
OperationSet);
}
COM_METHOD(HRESULT) GetEffectParameters(
UINT32 EffectIndex,
void *pParameters,
UINT32 ParametersByteSize
) {
return FAudioVoice_GetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize);
}
COM_METHOD(HRESULT) SetFilterParameters(
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
}
COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
{
FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
}
#if XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetOutputFilterParameters(
faudio_voice,
((XAudio2SubmixVoiceImpl *)pDestinationVoice)->faudio_voice,
pParameters,
OperationSet);
}
COM_METHOD(void) GetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters
) {
FAudioVoice_GetOutputFilterParameters(
faudio_voice, ((XAudio2SubmixVoiceImpl *)pDestinationVoice)->faudio_voice, pParameters);
}
#endif // XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
}
COM_METHOD(void) GetVolume(float *pVolume)
{
FAudioVoice_GetVolume(faudio_voice, pVolume);
}
COM_METHOD(HRESULT) SetChannelVolumes(
UINT32 Channels,
const float *pVolumes,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
}
COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
{
FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
}
COM_METHOD(HRESULT) SetOutputMatrix(
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
const float *pLevelMatrix,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
return FAudioVoice_SetOutputMatrix(
faudio_voice,
dest,
SourceChannels,
DestinationChannels,
pLevelMatrix,
OperationSet);
}
#if XAUDIO2_VERSION >= 1
COM_METHOD(void) GetOutputMatrix(
#else
COM_METHOD(HRESULT) GetOutputMatrix(
#endif
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
float *pLevelMatrix
) {
FAudioVoice_GetOutputMatrix(
faudio_voice,
pDestinationVoice->faudio_voice,
SourceChannels,
DestinationChannels,
pLevelMatrix);
#if XAUDIO2_VERSION < 1
return S_OK;
#endif // XAUDIO2_VERSION < 1
}
COM_METHOD(void) DestroyVoice()
{
FAudioVoice_DestroyVoice(faudio_voice);
// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
free_voice_sends(voice_sends);
free_effect_chain(effect_chain);
delete this;
}
private:
FAudioVoiceSends *voice_sends;
FAudioEffectChain *effect_chain;
};
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2MasteringVoice implementation
//
#if (XAUDIO2_VERSION >= 8)
uint32_t device_index_from_device_id(FAudio *faudio, LPCWSTR deviceId);
#endif // (XAUDIO2_VERSION >= 8)
class XAudio2MasteringVoiceImpl : public IXAudio2MasteringVoice
{
public:
#if (XAUDIO2_VERSION <= 7)
XAudio2MasteringVoiceImpl(
FAudio *faudio,
UINT32 InputChannels,
UINT32 InputSampleRate,
UINT32 Flags,
UINT32 DeviceIndex,
const XAUDIO2_EFFECT_CHAIN *pEffectChain
) {
voice_sends = NULL;
effect_chain = wrap_effect_chain(pEffectChain);
FAudio_CreateMasteringVoice(
faudio,
&faudio_voice,
InputChannels,
InputSampleRate,
Flags,
DeviceIndex,
effect_chain);
}
#else
XAudio2MasteringVoiceImpl(
FAudio *faudio,
UINT32 InputChannels,
UINT32 InputSampleRate,
UINT32 Flags,
LPCWSTR szDeviceId,
const XAUDIO2_EFFECT_CHAIN *pEffectChain,
int StreamCategory
) {
uint32_t device_index = 0;
if (szDeviceId != NULL)
{
device_index = device_index_from_device_id(faudio, szDeviceId);
}
voice_sends = NULL;
effect_chain = wrap_effect_chain(pEffectChain);
FAudio_CreateMasteringVoice(
faudio,
&faudio_voice,
InputChannels,
InputSampleRate,
Flags,
device_index,
effect_chain);
}
#endif
// IXAudio2Voice
COM_METHOD(void) GetVoiceDetails(XAUDIO2_VOICE_DETAILS *pVoiceDetails)
{
#if XAUDIO2_VERSION > 7
FAudioVoice_GetVoiceDetails(faudio_voice, (FAudioVoiceDetails*) pVoiceDetails);
#else
FAudioVoiceDetails fDetails;
FAudioVoice_GetVoiceDetails(faudio_voice, &fDetails);
pVoiceDetails->CreationFlags = fDetails.CreationFlags;
pVoiceDetails->InputChannels = fDetails.InputChannels;
pVoiceDetails->InputSampleRate = fDetails.InputSampleRate;
#endif // XAUDIO2_VERSION <= 7
}
COM_METHOD(HRESULT) SetOutputVoices(const XAUDIO2_VOICE_SENDS *pSendList)
{
free_voice_sends(voice_sends);
voice_sends = unwrap_voice_sends(pSendList);
return FAudioVoice_SetOutputVoices(faudio_voice, voice_sends);
}
COM_METHOD(HRESULT) SetEffectChain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
{
free_effect_chain(effect_chain);
effect_chain = wrap_effect_chain(pEffectChain);
return FAudioVoice_SetEffectChain(faudio_voice, effect_chain);
}
COM_METHOD(HRESULT) EnableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_EnableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(HRESULT) DisableEffect(UINT32 EffectIndex, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_DisableEffect(faudio_voice, EffectIndex, OperationSet);
}
COM_METHOD(void) GetEffectState(UINT32 EffectIndex, BOOL *pEnabled)
{
FAudioVoice_GetEffectState(faudio_voice, EffectIndex, pEnabled);
}
COM_METHOD(HRESULT) SetEffectParameters(
UINT32 EffectIndex,
const void *pParameters,
UINT32 ParametersByteSize,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize,
OperationSet);
}
COM_METHOD(HRESULT) GetEffectParameters(
UINT32 EffectIndex,
void *pParameters,
UINT32 ParametersByteSize
) {
return FAudioVoice_GetEffectParameters(
faudio_voice,
EffectIndex,
pParameters,
ParametersByteSize);
}
COM_METHOD(HRESULT) SetFilterParameters(
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetFilterParameters(faudio_voice, pParameters, OperationSet);
}
COM_METHOD(void) GetFilterParameters(XAUDIO2_FILTER_PARAMETERS *pParameters)
{
FAudioVoice_GetFilterParameters(faudio_voice, pParameters);
}
#if XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
const XAUDIO2_FILTER_PARAMETERS *pParameters,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetOutputFilterParameters(
faudio_voice,
((XAudio2MasteringVoiceImpl *)pDestinationVoice)->faudio_voice,
pParameters,
OperationSet);
}
COM_METHOD(void) GetOutputFilterParameters(
IXAudio2Voice *pDestinationVoice,
XAUDIO2_FILTER_PARAMETERS *pParameters
) {
FAudioVoice_GetOutputFilterParameters(
faudio_voice,
((XAudio2MasteringVoiceImpl *)pDestinationVoice)->faudio_voice,
pParameters);
}
#endif // XAUDIO2_VERSION >= 4
COM_METHOD(HRESULT) SetVolume(float Volume, UINT32 OperationSet = FAUDIO_COMMIT_NOW)
{
return FAudioVoice_SetVolume(faudio_voice, Volume, OperationSet);
}
COM_METHOD(void) GetVolume(float *pVolume)
{
FAudioVoice_GetVolume(faudio_voice, pVolume);
}
COM_METHOD(HRESULT) SetChannelVolumes(
UINT32 Channels,
const float *pVolumes,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
return FAudioVoice_SetChannelVolumes(faudio_voice, Channels, pVolumes, OperationSet);
}
COM_METHOD(void) GetChannelVolumes(UINT32 Channels, float *pVolumes)
{
FAudioVoice_GetChannelVolumes(faudio_voice, Channels, pVolumes);
}
COM_METHOD(HRESULT) SetOutputMatrix(
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
const float *pLevelMatrix,
UINT32 OperationSet = FAUDIO_COMMIT_NOW
) {
FAudioVoice *dest = (pDestinationVoice) ? pDestinationVoice->faudio_voice : NULL;
return FAudioVoice_SetOutputMatrix(
faudio_voice,
dest,
SourceChannels,
DestinationChannels,
pLevelMatrix,
OperationSet);
}
#if XAUDIO2_VERSION >= 1
COM_METHOD(void) GetOutputMatrix(
#else
COM_METHOD(HRESULT) GetOutputMatrix(
#endif
IXAudio2Voice *pDestinationVoice,
UINT32 SourceChannels,
UINT32 DestinationChannels,
float *pLevelMatrix
) {
FAudioVoice_GetOutputMatrix(
faudio_voice,
pDestinationVoice->faudio_voice,
SourceChannels,
DestinationChannels,
pLevelMatrix);
#if XAUDIO2_VERSION < 1
return S_OK;
#endif // XAUDIO2_VERSION < 1
}
COM_METHOD(void) DestroyVoice()
{
FAudioVoice_DestroyVoice(faudio_voice);
// FIXME: in theory FAudioVoice_DestroyVoice can fail but how would we ever now ? -JS
free_voice_sends(voice_sends);
free_effect_chain(effect_chain);
delete this;
}
// IXAudio2MasteringVoice
#if XAUDIO2_VERSION >= 8
COM_METHOD(HRESULT) GetChannelMask(uint32_t *pChannelmask)
{
return FAudioMasteringVoice_GetChannelMask(faudio_voice, pChannelmask);
}
#endif
private:
FAudioVoiceSends *voice_sends;
FAudioEffectChain *effect_chain;
};
///////////////////////////////////////////////////////////////////////////////
//
// IXAudio2 implementation
//
void* CDECL XAudio2_INTERNAL_Malloc(size_t size)
{
return CoTaskMemAlloc(size);
}
void CDECL XAudio2_INTERNAL_Free(void* ptr)
{
CoTaskMemFree(ptr);
}
void* CDECL XAudio2_INTERNAL_Realloc(void* ptr, size_t size)
{
return CoTaskMemRealloc(ptr, size);
}
class XAudio2Impl : public IXAudio2
{
public:
XAudio2Impl()
{
callback_list.com = NULL;
callback_list.next = NULL;
FAudioCOMConstructWithCustomAllocatorEXT(
&faudio,
XAUDIO2_VERSION,
XAudio2_INTERNAL_Malloc,
XAudio2_INTERNAL_Free,
XAudio2_INTERNAL_Realloc
);
}
XAudio2Impl(UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor)
{
callback_list.com = NULL;
callback_list.next = NULL;
FAudioCreateWithCustomAllocatorEXT(
&faudio,
Flags,
XAudio2Processor,
XAudio2_INTERNAL_Malloc,
XAudio2_INTERNAL_Free,
XAudio2_INTERNAL_Realloc
);
}
COM_METHOD(HRESULT) QueryInterface(REFIID riid, void **ppvInterface)
{
if (guid_equals(riid, IID_IXAudio2))
{
*ppvInterface = static_cast<IXAudio2 *>(this);
}
else if (guid_equals(riid, IID_IUnknown))
{
*ppvInterface = static_cast<IUnknown *>(this);
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown *>(*ppvInterface)->AddRef();
return S_OK;
}
COM_METHOD(ULONG) AddRef()
{
return FAudio_AddRef(faudio);
}
COM_METHOD(ULONG) Release()
{
ULONG refcount = FAudio_Release(faudio);
if (refcount == 0)
{
delete this;
}
return 1;
}
#if (XAUDIO2_VERSION <= 7)
COM_METHOD(HRESULT) GetDeviceCount(UINT32 *pCount)
{
return FAudio_GetDeviceCount(faudio, pCount);
}
COM_METHOD(HRESULT) GetDeviceDetails(UINT32 Index, XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
{
return FAudio_GetDeviceDetails(faudio, Index, pDeviceDetails);
}
COM_METHOD(HRESULT) Initialize(
UINT32 Flags = 0,
XAUDIO2_PROCESSOR XAudio2Processor = FAUDIO_DEFAULT_PROCESSOR
) {
return FAudio_Initialize(faudio, Flags, XAudio2Processor);
}
#endif // XAUDIO2_VERSION <= 7
COM_METHOD(HRESULT) RegisterForCallbacks(IXAudio2EngineCallback *pCallback)
{
FAudioCppEngineCallback *cb = wrap_engine_callback(pCallback);
cb->next = callback_list.next;
callback_list.next = cb;
return FAudio_RegisterForCallbacks(faudio, reinterpret_cast<FAudioEngineCallback *>(cb));
}
COM_METHOD(void) UnregisterForCallbacks(IXAudio2EngineCallback *pCallback)
{
FAudioCppEngineCallback *cb = find_and_remove_engine_callback(&callback_list, pCallback);
if (cb == NULL)
{
return;
}
FAudio_UnregisterForCallbacks(faudio, reinterpret_cast<FAudioEngineCallback *>(cb));
delete cb;
}
COM_METHOD(HRESULT) 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
) {
*ppSourceVoice = new XAudio2SourceVoiceImpl(
faudio, pSourceFormat, Flags, MaxFrequencyRatio, pCallback, pSendList, pEffectChain);
return S_OK;
}
COM_METHOD(HRESULT) 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
) {
*ppSubmixVoice = new XAudio2SubmixVoiceImpl(
faudio,
InputChannels,
InputSampleRate,
Flags,
ProcessingStage,
pSendList,
pEffectChain);
return S_OK;
}
#if (XAUDIO2_VERSION <= 7)
COM_METHOD(HRESULT) 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
) {
*ppMasteringVoice = new XAudio2MasteringVoiceImpl(
faudio, InputChannels, InputSampleRate, Flags, DeviceIndex, pEffectChain);
return S_OK;
}
#else
COM_METHOD(HRESULT) 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
) {
*ppMasteringVoice = new XAudio2MasteringVoiceImpl(
faudio,
InputChannels,
InputSampleRate,
Flags,
szDeviceId,
pEffectChain,
StreamCategory);
return S_OK;
}
#endif
COM_METHOD(HRESULT) StartEngine()
{
return FAudio_StartEngine(faudio);
}
COM_METHOD(void) StopEngine()
{
FAudio_StopEngine(faudio);
}
COM_METHOD(HRESULT) CommitChanges(UINT32 OperationSet)
{
return FAudio_CommitOperationSet(faudio, OperationSet);
}
COM_METHOD(void) GetPerformanceData(XAUDIO2_PERFORMANCE_DATA *pPerfData)
{
#if XAUDIO2_VERSION >= 3
FAudio_GetPerformanceData(faudio, pPerfData);
#else
FAudioPerformanceData fPerfData;
FAudio_GetPerformanceData(faudio, &fPerfData);
pPerfData->AudioCyclesSinceLastQuery = fPerfData.AudioCyclesSinceLastQuery;
pPerfData->TotalCyclesSinceLastQuery = fPerfData.TotalCyclesSinceLastQuery;
pPerfData->MinimumCyclesPerQuantum = fPerfData.MinimumCyclesPerQuantum;
pPerfData->MaximumCyclesPerQuantum = fPerfData.MaximumCyclesPerQuantum;
pPerfData->MemoryUsageInBytes = fPerfData.MemoryUsageInBytes;
pPerfData->CurrentLatencyInSamples = fPerfData.CurrentLatencyInSamples;
pPerfData->GlitchesSinceEngineStarted = fPerfData.GlitchesSinceEngineStarted;
pPerfData->ActiveSourceVoiceCount = fPerfData.ActiveSourceVoiceCount;
pPerfData->TotalSourceVoiceCount = fPerfData.TotalSourceVoiceCount;
pPerfData->ActiveSubmixVoiceCount = fPerfData.ActiveSubmixVoiceCount;
pPerfData->TotalSubmixVoiceCount = fPerfData.ActiveSubmixVoiceCount;
pPerfData->ActiveXmaSourceVoices = fPerfData.ActiveXmaSourceVoices;
pPerfData->ActiveXmaStreams = fPerfData.ActiveXmaStreams;
#endif // XAUDIO2_VERSION >= 3
}
COM_METHOD(void)
SetDebugConfiguration(
XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
void *pReserved = NULL
) {
FAudio_SetDebugConfiguration(
faudio,
pDebugConfiguration,
pReserved);
}
private:
FAudio *faudio;
FAudioCppEngineCallback callback_list;
};
///////////////////////////////////////////////////////////////////////////////
//
// Create function
//
void *CreateXAudio2Internal()
{
return new XAudio2Impl();
}
#if XAUDIO2_VERSION >= 8
extern "C" FAUDIOCPP_API XAudio2Create(IXAudio2 **ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor)
{
// FAudio only accepts one processor
*ppXAudio2 = new XAudio2Impl(Flags, FAUDIO_DEFAULT_PROCESSOR);
return S_OK;
}
#endif // XAUDIO2_VERSION >= 8