Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
References:
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/src/FAudioFX_volumemeter.c
281 lines | 7.9 KiB | text/x-c | CLexer
281 lines | 7.9 KiB | text/x-c | CLexer
r0 | /* FAudio - XAudio Reimplementation for FNA | |||
* | ||||
* Copyright (c) 2011-2020 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 "FAudioFX.h" | ||||
#include "FAudio_internal.h" | ||||
/* Volume Meter FAPO Implementation */ | ||||
const FAudioGUID FAudioFX_CLSID_AudioVolumeMeter = /* 2.7 */ | ||||
{ | ||||
0xCAC1105F, | ||||
0x619B, | ||||
0x4D04, | ||||
{ | ||||
0x83, | ||||
0x1A, | ||||
0x44, | ||||
0xE1, | ||||
0xCB, | ||||
0xF1, | ||||
0x2D, | ||||
0x57 | ||||
} | ||||
}; | ||||
static FAPORegistrationProperties VolumeMeterProperties = | ||||
{ | ||||
/* .clsid = */ {0}, | ||||
/* .FriendlyName = */ | ||||
{ | ||||
'V', 'o', 'l', 'u', 'm', 'e', 'M', 'e', 't', 'e', 'r', '\0' | ||||
}, | ||||
/*.CopyrightInfo = */ | ||||
{ | ||||
'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't', ' ', '(', 'c', ')', | ||||
'E', 't', 'h', 'a', 'n', ' ', 'L', 'e', 'e', '\0' | ||||
}, | ||||
/*.MajorVersion = */ 0, | ||||
/*.MinorVersion = */ 0, | ||||
/*.Flags = */( | ||||
FAPO_FLAG_CHANNELS_MUST_MATCH | | ||||
FAPO_FLAG_FRAMERATE_MUST_MATCH | | ||||
FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH | | ||||
FAPO_FLAG_BUFFERCOUNT_MUST_MATCH | | ||||
FAPO_FLAG_INPLACE_SUPPORTED | | ||||
FAPO_FLAG_INPLACE_REQUIRED | ||||
), | ||||
/*.MinInputBufferCount = */ 1, | ||||
/*.MaxInputBufferCount = */ 1, | ||||
/*.MinOutputBufferCount = */ 1, | ||||
/*.MaxOutputBufferCount =*/ 1 | ||||
}; | ||||
typedef struct FAudioFXVolumeMeter | ||||
{ | ||||
FAPOBase base; | ||||
uint16_t channels; | ||||
} FAudioFXVolumeMeter; | ||||
uint32_t FAudioFXVolumeMeter_LockForProcess( | ||||
FAudioFXVolumeMeter *fapo, | ||||
uint32_t InputLockedParameterCount, | ||||
const FAPOLockForProcessBufferParameters *pInputLockedParameters, | ||||
uint32_t OutputLockedParameterCount, | ||||
const FAPOLockForProcessBufferParameters *pOutputLockedParameters | ||||
) { | ||||
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*) | ||||
fapo->base.m_pParameterBlocks; | ||||
/* Verify parameter counts... */ | ||||
if ( InputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinInputBufferCount || | ||||
InputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxInputBufferCount || | ||||
OutputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinOutputBufferCount || | ||||
OutputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxOutputBufferCount ) | ||||
{ | ||||
return FAUDIO_E_INVALID_ARG; | ||||
} | ||||
/* Validate input/output formats */ | ||||
#define VERIFY_FORMAT_FLAG(flag, prop) \ | ||||
if ( (fapo->base.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->base.m_pRegistrationProperties->Flags & FAPO_FLAG_BUFFERCOUNT_MUST_MATCH) && | ||||
(InputLockedParameterCount != OutputLockedParameterCount) ) | ||||
{ | ||||
return FAUDIO_E_INVALID_ARG; | ||||
} | ||||
/* Allocate volume meter arrays */ | ||||
fapo->channels = pInputLockedParameters->pFormat->nChannels; | ||||
levels[0].pPeakLevels = (float*) fapo->base.pMalloc( | ||||
fapo->channels * sizeof(float) * 6 | ||||
); | ||||
FAudio_zero(levels[0].pPeakLevels, fapo->channels * sizeof(float) * 6); | ||||
levels[0].pRMSLevels = levels[0].pPeakLevels + fapo->channels; | ||||
levels[1].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 2); | ||||
levels[1].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 3); | ||||
levels[2].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 4); | ||||
levels[2].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 5); | ||||
fapo->base.m_fIsLocked = 1; | ||||
return 0; | ||||
} | ||||
void FAudioFXVolumeMeter_UnlockForProcess(FAudioFXVolumeMeter *fapo) | ||||
{ | ||||
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*) | ||||
fapo->base.m_pParameterBlocks; | ||||
fapo->base.pFree(levels[0].pPeakLevels); | ||||
fapo->base.m_fIsLocked = 0; | ||||
} | ||||
void FAudioFXVolumeMeter_Process( | ||||
FAudioFXVolumeMeter *fapo, | ||||
uint32_t InputProcessParameterCount, | ||||
const FAPOProcessBufferParameters* pInputProcessParameters, | ||||
uint32_t OutputProcessParameterCount, | ||||
FAPOProcessBufferParameters* pOutputProcessParameters, | ||||
int32_t IsEnabled | ||||
) { | ||||
float peak; | ||||
float total; | ||||
float *buffer; | ||||
uint32_t i, j; | ||||
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*) | ||||
FAPOBase_BeginProcess(&fapo->base); | ||||
/* TODO: This could probably be SIMD-ified... */ | ||||
for (i = 0; i < fapo->channels; i += 1) | ||||
{ | ||||
peak = 0.0f; | ||||
total = 0.0f; | ||||
buffer = ((float*) pInputProcessParameters->pBuffer) + i; | ||||
for (j = 0; j < pInputProcessParameters->ValidFrameCount; j += 1, buffer += fapo->channels) | ||||
{ | ||||
const float sampleAbs = FAudio_fabsf(*buffer); | ||||
if (sampleAbs > peak) | ||||
{ | ||||
peak = sampleAbs; | ||||
} | ||||
total += (*buffer) * (*buffer); | ||||
} | ||||
levels->pPeakLevels[i] = peak; | ||||
levels->pRMSLevels[i] = FAudio_sqrtf( | ||||
total / pInputProcessParameters->ValidFrameCount | ||||
); | ||||
} | ||||
FAPOBase_EndProcess(&fapo->base); | ||||
} | ||||
void FAudioFXVolumeMeter_GetParameters( | ||||
FAudioFXVolumeMeter *fapo, | ||||
FAudioFXVolumeMeterLevels *pParameters, | ||||
uint32_t ParameterByteSize | ||||
) { | ||||
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*) | ||||
fapo->base.m_pCurrentParameters; | ||||
FAudio_assert(ParameterByteSize == sizeof(FAudioFXVolumeMeterLevels)); | ||||
FAudio_assert(pParameters->ChannelCount == fapo->channels); | ||||
/* Copy what's current as of the last Process */ | ||||
if (pParameters->pPeakLevels != NULL) | ||||
{ | ||||
FAudio_memcpy( | ||||
pParameters->pPeakLevels, | ||||
levels->pPeakLevels, | ||||
fapo->channels * sizeof(float) | ||||
); | ||||
} | ||||
if (pParameters->pRMSLevels != NULL) | ||||
{ | ||||
FAudio_memcpy( | ||||
pParameters->pRMSLevels, | ||||
levels->pRMSLevels, | ||||
fapo->channels * sizeof(float) | ||||
); | ||||
} | ||||
} | ||||
void FAudioFXVolumeMeter_Free(void* fapo) | ||||
{ | ||||
FAudioFXVolumeMeter *volumemeter = (FAudioFXVolumeMeter*) fapo; | ||||
volumemeter->base.pFree(volumemeter->base.m_pParameterBlocks); | ||||
volumemeter->base.pFree(fapo); | ||||
} | ||||
/* Public API */ | ||||
uint32_t FAudioCreateVolumeMeter(FAPO** ppApo, uint32_t Flags) | ||||
{ | ||||
return FAudioCreateVolumeMeterWithCustomAllocatorEXT( | ||||
ppApo, | ||||
Flags, | ||||
FAudio_malloc, | ||||
FAudio_free, | ||||
FAudio_realloc | ||||
); | ||||
} | ||||
uint32_t FAudioCreateVolumeMeterWithCustomAllocatorEXT( | ||||
FAPO** ppApo, | ||||
uint32_t Flags, | ||||
FAudioMallocFunc customMalloc, | ||||
FAudioFreeFunc customFree, | ||||
FAudioReallocFunc customRealloc | ||||
) { | ||||
/* Allocate... */ | ||||
FAudioFXVolumeMeter *result = (FAudioFXVolumeMeter*) customMalloc( | ||||
sizeof(FAudioFXVolumeMeter) | ||||
); | ||||
uint8_t *params = (uint8_t*) customMalloc( | ||||
sizeof(FAudioFXVolumeMeterLevels) * 3 | ||||
); | ||||
FAudio_zero(params, sizeof(FAudioFXVolumeMeterLevels) * 3); | ||||
/* Initialize... */ | ||||
FAudio_memcpy( | ||||
&VolumeMeterProperties.clsid, | ||||
&FAudioFX_CLSID_AudioVolumeMeter, | ||||
sizeof(FAudioGUID) | ||||
); | ||||
CreateFAPOBaseWithCustomAllocatorEXT( | ||||
&result->base, | ||||
&VolumeMeterProperties, | ||||
params, | ||||
sizeof(FAudioFXVolumeMeterLevels), | ||||
1, | ||||
customMalloc, | ||||
customFree, | ||||
customRealloc | ||||
); | ||||
/* Function table... */ | ||||
result->base.base.LockForProcess = (LockForProcessFunc) | ||||
FAudioFXVolumeMeter_LockForProcess; | ||||
result->base.base.UnlockForProcess = (UnlockForProcessFunc) | ||||
FAudioFXVolumeMeter_UnlockForProcess; | ||||
result->base.base.Process = (ProcessFunc) | ||||
FAudioFXVolumeMeter_Process; | ||||
result->base.base.GetParameters = (GetParametersFunc) | ||||
FAudioFXVolumeMeter_GetParameters; | ||||
result->base.Destructor = FAudioFXVolumeMeter_Free; | ||||
/* Finally. */ | ||||
*ppApo = &result->base.base; | ||||
return 0; | ||||
} | ||||
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */ | ||||