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:
parent
fdce574cc5
commit
c02ea1ce83
5 changed files with 148 additions and 17 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue