|
|
|
@@ -11,6 +11,7 @@
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "RageMath.h"
|
|
|
|
|
#include "RageThreads.h"
|
|
|
|
|
#include "RageUtil_AutoPtr.h"
|
|
|
|
|
|
|
|
|
|
#include <numeric>
|
|
|
|
|
|
|
|
|
@@ -397,25 +398,28 @@ int PolyphaseFilter::NumInputsForOutputSamples( const State &State, int iOut, in
|
|
|
|
|
return iIn;
|
|
|
|
|
}
|
|
|
|
|
/** @brief Utilities for working with the PolyphaseFilter cache. */
|
|
|
|
|
typedef AutoPtrCopyOnWrite<PolyphaseFilter> PolyphaseFilterAutoPtr;
|
|
|
|
|
namespace PolyphaseFilterCache
|
|
|
|
|
{
|
|
|
|
|
/* Cache filter data, and reuse it without copying. All operations after creation
|
|
|
|
|
* are const, so this doesn't cause thread-safety problems. */
|
|
|
|
|
typedef map<pair<int,float>, PolyphaseFilter *> FilterMap;
|
|
|
|
|
typedef map<pair<int,float>, PolyphaseFilterAutoPtr> FilterMap;
|
|
|
|
|
static RageMutex PolyphaseFiltersLock("PolyphaseFiltersLock");
|
|
|
|
|
static FilterMap g_mapPolyphaseFilters;
|
|
|
|
|
|
|
|
|
|
const PolyphaseFilter *MakePolyphaseFilter( int iUpFactor, float fCutoffFrequency )
|
|
|
|
|
const PolyphaseFilterAutoPtr MakePolyphaseFilter( int iUpFactor, float fCutoffFrequency )
|
|
|
|
|
{
|
|
|
|
|
PolyphaseFilterAutoPtr result;
|
|
|
|
|
|
|
|
|
|
PolyphaseFiltersLock.Lock();
|
|
|
|
|
pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency) );
|
|
|
|
|
FilterMap::const_iterator it = g_mapPolyphaseFilters.find(params);
|
|
|
|
|
if( it != g_mapPolyphaseFilters.end() )
|
|
|
|
|
{
|
|
|
|
|
/* We already have a filter for this upsampling factor and cutoff; use it. */
|
|
|
|
|
PolyphaseFilter *pPolyphase = it->second;
|
|
|
|
|
result = it->second;
|
|
|
|
|
PolyphaseFiltersLock.Unlock();
|
|
|
|
|
return pPolyphase;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
int iWinSize = L*iUpFactor;
|
|
|
|
|
float *pFIR = smnew float[iWinSize];
|
|
|
|
@@ -428,12 +432,14 @@ namespace PolyphaseFilterCache
|
|
|
|
|
pPolyphase->Generate( pFIR );
|
|
|
|
|
delete [] pFIR;
|
|
|
|
|
|
|
|
|
|
g_mapPolyphaseFilters[params] = pPolyphase;
|
|
|
|
|
result = PolyphaseFilterAutoPtr(pPolyphase);
|
|
|
|
|
|
|
|
|
|
g_mapPolyphaseFilters[params] = result;
|
|
|
|
|
PolyphaseFiltersLock.Unlock();
|
|
|
|
|
return pPolyphase;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PolyphaseFilter *FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency )
|
|
|
|
|
const PolyphaseFilterAutoPtr FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency )
|
|
|
|
|
{
|
|
|
|
|
/* Find a cached filter with the same iUpFactor and a nearby cutoff frequency.
|
|
|
|
|
* Round the cutoff down, if possible; it's better to filter out too much than
|
|
|
|
@@ -444,7 +450,7 @@ namespace PolyphaseFilterCache
|
|
|
|
|
if( it != g_mapPolyphaseFilters.begin() )
|
|
|
|
|
--it;
|
|
|
|
|
ASSERT( it->first.first == iUpFactor );
|
|
|
|
|
PolyphaseFilter *pPolyphase = it->second;
|
|
|
|
|
PolyphaseFilterAutoPtr pPolyphase = it->second;
|
|
|
|
|
PolyphaseFiltersLock.Unlock();
|
|
|
|
|
return pPolyphase;
|
|
|
|
|
}
|
|
|
|
@@ -467,7 +473,7 @@ public:
|
|
|
|
|
* when filtering. This will only cause the low-pass filter to be rounded;
|
|
|
|
|
* the conversion ratio will always be exact. */
|
|
|
|
|
m_iUpFactor = iUpFactor;
|
|
|
|
|
m_pPolyphase = NULL;
|
|
|
|
|
m_pPolyphase = PolyphaseFilterAutoPtr(NULL);
|
|
|
|
|
|
|
|
|
|
int iFilterIncrement = max( (iMaxDownFactor - iMinDownFactor)/10, 1 );
|
|
|
|
|
for( int iDownFactor = iMinDownFactor; iDownFactor <= iMaxDownFactor; iDownFactor += iFilterIncrement )
|
|
|
|
@@ -532,13 +538,13 @@ private:
|
|
|
|
|
return fCutoffFrequency;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PolyphaseFilter *GetFilter( int iDownFactor ) const
|
|
|
|
|
const PolyphaseFilterAutoPtr GetFilter( int iDownFactor ) const
|
|
|
|
|
{
|
|
|
|
|
float fCutoffFrequency = GetCutoffFrequency( iDownFactor );
|
|
|
|
|
return PolyphaseFilterCache::FindNearestPolyphaseFilter( m_iUpFactor, fCutoffFrequency );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PolyphaseFilter *m_pPolyphase;
|
|
|
|
|
PolyphaseFilterAutoPtr m_pPolyphase;
|
|
|
|
|
PolyphaseFilter::State *m_pState;
|
|
|
|
|
int m_iUpFactor;
|
|
|
|
|
int m_iDownFactor;
|
|
|
|
|