Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/cpp/xaudio2.cpp
1396 lines | 36.3 KiB | text/x-c | CppLexer
#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