#include "fmod_settings.h" #ifdef FMOD_SUPPORT_SOFTWARE #include "fmod_dsp_connectionpool.h" #include "fmod_localcriticalsection.h" #include "fmod_memory.h" #include "fmod_systemi.h" namespace FMOD { /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] [SEE_ALSO] ] */ FMOD_RESULT DSPConnectionPool::init(SystemI *system, int numconnections, int numoutputlevels, int numinputlevels) { DSP_LEVEL_TYPE *leveldata; int count; unsigned int alignment = 0; if (numconnections < 0) { return FMOD_ERR_INVALID_PARAM; } for (int i=0; i < DSP_MAX_CONNECTION_BLOCKS; i++) { mConnection[i] = 0; mLevelData[i] = 0; } numconnections += 128; numconnections /= 128; numconnections *= 128; mNumConnections = numconnections; mConnectionMemory[0] = (DSPConnectionI *)FMOD_Memory_Calloc(mNumConnections * sizeof(DSPConnectionI) + 16); if (!mConnectionMemory[0]) { return FMOD_ERR_MEMORY; } mConnection[0] = (DSPConnectionI *)FMOD_ALIGNPOINTER(mConnectionMemory[0], 16); mNodeMemory[0] = (LinkedListNode *)FMOD_Memory_Calloc(mNumConnections * sizeof(LinkedListNode)); if (!mNodeMemory[0]) { return FMOD_ERR_MEMORY; } mNumOutputLevels = numoutputlevels; mNumInputLevels = numinputlevels; #ifdef PLATFORM_PS3 alignment = 128; #endif mLevelDataMemory[0] = (DSP_LEVEL_TYPE *)FMOD_Memory_Calloc(mNumConnections /* How many connections are we going to allow maximum. */ * (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */ * (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */ * sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */ * 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */ + alignment /* PS3 - 128 byte aligned for DMA */ ); if (!mLevelDataMemory[0]) { return FMOD_ERR_MEMORY; } #ifdef PLATFORM_PS3 mLevelData[0] = (DSP_LEVEL_TYPE *)FMOD_ALIGNPOINTER(mLevelDataMemory[0], 128); #else mLevelData[0] = mLevelDataMemory[0]; #endif leveldata = mLevelData[0]; mFreeListHead.initNode(); for (count = 0; count < mNumConnections; count++) { DSPConnectionI *conn = &mConnection[0][count]; new (conn) DSPConnectionI; conn->init(leveldata, numoutputlevels, numinputlevels); conn->mNode = &mNodeMemory[0][count]; conn->mNode->setData(conn); conn->mNode->addAfter(&mFreeListHead); } mSystem = system; return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] [SEE_ALSO] ] */ FMOD_RESULT DSPConnectionPool::close() { int i; for (i = 0; i < DSP_MAX_CONNECTION_BLOCKS; i++) { if (mConnectionMemory[i]) { FMOD_Memory_Free(mConnectionMemory[i]); mConnectionMemory[i] = 0; } mConnection[i] = 0; if (mLevelDataMemory[i]) { FMOD_Memory_Free(mLevelDataMemory[i]); mLevelDataMemory[i] = 0; } mLevelData[i] = 0; if (mNodeMemory[i]) { FMOD_Memory_Free(mNodeMemory[i]); mNodeMemory[i] = 0; } } return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] [SEE_ALSO] ] */ FMOD_RESULT DSPConnectionPool::alloc(DSPConnectionI **connection, bool protect) { LocalCriticalSection crit(mSystem->mDSPConnectionCrit); DSPConnectionI *newconnection; unsigned int alignment = 0; if (!mSystem) { return FMOD_ERR_UNINITIALIZED; } if (!connection) { return FMOD_ERR_INVALID_PARAM; } if (protect) { crit.enter(); } if (mFreeListHead.isEmpty()) { int newblock, count; DSP_LEVEL_TYPE *leveldata = 0; for (newblock = 0; newblock < DSP_MAX_CONNECTION_BLOCKS; newblock++) { if (!mConnectionMemory[newblock]) { break; } } if (newblock >= DSP_MAX_CONNECTION_BLOCKS) { FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DSPConnectionPool::alloc", "DSP_MAX_CONNECTION_BLOCKS exceeded! Memory will leak!\n")); return FMOD_ERR_INTERNAL; } mConnectionMemory[newblock] = (DSPConnectionI *)FMOD_Memory_Calloc(mNumConnections * sizeof(DSPConnectionI) + 16); if (!mConnectionMemory[newblock]) { return FMOD_ERR_MEMORY; } mConnection[newblock] = (DSPConnectionI *)FMOD_ALIGNPOINTER(mConnectionMemory[newblock], 16); #ifdef PLATFORM_PS3 alignment = 128; #endif mNodeMemory[newblock] = (LinkedListNode *)FMOD_Memory_Calloc(mNumConnections * sizeof(LinkedListNode)); if (!mNodeMemory[newblock]) { return FMOD_ERR_MEMORY; } mLevelDataMemory[newblock] = (DSP_LEVEL_TYPE *)FMOD_Memory_Calloc(mNumConnections /* How many connections are we going to allow maximum. */ * (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */ * (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */ * sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */ * 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */ + alignment /* PS3 - 128 byte aligned for DMA */ ); if (!mLevelDataMemory[newblock]) { return FMOD_ERR_MEMORY; } #ifdef PLATFORM_PS3 mLevelData[newblock] = (DSP_LEVEL_TYPE *)FMOD_ALIGNPOINTER(mLevelDataMemory[newblock], 128); #else mLevelData[newblock] = mLevelDataMemory[newblock]; #endif leveldata = mLevelData[newblock]; for (count = 0; count < mNumConnections; count++) { DSPConnectionI *conn = &mConnection[newblock][count]; new (conn) DSPConnectionI; conn->init(leveldata, mNumOutputLevels, mNumInputLevels); conn->mNode = &mNodeMemory[newblock][count]; conn->mNode->setData(conn); conn->mNode->addAfter(&mFreeListHead); } } newconnection = (DSPConnectionI *)mFreeListHead.getNext()->getData(); newconnection->mInputNode.setData(newconnection); newconnection->mOutputNode.setData(newconnection); newconnection->mNode->removeNode(); newconnection->mNode->addAfter(&mUsedListHead); if (protect) { crit.leave(); } *connection = newconnection; return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] [SEE_ALSO] ] */ FMOD_RESULT DSPConnectionPool::free(DSPConnectionI *connection, bool protect) { LocalCriticalSection crit(mSystem->mDSPConnectionCrit); if (!connection) { return FMOD_ERR_INVALID_PARAM; } if (protect) { crit.enter(); } connection->mInputNode.removeNode(); connection->mOutputNode.removeNode(); connection->mInputUnit = 0; connection->mOutputUnit = 0; connection->mNode->removeNode(); connection->mNode->addAfter(&mFreeListHead); connection->mNode->setData(connection); if (protect) { crit.leave(); } return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] [SEE_ALSO] ] */ #ifdef FMOD_SUPPORT_MEMORYTRACKER FMOD_RESULT DSPConnectionPool::getMemoryUsedImpl(MemoryTracker *tracker) { for (int i=0; i < DSP_MAX_CONNECTION_BLOCKS; i++) { if (mConnectionMemory[i]) { tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections * sizeof(DSPConnectionI) + 16); } if (mNodeMemory[i]) { tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections * sizeof(LinkedListNode)); } if (mLevelDataMemory[i]) { unsigned int alignment = 0; #ifdef PLATFORM_PS3 alignment = 128; #endif tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections /* How many connections are we going to allow maximum. */ * (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */ * (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */ * sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */ * 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */ + alignment /* PS3 - 128 byte aligned for DMA */ ); } } return FMOD_OK; } #endif } #endif