Switch to floating-point sound internally.

This allows us to change the volume of sounds in filters ("volume",
"fade" properties) without quantizing the audio prematurely.  Previously,
we had a hack to apply volume changes as a mixing-time step.  This
can be done at any point in the filter chain now.

This also means we only need to worry about clipping at the very
last mixing step, instead of at every place we change sound.

Dithering for 16-bit audio and more intelligent gain control
is possible, as we have full-resolution, unclipped sound at the
mixing phase.

We support high resolution source sounds; both Vorbis and MAD
supply more than 16 bits.

Several filters, such as resampling, are easier to implement as
floats; these no longer need to convert back and forth.

Negatives:
 - More memory use.  The main case of this is in RageSoundReader_Preload,
which will be fixed: we can preload in 16-bit without losing most of the
above.
 - Some extra overhead for accessing more memory.
This commit is contained in:
Glenn Maynard
2007-01-27 07:14:58 +00:00
parent cc8182fb7e
commit 1bd5513698
33 changed files with 185 additions and 150 deletions
+14 -19
View File
@@ -14,7 +14,6 @@ RageSoundMixBuffer::RageSoundMixBuffer()
m_iBufSize = m_iBufUsed = 0;
m_pMixbuf = NULL;
m_iOffset = 0;
SetVolume( 1.0f );
#ifdef USE_VEC
g_bVector = Vector::CheckForVector();
#endif
@@ -25,11 +24,6 @@ RageSoundMixBuffer::~RageSoundMixBuffer()
free( m_pMixbuf );
}
void RageSoundMixBuffer::SetVolume( float f )
{
m_iVolumeFactor = int(256*f);
}
/* write() will start mixing iOffset samples into the buffer. Be careful; this is
* measured in samples, not frames, so if the data is stereo, multiply by two. */
void RageSoundMixBuffer::SetWriteOffset( int iOffset )
@@ -42,18 +36,18 @@ void RageSoundMixBuffer::Extend( unsigned iSamples )
const unsigned realsize = iSamples+m_iOffset;
if( m_iBufSize < realsize )
{
m_pMixbuf = (int32_t *) realloc( m_pMixbuf, sizeof(int32_t) * realsize );
m_pMixbuf = (float *) realloc( m_pMixbuf, sizeof(float) * realsize );
m_iBufSize = realsize;
}
if( m_iBufUsed < realsize )
{
memset( m_pMixbuf + m_iBufUsed, 0, (realsize - m_iBufUsed) * sizeof(int32_t) );
memset( m_pMixbuf + m_iBufUsed, 0, (realsize - m_iBufUsed) * sizeof(float) );
m_iBufUsed = realsize;
}
}
void RageSoundMixBuffer::write( const int16_t *pBuf, unsigned iSize, int iSourceStride, int iDestStride )
void RageSoundMixBuffer::write( const float *pBuf, unsigned iSize, int iSourceStride, int iDestStride )
{
if( iSize == 0 )
return;
@@ -63,17 +57,19 @@ void RageSoundMixBuffer::write( const int16_t *pBuf, unsigned iSize, int iSource
Extend( iSize * iDestStride - (iDestStride-1) );
/* Scale volume and add. */
int32_t *pDestBuf = m_pMixbuf+m_iOffset;
#ifdef USE_VEC
float *pDestBuf = m_pMixbuf+m_iOffset;
/* #ifdef USE_VEC
if( g_bVector && iSourceStride == 1 && iDestStride == 1 )
{
Vector::FastSoundWrite( pDestBuf, pBuf, iSize, m_iVolumeFactor );
Vector::FastSoundWrite( pDestBuf, pBuf, iSize, 1 );
return;
}
#endif
#endif */
while( iSize )
{
*pDestBuf += *pBuf * m_iVolumeFactor;
*pDestBuf += *pBuf;
pBuf += iSourceStride;
pDestBuf += iDestStride;
--iSize;
@@ -92,8 +88,9 @@ void RageSoundMixBuffer::read( int16_t *pBuf )
#endif
for( unsigned iPos = 0; iPos < m_iBufUsed; ++iPos )
{
int32_t iOut = (m_pMixbuf[iPos]) / 256;
pBuf[iPos] = (int16_t) clamp( iOut, -32768, 32767 );
float iOut = m_pMixbuf[iPos];
iOut = clamp( iOut, -1.0f, +1.0f );
pBuf[iPos] = lrintf(iOut * 32767);
}
m_iBufUsed = 0;
}
@@ -108,11 +105,9 @@ void RageSoundMixBuffer::read( float *pBuf )
return;
}
#endif
const int iMinimum = -32768 * 256;
const int iMaximum = 32767 * 256;
for( unsigned pos = 0; pos < m_iBufUsed; ++pos )
pBuf[pos] = SCALE( (float)m_pMixbuf[pos], iMinimum, iMaximum, -1.0f, 1.0f );
pBuf[pos] = m_pMixbuf[pos];
m_iBufUsed = 0;
}
+3 -4
View File
@@ -10,22 +10,21 @@ public:
~RageSoundMixBuffer();
/* Mix the given buffer of samples. */
void write( const int16_t *buf, unsigned size, int iSourceStride = 1, int iDestStride = 1 );
void write( const float *pBuf, unsigned iSize, int iSourceStride = 1, int iDestStride = 1 );
/* Extend the buffer as if write() was called with a buffer of silence. */
void Extend( unsigned iSamples );
void read( int16_t *pBuf );
void read( float *pBuf );
float *read() { return m_pMixbuf; }
unsigned size() const { return m_iBufUsed; }
void SetVolume( float f );
void SetWriteOffset( int iOffset );
private:
int32_t *m_pMixbuf;
float *m_pMixbuf;
unsigned m_iBufSize; /* actual allocated samples */
unsigned m_iBufUsed; /* used samples */
int m_iVolumeFactor; /* vol * 256 */
int m_iOffset;
};
+1 -1
View File
@@ -6,7 +6,7 @@
REGISTER_CLASS_TRAITS( RageSoundReader, pCopy->Copy() );
/* Read(), handling the STREAM_LOOPED and empty return cases. */
int RageSoundReader::RetriedRead( int16_t *pBuffer, int iFrames, int *iSourceFrame, float *fRate )
int RageSoundReader::RetriedRead( float *pBuffer, int iFrames, int *iSourceFrame, float *fRate )
{
if( iFrames == 0 )
return 0;
+2 -2
View File
@@ -9,7 +9,7 @@ public:
virtual int GetLength() const = 0; /* ms */
virtual int GetLength_Fast() const { return GetLength(); } /* ms */
virtual int SetPosition( int iSample ) = 0;
virtual int Read( int16_t *pBuf, int iFrames ) = 0;
virtual int Read( float *pBuf, int iFrames ) = 0;
virtual ~RageSoundReader() { }
virtual RageSoundReader *Copy() const = 0;
virtual int GetSampleRate() const = 0;
@@ -40,7 +40,7 @@ public:
virtual float GetStreamToSourceRatio() const = 0;
virtual RString GetError() const = 0;
int RetriedRead( int16_t *pBuffer, int iFrames, int *iSourceFrame = NULL, float *fRate = NULL );
int RetriedRead( float *pBuffer, int iFrames, int *iSourceFrame = NULL, float *fRate = NULL );
};
#endif
+3 -3
View File
@@ -299,7 +299,7 @@ float RageSoundReader_Chain::GetStreamToSourceRatio() const
/* As we iterate through the sound tree, we'll find that we need data from different
* sounds; a sound may be needed by more than one other sound. */
int RageSoundReader_Chain::Read( int16_t *pBuffer, int iFrames )
int RageSoundReader_Chain::Read( float *pBuffer, int iFrames )
{
while( m_iNextSound < m_aSounds.size() && m_iCurrentFrame == m_aSounds[m_iNextSound].GetOffsetFrame(m_iActualSampleRate) )
{
@@ -339,14 +339,14 @@ int RageSoundReader_Chain::Read( int16_t *pBuffer, int iFrames )
{
/* If we have more sounds ahead of us, pretend we read the entire block, since
* there's silence in between. Otherwise, we're at EOF. */
memset( pBuffer, 0, iFrames * m_iChannels * sizeof(int16_t) );
memset( pBuffer, 0, iFrames * m_iChannels * sizeof(float) );
m_iCurrentFrame += iFrames;
return iFrames;
}
RageSoundMixBuffer mix;
/* Read iFrames from each sound. */
int16_t Buffer[2048];
float Buffer[2048];
iFrames = min( iFrames, (int) (ARRAYLEN(Buffer) / m_iChannels) );
for( unsigned i = 0; i < m_apActiveSounds.size(); )
{
+1 -1
View File
@@ -34,7 +34,7 @@ public:
int GetLength() const;
int GetLength_Fast() const;
int SetPosition( int iFrame );
int Read( int16_t *pBuf, int iFrames );
int Read( float *pBuf, int iFrames );
int GetSampleRate() const { return m_iActualSampleRate; }
unsigned GetNumChannels() const { return m_iChannels; }
bool SetProperty( const RString &sProperty, float fValue );
@@ -77,7 +77,7 @@ public:
/* m_sBuffer[0] corresponds to frame number m_iBufferPositionFrames. */
int m_iBufferPositionFrames;
vector<int16_t> m_sBuffer;
vector<float> m_sBuffer;
};
int RageSoundReader_Split::GetLength() const { return m_pImpl->m_pSource->GetLength(); }
@@ -132,13 +132,13 @@ bool RageSoundReader_Split::SetProperty( const RString &sProperty, float fValue
return m_pImpl->m_pSource->SetProperty( sProperty, fValue );
}
int RageSoundReader_Split::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_Split::Read( float *pBuf, int iFrames )
{
m_iRequestFrames = iFrames;
int iRet = m_pImpl->ReadBuffer();
int iSamplesAvailable = m_pImpl->m_sBuffer.size();
const int16_t *pSrc = &m_pImpl->m_sBuffer[0];
const float *pSrc = &m_pImpl->m_sBuffer[0];
if( m_pImpl->m_iBufferPositionFrames < m_iPositionFrame )
{
int iSkipFrames = m_iPositionFrame - m_pImpl->m_iBufferPositionFrames;
+1 -1
View File
@@ -17,7 +17,7 @@ public:
virtual int GetLength() const;
virtual int GetLength_Fast() const;
virtual int SetPosition( int iFrame );
virtual int Read( int16_t *pBuf, int iFrames );
virtual int Read( float *pBuf, int iFrames );
virtual int GetSampleRate() const;
virtual unsigned GetNumChannels() const;
virtual bool SetProperty( const RString &sProperty, float fValue );
+4 -4
View File
@@ -48,7 +48,7 @@ int RageSoundReader_Extend::GetEndFrame() const
return m_iStartFrames + m_iLengthFrames;
}
int RageSoundReader_Extend::GetData( int16_t *pBuffer, int iFrames )
int RageSoundReader_Extend::GetData( float *pBuffer, int iFrames )
{
int iFramesToRead = iFrames;
if( m_iLengthFrames != -1 )
@@ -66,7 +66,7 @@ int RageSoundReader_Extend::GetData( int16_t *pBuffer, int iFrames )
iFramesToRead = min( iFramesToRead, -m_iPositionFrames );
m_iPositionFrames += iFramesToRead;
memset( pBuffer, 0, iFramesToRead * sizeof(int16_t) * this->GetNumChannels() );
memset( pBuffer, 0, iFramesToRead * sizeof(float) * this->GetNumChannels() );
return iFramesToRead;
}
@@ -80,7 +80,7 @@ int RageSoundReader_Extend::GetData( int16_t *pBuffer, int iFrames )
return iRet;
}
int RageSoundReader_Extend::Read( int16_t *pBuffer, int iFrames )
int RageSoundReader_Extend::Read( float *pBuffer, int iFrames )
{
int iFramesRead = GetData( pBuffer, iFrames );
if( iFramesRead == RageSoundReader::END_OF_FILE )
@@ -91,7 +91,7 @@ int RageSoundReader_Extend::Read( int16_t *pBuffer, int iFrames )
iFramesRead = iFrames;
if( m_StopMode != M_CONTINUE )
iFramesRead = min( GetEndFrame() - m_iPositionFrames, iFramesRead );
memset( pBuffer, 0, iFramesRead * sizeof(int16_t) * this->GetNumChannels() );
memset( pBuffer, 0, iFramesRead * sizeof(float) * this->GetNumChannels() );
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ class RageSoundReader_Extend: public RageSoundReader_Filter
public:
RageSoundReader_Extend( RageSoundReader *pSource );
virtual int SetPosition( int iFrame );
virtual int Read( int16_t *pBuffer, int iFrames );
virtual int Read( float *pBuffer, int iFrames );
virtual int GetNextSourceFrame() const;
virtual bool SetProperty( const RString &sProperty, float fValue );
@@ -19,7 +19,7 @@ public:
private:
int GetEndFrame() const;
int GetData( int16_t *pBuffer, int iFrames );
int GetData( float *pBuffer, int iFrames );
int m_iPositionFrames;
+1 -1
View File
@@ -16,7 +16,7 @@ public:
virtual int GetLength() const { return m_pSource->GetLength(); }
virtual int GetLength_Fast() const { return m_pSource->GetLength_Fast(); }
virtual int SetPosition( int iFrame ) { return m_pSource->SetPosition( iFrame ); }
virtual int Read( int16_t *pBuf, int iFrames ) { return m_pSource->Read( pBuf, iFrames ); }
virtual int Read( float *pBuf, int iFrames ) { return m_pSource->Read( pBuf, iFrames ); }
virtual int GetSampleRate() const { return m_pSource->GetSampleRate(); }
virtual unsigned GetNumChannels() const { return m_pSource->GetNumChannels(); }
virtual bool SetProperty( const RString &sProperty, float fValue ) { return m_pSource->SetProperty( sProperty, fValue ); }
+16 -17
View File
@@ -204,7 +204,8 @@ struct madlib_t
bitrate = 0;
}
uint8_t inbuf[16384], outbuf[8192];
uint8_t inbuf[16384];
float outbuf[8192];
int outpos;
unsigned outleft;
@@ -268,7 +269,7 @@ struct madlib_t
static signed int scale(mad_fixed_t sample)
static float scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
@@ -279,8 +280,7 @@ static signed int scale(mad_fixed_t sample)
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
return (double) sample / (1<<MAD_F_FRACBITS);
}
static int get_this_frame_byte( const madlib_t *mad )
@@ -542,9 +542,9 @@ void RageSoundReader_MP3::synth_output()
{
for(int chan = 0; chan < this->Channels; ++chan)
{
short Sample = (short) scale(mad->Synth.pcm.samples[chan][i]);
*((short *) (mad->outbuf + mad->outleft)) = Sample;
mad->outleft += 2;
float Sample = scale(mad->Synth.pcm.samples[chan][i]);
mad->outbuf[mad->outleft] = Sample;
++mad->outleft;
}
}
}
@@ -743,7 +743,7 @@ static void mono_to_stereo( char *dst, const char *src, unsigned len )
}
}
int RageSoundReader_MP3::Read( int16_t *buf, int iFrames )
int RageSoundReader_MP3::Read( float *buf, int iFrames )
{
int iFramesWritten = 0;
@@ -751,17 +751,17 @@ int RageSoundReader_MP3::Read( int16_t *buf, int iFrames )
{
if( mad->outleft > 0 )
{
int iFramesToCopy = min( iFrames, int(mad->outleft / (sizeof(int16_t) * GetNumChannels())) );
int iFramesToCopy = min( iFrames, int(mad->outleft / GetNumChannels()) );
const int iSamplesToCopy = iFramesToCopy * GetNumChannels();
const int iBytesToCopy = iSamplesToCopy * sizeof(int16_t);
const int iBytesToCopy = iSamplesToCopy * sizeof(float);
memcpy( buf, mad->outbuf + mad->outpos, iBytesToCopy );
buf += iSamplesToCopy;
iFrames -= iFramesToCopy;
iFramesWritten += iFramesToCopy;
mad->outpos += iBytesToCopy;
mad->outleft -= iBytesToCopy;
mad->outpos += iSamplesToCopy;
mad->outleft -= iSamplesToCopy;
continue;
}
@@ -936,10 +936,9 @@ int RageSoundReader_MP3::SetPosition_hard( int iFrame )
int samples = mad_timer_count( skip, (mad_units) SampleRate );
/* Skip 'samples' samples; each sample is 2 * channels bytes, since
* we're currently always using AUDIO_S16SYS. */
mad->outpos = samples * 2 * this->Channels;
mad->outleft -= samples * 2 * this->Channels;
/* Skip 'samples' samples. */
mad->outpos = samples * this->Channels;
mad->outleft -= samples * this->Channels;
return 1;
}
@@ -1052,7 +1051,7 @@ bool RageSoundReader_MP3::SetProperty( const RString &sProperty, float fValue )
int RageSoundReader_MP3::GetNextSourceFrame() const
{
int iFrame = mad_timer_count( mad->Timer, mad_units(mad->Frame.header.samplerate) );
iFrame += mad->outpos / (sizeof(int16_t) * this->Channels);
iFrame += mad->outpos / this->Channels;
return iFrame;
}
+1 -1
View File
@@ -16,7 +16,7 @@ public:
int GetLength() const { return GetLengthConst(false); }
int GetLength_Fast() const { return GetLengthConst(true); }
int SetPosition( int iSample );
int Read( int16_t *pBuf, int iFrames );
int Read( float *pBuf, int iFrames );
unsigned GetNumChannels() const { return Channels; }
int GetSampleRate() const { return SampleRate; }
int GetNextSourceFrame() const;
+1 -1
View File
@@ -9,7 +9,7 @@ RageSoundReader_Pan::RageSoundReader_Pan( RageSoundReader *pSource ):
}
int RageSoundReader_Pan::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_Pan::Read( float *pBuf, int iFrames )
{
iFrames = m_pSource->Read( pBuf, iFrames );
if( iFrames < 0 )
+1 -1
View File
@@ -11,7 +11,7 @@ public:
RageSoundReader_Pan( RageSoundReader *pSource );
RageSoundReader_Pan *Copy() const { return new RageSoundReader_Pan(*this); }
virtual unsigned GetNumChannels() const;
virtual int Read( int16_t *pBuf, int iFrames );
virtual int Read( float *pBuf, int iFrames );
virtual bool SetProperty( const RString &sProperty, float fValue );
private:
@@ -40,7 +40,7 @@ RageSoundReader_PitchChange::RageSoundReader_PitchChange( const RageSoundReader_
m_fLastSetPitchRatio = cpy.m_fLastSetPitchRatio;
}
int RageSoundReader_PitchChange::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_PitchChange::Read( float *pBuf, int iFrames )
{
/* m_pSpeedChange->NextReadWillStep is true if speed changes will be applied
* immediately on the next Read(). When this is true, apply the ratio to the
+1 -1
View File
@@ -13,7 +13,7 @@ public:
RageSoundReader_PitchChange( RageSoundReader *pSource );
RageSoundReader_PitchChange( const RageSoundReader_PitchChange &cpy );
virtual int Read( int16_t *pBuf, int iFrames );
virtual int Read( float *pBuf, int iFrames );
virtual bool SetProperty( const RString &sProperty, float fValue );
void SetSpeedRatio( float fRatio ) { m_fSpeedRatio = fRatio; }
@@ -15,7 +15,7 @@ RageSoundReader_PostBuffering::RageSoundReader_PostBuffering( RageSoundReader *p
}
int RageSoundReader_PostBuffering::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_PostBuffering::Read( float *pBuf, int iFrames )
{
iFrames = m_pSource->Read( pBuf, iFrames );
if( iFrames < 0 )
@@ -10,7 +10,7 @@ class RageSoundReader_PostBuffering: public RageSoundReader_Filter
public:
RageSoundReader_PostBuffering( RageSoundReader *pSource );
RageSoundReader_PostBuffering *Copy() const { return new RageSoundReader_PostBuffering(*this); }
virtual int Read( int16_t *pBuf, int iFrames );
virtual int Read( float *pBuf, int iFrames );
virtual bool SetProperty( const RString &sProperty, float fValue );
private:
+3 -3
View File
@@ -5,7 +5,7 @@
#include "RageSoundReader_Preload.h"
#include "RageUtil.h"
#define samplesize (sizeof(int16_t) * m_iChannels) /* 16-bit */
#define samplesize (sizeof(float) * m_iChannels) /* 16-bit */
/* If a sound is smaller than this, we'll load it entirely into memory. */
const unsigned max_prebuf_size = 1024*256;
@@ -61,7 +61,7 @@ bool RageSoundReader_Preload::Open( RageSoundReader *pSource )
if( pSource->GetStreamToSourceRatio() != m_fRate )
return false; /* Don't bother trying to preload it. */
int16_t buffer[1024];
float buffer[1024];
int iCnt = pSource->Read( buffer, ARRAYSIZE(buffer) / m_iChannels );
if( iCnt == END_OF_FILE )
@@ -110,7 +110,7 @@ int RageSoundReader_Preload::GetNextSourceFrame() const
return lrintf(m_iPosition * m_fRate);
}
int RageSoundReader_Preload::Read( int16_t *pBuffer, int iFrames )
int RageSoundReader_Preload::Read( float *pBuffer, int iFrames )
{
const int iSizeFrames = m_Buffer->size() / samplesize;
const int iFramesAvail = iSizeFrames - m_iPosition;
+1 -1
View File
@@ -16,7 +16,7 @@ public:
int GetLength() const;
int GetLength_Fast() const;
int SetPosition( int iFrame );
int Read( int16_t *pBuffer, int iLength );
int Read( float *pBuffer, int iLength );
int GetSampleRate() const { return m_iSampleRate; }
unsigned GetNumChannels() const { return m_iChannels; }
int GetNextSourceFrame() const;
@@ -647,7 +647,7 @@ int RageSoundReader_Resample_Good::SetPosition( int iFrame )
return m_pSource->SetPosition( iFrame );
}
int RageSoundReader_Resample_Good::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_Resample_Good::Read( float *pBuf, int iFrames )
{
int iChannels = m_apResamplers.size();
@@ -663,7 +663,7 @@ int RageSoundReader_Resample_Good::Read( int16_t *pBuf, int iFrames )
{
int iFramesNeeded = m_apResamplers[0]->NumInputsForOutputSamples(iFrames);
int16_t *pTmpBuf = (int16_t *) alloca( iFramesNeeded * sizeof(int16_t) * iChannels );
float *pTmpBuf = (float *) alloca( iFramesNeeded * sizeof(float) * iChannels );
ASSERT( pTmpBuf );
int iFramesIn = m_pSource->Read( pTmpBuf, iFramesNeeded );
if( iFramesIn < 0 )
@@ -676,7 +676,7 @@ int RageSoundReader_Resample_Good::Read( int16_t *pBuf, int iFrames )
for( int iChannel = 0; iChannel < iChannels; ++iChannel )
{
{
int16_t *pBufIn = pTmpBuf + iChannel;
float *pBufIn = pTmpBuf + iChannel;
float *pBufOut = pFloatBuf;
for( int i = 0; i < iSamplesIn; i += iChannels )
*(pBufOut++) = (float) pBufIn[i];
@@ -685,10 +685,10 @@ int RageSoundReader_Resample_Good::Read( int16_t *pBuf, int iFrames )
int iGotFrames = m_apResamplers[iChannel]->Run( pFloatBuf, iFramesIn, pFloatOut, iFrames );
ASSERT( iGotFrames <= iFrames );
int16_t *pBufOut = pBuf + iChannel;
float *pBufOut = pBuf + iChannel;
for( int i = 0; i < iGotFrames; ++i )
{
*pBufOut = int16_t(lrintf(clamp(pFloatOut[i], -32768, 32767)));
*pBufOut = pFloatOut[i];
pBufOut += iChannels;
}
if( iChannel == 0 )
@@ -15,7 +15,7 @@ public:
RageSoundReader_Resample_Good( RageSoundReader *pSource, int iSampleRate );
RageSoundReader_Resample_Good( const RageSoundReader_Resample_Good &cpy );
int SetPosition( int iFrame );
int Read( int16_t *pBuf, int iFrames );
int Read( float *pBuf, int iFrames );
virtual ~RageSoundReader_Resample_Good();
RageSoundReader_Resample_Good *Copy() const;
bool SetProperty( const RString &sProperty, float fValue );
+17 -17
View File
@@ -44,7 +44,7 @@ void RageSoundReader_SpeedChange::Reset()
m_fErrorFrames = 0;
}
static int FindClosestMatch( const int16_t *pBuffer, int iBufferSize, const int16_t *pCorrelateBuffer, int iCorrelateBufferSize, int iStride )
static int FindClosestMatch( const float *pBuffer, int iBufferSize, const float *pCorrelateBuffer, int iCorrelateBufferSize, int iStride )
{
if( iBufferSize <= iCorrelateBufferSize )
return 0;
@@ -55,20 +55,20 @@ static int FindClosestMatch( const int16_t *pBuffer, int iBufferSize, const int1
int iBufferDistanceToSearch = iBufferSize - iCorrelateBufferSize;
int iBestOffset = 0;
int iBestScore = 0;
int fBestScore = 0;
for( int i = 0; i < iBufferDistanceToSearch; i += iStride )
{
int iScore = 0;
const int16_t *pFrames = pBuffer + i;
float fScore = 0;
const float *pFrames = pBuffer + i;
for( int j = 0; j < iCorrelateBufferSize; j += iStride )
{
int iDiff = pFrames[j] - pCorrelateBuffer[j];
iScore += abs(iDiff);
float fDiff = pFrames[j] - pCorrelateBuffer[j];
fScore += fabsf(fDiff);
}
if( i == 0 || iScore < iBestScore )
if( i == 0 || fScore < fBestScore )
{
iBestScore = iScore;
fBestScore = fScore;
iBestOffset = i;
}
}
@@ -85,11 +85,11 @@ int RageSoundReader_SpeedChange::FillData( int iMaxFrames )
while( iMaxFrames > 0 )
{
int iFramesToRead = iMaxFrames - m_iDataBufferAvailFrames;
int iBytesToRead = iFramesToRead * m_Channels.size() * sizeof(int16_t);
int iBytesToRead = iFramesToRead * m_Channels.size() * sizeof(float);
if( iBytesToRead <= 0 )
return m_iDataBufferAvailFrames;
int16_t *pTempBuffer = (int16_t *) alloca( iBytesToRead );
float *pTempBuffer = (float *) alloca( iBytesToRead );
int iGotFrames = m_pSource->Read( pTempBuffer, iFramesToRead );
if( iGotFrames < 0 )
{
@@ -105,8 +105,8 @@ int RageSoundReader_SpeedChange::FillData( int iMaxFrames )
if( (int) c.m_DataBuffer.size() < iMaxFrames )
c.m_DataBuffer.resize( iMaxFrames );
const int16_t *pIn = pTempBuffer + i;
int16_t *pOut = &c.m_DataBuffer[m_iDataBufferAvailFrames];
const float *pIn = pTempBuffer + i;
float *pOut = &c.m_DataBuffer[m_iDataBufferAvailFrames];
for( int j = 0; j < iGotFrames; ++j )
{
*pOut = *pIn;
@@ -133,7 +133,7 @@ void RageSoundReader_SpeedChange::EraseData( int iFramesToDelete )
{
ChannelInfo &c = m_Channels[i];
if( iFramesToMove )
memmove( &c.m_DataBuffer[0], &c.m_DataBuffer[iFramesToDelete], iFramesToMove * sizeof(int16_t) );
memmove( &c.m_DataBuffer[0], &c.m_DataBuffer[iFramesToDelete], iFramesToMove * sizeof(float) );
ASSERT( c.m_iCorrelatedPos >= iFramesToDelete );
c.m_iCorrelatedPos -= iFramesToDelete;
}
@@ -233,7 +233,7 @@ int RageSoundReader_SpeedChange::GetCursorAvail() const
return iCursorAvail;
}
int RageSoundReader_SpeedChange::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_SpeedChange::Read( float *pBuf, int iFrames )
{
while( 1 )
{
@@ -269,9 +269,9 @@ int RageSoundReader_SpeedChange::Read( int16_t *pBuf, int iFrames )
for( size_t i = 0; i < m_Channels.size(); ++i )
{
ChannelInfo &c = m_Channels[i];
int i1 = c.m_DataBuffer[c.m_iCorrelatedPos+m_iPos];
int i2 = c.m_DataBuffer[c.m_iLastCorrelatedPos+m_iPos];
*pBuf++ = int16_t( SCALE( m_iPos, 0, iWindowSizeFrames, i2, i1 ) );
float i1 = c.m_DataBuffer[c.m_iCorrelatedPos+m_iPos];
float i2 = c.m_DataBuffer[c.m_iLastCorrelatedPos+m_iPos];
*pBuf++ = SCALE( m_iPos, 0, iWindowSizeFrames, i2, i1 );
}
++m_iPos;
+2 -2
View File
@@ -11,7 +11,7 @@ public:
RageSoundReader_SpeedChange( RageSoundReader *pSource );
virtual int SetPosition( int iFrame );
virtual int Read( int16_t *pBuf, int iFrames );
virtual int Read( float *pBuf, int iFrames );
virtual RageSoundReader_SpeedChange *Copy() const { return new RageSoundReader_SpeedChange(*this); }
virtual bool SetProperty( const RString &sProperty, float fValue );
virtual int GetNextSourceFrame() const;
@@ -40,7 +40,7 @@ protected:
int m_iDataBufferAvailFrames;
struct ChannelInfo
{
vector<int16_t> m_DataBuffer;
vector<float> m_DataBuffer;
int m_iCorrelatedPos;
int m_iLastCorrelatedPos;
};
@@ -32,7 +32,7 @@ RageSoundReader_ThreadedBuffer::RageSoundReader_ThreadedBuffer( RageSoundReader
m_iSampleRate = pSource->GetSampleRate();
m_iChannels = pSource->GetNumChannels();
int iFrameSize = sizeof(int16_t) * this->GetNumChannels();
int iFrameSize = sizeof(float) * this->GetNumChannels();
m_DataBuffer.reserve( g_iStreamingBufferFrames * iFrameSize, iFrameSize );
m_bEOF = false;
@@ -279,7 +279,7 @@ int RageSoundReader_ThreadedBuffer::FillBlock()
{
/* We own m_pSource, even after unlocking, because m_bFilling is true. */
unsigned iBufSize;
int16_t *pBuf = m_DataBuffer.get_write_pointer( &iBufSize );
float *pBuf = m_DataBuffer.get_write_pointer( &iBufSize );
ASSERT( (iBufSize % iSamplesPerFrame) == 0 );
iGotFrames = m_pSource->RetriedRead( pBuf, min(g_iReadBlockSizeFrames, iBufSize / iSamplesPerFrame), &iNextSourceFrame, &fRate );
}
@@ -306,7 +306,7 @@ int RageSoundReader_ThreadedBuffer::FillBlock()
return iGotFrames;
}
int RageSoundReader_ThreadedBuffer::Read( int16_t *pBuffer, int iFrames )
int RageSoundReader_ThreadedBuffer::Read( float *pBuffer, int iFrames )
{
if( !m_bEOF )
EnableBuffering();
@@ -18,7 +18,7 @@ public:
RageSoundReader_ThreadedBuffer *Copy() const { return new RageSoundReader_ThreadedBuffer(*this); }
virtual int SetPosition( int iFrame );
virtual int Read( int16_t *pBuffer, int iLength );
virtual int Read( float *pBuffer, int iLength );
virtual int GetNextSourceFrame() const;
virtual int GetLength() const;
@@ -46,7 +46,7 @@ private:
int m_iSampleRate;
int m_iChannels;
CircBuf<int16_t> m_DataBuffer;
CircBuf<float> m_DataBuffer;
struct Mapping
{
+43 -10
View File
@@ -160,15 +160,15 @@ int RageSoundReader_Vorbisfile::SetPosition( int iFrame )
return 1;
}
int RageSoundReader_Vorbisfile::Read( int16_t *buf, int iFrames )
int RageSoundReader_Vorbisfile::Read( float *buf, int iFrames )
{
int frames_read = 0;
while( iFrames && !eof )
{
const int bytes_per_frame = sizeof(int16_t)*channels;
const int bytes_per_frame = sizeof(float)*channels;
int ret = 0;
int iFramesRead = 0;
{
int curofs = (int) ov_pcm_tell(vf);
@@ -193,18 +193,20 @@ int RageSoundReader_Vorbisfile::Read( int16_t *buf, int iFrames )
CHECKPOINT_M( ssprintf("p %i,%i: %i frames of silence needed", curofs, read_offset, silence) );
memset( buf, 0, silence );
ret = silence;
iFramesRead = iSilentFrames;
}
}
if( ret == 0 )
if( iFramesRead == 0 )
{
int bstream;
#if defined(INTEGER_VORBIS)
ret = ov_read( vf, (char *) buf, iFrames * bytes_per_frame, &bstream );
int ret = ov_read( vf, (char *) buf, iFrames * channels * sizeof(int16_t), &bstream );
#else // float vorbis decoder
ret = ov_read( vf, (char *) buf, iFrames * bytes_per_frame, (BYTE_ORDER == BIG_ENDIAN)?1:0, 2, 1, &bstream );
float **pcm;
int ret = ov_read_float( vf, &pcm, iFrames, &bstream );
#endif
{
vorbis_info *vi = ov_info( vf, -1 );
ASSERT( vi != NULL );
@@ -228,12 +230,43 @@ int RageSoundReader_Vorbisfile::Read( int16_t *buf, int iFrames )
eof = true;
continue;
}
#if defined(INTEGER_VORBIS)
if( ret > 0 )
{
int iSamplesRead = ret / sizeof(int16_t);
iFramesRead = iSamplesRead / channels;
/* Convert in reverse, so we can do it in-place. */
const int16_t *pIn = (int16_t *) buf;
float *pOut = (float *) buf;
for( int i = iSamplesRead-1; i >= 0; --i )
pOut[i] = pIn[i] / 32768.0f;
}
#else
if( ret > 0 )
{
iFramesRead = ret;
int iNumChannels = channels;
for( int iChannel = 0; iChannel < iNumChannels; ++iChannel )
{
const float *pChannelIn = pcm[iChannel];
float *pChannelOut = &buf[iChannel];
for( int i = 0; i < iFramesRead; ++i )
{
*pChannelOut = *pChannelIn;
++pChannelIn;
pChannelOut += iNumChannels;
}
}
}
#endif
}
int iFramesRead = ret / bytes_per_frame;
read_offset += ret / bytes_per_frame;
read_offset += iFramesRead;
buf += ret / sizeof(int16_t);
buf += iFramesRead * channels;
frames_read += iFramesRead;
iFrames -= iFramesRead;
}
+1 -1
View File
@@ -16,7 +16,7 @@ public:
int GetLength() const;
int SetPosition( int iFrame );
int Read( int16_t *pBuf, int iFrames );
int Read( float *pBuf, int iFrames );
int GetSampleRate() const;
unsigned GetNumChannels() const { return channels; }
int GetNextSourceFrame() const;
+34 -25
View File
@@ -19,21 +19,31 @@ namespace
{
/* pBuf contains iSamples 8-bit samples; convert to 16-bit. pBuf must
* have enough storage to hold the resulting data. */
void Convert8bitTo16bit( void *pBuf, int iSamples )
void Convert8bitToFloat( void *pBuf, int iSamples )
{
/* Convert in reverse, so we can do it in-place. */
const uint8_t *pIn = (uint8_t *) pBuf;
int16_t *pOut = (int16_t *) pBuf;
float *pOut = (float *) pBuf;
for( int i = iSamples-1; i >= 0; --i )
pOut[i] = SCALE( pIn[i], 0, 255, -32768, 32767 );
{
int iSample = pIn[i];
iSample -= 128; /* 0..255 -> -128..127 */
pOut[i] = iSample / 128.0f;
}
}
/* Flip 16-bit samples if necessary. On little-endian systems, this will
* optimize out. */
void Convert16BitFromLittleEndian( int16_t *pBuf, int iSamples )
void ConvertLittleEndian16BitToFloat( void *pBuf, int iSamples )
{
for( int i = 0; i < iSamples; ++i )
pBuf[i] = Swap16LE( pBuf[i] );
/* Convert in reverse, so we can do it in-place. */
const int16_t *pIn = (int16_t *) pBuf;
float *pOut = (float *) pBuf;
for( int i = iSamples-1; i >= 0; --i )
{
int16_t iSample = Swap16LE( pIn[i] );
pOut[i] = iSample / 32768.0f;
}
}
};
@@ -42,7 +52,7 @@ struct WavReader
WavReader( RageFile &f, const RageSoundReader_WAV::WavData &data ):
m_File(f), m_WavData(data) { }
virtual ~WavReader() { }
virtual int Read( int16_t *pBuf, int iFrames ) = 0;
virtual int Read( float *pBuf, int iFrames ) = 0;
virtual int GetLength() const = 0;
virtual bool Init() = 0;
virtual int SetPosition( int iFrame ) = 0;
@@ -72,11 +82,10 @@ struct WavReaderPCM: public WavReader
return true;
}
int Read( int16_t *buf, int iFrames )
int Read( float *buf, int iFrames )
{
int len = iFrames * m_WavData.m_iChannels * sizeof(int16_t);
if( m_WavData.m_iBitsPerSample == 8 )
len /= 2;
int len = iFrames * m_WavData.m_iChannels;
len *= m_WavData.m_iBitsPerSample/8;
const int iBytesLeftInDataChunk = m_WavData.m_iDataChunkSize - (m_File.Tell() - m_WavData.m_iDataChunkPos);
if( !iBytesLeftInDataChunk )
@@ -84,16 +93,16 @@ struct WavReaderPCM: public WavReader
len = min( len, iBytesLeftInDataChunk );
int iGot = m_File.Read( buf, len );
int iGotSamples = 0;
int iBytesPerSample = m_WavData.m_iBitsPerSample/8;
int iGotSamples = iGot / iBytesPerSample;
switch( m_WavData.m_iBitsPerSample )
{
case 8:
Convert8bitTo16bit( buf, iGot );
iGotSamples = iGot;
Convert8bitToFloat( buf, iGotSamples );
break;
case 16:
Convert16BitFromLittleEndian( buf, iGot/2 );
iGotSamples = iGot / 2;
ConvertLittleEndian16BitToFloat( buf, iGotSamples );
break;
}
return iGotSamples / m_WavData.m_iChannels;
@@ -133,7 +142,7 @@ struct WavReaderADPCM: public WavReader
public:
vector<int16_t> m_iaCoef1, m_iaCoef2;
int16_t m_iFramesPerBlock;
int8_t *m_pBuffer;
float *m_pBuffer;
int m_iBufferAvail, m_iBufferUsed;
WavReaderADPCM( RageFile &f, const RageSoundReader_WAV::WavData &data ):
@@ -170,7 +179,7 @@ public:
if( m_sError.size() != 0 )
return false;
m_pBuffer = new int8_t[m_iFramesPerBlock*m_WavData.m_iChannels*sizeof(int16_t)];
m_pBuffer = new float[m_iFramesPerBlock*m_WavData.m_iChannels];
m_iBufferAvail = m_iBufferUsed = 0;
m_File.Seek( m_WavData.m_iDataChunkPos );
@@ -207,7 +216,7 @@ public:
if( m_File.Tell() >= m_WavData.m_iDataChunkSize+m_WavData.m_iDataChunkPos || m_File.AtEOF() )
return true; /* past the data chunk */
int16_t *pBuffer = (int16_t *) m_pBuffer;
float *pBuffer = m_pBuffer;
int iCoef1[2], iCoef2[2];
for( int i = 0; i < m_WavData.m_iChannels; ++i )
{
@@ -239,9 +248,9 @@ public:
}
for( int i = 0; i < m_WavData.m_iChannels; ++i )
pBuffer[m_iBufferAvail++] = iSamp2[i];
pBuffer[m_iBufferAvail++] = iSamp2[i] / 32768.0f;
for( int i = 0; i < m_WavData.m_iChannels; ++i )
pBuffer[m_iBufferAvail++] = iSamp1[i];
pBuffer[m_iBufferAvail++] = iSamp1[i] / 32768.0f;
int8_t iBuf = 0, iBufSize = 0;
@@ -272,7 +281,7 @@ public:
int32_t iNewSample = iPredSample + (iDelta[c] * iErrorDelta);
iNewSample = clamp( iNewSample, -32768, 32767 );
pBuffer[m_iBufferAvail++] = (int16_t) iNewSample;
pBuffer[m_iBufferAvail++] = iNewSample / 32768.0f;
static const int aAdaptionTable[] = {
768, 614, 512, 409, 307, 230, 230, 230,
@@ -290,10 +299,10 @@ public:
return true;
}
int Read( int16_t *buf, int iFrames )
int Read( float *buf, int iFrames )
{
int iSamplesPerFrame = m_WavData.m_iChannels;
int iBytesPerFrame = iSamplesPerFrame * sizeof(int16_t);
int iBytesPerFrame = iSamplesPerFrame * sizeof(float);
int iGotFrames = 0;
while( iGotFrames < (int) iFrames )
{
@@ -541,7 +550,7 @@ int RageSoundReader_WAV::GetNextSourceFrame() const
return m_pImpl->GetNextSourceFrame();
}
int RageSoundReader_WAV::Read( int16_t *pBuf, int iFrames )
int RageSoundReader_WAV::Read( float *pBuf, int iFrames )
{
ASSERT( m_pImpl != NULL );
return m_pImpl->Read( pBuf, iFrames );
+1 -1
View File
@@ -14,7 +14,7 @@ public:
void Close();
int GetLength() const;
int SetPosition( int iFrame );
int Read( int16_t *pBuf, int iFrames );
int Read( float *pBuf, int iFrames );
int GetSampleRate() const { return m_WavData.m_iSampleRate; }
unsigned GetNumChannels() const { return m_WavData.m_iChannels; }
int GetNextSourceFrame() const;
+10 -10
View File
@@ -5,17 +5,17 @@
/* Some of these functions assume a channel count: */
static const int channels = 2;
void RageSoundUtil::Attenuate( int16_t *pBuf, int iSamples, float fVolume )
void RageSoundUtil::Attenuate( float *pBuf, int iSamples, float fVolume )
{
while( iSamples-- )
{
*pBuf = int16_t( (*pBuf) * fVolume );
*pBuf *= fVolume;
++pBuf;
}
}
/* Pan buffer left or right; fPos is -1...+1. Buffer is assumed to be stereo. */
void RageSoundUtil::Pan( int16_t *buffer, int frames, float fPos )
void RageSoundUtil::Pan( float *buffer, int frames, float fPos )
{
if( fPos == 0 )
return; /* no change */
@@ -40,15 +40,15 @@ void RageSoundUtil::Pan( int16_t *buffer, int frames, float fPos )
ASSERT_M( channels == 2, ssprintf("%i", channels) );
for( int samp = 0; samp < frames; ++samp )
{
int16_t l = int16_t(buffer[0]*fLeftFactors[0] + buffer[1]*fLeftFactors[1]);
int16_t r = int16_t(buffer[0]*fRightFactors[0] + buffer[1]*fRightFactors[1]);
float l = buffer[0]*fLeftFactors[0] + buffer[1]*fLeftFactors[1];
float r = buffer[0]*fRightFactors[0] + buffer[1]*fRightFactors[1];
buffer[0] = l;
buffer[1] = r;
buffer += 2;
}
}
void RageSoundUtil::Fade( int16_t *buffer, int frames, float fStartVolume, float fEndVolume )
void RageSoundUtil::Fade( float *buffer, int frames, float fStartVolume, float fEndVolume )
{
/* If the whole buffer is full volume, skip. */
if( fStartVolume > .9999f && fEndVolume > .9999f )
@@ -61,17 +61,17 @@ void RageSoundUtil::Fade( int16_t *buffer, int frames, float fStartVolume, float
fVolPercent = clamp( fVolPercent, 0.f, 1.f );
for(int i = 0; i < channels; ++i)
{
*buffer = short(*buffer * fVolPercent);
*buffer *= fVolPercent;
buffer++;
}
}
}
/* Dupe mono to stereo in-place; do it in reverse, to handle overlap. */
void RageSoundUtil::ConvertMonoToStereoInPlace( int16_t *data, int iFrames )
void RageSoundUtil::ConvertMonoToStereoInPlace( float *data, int iFrames )
{
int16_t *input = data;
int16_t *output = input;
float *input = data;
float *output = input;
input += iFrames;
output += iFrames * 2;
while( iFrames-- )
+4 -4
View File
@@ -5,10 +5,10 @@
namespace RageSoundUtil
{
void Attenuate( int16_t *pBuf, int iSamples, float fVolume );
void Pan( int16_t *pBuffer, int iFrames, float fPos );
void Fade( int16_t *pBuffer, int iFrames, float fStartVolume, float fEndVolume );
void ConvertMonoToStereoInPlace( int16_t *pBuffer, int iFrames );
void Attenuate( float *pBuf, int iSamples, float fVolume );
void Pan( float *pBuffer, int iFrames, float fPos );
void Fade( float *pBuffer, int iFrames, float fStartVolume, float fEndVolume );
void ConvertMonoToStereoInPlace( float *pBuffer, int iFrames );
};
#endif