support dynamic rate changing

This commit is contained in:
Glenn Maynard
2006-11-30 03:57:09 +00:00
parent eee319b535
commit 9e261cca19
2 changed files with 62 additions and 4 deletions
@@ -433,10 +433,10 @@ namespace PolyphaseFilterCache
const PolyphaseFilter *FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency ) const PolyphaseFilter *FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency )
{ {
/* Find a cached filter with the same iUpFactor and a nearby cutoff frequency. /* 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 * Round the cutoff down, if possible; it's better to filter out too much than
* too little. */ * too little. */
PolyphaseFiltersLock.Lock(); PolyphaseFiltersLock.Lock();
pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency) ); pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency + 0.0001f) );
FilterMap::const_iterator it = g_mapPolyphaseFilters.upper_bound( params ); FilterMap::const_iterator it = g_mapPolyphaseFilters.upper_bound( params );
if( it != g_mapPolyphaseFilters.begin() ) if( it != g_mapPolyphaseFilters.begin() )
--it; --it;
@@ -551,9 +551,22 @@ int RageSoundReader_Resample_Good::GetNextSourceFrame() const
return (int) iPosition; return (int) iPosition;
} }
bool RageSoundReader_Resample_Good::SetProperty( const RString &sProperty, float fValue )
{
if( sProperty == "Rate" )
{
SetRate( fValue );
return true;
}
return m_pSource->SetProperty( sProperty, fValue );
}
float RageSoundReader_Resample_Good::GetStreamToSourceRatio() const float RageSoundReader_Resample_Good::GetStreamToSourceRatio() const
{ {
float fRatio = m_pSource->GetStreamToSourceRatio(); float fRatio = m_pSource->GetStreamToSourceRatio();
if( m_fRate != -1 )
fRatio *= m_fRate;
return fRatio; return fRatio;
} }
@@ -561,6 +574,7 @@ RageSoundReader_Resample_Good::RageSoundReader_Resample_Good( RageSoundReader *p
{ {
m_pSource = pSource; m_pSource = pSource;
m_iSampleRate = iSampleRate; m_iSampleRate = iSampleRate;
m_fRate = -1;
ReopenResampler(); ReopenResampler();
} }
@@ -586,11 +600,24 @@ void RageSoundReader_Resample_Good::ReopenResampler()
iUpFactor /= iGCD; iUpFactor /= iGCD;
iDownFactor /= iGCD; iDownFactor /= iGCD;
} }
bool bRateChangingEnabled = m_fRate != -1;
if( bRateChangingEnabled )
{
iUpFactor *= 100;
iDownFactor *= 100;
}
m_iDownFactor = iDownFactor; 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, iDownFactor ); int iMinDownFactor = iDownFactor;
int iMaxDownFactor = iDownFactor;
if( bRateChangingEnabled )
iMaxDownFactor *= 5;
RageSoundResampler_Polyphase *p = new RageSoundResampler_Polyphase( iUpFactor, iMinDownFactor, iMaxDownFactor );
m_apResamplers.push_back( p ); m_apResamplers.push_back( p );
} }
} }
@@ -626,8 +653,12 @@ 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 )
{ {
int iDownFactor = m_iDownFactor;
if( m_fRate != -1 )
lrintf( m_fRate * iDownFactor );
for( size_t iChannel = 0; iChannel < m_apResamplers.size(); ++iChannel ) for( size_t iChannel = 0; iChannel < m_apResamplers.size(); ++iChannel )
m_apResamplers[iChannel]->SetDownFactor( m_iDownFactor ); m_apResamplers[iChannel]->SetDownFactor( iDownFactor );
int iChannels = m_apResamplers.size(); int iChannels = m_apResamplers.size();
int iBytesPerFrame = sizeof(int16_t) * iChannels; int iBytesPerFrame = sizeof(int16_t) * iChannels;
@@ -684,6 +715,26 @@ int RageSoundReader_Resample_Good::Read( char *pBuf_, unsigned iLen )
return iFramesRead * iBytesPerFrame; return iFramesRead * iBytesPerFrame;
} }
/*
* A resampler is commonly used for two things: to change the sample rate of audio,
* in order to give an audio driver what it wants (SetSampleRate), and to change the
* sound of audio, changing its speed and pitch (SetRate). These are the same
* operation, and we do both in the same pass; the only difference is that SetSampleRate
* causes GetSampleRate() to change, while SetRate() causes GetStreamToSourceRatio() to change.
*
* Changing these values will take effect immediately, with a buffering latency of L/4
* frames.
*/
void RageSoundReader_Resample_Good::SetRate( float fRatio )
{
ASSERT( fRatio > 0 );
bool bRateChangingWasEnabled = m_fRate != -1;
m_fRate = fRatio;
if( !bRateChangingWasEnabled )
ReopenResampler();
}
RageSoundReader_Resample_Good::RageSoundReader_Resample_Good( const RageSoundReader_Resample_Good &cpy ): RageSoundReader_Resample_Good::RageSoundReader_Resample_Good( const RageSoundReader_Resample_Good &cpy ):
RageSoundReader(cpy) RageSoundReader(cpy)
{ {
@@ -692,6 +743,7 @@ RageSoundReader_Resample_Good::RageSoundReader_Resample_Good( const RageSoundRea
this->m_pSource = cpy.m_pSource->Copy(); this->m_pSource = cpy.m_pSource->Copy();
this->m_iSampleRate = cpy.m_iSampleRate; this->m_iSampleRate = cpy.m_iSampleRate;
this->m_iDownFactor = cpy.m_iDownFactor; this->m_iDownFactor = cpy.m_iDownFactor;
this->m_fRate = cpy.m_fRate;
} }
RageSoundReader_Resample_Good *RageSoundReader_Resample_Good::Copy() const RageSoundReader_Resample_Good *RageSoundReader_Resample_Good::Copy() const
@@ -21,8 +21,13 @@ public:
int Read( char *pBuf, unsigned iLen ); int Read( char *pBuf, unsigned iLen );
virtual ~RageSoundReader_Resample_Good(); virtual ~RageSoundReader_Resample_Good();
RageSoundReader_Resample_Good *Copy() const; RageSoundReader_Resample_Good *Copy() const;
bool SetProperty( const RString &sProperty, float fValue );
int GetNextSourceFrame() const; int GetNextSourceFrame() const;
float GetStreamToSourceRatio() const; float GetStreamToSourceRatio() const;
RageSoundReader *GetSource() { return m_pSource; }
/* Change the rate of a sound without changing the sample rate. */
void SetRate( float fRatio );
int GetSampleRate() const { return m_iSampleRate; } int GetSampleRate() const { return m_iSampleRate; }
unsigned GetNumChannels() const { return m_pSource->GetNumChannels(); } unsigned GetNumChannels() const { return m_pSource->GetNumChannels(); }
@@ -37,6 +42,7 @@ private:
SoundReader *m_pSource; SoundReader *m_pSource;
int m_iSampleRate; int m_iSampleRate;
int m_iDownFactor; int m_iDownFactor;
float m_fRate;
}; };
#endif #endif