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:
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 << " | s: " << dsq->continuity.seconds;
|
||||
os << " | evQ: " << core->eventQueue.getSize();
|
||||
os << " | sndQ: " << core->dbg_numThreadDecoders;
|
||||
/*
|
||||
os << " | s: " << dsq->continuity.seconds;
|
||||
os << " cr: " << core->cullRadius;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -624,11 +646,18 @@ FMOD_RESULT OpenALSound::release()
|
|||
{
|
||||
refcount--;
|
||||
if (refcount <= 0)
|
||||
{
|
||||
if(raw)
|
||||
{
|
||||
alDeleteBuffers(1, &bid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
else
|
||||
free(data);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
return FMOD_OK;
|
||||
|
@ -738,6 +767,13 @@ bool OpenALChannel::start(OpenALSound *sound)
|
|||
{
|
||||
if (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())
|
||||
decoder = new OggDecoder(sound->getFile());
|
||||
else
|
||||
|
@ -748,6 +784,7 @@ bool OpenALChannel::start(OpenALSound *sound)
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue