Modularize preloading with a sound reader, so the !big logic
in RageSound can go away
This commit is contained in:
@@ -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
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -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
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
Reference in New Issue
Block a user