diff --git a/stepmania/src/RageSoundReader_Preload.cpp b/stepmania/src/RageSoundReader_Preload.cpp new file mode 100644 index 0000000000..6d21d58f78 --- /dev/null +++ b/stepmania/src/RageSoundReader_Preload.cpp @@ -0,0 +1,140 @@ +#include "global.h" +#include "RageSoundReader_Preload.h" + +const int channels = 2; +const int samplesize = 2 * channels; /* 16-bit */ +const int samplerate = 44100; + +const int max_prebuf_size = 1024*256*10; + +int SoundReader_Preload::total_samples() const +{ + return buf.get().size() / samplesize; +} + +bool SoundReader_Preload::Open(SoundReader *source) +{ + /* Check the length, and see if we think it'll fit in the buffer. */ + int len = source->GetLength_Fast(); + if(len != -1) + { + float secs = len / 1000.f; + + int pcmsize = int(secs * samplerate * samplesize); /* seconds -> bytes */ + if(pcmsize > max_prebuf_size) + return false; /* Don't bother trying to preload it. */ + + buf.get_owned().reserve(pcmsize); + } + + while(1) { + char buffer[1024]; + int cnt = source->Read(buffer, sizeof(buffer)); + + if(cnt < 0) { + /* XXX untested */ + SetError(source->GetError()); + return false; + } + + if(!cnt) break; /* eof */ + + /* Add the buffer. */ + buf.get_owned().append(buffer, buffer+cnt); + + if(buf.get_owned().size() > max_prebuf_size) + return false; /* too big */ + } + + position = 0; + return true; +} + +int SoundReader_Preload::GetLength() const +{ + return int(float(total_samples()) * 1000.f / samplerate); +} + +int SoundReader_Preload::GetLength_Fast() const +{ + return GetLength(); +} + +int SoundReader_Preload::SetPosition_Accurate(int ms) +{ + const int sample = int((ms / 1000.0f) * samplerate); + position = sample * samplesize; + + if(position >= int(buf.get().size())) + position = 0; + + return position; +} + +int SoundReader_Preload::SetPosition_Fast(int ms) +{ + return SetPosition_Accurate(ms); +} + +int SoundReader_Preload::Read(char *buffer, unsigned len) +{ + const unsigned bytes_avail = buf.get().size() - position; + + len = min(len, bytes_avail); + memcpy(buffer, buf.get().data()+position, len); + position += len; + + return len; +} + +SoundReader *SoundReader_Preload::Copy() const +{ + return new SoundReader_Preload(*this); +} + +rc_string::rc_string() +{ + buf = new string; + cnt = new int(1); +} + +rc_string::rc_string(const rc_string &rhs) +{ + buf = rhs.buf; + cnt = rhs.cnt; + (*cnt)++; +} + +rc_string::~rc_string() +{ + (*cnt)--; + if(!*cnt) + { + delete buf; + delete cnt; + } +} + +string &rc_string::get_owned() +{ + if(*cnt != 1) + { + (*cnt)--; + buf = new string(*buf); + cnt = new int(1); + } + + return *buf; +} + +const string &rc_string::get() const +{ + return *buf; +} + +/* +----------------------------------------------------------------------------- + Copyright (c) 2003 by the person(s) listed below. All rights reserved. + Glenn Maynard +----------------------------------------------------------------------------- +*/ diff --git a/stepmania/src/RageSoundReader_Preload.h b/stepmania/src/RageSoundReader_Preload.h new file mode 100644 index 0000000000..a6948857f5 --- /dev/null +++ b/stepmania/src/RageSoundReader_Preload.h @@ -0,0 +1,51 @@ +#ifndef RAGE_SOUND_READER_PRELOAD +#define RAGE_SOUND_READER_PRELOAD + +#include "RageSoundReader.h" + +/* This reader simply precaches all of the data from another reader. This + * reduces CPU usage for sounds that are played several times at once. */ + +/* Trivial wrapper to refcount strings, since std::string is not always + * refcounted. Without this, Copy() is very slow. */ +class rc_string +{ + mutable string *buf; + mutable int *cnt; + +public: + rc_string(); + rc_string(const rc_string &rhs); + ~rc_string(); + string &get_owned(); + const string &get() const; +}; + +class SoundReader_Preload: public SoundReader { + rc_string buf; + + /* Bytes: */ + int position; + + int total_samples() const; + +public: + /* This will throw a nonfatal exception if this sound isn't + * suitable for preloading. */ + bool Open(SoundReader *source); + int GetLength() const; + int GetLength_Fast() const; + int SetPosition_Accurate(int ms); + int SetPosition_Fast(int ms); + int Read(char *buf, unsigned len); + SoundReader *Copy() const; + ~SoundReader_Preload() { } +}; + +#endif +/* +----------------------------------------------------------------------------- + Copyright (c) 2003 by the person(s) listed below. All rights reserved. + Glenn Maynard +----------------------------------------------------------------------------- +*/