Path: blob/master/libs/faudio/src/FAudio_operationset.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/* FAudio_operationset.c originally written by Tyler Glaiel */2728#include "FAudio_internal.h"2930/* Core OperationSet Types */3132typedef enum FAudio_OPERATIONSET_Type33{34FAUDIOOP_ENABLEEFFECT,35FAUDIOOP_DISABLEEFFECT,36FAUDIOOP_SETEFFECTPARAMETERS,37FAUDIOOP_SETFILTERPARAMETERS,38FAUDIOOP_SETOUTPUTFILTERPARAMETERS,39FAUDIOOP_SETVOLUME,40FAUDIOOP_SETCHANNELVOLUMES,41FAUDIOOP_SETOUTPUTMATRIX,42FAUDIOOP_START,43FAUDIOOP_STOP,44FAUDIOOP_EXITLOOP,45FAUDIOOP_SETFREQUENCYRATIO46} FAudio_OPERATIONSET_Type;4748struct FAudio_OPERATIONSET_Operation49{50FAudio_OPERATIONSET_Type Type;51uint32_t OperationSet;52FAudioVoice *Voice;5354union55{56struct57{58uint32_t EffectIndex;59} EnableEffect;60struct61{62uint32_t EffectIndex;63} DisableEffect;64struct65{66uint32_t EffectIndex;67void *pParameters;68uint32_t ParametersByteSize;69} SetEffectParameters;70struct71{72FAudioFilterParametersEXT Parameters;73} SetFilterParameters;74struct75{76FAudioVoice *pDestinationVoice;77FAudioFilterParametersEXT Parameters;78} SetOutputFilterParameters;79struct80{81float Volume;82} SetVolume;83struct84{85uint32_t Channels;86float *pVolumes;87} SetChannelVolumes;88struct89{90FAudioVoice *pDestinationVoice;91uint32_t SourceChannels;92uint32_t DestinationChannels;93float *pLevelMatrix;94} SetOutputMatrix;95struct96{97uint32_t Flags;98} Start;99struct100{101uint32_t Flags;102} Stop;103/* No special data for ExitLoop104struct105{106} ExitLoop;107*/108struct109{110float Ratio;111} SetFrequencyRatio;112} Data;113114FAudio_OPERATIONSET_Operation *next;115};116117/* Used by both Commit and Clear routines */118119static inline void DeleteOperation(120FAudio_OPERATIONSET_Operation *op,121FAudioFreeFunc pFree122) {123if (op->Type == FAUDIOOP_SETEFFECTPARAMETERS)124{125pFree(op->Data.SetEffectParameters.pParameters);126}127else if (op->Type == FAUDIOOP_SETCHANNELVOLUMES)128{129pFree(op->Data.SetChannelVolumes.pVolumes);130}131else if (op->Type == FAUDIOOP_SETOUTPUTMATRIX)132{133pFree(op->Data.SetOutputMatrix.pLevelMatrix);134}135pFree(op);136}137138/* OperationSet Execution */139140static inline void ExecuteOperation(FAudio_OPERATIONSET_Operation *op)141{142switch (op->Type)143{144case FAUDIOOP_ENABLEEFFECT:145FAudioVoice_EnableEffect(146op->Voice,147op->Data.EnableEffect.EffectIndex,148FAUDIO_COMMIT_NOW149);150break;151152case FAUDIOOP_DISABLEEFFECT:153FAudioVoice_DisableEffect(154op->Voice,155op->Data.DisableEffect.EffectIndex,156FAUDIO_COMMIT_NOW157);158break;159160case FAUDIOOP_SETEFFECTPARAMETERS:161FAudioVoice_SetEffectParameters(162op->Voice,163op->Data.SetEffectParameters.EffectIndex,164op->Data.SetEffectParameters.pParameters,165op->Data.SetEffectParameters.ParametersByteSize,166FAUDIO_COMMIT_NOW167);168break;169170case FAUDIOOP_SETFILTERPARAMETERS:171FAudioVoice_SetFilterParametersEXT(172op->Voice,173&op->Data.SetFilterParameters.Parameters,174FAUDIO_COMMIT_NOW175);176break;177178case FAUDIOOP_SETOUTPUTFILTERPARAMETERS:179FAudioVoice_SetOutputFilterParametersEXT(180op->Voice,181op->Data.SetOutputFilterParameters.pDestinationVoice,182&op->Data.SetOutputFilterParameters.Parameters,183FAUDIO_COMMIT_NOW184);185break;186187case FAUDIOOP_SETVOLUME:188FAudioVoice_SetVolume(189op->Voice,190op->Data.SetVolume.Volume,191FAUDIO_COMMIT_NOW192);193break;194195case FAUDIOOP_SETCHANNELVOLUMES:196FAudioVoice_SetChannelVolumes(197op->Voice,198op->Data.SetChannelVolumes.Channels,199op->Data.SetChannelVolumes.pVolumes,200FAUDIO_COMMIT_NOW201);202break;203204case FAUDIOOP_SETOUTPUTMATRIX:205FAudioVoice_SetOutputMatrix(206op->Voice,207op->Data.SetOutputMatrix.pDestinationVoice,208op->Data.SetOutputMatrix.SourceChannels,209op->Data.SetOutputMatrix.DestinationChannels,210op->Data.SetOutputMatrix.pLevelMatrix,211FAUDIO_COMMIT_NOW212);213break;214215case FAUDIOOP_START:216FAudioSourceVoice_Start(217op->Voice,218op->Data.Start.Flags,219FAUDIO_COMMIT_NOW220);221break;222223case FAUDIOOP_STOP:224FAudioSourceVoice_Stop(225op->Voice,226op->Data.Stop.Flags,227FAUDIO_COMMIT_NOW228);229break;230231case FAUDIOOP_EXITLOOP:232FAudioSourceVoice_ExitLoop(233op->Voice,234FAUDIO_COMMIT_NOW235);236break;237238case FAUDIOOP_SETFREQUENCYRATIO:239FAudioSourceVoice_SetFrequencyRatio(240op->Voice,241op->Data.SetFrequencyRatio.Ratio,242FAUDIO_COMMIT_NOW243);244break;245246default:247FAudio_assert(0 && "Unrecognized operation type!");248break;249}250}251252void FAudio_OPERATIONSET_CommitAll(FAudio *audio)253{254FAudio_OPERATIONSET_Operation *op, *next, **committed_end;255256FAudio_PlatformLockMutex(audio->operationLock);257LOG_MUTEX_LOCK(audio, audio->operationLock)258259if (audio->queuedOperations == NULL)260{261FAudio_PlatformUnlockMutex(audio->operationLock);262LOG_MUTEX_UNLOCK(audio, audio->operationLock)263return;264}265266committed_end = &audio->committedOperations;267while (*committed_end)268{269committed_end = &((*committed_end)->next);270}271272op = audio->queuedOperations;273do274{275next = op->next;276277*committed_end = op;278op->next = NULL;279committed_end = &op->next;280281op = next;282} while (op != NULL);283audio->queuedOperations = NULL;284285FAudio_PlatformUnlockMutex(audio->operationLock);286LOG_MUTEX_UNLOCK(audio, audio->operationLock)287}288289void FAudio_OPERATIONSET_Commit(FAudio *audio, uint32_t OperationSet)290{291FAudio_OPERATIONSET_Operation *op, *next, *prev, **committed_end;292293FAudio_PlatformLockMutex(audio->operationLock);294LOG_MUTEX_LOCK(audio, audio->operationLock)295296if (audio->queuedOperations == NULL)297{298FAudio_PlatformUnlockMutex(audio->operationLock);299LOG_MUTEX_UNLOCK(audio, audio->operationLock)300return;301}302303committed_end = &audio->committedOperations;304while (*committed_end)305{306committed_end = &((*committed_end)->next);307}308309op = audio->queuedOperations;310prev = NULL;311do312{313next = op->next;314if (op->OperationSet == OperationSet)315{316if (prev == NULL) /* Start of linked list */317{318audio->queuedOperations = next;319}320else321{322prev->next = next;323}324325*committed_end = op;326op->next = NULL;327committed_end = &op->next;328}329else330{331prev = op;332}333op = next;334} while (op != NULL);335336FAudio_PlatformUnlockMutex(audio->operationLock);337LOG_MUTEX_UNLOCK(audio, audio->operationLock)338}339340void FAudio_OPERATIONSET_Execute(FAudio *audio)341{342FAudio_OPERATIONSET_Operation *op, *next;343344FAudio_PlatformLockMutex(audio->operationLock);345LOG_MUTEX_LOCK(audio, audio->operationLock)346347op = audio->committedOperations;348while (op != NULL)349{350next = op->next;351ExecuteOperation(op);352DeleteOperation(op, audio->pFree);353op = next;354}355audio->committedOperations = NULL;356357FAudio_PlatformUnlockMutex(audio->operationLock);358LOG_MUTEX_UNLOCK(audio, audio->operationLock)359}360361/* OperationSet Compilation */362363static inline FAudio_OPERATIONSET_Operation* QueueOperation(364FAudioVoice *voice,365FAudio_OPERATIONSET_Type type,366uint32_t operationSet367) {368FAudio_OPERATIONSET_Operation *latest;369FAudio_OPERATIONSET_Operation *newop = voice->audio->pMalloc(370sizeof(FAudio_OPERATIONSET_Operation)371);372373newop->Type = type;374newop->Voice = voice;375newop->OperationSet = operationSet;376newop->next = NULL;377378if (voice->audio->queuedOperations == NULL)379{380voice->audio->queuedOperations = newop;381}382else383{384latest = voice->audio->queuedOperations;385while (latest->next != NULL)386{387latest = latest->next;388}389latest->next = newop;390}391392return newop;393}394395void FAudio_OPERATIONSET_QueueEnableEffect(396FAudioVoice *voice,397uint32_t EffectIndex,398uint32_t OperationSet399) {400FAudio_OPERATIONSET_Operation *op;401402FAudio_PlatformLockMutex(voice->audio->operationLock);403LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)404405op = QueueOperation(406voice,407FAUDIOOP_ENABLEEFFECT,408OperationSet409);410411op->Data.EnableEffect.EffectIndex = EffectIndex;412413FAudio_PlatformUnlockMutex(voice->audio->operationLock);414LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)415}416417void FAudio_OPERATIONSET_QueueDisableEffect(418FAudioVoice *voice,419uint32_t EffectIndex,420uint32_t OperationSet421) {422FAudio_OPERATIONSET_Operation *op;423424FAudio_PlatformLockMutex(voice->audio->operationLock);425LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)426427op = QueueOperation(428voice,429FAUDIOOP_DISABLEEFFECT,430OperationSet431);432433op->Data.DisableEffect.EffectIndex = EffectIndex;434435FAudio_PlatformUnlockMutex(voice->audio->operationLock);436LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)437}438439void FAudio_OPERATIONSET_QueueSetEffectParameters(440FAudioVoice *voice,441uint32_t EffectIndex,442const void *pParameters,443uint32_t ParametersByteSize,444uint32_t OperationSet445) {446FAudio_OPERATIONSET_Operation *op;447448FAudio_PlatformLockMutex(voice->audio->operationLock);449LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)450451op = QueueOperation(452voice,453FAUDIOOP_SETEFFECTPARAMETERS,454OperationSet455);456457op->Data.SetEffectParameters.EffectIndex = EffectIndex;458op->Data.SetEffectParameters.pParameters = voice->audio->pMalloc(459ParametersByteSize460);461FAudio_memcpy(462op->Data.SetEffectParameters.pParameters,463pParameters,464ParametersByteSize465);466op->Data.SetEffectParameters.ParametersByteSize = ParametersByteSize;467468FAudio_PlatformUnlockMutex(voice->audio->operationLock);469LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)470}471472void FAudio_OPERATIONSET_QueueSetFilterParameters(473FAudioVoice *voice,474const FAudioFilterParametersEXT *pParameters,475uint32_t OperationSet476) {477FAudio_OPERATIONSET_Operation *op;478479FAudio_PlatformLockMutex(voice->audio->operationLock);480LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)481482op = QueueOperation(483voice,484FAUDIOOP_SETFILTERPARAMETERS,485OperationSet486);487488FAudio_memcpy(489&op->Data.SetFilterParameters.Parameters,490pParameters,491sizeof(FAudioFilterParametersEXT)492);493494FAudio_PlatformUnlockMutex(voice->audio->operationLock);495LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)496}497498void FAudio_OPERATIONSET_QueueSetOutputFilterParameters(499FAudioVoice *voice,500FAudioVoice *pDestinationVoice,501const FAudioFilterParametersEXT *pParameters,502uint32_t OperationSet503) {504FAudio_OPERATIONSET_Operation *op;505506FAudio_PlatformLockMutex(voice->audio->operationLock);507LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)508509op = QueueOperation(510voice,511FAUDIOOP_SETOUTPUTFILTERPARAMETERS,512OperationSet513);514515op->Data.SetOutputFilterParameters.pDestinationVoice = pDestinationVoice;516FAudio_memcpy(517&op->Data.SetOutputFilterParameters.Parameters,518pParameters,519sizeof(FAudioFilterParametersEXT)520);521522FAudio_PlatformUnlockMutex(voice->audio->operationLock);523LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)524}525526void FAudio_OPERATIONSET_QueueSetVolume(527FAudioVoice *voice,528float Volume,529uint32_t OperationSet530) {531FAudio_OPERATIONSET_Operation *op;532533FAudio_PlatformLockMutex(voice->audio->operationLock);534LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)535536op = QueueOperation(537voice,538FAUDIOOP_SETVOLUME,539OperationSet540);541542op->Data.SetVolume.Volume = Volume;543544FAudio_PlatformUnlockMutex(voice->audio->operationLock);545LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)546}547548void FAudio_OPERATIONSET_QueueSetChannelVolumes(549FAudioVoice *voice,550uint32_t Channels,551const float *pVolumes,552uint32_t OperationSet553) {554FAudio_OPERATIONSET_Operation *op;555556FAudio_PlatformLockMutex(voice->audio->operationLock);557LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)558559op = QueueOperation(560voice,561FAUDIOOP_SETCHANNELVOLUMES,562OperationSet563);564565op->Data.SetChannelVolumes.Channels = Channels;566op->Data.SetChannelVolumes.pVolumes = voice->audio->pMalloc(567sizeof(float) * Channels568);569FAudio_memcpy(570op->Data.SetChannelVolumes.pVolumes,571pVolumes,572sizeof(float) * Channels573);574575FAudio_PlatformUnlockMutex(voice->audio->operationLock);576LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)577}578579void FAudio_OPERATIONSET_QueueSetOutputMatrix(580FAudioVoice *voice,581FAudioVoice *pDestinationVoice,582uint32_t SourceChannels,583uint32_t DestinationChannels,584const float *pLevelMatrix,585uint32_t OperationSet586) {587FAudio_OPERATIONSET_Operation *op;588589FAudio_PlatformLockMutex(voice->audio->operationLock);590LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)591592op = QueueOperation(593voice,594FAUDIOOP_SETOUTPUTMATRIX,595OperationSet596);597598op->Data.SetOutputMatrix.pDestinationVoice = pDestinationVoice;599op->Data.SetOutputMatrix.SourceChannels = SourceChannels;600op->Data.SetOutputMatrix.DestinationChannels = DestinationChannels;601op->Data.SetOutputMatrix.pLevelMatrix = voice->audio->pMalloc(602sizeof(float) * SourceChannels * DestinationChannels603);604FAudio_memcpy(605op->Data.SetOutputMatrix.pLevelMatrix,606pLevelMatrix,607sizeof(float) * SourceChannels * DestinationChannels608);609610FAudio_PlatformUnlockMutex(voice->audio->operationLock);611LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)612}613614void FAudio_OPERATIONSET_QueueStart(615FAudioSourceVoice *voice,616uint32_t Flags,617uint32_t OperationSet618) {619FAudio_OPERATIONSET_Operation *op;620621FAudio_PlatformLockMutex(voice->audio->operationLock);622LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)623624op = QueueOperation(625voice,626FAUDIOOP_START,627OperationSet628);629630op->Data.Start.Flags = Flags;631632FAudio_PlatformUnlockMutex(voice->audio->operationLock);633LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)634}635636void FAudio_OPERATIONSET_QueueStop(637FAudioSourceVoice *voice,638uint32_t Flags,639uint32_t OperationSet640) {641FAudio_OPERATIONSET_Operation *op;642643FAudio_PlatformLockMutex(voice->audio->operationLock);644LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)645646op = QueueOperation(647voice,648FAUDIOOP_STOP,649OperationSet650);651652op->Data.Stop.Flags = Flags;653654FAudio_PlatformUnlockMutex(voice->audio->operationLock);655LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)656}657658void FAudio_OPERATIONSET_QueueExitLoop(659FAudioSourceVoice *voice,660uint32_t OperationSet661) {662FAudio_PlatformLockMutex(voice->audio->operationLock);663LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)664665QueueOperation(666voice,667FAUDIOOP_EXITLOOP,668OperationSet669);670671/* No special data for ExitLoop */672673FAudio_PlatformUnlockMutex(voice->audio->operationLock);674LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)675}676677void FAudio_OPERATIONSET_QueueSetFrequencyRatio(678FAudioSourceVoice *voice,679float Ratio,680uint32_t OperationSet681) {682FAudio_OPERATIONSET_Operation *op;683684FAudio_PlatformLockMutex(voice->audio->operationLock);685LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)686687op = QueueOperation(688voice,689FAUDIOOP_SETFREQUENCYRATIO,690OperationSet691);692693op->Data.SetFrequencyRatio.Ratio = Ratio;694695FAudio_PlatformUnlockMutex(voice->audio->operationLock);696LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)697}698699/* Called when releasing the engine */700701void FAudio_OPERATIONSET_ClearAll(FAudio *audio)702{703FAudio_OPERATIONSET_Operation *current, *next;704705FAudio_PlatformLockMutex(audio->operationLock);706LOG_MUTEX_LOCK(audio, audio->operationLock)707708current = audio->queuedOperations;709while (current != NULL)710{711next = current->next;712DeleteOperation(current, audio->pFree);713current = next;714}715audio->queuedOperations = NULL;716717FAudio_PlatformUnlockMutex(audio->operationLock);718LOG_MUTEX_UNLOCK(audio, audio->operationLock)719}720721/* Called when releasing a voice */722723static inline void RemoveFromList(724FAudioVoice *voice,725FAudio_OPERATIONSET_Operation **list726) {727FAudio_OPERATIONSET_Operation *current, *next, *prev;728729current = *list;730prev = NULL;731while (current != NULL)732{733const uint8_t baseVoice = (voice == current->Voice);734const uint8_t dstVoice = (735current->Type == FAUDIOOP_SETOUTPUTFILTERPARAMETERS &&736voice == current->Data.SetOutputFilterParameters.pDestinationVoice737) || (738current->Type == FAUDIOOP_SETOUTPUTMATRIX &&739voice == current->Data.SetOutputMatrix.pDestinationVoice740);741742next = current->next;743if (baseVoice || dstVoice)744{745if (prev == NULL) /* Start of linked list */746{747*list = next;748}749else750{751prev->next = next;752}753754DeleteOperation(current, voice->audio->pFree);755}756else757{758prev = current;759}760current = next;761}762}763764void FAudio_OPERATIONSET_ClearAllForVoice(FAudioVoice *voice)765{766FAudio_PlatformLockMutex(voice->audio->operationLock);767LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)768769RemoveFromList(voice, &voice->audio->queuedOperations);770RemoveFromList(voice, &voice->audio->committedOperations);771772FAudio_PlatformUnlockMutex(voice->audio->operationLock);773LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)774}775776/* vim: set noexpandtab shiftwidth=8 tabstop=8: */777778779