Path: blob/master/libs/faudio/src/FAudioFX_volumemeter.c
4389 views
/* FAudio - XAudio Reimplementation for FNA1*2* Copyright (c) 2011-2024 Ethan Lee, Luigi Auriemma, and the MonoGame Team3*4* This software is provided 'as-is', without any express or implied warranty.5* In no event will the authors be held liable for any damages arising from6* the use of this software.7*8* Permission is granted to anyone to use this software for any purpose,9* including commercial applications, and to alter it and redistribute it10* freely, subject to the following restrictions:11*12* 1. The origin of this software must not be misrepresented; you must not13* claim that you wrote the original software. If you use this software in a14* product, an acknowledgment in the product documentation would be15* appreciated but is not required.16*17* 2. Altered source versions must be plainly marked as such, and must not be18* misrepresented as being the original software.19*20* 3. This notice may not be removed or altered from any source distribution.21*22* Ethan "flibitijibibo" Lee <[email protected]>23*24*/2526#include "FAudioFX.h"27#include "FAudio_internal.h"2829/* Volume Meter FAPO Implementation */3031const FAudioGUID FAudioFX_CLSID_AudioVolumeMeter = /* 2.7 */32{330xCAC1105F,340x619B,350x4D04,36{370x83,380x1A,390x44,400xE1,410xCB,420xF1,430x2D,440x5745}46};4748static FAPORegistrationProperties VolumeMeterProperties =49{50/* .clsid = */ {0},51/* .FriendlyName = */52{53'V', 'o', 'l', 'u', 'm', 'e', 'M', 'e', 't', 'e', 'r', '\0'54},55/*.CopyrightInfo = */56{57'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't', ' ', '(', 'c', ')',58'E', 't', 'h', 'a', 'n', ' ', 'L', 'e', 'e', '\0'59},60/*.MajorVersion = */ 0,61/*.MinorVersion = */ 0,62/*.Flags = */(63FAPO_FLAG_CHANNELS_MUST_MATCH |64FAPO_FLAG_FRAMERATE_MUST_MATCH |65FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH |66FAPO_FLAG_BUFFERCOUNT_MUST_MATCH |67FAPO_FLAG_INPLACE_SUPPORTED |68FAPO_FLAG_INPLACE_REQUIRED69),70/*.MinInputBufferCount = */ 1,71/*.MaxInputBufferCount = */ 1,72/*.MinOutputBufferCount = */ 1,73/*.MaxOutputBufferCount =*/ 174};7576typedef struct FAudioFXVolumeMeter77{78FAPOBase base;79uint16_t channels;80} FAudioFXVolumeMeter;8182uint32_t FAudioFXVolumeMeter_LockForProcess(83FAudioFXVolumeMeter *fapo,84uint32_t InputLockedParameterCount,85const FAPOLockForProcessBufferParameters *pInputLockedParameters,86uint32_t OutputLockedParameterCount,87const FAPOLockForProcessBufferParameters *pOutputLockedParameters88) {89FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)90fapo->base.m_pParameterBlocks;9192/* Verify parameter counts... */93if ( InputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinInputBufferCount ||94InputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxInputBufferCount ||95OutputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinOutputBufferCount ||96OutputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxOutputBufferCount )97{98return FAUDIO_E_INVALID_ARG;99}100101102/* Validate input/output formats */103#define VERIFY_FORMAT_FLAG(flag, prop) \104if ( (fapo->base.m_pRegistrationProperties->Flags & flag) && \105(pInputLockedParameters->pFormat->prop != pOutputLockedParameters->pFormat->prop) ) \106{ \107return FAUDIO_E_INVALID_ARG; \108}109VERIFY_FORMAT_FLAG(FAPO_FLAG_CHANNELS_MUST_MATCH, nChannels)110VERIFY_FORMAT_FLAG(FAPO_FLAG_FRAMERATE_MUST_MATCH, nSamplesPerSec)111VERIFY_FORMAT_FLAG(FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH, wBitsPerSample)112#undef VERIFY_FORMAT_FLAG113if ( (fapo->base.m_pRegistrationProperties->Flags & FAPO_FLAG_BUFFERCOUNT_MUST_MATCH) &&114(InputLockedParameterCount != OutputLockedParameterCount) )115{116return FAUDIO_E_INVALID_ARG;117}118119/* Allocate volume meter arrays */120fapo->channels = pInputLockedParameters->pFormat->nChannels;121levels[0].pPeakLevels = (float*) fapo->base.pMalloc(122fapo->channels * sizeof(float) * 6123);124FAudio_zero(levels[0].pPeakLevels, fapo->channels * sizeof(float) * 6);125levels[0].pRMSLevels = levels[0].pPeakLevels + fapo->channels;126levels[1].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 2);127levels[1].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 3);128levels[2].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 4);129levels[2].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 5);130131fapo->base.m_fIsLocked = 1;132return 0;133}134135void FAudioFXVolumeMeter_UnlockForProcess(FAudioFXVolumeMeter *fapo)136{137FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)138fapo->base.m_pParameterBlocks;139fapo->base.pFree(levels[0].pPeakLevels);140fapo->base.m_fIsLocked = 0;141}142143void FAudioFXVolumeMeter_Process(144FAudioFXVolumeMeter *fapo,145uint32_t InputProcessParameterCount,146const FAPOProcessBufferParameters* pInputProcessParameters,147uint32_t OutputProcessParameterCount,148FAPOProcessBufferParameters* pOutputProcessParameters,149int32_t IsEnabled150) {151float peak;152float total;153float *buffer;154uint32_t i, j;155FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)156FAPOBase_BeginProcess(&fapo->base);157158/* TODO: This could probably be SIMD-ified... */159for (i = 0; i < fapo->channels; i += 1)160{161peak = 0.0f;162total = 0.0f;163buffer = ((float*) pInputProcessParameters->pBuffer) + i;164for (j = 0; j < pInputProcessParameters->ValidFrameCount; j += 1, buffer += fapo->channels)165{166const float sampleAbs = FAudio_fabsf(*buffer);167if (sampleAbs > peak)168{169peak = sampleAbs;170}171total += (*buffer) * (*buffer);172}173levels->pPeakLevels[i] = peak;174levels->pRMSLevels[i] = FAudio_sqrtf(175total / pInputProcessParameters->ValidFrameCount176);177}178179FAPOBase_EndProcess(&fapo->base);180}181182void FAudioFXVolumeMeter_GetParameters(183FAudioFXVolumeMeter *fapo,184FAudioFXVolumeMeterLevels *pParameters,185uint32_t ParameterByteSize186) {187FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)188fapo->base.m_pCurrentParameters;189FAudio_assert(ParameterByteSize == sizeof(FAudioFXVolumeMeterLevels));190FAudio_assert(pParameters->ChannelCount == fapo->channels);191192/* Copy what's current as of the last Process */193if (pParameters->pPeakLevels != NULL)194{195FAudio_memcpy(196pParameters->pPeakLevels,197levels->pPeakLevels,198fapo->channels * sizeof(float)199);200}201if (pParameters->pRMSLevels != NULL)202{203FAudio_memcpy(204pParameters->pRMSLevels,205levels->pRMSLevels,206fapo->channels * sizeof(float)207);208}209}210211void FAudioFXVolumeMeter_Free(void* fapo)212{213FAudioFXVolumeMeter *volumemeter = (FAudioFXVolumeMeter*) fapo;214volumemeter->base.pFree(volumemeter->base.m_pParameterBlocks);215volumemeter->base.pFree(fapo);216}217218/* Public API */219220uint32_t FAudioCreateVolumeMeter(FAPO** ppApo, uint32_t Flags)221{222return FAudioCreateVolumeMeterWithCustomAllocatorEXT(223ppApo,224Flags,225FAudio_malloc,226FAudio_free,227FAudio_realloc228);229}230231uint32_t FAudioCreateVolumeMeterWithCustomAllocatorEXT(232FAPO** ppApo,233uint32_t Flags,234FAudioMallocFunc customMalloc,235FAudioFreeFunc customFree,236FAudioReallocFunc customRealloc237) {238/* Allocate... */239FAudioFXVolumeMeter *result = (FAudioFXVolumeMeter*) customMalloc(240sizeof(FAudioFXVolumeMeter)241);242uint8_t *params = (uint8_t*) customMalloc(243sizeof(FAudioFXVolumeMeterLevels) * 3244);245FAudio_zero(params, sizeof(FAudioFXVolumeMeterLevels) * 3);246247/* Initialize... */248FAudio_memcpy(249&VolumeMeterProperties.clsid,250&FAudioFX_CLSID_AudioVolumeMeter,251sizeof(FAudioGUID)252);253CreateFAPOBaseWithCustomAllocatorEXT(254&result->base,255&VolumeMeterProperties,256params,257sizeof(FAudioFXVolumeMeterLevels),2581,259customMalloc,260customFree,261customRealloc262);263264/* Function table... */265result->base.base.LockForProcess = (LockForProcessFunc)266FAudioFXVolumeMeter_LockForProcess;267result->base.base.UnlockForProcess = (UnlockForProcessFunc)268FAudioFXVolumeMeter_UnlockForProcess;269result->base.base.Process = (ProcessFunc)270FAudioFXVolumeMeter_Process;271result->base.base.GetParameters = (GetParametersFunc)272FAudioFXVolumeMeter_GetParameters;273result->base.Destructor = FAudioFXVolumeMeter_Free;274275/* Finally. */276*ppApo = &result->base.base;277return 0;278}279280/* vim: set noexpandtab shiftwidth=8 tabstop=8: */281282283