allow modifying the downsampling ratio on the fly
This commit is contained in:
@@ -429,6 +429,22 @@ namespace PolyphaseFilterCache
|
|||||||
PolyphaseFiltersLock.Unlock();
|
PolyphaseFiltersLock.Unlock();
|
||||||
return pPolyphase;
|
return pPolyphase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PolyphaseFilter *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 tha
|
||||||
|
* too little. */
|
||||||
|
PolyphaseFiltersLock.Lock();
|
||||||
|
pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency) );
|
||||||
|
FilterMap::const_iterator it = g_mapPolyphaseFilters.upper_bound( params );
|
||||||
|
if( it != g_mapPolyphaseFilters.begin() )
|
||||||
|
--it;
|
||||||
|
ASSERT( it->first.first == iUpFactor );
|
||||||
|
PolyphaseFilter *pPolyphase = it->second;
|
||||||
|
PolyphaseFiltersLock.Unlock();
|
||||||
|
return pPolyphase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -438,14 +454,26 @@ namespace PolyphaseFilterCache
|
|||||||
class RageSoundResampler_Polyphase
|
class RageSoundResampler_Polyphase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RageSoundResampler_Polyphase( int iUpFactor, int iDownFactor )
|
/* Note that going outside of [iMinDownFactor,iMaxDownFactor] while resampling isn't
|
||||||
|
* fatal. It'll only cause aliasing, by not having a LPF that's low enough, or cause
|
||||||
|
* too much filtering, by not having a LPF that's high enough. */
|
||||||
|
RageSoundResampler_Polyphase( int iUpFactor, int iMinDownFactor, int iMaxDownFactor )
|
||||||
{
|
{
|
||||||
|
/* Cache filters between iMinDownFactor and iMaxDownFactor. Do them in
|
||||||
|
* iFilterIncrement increments; we'll round down to the closest match
|
||||||
|
* when filtering. This will only cause the low-pass filter to be rounded;
|
||||||
|
* the conversion ratio will always be exact. */
|
||||||
m_iUpFactor = iUpFactor;
|
m_iUpFactor = iUpFactor;
|
||||||
m_iDownFactor = iDownFactor;
|
m_pPolyphase = NULL;
|
||||||
|
|
||||||
float fCutoffFrequency = GetCutoffFrequency( iDownFactor );
|
int iFilterIncrement = (iMaxDownFactor - iMinDownFactor)/10;
|
||||||
|
for( int iDownFactor = iMinDownFactor; iDownFactor <= iMaxDownFactor; iDownFactor += iFilterIncrement )
|
||||||
|
{
|
||||||
|
float fCutoffFrequency = GetCutoffFrequency( iDownFactor );
|
||||||
|
PolyphaseFilterCache::MakePolyphaseFilter( m_iUpFactor, fCutoffFrequency );
|
||||||
|
}
|
||||||
|
|
||||||
m_pPolyphase = PolyphaseFilterCache::MakePolyphaseFilter( iUpFactor, fCutoffFrequency );
|
SetDownFactor( iUpFactor );
|
||||||
|
|
||||||
m_pState = new PolyphaseFilter::State( iUpFactor );
|
m_pState = new PolyphaseFilter::State( iUpFactor );
|
||||||
}
|
}
|
||||||
@@ -455,6 +483,12 @@ public:
|
|||||||
delete m_pState;
|
delete m_pState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDownFactor( int iDownFactor )
|
||||||
|
{
|
||||||
|
m_iDownFactor = iDownFactor;
|
||||||
|
m_pPolyphase = GetFilter( m_iDownFactor );
|
||||||
|
}
|
||||||
|
|
||||||
int Run( const float *pIn, int iSamplesIn, float *pOut, int iSamplesOut ) const
|
int Run( const float *pIn, int iSamplesIn, float *pOut, int iSamplesOut ) const
|
||||||
{
|
{
|
||||||
return m_pPolyphase->RunPolyphaseFilter( *m_pState, pIn, iSamplesIn, m_iDownFactor, pOut, iSamplesOut );
|
return m_pPolyphase->RunPolyphaseFilter( *m_pState, pIn, iSamplesIn, m_iDownFactor, pOut, iSamplesOut );
|
||||||
@@ -494,6 +528,12 @@ private:
|
|||||||
return fCutoffFrequency;
|
return fCutoffFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PolyphaseFilter *GetFilter( int iDownFactor ) const
|
||||||
|
{
|
||||||
|
float fCutoffFrequency = GetCutoffFrequency( iDownFactor );
|
||||||
|
return PolyphaseFilterCache::FindNearestPolyphaseFilter( m_iUpFactor, fCutoffFrequency );
|
||||||
|
}
|
||||||
|
|
||||||
const PolyphaseFilter *m_pPolyphase;
|
const PolyphaseFilter *m_pPolyphase;
|
||||||
PolyphaseFilter::State *m_pState;
|
PolyphaseFilter::State *m_pState;
|
||||||
int m_iUpFactor;
|
int m_iUpFactor;
|
||||||
@@ -528,10 +568,11 @@ void RageSoundReader_Resample_Good::ReopenResampler()
|
|||||||
iUpFactor /= iGCD;
|
iUpFactor /= iGCD;
|
||||||
iDownFactor /= iGCD;
|
iDownFactor /= iGCD;
|
||||||
}
|
}
|
||||||
|
m_iDownFactor = iDownFactor;
|
||||||
|
|
||||||
for( size_t iChannel = 0; iChannel < m_pSource->GetNumChannels(); ++iChannel )
|
for( size_t iChannel = 0; iChannel < m_pSource->GetNumChannels(); ++iChannel )
|
||||||
{
|
{
|
||||||
RageSoundResampler_Polyphase *p = new RageSoundResampler_Polyphase( iUpFactor, iDownFactor );
|
RageSoundResampler_Polyphase *p = new RageSoundResampler_Polyphase( iUpFactor, iDownFactor, iDownFactor );
|
||||||
m_apResamplers.push_back( p );
|
m_apResamplers.push_back( p );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,6 +621,9 @@ int RageSoundReader_Resample_Good::SetPosition_Fast( int iMS )
|
|||||||
|
|
||||||
int RageSoundReader_Resample_Good::Read( char *pBuf_, unsigned iLen )
|
int RageSoundReader_Resample_Good::Read( char *pBuf_, unsigned iLen )
|
||||||
{
|
{
|
||||||
|
for( size_t iChannel = 0; iChannel < m_apResamplers.size(); ++iChannel )
|
||||||
|
m_apResamplers[iChannel]->SetDownFactor( m_iDownFactor );
|
||||||
|
|
||||||
int iChannels = m_apResamplers.size();
|
int iChannels = m_apResamplers.size();
|
||||||
int iBytesPerFrame = sizeof(int16_t) * iChannels;
|
int iBytesPerFrame = sizeof(int16_t) * iChannels;
|
||||||
|
|
||||||
@@ -644,6 +688,7 @@ RageSoundReader_Resample_Good *RageSoundReader_Resample_Good::Copy() const
|
|||||||
ret->m_apResamplers.push_back( new RageSoundResampler_Polyphase(*m_apResamplers[i]) );
|
ret->m_apResamplers.push_back( new RageSoundResampler_Polyphase(*m_apResamplers[i]) );
|
||||||
ret->m_pSource = pSource;
|
ret->m_pSource = pSource;
|
||||||
ret->m_iSampleRate = m_iSampleRate;
|
ret->m_iSampleRate = m_iSampleRate;
|
||||||
|
ret->m_iDownFactor = m_iDownFactor;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ private:
|
|||||||
|
|
||||||
SoundReader *m_pSource;
|
SoundReader *m_pSource;
|
||||||
int m_iSampleRate;
|
int m_iSampleRate;
|
||||||
|
int m_iDownFactor;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user