1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-25 14:15: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 << " | s: " << dsq->continuity.seconds;
os << " | evQ: " << core->eventQueue.getSize();
os << " | sndQ: " << core->dbg_numThreadDecoders;
/*
os << " | s: " << dsq->continuity.seconds;
os << " cr: " << core->cullRadius;

View file

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

View file

@ -85,12 +85,13 @@ public:
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 octave;
float voxvol, sfxvol, musvol;
int subtitles;
std::string deviceName;
int prebuffer;
} audio;
struct Video

View file

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

View file

@ -250,6 +250,8 @@ void OggDecoder::decode_loop(OggDecoder *this_)
decoderList.erase(it++);
}
}
core->dbg_numThreadDecoders = decoderList.size();
}
}
@ -584,14 +586,17 @@ namespace FMOD {
class OpenALSound
{
public:
OpenALSound(FILE *_fp, const bool _looping);
OpenALSound(void *_data, long _size, const bool _looping);
OpenALSound(FILE *_fp, const bool _looping); // ctor for ogg streamed from file
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; }
const void *getData() const { return data; }
long getSize() const { return size; }
bool isLooping() const { return looping; }
bool isRaw() const { return raw; }
FMOD_RESULT release();
void reference() { refcount++; }
ALuint getBufferName() const { return bid; }
private:
FILE * const fp;
@ -599,6 +604,8 @@ private:
const long size; // Only used if fp==NULL
const bool looping;
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)
@ -607,6 +614,8 @@ OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
, size(0)
, looping(_looping)
, refcount(1)
, raw(false)
, bid(0)
{
}
@ -616,6 +625,19 @@ OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
, size(_size)
, looping(_looping)
, 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)
{
}
@ -625,10 +647,17 @@ FMOD_RESULT OpenALSound::release()
refcount--;
if (refcount <= 0)
{
if (fp)
fclose(fp);
else
free(data);
if(raw)
{
alDeleteBuffers(1, &bid);
}
else
{
if (fp)
fclose(fp);
else
free(data);
}
delete this;
}
return FMOD_OK;
@ -738,15 +767,23 @@ bool OpenALChannel::start(OpenALSound *sound)
{
if (decoder)
delete decoder;
if (sound->getFile())
decoder = new OggDecoder(sound->getFile());
else
decoder = new OggDecoder(sound->getData(), sound->getSize());
if (!decoder->start(sid, sound->isLooping()))
if (sound->isRaw())
{
delete decoder;
decoder = NULL;
return false;
alSourcei(sid, AL_BUFFER, sound->getBufferName());
alSourcei(sid, AL_LOOPING, sound->isLooping() ? AL_TRUE : AL_FALSE);
}
else
{
if (sound->getFile())
decoder = new OggDecoder(sound->getFile());
else
decoder = new OggDecoder(sound->getData(), sound->getSize());
if (!decoder->start(sid, sound->isLooping()))
{
delete decoder;
decoder = NULL;
return false;
}
}
return true;
}
@ -1014,6 +1051,9 @@ FMOD_RESULT DSP::setParameter(int index, float value)
void OpenALChannel::setSound(OpenALSound *_sound)
{
if(sound == _sound)
return;
if (sound)
sound->release();
@ -1115,6 +1155,58 @@ FMOD_RESULT OpenALSystem::createDSPByType(const FMOD_DSP_TYPE type, DSP **dsp)
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))
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)
{
// Create streaming file handle decoder
*sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
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
{
// Create streaming memory decoder
fseek(io, 0, SEEK_END);
long size = ftell(io);
if (fseek(io, 0, SEEK_SET) != 0)