use RageSoundReader_Extend to implement some features
This commit is contained in:
+38
-117
@@ -28,6 +28,7 @@
|
|||||||
#include "PrefsManager.h"
|
#include "PrefsManager.h"
|
||||||
#include "RageSoundUtil.h"
|
#include "RageSoundUtil.h"
|
||||||
|
|
||||||
|
#include "RageSoundReader_Extend.h"
|
||||||
#include "RageSoundReader_Pan.h"
|
#include "RageSoundReader_Pan.h"
|
||||||
#include "RageSoundReader_PitchChange.h"
|
#include "RageSoundReader_PitchChange.h"
|
||||||
#include "RageSoundReader_Preload.h"
|
#include "RageSoundReader_Preload.h"
|
||||||
@@ -218,6 +219,8 @@ bool RageSound::Load( RString sSoundFilePath, bool bPrecache, const RageSoundLoa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pSource = new RageSoundReader_Extend( m_pSource );
|
||||||
|
|
||||||
if( pParams->m_bSupportRateChanging )
|
if( pParams->m_bSupportRateChanging )
|
||||||
{
|
{
|
||||||
RageSoundReader_PitchChange *pRate = new RageSoundReader_PitchChange( m_pSource );
|
RageSoundReader_PitchChange *pRate = new RageSoundReader_PitchChange( m_pSource );
|
||||||
@@ -255,96 +258,35 @@ void RageSound::LoadSoundReader( RageSoundReader *pSound )
|
|||||||
* that would be read. */
|
* that would be read. */
|
||||||
int RageSound::GetData( char *pBuffer, int iFrames )
|
int RageSound::GetData( char *pBuffer, int iFrames )
|
||||||
{
|
{
|
||||||
if( m_Param.m_LengthSeconds != -1 )
|
|
||||||
{
|
|
||||||
/* We have a length; only read up to the end. */
|
|
||||||
const float fLastSecond = m_Param.m_StartSecond + m_Param.m_LengthSeconds;
|
|
||||||
int iFramesToRead = int(fLastSecond*samplerate()) - m_iSourceFrame;
|
|
||||||
|
|
||||||
/* If it's negative, we're past the end, so cap it at 0. Don't read
|
|
||||||
* more than size. */
|
|
||||||
iFrames = clamp( iFramesToRead, 0, iFrames );
|
|
||||||
}
|
|
||||||
|
|
||||||
int iGotFrames = 0;
|
int iGotFrames = 0;
|
||||||
float fRate = 1.0f;
|
float fRate = 1.0f;
|
||||||
int iSourceFrame = m_iSourceFrame;
|
int iSourceFrame = m_iSourceFrame;
|
||||||
if( m_iSourceFrame < 0 )
|
|
||||||
|
if( iFrames == 0 )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Read data from our source. */
|
||||||
|
ASSERT( m_pSource );
|
||||||
|
iGotFrames = m_pSource->RetriedRead( pBuffer, iFrames, &iSourceFrame, &fRate );
|
||||||
|
|
||||||
|
if( iGotFrames == RageSoundReader::ERROR )
|
||||||
{
|
{
|
||||||
/* We havn't *really* started playing yet, so just feed silence. How
|
Fail( m_pSource->GetError() );
|
||||||
* many more bytes of silence do we need? */
|
|
||||||
iSourceFrame = m_iSourceFrame;
|
/* Pretend we got EOF. */
|
||||||
iGotFrames = -m_iSourceFrame;
|
return RageSoundReader::END_OF_FILE;
|
||||||
iGotFrames = min( iGotFrames, iFrames );
|
|
||||||
memset( pBuffer, 0, iGotFrames*framesize );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( iGotFrames == 0 && iFrames )
|
if( iGotFrames < 0 )
|
||||||
{
|
return iGotFrames;
|
||||||
/* Read data from our source. */
|
|
||||||
ASSERT( m_pSource );
|
|
||||||
|
|
||||||
int iNewSourceFrame;
|
ASSERT_M( iGotFrames >= 0, ssprintf("%i", iGotFrames) ); // unhandled error condition
|
||||||
iGotFrames = m_pSource->RetriedRead( pBuffer, iFrames, &iNewSourceFrame, &fRate );
|
|
||||||
|
|
||||||
if( iGotFrames == RageSoundReader::ERROR )
|
if( m_pSource->GetNumChannels() == 1 )
|
||||||
{
|
RageSoundUtil::ConvertMonoToStereoInPlace( (int16_t *) pBuffer, iGotFrames );
|
||||||
Fail( m_pSource->GetError() );
|
|
||||||
|
|
||||||
/* Pretend we got EOF. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iGotFrames == RageSoundReader::END_OF_FILE )
|
|
||||||
iGotFrames = 0;
|
|
||||||
|
|
||||||
/* If we didn't get any data, don't update iSourceFrame, so we just keep
|
|
||||||
* extrapolating if we're in M_CONTINUE. */
|
|
||||||
if( iGotFrames == 0 )
|
|
||||||
iSourceFrame = iNewSourceFrame;
|
|
||||||
|
|
||||||
if( m_pSource->GetNumChannels() == 1 )
|
|
||||||
RageSoundUtil::ConvertMonoToStereoInPlace( (int16_t *) pBuffer, iGotFrames );
|
|
||||||
}
|
|
||||||
// LOG->Trace( "add %i, %f (%i)", iSourceFrame, fRate, iGotFrames );
|
// LOG->Trace( "add %i, %f (%i)", iSourceFrame, fRate, iGotFrames );
|
||||||
|
|
||||||
/* If we didn't get any data, see if we need to pad the end of the file with
|
|
||||||
* silence for m_LengthSeconds. */
|
|
||||||
if( iGotFrames == 0 && m_Param.m_LengthSeconds != -1 )
|
|
||||||
{
|
|
||||||
const float fLastSecond = m_Param.m_StartSecond + m_Param.m_LengthSeconds;
|
|
||||||
int iLastFrame = int(fLastSecond*samplerate());
|
|
||||||
int iFramesOfSilence = iLastFrame - m_iSourceFrame;
|
|
||||||
iFramesOfSilence = clamp( iFramesOfSilence, 0, iFrames );
|
|
||||||
if( iFramesOfSilence > 0 )
|
|
||||||
{
|
|
||||||
memset( pBuffer, 0, iFramesOfSilence * framesize );
|
|
||||||
iGotFrames = iFramesOfSilence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iGotFrames == 0 && GetStopMode() == RageSoundParams::M_CONTINUE )
|
|
||||||
{
|
|
||||||
/* Keep playing silence past EOF. */
|
|
||||||
memset( pBuffer, 0, iFrames*framesize );
|
|
||||||
iGotFrames = iFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We want to fade when there's m_FadeLength seconds left, but if
|
|
||||||
* m_LengthFrames is -1, we don't know the length we're playing.
|
|
||||||
* (m_LengthFrames is the length to play, not the length of the
|
|
||||||
* source.) If we don't know the length, don't fade. */
|
|
||||||
if( m_Param.m_FadeLength != 0 && m_Param.m_LengthSeconds != -1 )
|
|
||||||
{
|
|
||||||
const float fFinishFadingOutAt = m_Param.m_StartSecond + m_Param.m_LengthSeconds;
|
|
||||||
const float fStartFadingOutAt = fFinishFadingOutAt - m_Param.m_FadeLength;
|
|
||||||
const float fStartSecond = float(iSourceFrame) / samplerate();
|
|
||||||
const float fEndSecond = float(iSourceFrame+lrintf(iGotFrames * fRate)) / samplerate();
|
|
||||||
const float fStartVolume = SCALE( fStartSecond, fStartFadingOutAt, fFinishFadingOutAt, 1.0f, 0.0f );
|
|
||||||
const float fEndVolume = SCALE( fEndSecond, fStartFadingOutAt, fFinishFadingOutAt, 1.0f, 0.0f );
|
|
||||||
RageSoundUtil::Fade( (int16_t *) pBuffer, iGotFrames, fStartVolume, fEndVolume );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Mutex.Lock();
|
m_Mutex.Lock();
|
||||||
m_StreamToSourceMap.Insert( m_iStreamFrame, iGotFrames, iSourceFrame, fRate );
|
m_StreamToSourceMap.Insert( m_iStreamFrame, iGotFrames, iSourceFrame, fRate );
|
||||||
m_Mutex.Unlock();
|
m_Mutex.Unlock();
|
||||||
@@ -382,44 +324,8 @@ int RageSound::GetDataToPlay( int16_t *pBuffer, int iFrames, int64_t &iStreamFra
|
|||||||
{
|
{
|
||||||
/* Get a block of data. */
|
/* Get a block of data. */
|
||||||
int iGotFrames = GetData( (char *) pBuffer, iFrames );
|
int iGotFrames = GetData( (char *) pBuffer, iFrames );
|
||||||
|
if( iGotFrames < 0 )
|
||||||
if( !iGotFrames )
|
return iGotFrames;
|
||||||
{
|
|
||||||
/* EOF. */
|
|
||||||
switch( GetStopMode() )
|
|
||||||
{
|
|
||||||
case RageSoundParams::M_STOP:
|
|
||||||
/* Not looping. Normally, we'll just stop here. */
|
|
||||||
return RageSoundReader::END_OF_FILE;
|
|
||||||
|
|
||||||
case RageSoundParams::M_LOOP:
|
|
||||||
/* Rewind and restart. */
|
|
||||||
iNumRewindsThisCall++;
|
|
||||||
if( iNumRewindsThisCall > 3 )
|
|
||||||
{
|
|
||||||
/* We're rewinding a bunch of times in one call. This probably means
|
|
||||||
* that the length is too short. It might also mean that the start
|
|
||||||
* position is very close to the end of the file, so we're looping
|
|
||||||
* over the remainder. If we keep doing this, we'll chew CPU rewinding,
|
|
||||||
* so stop. */
|
|
||||||
LOG->Warn( "Sound %s is busy looping. Sound stopped (start = %f, length = %f)",
|
|
||||||
GetLoadedFilePath().c_str(), m_Param.m_StartSecond, m_Param.m_LengthSeconds );
|
|
||||||
|
|
||||||
return RageSoundReader::END_OF_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rewind and start over. XXX: this will take an exclusive lock */
|
|
||||||
SetPositionSeconds( m_Param.m_StartSecond );
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case RageSoundParams::M_CONTINUE:
|
|
||||||
FAIL_M("M_CONTINUE");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iFramesStored += iGotFrames;
|
iFramesStored += iGotFrames;
|
||||||
iFrames -= iGotFrames;
|
iFrames -= iGotFrames;
|
||||||
@@ -775,6 +681,21 @@ void RageSound::ApplyParams()
|
|||||||
|
|
||||||
m_pSource->SetProperty( "Pitch", m_Param.m_fPitch );
|
m_pSource->SetProperty( "Pitch", m_Param.m_fPitch );
|
||||||
m_pSource->SetProperty( "Speed", m_Param.m_fSpeed );
|
m_pSource->SetProperty( "Speed", m_Param.m_fSpeed );
|
||||||
|
m_pSource->SetProperty( "StartSecond", m_Param.m_StartSecond );
|
||||||
|
m_pSource->SetProperty( "LengthSeconds", m_Param.m_LengthSeconds );
|
||||||
|
m_pSource->SetProperty( "FadeSeconds", m_Param.m_FadeLength );
|
||||||
|
switch( GetStopMode() )
|
||||||
|
{
|
||||||
|
case RageSoundParams::M_LOOP:
|
||||||
|
m_pSource->SetProperty( "Loop", 1.0f );
|
||||||
|
break;
|
||||||
|
case RageSoundParams::M_STOP:
|
||||||
|
m_pSource->SetProperty( "Stop", 1.0f );
|
||||||
|
break;
|
||||||
|
case RageSoundParams::M_CONTINUE:
|
||||||
|
m_pSource->SetProperty( "Continue", 1.0f );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RageSound::SetProperty( const RString &sProperty, float fValue )
|
bool RageSound::SetProperty( const RString &sProperty, float fValue )
|
||||||
|
|||||||
Reference in New Issue
Block a user