1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-25 22:25:46 +00:00

Re-implement (optionally) pre-decoding audio to reduce disk seek/decoding time.

This was removed in HG changeset 7ec478d993b7, and is now implemented
in a way that is better than before: voice overs and music
no longer cause decoding lag, as they are always decoded on-the-fly.
The additional memory use (~40 MB) should be no problem for anyone.
The default is still to decode everything on the fly.
This commit is contained in:
fgenesis 2012-05-27 04:46:36 +02:00
parent fdce574cc5
commit c02ea1ce83
5 changed files with 148 additions and 17 deletions

View file

@ -4484,6 +4484,7 @@ void DSQ::onUpdate(float dt)
os << " | p: " << core->processedRenderObjectCount << " | t: " << core->totalRenderObjectCount; os << " | p: " << core->processedRenderObjectCount << " | t: " << core->totalRenderObjectCount;
os << " | s: " << dsq->continuity.seconds; os << " | s: " << dsq->continuity.seconds;
os << " | evQ: " << core->eventQueue.getSize(); os << " | evQ: " << core->eventQueue.getSize();
os << " | sndQ: " << core->dbg_numThreadDecoders;
/* /*
os << " | s: " << dsq->continuity.seconds; os << " | s: " << dsq->continuity.seconds;
os << " cr: " << core->cullRadius; os << " cr: " << core->cullRadius;

View file

@ -87,12 +87,17 @@ void UserSettings::save()
} }
xml_audio.InsertEndChild(xml_volume); xml_audio.InsertEndChild(xml_volume);
TiXmlElement xml_device("Device"); TiXmlElement xml_device("Device");
{ {
xml_device.SetAttribute("name", audio.deviceName); xml_device.SetAttribute("name", audio.deviceName);
} }
xml_audio.InsertEndChild(xml_device); xml_audio.InsertEndChild(xml_device);
TiXmlElement xml_prebuf("Prebuffer");
{
xml_prebuf.SetAttribute("on", audio.prebuffer);
}
xml_audio.InsertEndChild(xml_prebuf);
} }
doc.InsertEndChild(xml_audio); doc.InsertEndChild(xml_audio);
@ -393,6 +398,12 @@ void UserSettings::load(bool doApply, const std::string &overrideFile)
{ {
audio.deviceName = xml_device->Attribute("name"); audio.deviceName = xml_device->Attribute("name");
} }
TiXmlElement *xml_prebuf = xml_audio->FirstChildElement("Prebuffer");
if (xml_prebuf)
{
xml_prebuf->Attribute("on", &audio.prebuffer);
}
} }
TiXmlElement *xml_video = doc.FirstChildElement("Video"); TiXmlElement *xml_video = doc.FirstChildElement("Video");
if (xml_video) if (xml_video)
@ -547,6 +558,8 @@ void UserSettings::apply()
} }
dsq->bindInput(); dsq->bindInput();
core->settings.prebufferSounds = audio.prebuffer;
#endif #endif
} }

View file

@ -85,12 +85,13 @@ public:
struct Audio struct Audio
{ {
Audio() { micOn = 0; octave=0; musvol=voxvol=sfxvol=1.0; subtitles=false; } Audio() { micOn = 0; octave=0; musvol=voxvol=sfxvol=1.0; subtitles=false; prebuffer=false;}
int micOn; int micOn;
int octave; int octave;
float voxvol, sfxvol, musvol; float voxvol, sfxvol, musvol;
int subtitles; int subtitles;
std::string deviceName; std::string deviceName;
int prebuffer;
} audio; } audio;
struct Video struct Video

View file

@ -77,10 +77,11 @@ struct ScreenMode
struct CoreSettings struct CoreSettings
{ {
CoreSettings() { renderOn = true; updateOn = true; runInBackground = false; } CoreSettings() { renderOn = true; updateOn = true; runInBackground = false; prebufferSounds = false; }
bool renderOn; bool renderOn;
bool runInBackground; bool runInBackground;
bool updateOn; // NOT IMPLEMENTED YET bool updateOn; // NOT IMPLEMENTED YET
bool prebufferSounds;
}; };
enum CoreFlags enum CoreFlags
@ -1306,6 +1307,8 @@ public:
int tgaSave(const char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData); int tgaSave(const char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);
volatile int dbg_numThreadDecoders;
protected: protected:
std::string fpsDebugString; std::string fpsDebugString;

View file

@ -250,6 +250,8 @@ void OggDecoder::decode_loop(OggDecoder *this_)
decoderList.erase(it++); decoderList.erase(it++);
} }
} }
core->dbg_numThreadDecoders = decoderList.size();
} }
} }
@ -584,14 +586,17 @@ namespace FMOD {
class OpenALSound class OpenALSound
{ {
public: public:
OpenALSound(FILE *_fp, const bool _looping); OpenALSound(FILE *_fp, const bool _looping); // ctor for ogg streamed from file
OpenALSound(void *_data, long _size, const bool _looping); OpenALSound(void *_data, long _size, const bool _looping); // ctor for ogg streamed from memory
OpenALSound(ALuint _bid, const bool _looping); // ctor for raw samples already assigned an opanAL buffer ID
FILE *getFile() const { return fp; } FILE *getFile() const { return fp; }
const void *getData() const { return data; } const void *getData() const { return data; }
long getSize() const { return size; } long getSize() const { return size; }
bool isLooping() const { return looping; } bool isLooping() const { return looping; }
bool isRaw() const { return raw; }
FMOD_RESULT release(); FMOD_RESULT release();
void reference() { refcount++; } void reference() { refcount++; }
ALuint getBufferName() const { return bid; }
private: private:
FILE * const fp; FILE * const fp;
@ -599,6 +604,8 @@ private:
const long size; // Only used if fp==NULL const long size; // Only used if fp==NULL
const bool looping; const bool looping;
int refcount; int refcount;
const bool raw; // true if buffer holds raw PCM data
ALuint bid; // only used if raw == true
}; };
OpenALSound::OpenALSound(FILE *_fp, const bool _looping) OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
@ -607,6 +614,8 @@ OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
, size(0) , size(0)
, looping(_looping) , looping(_looping)
, refcount(1) , refcount(1)
, raw(false)
, bid(0)
{ {
} }
@ -616,6 +625,19 @@ OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
, size(_size) , size(_size)
, looping(_looping) , looping(_looping)
, refcount(1) , refcount(1)
, raw(false)
, bid(0)
{
}
OpenALSound::OpenALSound(ALuint _bid, const bool _looping)
: fp(NULL)
, data(NULL)
, size(0)
, looping(_looping)
, refcount(1)
, raw(true)
, bid(_bid)
{ {
} }
@ -624,11 +646,18 @@ FMOD_RESULT OpenALSound::release()
{ {
refcount--; refcount--;
if (refcount <= 0) if (refcount <= 0)
{
if(raw)
{
alDeleteBuffers(1, &bid);
}
else
{ {
if (fp) if (fp)
fclose(fp); fclose(fp);
else else
free(data); free(data);
}
delete this; delete this;
} }
return FMOD_OK; return FMOD_OK;
@ -738,6 +767,13 @@ bool OpenALChannel::start(OpenALSound *sound)
{ {
if (decoder) if (decoder)
delete decoder; delete decoder;
if (sound->isRaw())
{
alSourcei(sid, AL_BUFFER, sound->getBufferName());
alSourcei(sid, AL_LOOPING, sound->isLooping() ? AL_TRUE : AL_FALSE);
}
else
{
if (sound->getFile()) if (sound->getFile())
decoder = new OggDecoder(sound->getFile()); decoder = new OggDecoder(sound->getFile());
else else
@ -748,6 +784,7 @@ bool OpenALChannel::start(OpenALSound *sound)
decoder = NULL; decoder = NULL;
return false; return false;
} }
}
return true; return true;
} }
@ -1014,6 +1051,9 @@ FMOD_RESULT DSP::setParameter(int index, float value)
void OpenALChannel::setSound(OpenALSound *_sound) void OpenALChannel::setSound(OpenALSound *_sound)
{ {
if(sound == _sound)
return;
if (sound) if (sound)
sound->release(); sound->release();
@ -1115,6 +1155,58 @@ FMOD_RESULT OpenALSystem::createDSPByType(const FMOD_DSP_TYPE type, DSP **dsp)
return FMOD_ERR_INTERNAL; return FMOD_ERR_INTERNAL;
} }
static void *decode_to_pcm(FILE *io, ALenum &format, ALsizei &size, ALuint &freq)
{
ALubyte *retval = NULL;
// Uncompress and feed to the AL.
OggVorbis_File vf;
memset(&vf, '\0', sizeof (vf));
if (ov_open(io, &vf, NULL, 0) == 0)
{
int bitstream = 0;
vorbis_info *info = ov_info(&vf, -1);
size = 0;
format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
freq = info->rate;
if ((info->channels != 1) && (info->channels != 2))
{
ov_clear(&vf);
return NULL;
}
char buf[1024 * 16];
long rc = 0;
size_t allocated = 64 * 1024;
retval = (ALubyte *) malloc(allocated);
while ( (rc = ov_read(&vf, buf, sizeof (buf), BBGE_BIGENDIAN, 2, 1, &bitstream)) != 0 )
{
if (rc > 0)
{
size += rc;
if (size >= allocated)
{
allocated *= 2;
ALubyte *tmp = (ALubyte *) realloc(retval, allocated);
if (tmp == NULL)
{
free(retval);
retval = NULL;
break;
}
retval = tmp;
}
memcpy(retval + (size - rc), buf, rc);
}
}
ov_clear(&vf);
return retval;
}
return NULL;
}
ALBRIDGE(System,createSound,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound)) ALBRIDGE(System,createSound,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound))
FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE mode, const FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound) FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE mode, const FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound)
{ {
@ -1137,11 +1229,32 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
if (mode & FMOD_CREATESTREAM) if (mode & FMOD_CREATESTREAM)
{ {
// Create streaming file handle decoder
*sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL))); *sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
retval = FMOD_OK; retval = FMOD_OK;
} }
else if(core->settings.prebufferSounds)
{
// Pre-decode the sound file and store the raw PCM buffer
ALenum format = AL_NONE;
ALsizei size = 0;
ALuint freq = 0;
void *data = decode_to_pcm(io, format, size, freq);
fclose(io);
ALuint bid = 0;
alGenBuffers(1, &bid);
if (bid != 0)
{
alBufferData(bid, format, data, size, freq);
*sound = (Sound *) new OpenALSound(bid, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
retval = FMOD_OK;
}
free(data);
}
else else
{ {
// Create streaming memory decoder
fseek(io, 0, SEEK_END); fseek(io, 0, SEEK_END);
long size = ftell(io); long size = ftell(io);
if (fseek(io, 0, SEEK_SET) != 0) if (fseek(io, 0, SEEK_SET) != 0)