452 lines
13 KiB
C
452 lines
13 KiB
C
/* FAudio - XAudio Reimplementation for FNA
|
|
*
|
|
* Copyright (c) 2011-2021 Ethan Lee, Luigi Auriemma, and the MonoGame Team
|
|
*
|
|
* This software is provided 'as-is', without any express or implied warranty.
|
|
* In no event will the authors be held liable for any damages arising from
|
|
* the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software in a
|
|
* product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
* Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
|
|
*
|
|
*/
|
|
|
|
#include "FAPOBase.h"
|
|
#include "FAudio_internal.h"
|
|
|
|
/* FAPOBase Interface */
|
|
|
|
void CreateFAPOBase(
|
|
FAPOBase *fapo,
|
|
const FAPORegistrationProperties *pRegistrationProperties,
|
|
uint8_t *pParameterBlocks,
|
|
uint32_t uParameterBlockByteSize,
|
|
uint8_t fProducer
|
|
) {
|
|
CreateFAPOBaseWithCustomAllocatorEXT(
|
|
fapo,
|
|
pRegistrationProperties,
|
|
pParameterBlocks,
|
|
uParameterBlockByteSize,
|
|
fProducer,
|
|
FAudio_malloc,
|
|
FAudio_free,
|
|
FAudio_realloc
|
|
);
|
|
}
|
|
|
|
void CreateFAPOBaseWithCustomAllocatorEXT(
|
|
FAPOBase *fapo,
|
|
const FAPORegistrationProperties *pRegistrationProperties,
|
|
uint8_t *pParameterBlocks,
|
|
uint32_t uParameterBlockByteSize,
|
|
uint8_t fProducer,
|
|
FAudioMallocFunc customMalloc,
|
|
FAudioFreeFunc customFree,
|
|
FAudioReallocFunc customRealloc
|
|
) {
|
|
/* Base Classes/Interfaces */
|
|
#define ASSIGN_VT(name) \
|
|
fapo->base.name = (name##Func) FAPOBase_##name;
|
|
ASSIGN_VT(AddRef)
|
|
ASSIGN_VT(Release)
|
|
ASSIGN_VT(GetRegistrationProperties)
|
|
ASSIGN_VT(IsInputFormatSupported)
|
|
ASSIGN_VT(IsOutputFormatSupported)
|
|
ASSIGN_VT(Initialize)
|
|
ASSIGN_VT(Reset)
|
|
ASSIGN_VT(LockForProcess)
|
|
ASSIGN_VT(UnlockForProcess)
|
|
ASSIGN_VT(CalcInputFrames)
|
|
ASSIGN_VT(CalcOutputFrames)
|
|
ASSIGN_VT(SetParameters)
|
|
ASSIGN_VT(GetParameters)
|
|
#undef ASSIGN_VT
|
|
|
|
/* Public Virtual Functions */
|
|
fapo->OnSetParameters = (OnSetParametersFunc)
|
|
FAPOBase_OnSetParameters;
|
|
|
|
/* Private Variables */
|
|
fapo->m_pRegistrationProperties = pRegistrationProperties; /* FIXME */
|
|
fapo->m_pfnMatrixMixFunction = NULL; /* FIXME */
|
|
fapo->m_pfl32MatrixCoefficients = NULL; /* FIXME */
|
|
fapo->m_nSrcFormatType = 0; /* FIXME */
|
|
fapo->m_fIsScalarMatrix = 0; /* FIXME: */
|
|
fapo->m_fIsLocked = 0;
|
|
fapo->m_pParameterBlocks = pParameterBlocks;
|
|
fapo->m_pCurrentParameters = pParameterBlocks;
|
|
fapo->m_pCurrentParametersInternal = pParameterBlocks;
|
|
fapo->m_uCurrentParametersIndex = 0;
|
|
fapo->m_uParameterBlockByteSize = uParameterBlockByteSize;
|
|
fapo->m_fNewerResultsReady = 0;
|
|
fapo->m_fProducer = fProducer;
|
|
|
|
/* Allocator Callbacks */
|
|
fapo->pMalloc = customMalloc;
|
|
fapo->pFree = customFree;
|
|
fapo->pRealloc = customRealloc;
|
|
|
|
/* Protected Variables */
|
|
fapo->m_lReferenceCount = 1;
|
|
}
|
|
|
|
int32_t FAPOBase_AddRef(FAPOBase *fapo)
|
|
{
|
|
fapo->m_lReferenceCount += 1;
|
|
return fapo->m_lReferenceCount;
|
|
}
|
|
|
|
int32_t FAPOBase_Release(FAPOBase *fapo)
|
|
{
|
|
fapo->m_lReferenceCount -= 1;
|
|
if (fapo->m_lReferenceCount == 0)
|
|
{
|
|
fapo->Destructor(fapo);
|
|
return 0;
|
|
}
|
|
return fapo->m_lReferenceCount;
|
|
}
|
|
|
|
uint32_t FAPOBase_GetRegistrationProperties(
|
|
FAPOBase *fapo,
|
|
FAPORegistrationProperties **ppRegistrationProperties
|
|
) {
|
|
*ppRegistrationProperties = (FAPORegistrationProperties*) fapo->pMalloc(
|
|
sizeof(FAPORegistrationProperties)
|
|
);
|
|
FAudio_memcpy(
|
|
*ppRegistrationProperties,
|
|
fapo->m_pRegistrationProperties,
|
|
sizeof(FAPORegistrationProperties)
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t FAPOBase_IsInputFormatSupported(
|
|
FAPOBase *fapo,
|
|
const FAudioWaveFormatEx *pOutputFormat,
|
|
const FAudioWaveFormatEx *pRequestedInputFormat,
|
|
FAudioWaveFormatEx **ppSupportedInputFormat
|
|
) {
|
|
if ( pRequestedInputFormat->wFormatTag != FAPOBASE_DEFAULT_FORMAT_TAG ||
|
|
pRequestedInputFormat->nChannels < FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS ||
|
|
pRequestedInputFormat->nChannels > FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS ||
|
|
pRequestedInputFormat->nSamplesPerSec < FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE ||
|
|
pRequestedInputFormat->nSamplesPerSec > FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE ||
|
|
pRequestedInputFormat->wBitsPerSample != FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE )
|
|
{
|
|
if (ppSupportedInputFormat != NULL)
|
|
{
|
|
(*ppSupportedInputFormat)->wFormatTag =
|
|
FAPOBASE_DEFAULT_FORMAT_TAG;
|
|
(*ppSupportedInputFormat)->nChannels = FAudio_clamp(
|
|
pRequestedInputFormat->nChannels,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS
|
|
);
|
|
(*ppSupportedInputFormat)->nSamplesPerSec = FAudio_clamp(
|
|
pRequestedInputFormat->nSamplesPerSec,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE
|
|
);
|
|
(*ppSupportedInputFormat)->wBitsPerSample =
|
|
FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE;
|
|
}
|
|
return FAPO_E_FORMAT_UNSUPPORTED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t FAPOBase_IsOutputFormatSupported(
|
|
FAPOBase *fapo,
|
|
const FAudioWaveFormatEx *pInputFormat,
|
|
const FAudioWaveFormatEx *pRequestedOutputFormat,
|
|
FAudioWaveFormatEx **ppSupportedOutputFormat
|
|
) {
|
|
if ( pRequestedOutputFormat->wFormatTag != FAPOBASE_DEFAULT_FORMAT_TAG ||
|
|
pRequestedOutputFormat->nChannels < FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS ||
|
|
pRequestedOutputFormat->nChannels > FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS ||
|
|
pRequestedOutputFormat->nSamplesPerSec < FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE ||
|
|
pRequestedOutputFormat->nSamplesPerSec > FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE ||
|
|
pRequestedOutputFormat->wBitsPerSample != FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE )
|
|
{
|
|
if (ppSupportedOutputFormat != NULL)
|
|
{
|
|
(*ppSupportedOutputFormat)->wFormatTag =
|
|
FAPOBASE_DEFAULT_FORMAT_TAG;
|
|
(*ppSupportedOutputFormat)->nChannels = FAudio_clamp(
|
|
pRequestedOutputFormat->nChannels,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS
|
|
);
|
|
(*ppSupportedOutputFormat)->nSamplesPerSec = FAudio_clamp(
|
|
pRequestedOutputFormat->nSamplesPerSec,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE
|
|
);
|
|
(*ppSupportedOutputFormat)->wBitsPerSample =
|
|
FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE;
|
|
}
|
|
return FAPO_E_FORMAT_UNSUPPORTED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t FAPOBase_Initialize(
|
|
FAPOBase *fapo,
|
|
const void* pData,
|
|
uint32_t DataByteSize
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
void FAPOBase_Reset(FAPOBase *fapo)
|
|
{
|
|
}
|
|
|
|
uint32_t FAPOBase_LockForProcess(
|
|
FAPOBase *fapo,
|
|
uint32_t InputLockedParameterCount,
|
|
const FAPOLockForProcessBufferParameters *pInputLockedParameters,
|
|
uint32_t OutputLockedParameterCount,
|
|
const FAPOLockForProcessBufferParameters *pOutputLockedParameters
|
|
) {
|
|
/* Verify parameter counts... */
|
|
if ( InputLockedParameterCount < fapo->m_pRegistrationProperties->MinInputBufferCount ||
|
|
InputLockedParameterCount > fapo->m_pRegistrationProperties->MaxInputBufferCount ||
|
|
OutputLockedParameterCount < fapo->m_pRegistrationProperties->MinOutputBufferCount ||
|
|
OutputLockedParameterCount > fapo->m_pRegistrationProperties->MaxOutputBufferCount )
|
|
{
|
|
return FAUDIO_E_INVALID_ARG;
|
|
}
|
|
|
|
|
|
/* Validate input/output formats */
|
|
#define VERIFY_FORMAT_FLAG(flag, prop) \
|
|
if ( (fapo->m_pRegistrationProperties->Flags & flag) && \
|
|
(pInputLockedParameters->pFormat->prop != pOutputLockedParameters->pFormat->prop) ) \
|
|
{ \
|
|
return FAUDIO_E_INVALID_ARG; \
|
|
}
|
|
VERIFY_FORMAT_FLAG(FAPO_FLAG_CHANNELS_MUST_MATCH, nChannels)
|
|
VERIFY_FORMAT_FLAG(FAPO_FLAG_FRAMERATE_MUST_MATCH, nSamplesPerSec)
|
|
VERIFY_FORMAT_FLAG(FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH, wBitsPerSample)
|
|
#undef VERIFY_FORMAT_FLAG
|
|
if ( (fapo->m_pRegistrationProperties->Flags & FAPO_FLAG_BUFFERCOUNT_MUST_MATCH) &&
|
|
(InputLockedParameterCount != OutputLockedParameterCount) )
|
|
{
|
|
return FAUDIO_E_INVALID_ARG;
|
|
}
|
|
fapo->m_fIsLocked = 1;
|
|
return 0;
|
|
}
|
|
|
|
void FAPOBase_UnlockForProcess(FAPOBase *fapo)
|
|
{
|
|
fapo->m_fIsLocked = 0;
|
|
}
|
|
|
|
uint32_t FAPOBase_CalcInputFrames(FAPOBase *fapo, uint32_t OutputFrameCount)
|
|
{
|
|
return OutputFrameCount;
|
|
}
|
|
|
|
uint32_t FAPOBase_CalcOutputFrames(FAPOBase *fapo, uint32_t InputFrameCount)
|
|
{
|
|
return InputFrameCount;
|
|
}
|
|
|
|
uint32_t FAPOBase_ValidateFormatDefault(
|
|
FAPOBase *fapo,
|
|
FAudioWaveFormatEx *pFormat,
|
|
uint8_t fOverwrite
|
|
) {
|
|
if ( pFormat->wFormatTag != FAPOBASE_DEFAULT_FORMAT_TAG ||
|
|
pFormat->nChannels < FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS ||
|
|
pFormat->nChannels > FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS ||
|
|
pFormat->nSamplesPerSec < FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE ||
|
|
pFormat->nSamplesPerSec > FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE ||
|
|
pFormat->wBitsPerSample != FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE )
|
|
{
|
|
if (fOverwrite)
|
|
{
|
|
pFormat->wFormatTag =
|
|
FAPOBASE_DEFAULT_FORMAT_TAG;
|
|
pFormat->nChannels = FAudio_clamp(
|
|
pFormat->nChannels,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS
|
|
);
|
|
pFormat->nSamplesPerSec = FAudio_clamp(
|
|
pFormat->nSamplesPerSec,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE
|
|
);
|
|
pFormat->wBitsPerSample =
|
|
FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE;
|
|
}
|
|
return FAPO_E_FORMAT_UNSUPPORTED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t FAPOBase_ValidateFormatPair(
|
|
FAPOBase *fapo,
|
|
const FAudioWaveFormatEx *pSupportedFormat,
|
|
FAudioWaveFormatEx *pRequestedFormat,
|
|
uint8_t fOverwrite
|
|
) {
|
|
if ( pRequestedFormat->wFormatTag != FAPOBASE_DEFAULT_FORMAT_TAG ||
|
|
pRequestedFormat->nChannels < FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS ||
|
|
pRequestedFormat->nChannels > FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS ||
|
|
pRequestedFormat->nSamplesPerSec < FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE ||
|
|
pRequestedFormat->nSamplesPerSec > FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE ||
|
|
pRequestedFormat->wBitsPerSample != FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE )
|
|
{
|
|
if (fOverwrite)
|
|
{
|
|
pRequestedFormat->wFormatTag =
|
|
FAPOBASE_DEFAULT_FORMAT_TAG;
|
|
pRequestedFormat->nChannels = FAudio_clamp(
|
|
pRequestedFormat->nChannels,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS
|
|
);
|
|
pRequestedFormat->nSamplesPerSec = FAudio_clamp(
|
|
pRequestedFormat->nSamplesPerSec,
|
|
FAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE,
|
|
FAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE
|
|
);
|
|
pRequestedFormat->wBitsPerSample =
|
|
FAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE;
|
|
}
|
|
return FAPO_E_FORMAT_UNSUPPORTED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void FAPOBase_ProcessThru(
|
|
FAPOBase *fapo,
|
|
void* pInputBuffer,
|
|
float *pOutputBuffer,
|
|
uint32_t FrameCount,
|
|
uint16_t InputChannelCount,
|
|
uint16_t OutputChannelCount,
|
|
uint8_t MixWithOutput
|
|
) {
|
|
uint32_t i, co, ci;
|
|
float *input = (float*) pInputBuffer;
|
|
|
|
if (MixWithOutput)
|
|
{
|
|
/* TODO: SSE */
|
|
for (i = 0; i < FrameCount; i += 1)
|
|
for (co = 0; co < OutputChannelCount; co += 1)
|
|
for (ci = 0; ci < InputChannelCount; ci += 1)
|
|
{
|
|
/* Add, don't overwrite! */
|
|
pOutputBuffer[i * OutputChannelCount + co] +=
|
|
input[i * InputChannelCount + ci];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* TODO: SSE */
|
|
for (i = 0; i < FrameCount; i += 1)
|
|
for (co = 0; co < OutputChannelCount; co += 1)
|
|
for (ci = 0; ci < InputChannelCount; ci += 1)
|
|
{
|
|
/* Overwrite, don't add! */
|
|
pOutputBuffer[i * OutputChannelCount + co] =
|
|
input[i * InputChannelCount + ci];
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAPOBase_SetParameters(
|
|
FAPOBase *fapo,
|
|
const void* pParameters,
|
|
uint32_t ParameterByteSize
|
|
) {
|
|
FAudio_assert(!fapo->m_fProducer);
|
|
|
|
/* User callback for validation */
|
|
fapo->OnSetParameters(
|
|
fapo,
|
|
pParameters,
|
|
ParameterByteSize
|
|
);
|
|
|
|
/* Increment parameter block index... */
|
|
fapo->m_uCurrentParametersIndex += 1;
|
|
if (fapo->m_uCurrentParametersIndex == 3)
|
|
{
|
|
fapo->m_uCurrentParametersIndex = 0;
|
|
}
|
|
fapo->m_pCurrentParametersInternal = fapo->m_pParameterBlocks + (
|
|
fapo->m_uParameterBlockByteSize *
|
|
fapo->m_uCurrentParametersIndex
|
|
);
|
|
|
|
/* Copy to what will eventually be the next parameter update */
|
|
FAudio_memcpy(
|
|
fapo->m_pCurrentParametersInternal,
|
|
pParameters,
|
|
ParameterByteSize
|
|
);
|
|
}
|
|
|
|
void FAPOBase_GetParameters(
|
|
FAPOBase *fapo,
|
|
void* pParameters,
|
|
uint32_t ParameterByteSize
|
|
) {
|
|
/* Copy what's current as of the last Process */
|
|
FAudio_memcpy(
|
|
pParameters,
|
|
fapo->m_pCurrentParameters,
|
|
ParameterByteSize
|
|
);
|
|
}
|
|
|
|
void FAPOBase_OnSetParameters(
|
|
FAPOBase *fapo,
|
|
const void* parameters,
|
|
uint32_t parametersSize
|
|
) {
|
|
}
|
|
|
|
uint8_t FAPOBase_ParametersChanged(FAPOBase *fapo)
|
|
{
|
|
/* Internal will get updated when SetParameters is called */
|
|
return fapo->m_pCurrentParametersInternal != fapo->m_pCurrentParameters;
|
|
}
|
|
|
|
uint8_t* FAPOBase_BeginProcess(FAPOBase *fapo)
|
|
{
|
|
/* Set the latest block as "current", this is what Process will use now */
|
|
fapo->m_pCurrentParameters = fapo->m_pCurrentParametersInternal;
|
|
return fapo->m_pCurrentParameters;
|
|
}
|
|
|
|
void FAPOBase_EndProcess(FAPOBase *fapo)
|
|
{
|
|
/* I'm 100% sure my parameter block increment is wrong... */
|
|
}
|
|
|
|
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */
|