2004-05-06 02:40:33 +00:00
|
|
|
/* This reader simply precaches all of the data from another reader. This
|
|
|
|
|
* reduces CPU usage for sounds that are played several times at once. */
|
|
|
|
|
|
2003-03-15 23:28:05 +00:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "RageSoundReader_Preload.h"
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
#define samplesize (2 * m_iChannels) /* 16-bit */
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2003-03-15 23:55:24 +00:00
|
|
|
/* If a sound is smaller than this, we'll load it entirely into memory. */
|
2003-08-01 12:12:02 +00:00
|
|
|
const unsigned max_prebuf_size = 1024*256;
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2004-10-24 19:25:21 +00:00
|
|
|
bool RageSoundReader_Preload::PreloadSound( SoundReader *&pSound )
|
|
|
|
|
{
|
|
|
|
|
RageSoundReader_Preload *pPreload = new RageSoundReader_Preload;
|
|
|
|
|
if( !pPreload->Open(pSound) )
|
|
|
|
|
{
|
|
|
|
|
/* Preload failed. It read some data, so we need to rewind the reader. */
|
|
|
|
|
pSound->SetPosition_Fast( 0 );
|
|
|
|
|
delete pPreload;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pSound = pPreload;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-26 18:33:29 +00:00
|
|
|
RageSoundReader_Preload::RageSoundReader_Preload():
|
|
|
|
|
m_Buffer( new RString )
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
int RageSoundReader_Preload::GetTotalSamples() const
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-26 18:33:29 +00:00
|
|
|
return m_Buffer->size() / samplesize;
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
bool RageSoundReader_Preload::Open( SoundReader *pSource )
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
ASSERT( pSource );
|
|
|
|
|
m_iSampleRate = pSource->GetSampleRate();
|
|
|
|
|
m_iChannels = pSource->GetNumChannels();
|
2004-07-24 01:22:10 +00:00
|
|
|
|
2003-03-15 23:28:05 +00:00
|
|
|
/* Check the length, and see if we think it'll fit in the buffer. */
|
2006-11-25 22:46:47 +00:00
|
|
|
int iLen = pSource->GetLength_Fast();
|
|
|
|
|
if( iLen != -1 )
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
float fSecs = iLen / 1000.f;
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
unsigned iPCMSize = unsigned( fSecs * m_iSampleRate * samplesize ); /* seconds -> bytes */
|
|
|
|
|
if( iPCMSize > max_prebuf_size )
|
2003-03-15 23:28:05 +00:00
|
|
|
return false; /* Don't bother trying to preload it. */
|
|
|
|
|
|
2006-11-26 18:33:29 +00:00
|
|
|
m_Buffer.Get()->reserve( iPCMSize );
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
while(1)
|
|
|
|
|
{
|
2003-03-15 23:28:05 +00:00
|
|
|
char buffer[1024];
|
2006-11-25 22:46:47 +00:00
|
|
|
int iCnt = pSource->Read(buffer, sizeof(buffer));
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
if( iCnt < 0 )
|
|
|
|
|
{
|
2003-03-15 23:28:05 +00:00
|
|
|
/* XXX untested */
|
2006-11-25 22:46:47 +00:00
|
|
|
SetError(pSource->GetError());
|
2003-03-15 23:28:05 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
if( !iCnt )
|
|
|
|
|
break; /* eof */
|
2003-03-15 23:28:05 +00:00
|
|
|
|
|
|
|
|
/* Add the buffer. */
|
2006-11-26 18:33:29 +00:00
|
|
|
m_Buffer.Get()->append( buffer, buffer+iCnt );
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-26 18:33:29 +00:00
|
|
|
if( m_Buffer.Get()->size() > max_prebuf_size )
|
2003-03-15 23:28:05 +00:00
|
|
|
return false; /* too big */
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
m_iPosition = 0;
|
|
|
|
|
delete pSource;
|
2003-03-15 23:28:05 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-24 19:25:21 +00:00
|
|
|
int RageSoundReader_Preload::GetLength() const
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
return int(float(GetTotalSamples()) * 1000.f / m_iSampleRate);
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2004-10-24 19:25:21 +00:00
|
|
|
int RageSoundReader_Preload::GetLength_Fast() const
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
|
|
|
|
return GetLength();
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-24 19:25:21 +00:00
|
|
|
int RageSoundReader_Preload::SetPosition_Accurate(int ms)
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
const int sample = int((ms / 1000.0f) * m_iSampleRate);
|
|
|
|
|
m_iPosition = sample * samplesize;
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-26 18:33:29 +00:00
|
|
|
if( m_iPosition >= int(m_Buffer->size()) )
|
2004-01-22 04:41:56 +00:00
|
|
|
{
|
2006-11-26 18:33:29 +00:00
|
|
|
m_iPosition = m_Buffer->size();
|
2004-01-22 04:41:56 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-26 21:54:47 +00:00
|
|
|
return ms;
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
int RageSoundReader_Preload::SetPosition_Fast( int iMS )
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
return SetPosition_Accurate( iMS );
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
int RageSoundReader_Preload::Read( char *pBuffer, unsigned iLen )
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2006-11-26 18:33:29 +00:00
|
|
|
const unsigned bytes_avail = m_Buffer->size() - m_iPosition;
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
iLen = min( iLen, bytes_avail );
|
2006-11-26 18:33:29 +00:00
|
|
|
memcpy( pBuffer, m_Buffer->data()+m_iPosition, iLen );
|
2006-11-25 22:46:47 +00:00
|
|
|
m_iPosition += iLen;
|
2003-03-15 23:28:05 +00:00
|
|
|
|
2006-11-25 22:46:47 +00:00
|
|
|
return iLen;
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2006-10-20 00:01:18 +00:00
|
|
|
RageSoundReader_Preload *RageSoundReader_Preload::Copy() const
|
2003-03-15 23:28:05 +00:00
|
|
|
{
|
2004-10-24 19:25:21 +00:00
|
|
|
return new RageSoundReader_Preload(*this);
|
2003-03-15 23:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-18 19:06:32 +00:00
|
|
|
int RageSoundReader_Preload::GetReferenceCount() const
|
|
|
|
|
{
|
2006-11-25 22:46:47 +00:00
|
|
|
return m_Buffer.GetReferenceCount();
|
2005-07-18 19:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-15 23:28:05 +00:00
|
|
|
/*
|
2004-05-06 02:40:33 +00:00
|
|
|
* Copyright (c) 2003 Glenn Maynard
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|