Separate sound buffer pool from sound manager
parent
2d61db555b
commit
944033db4e
@ -0,0 +1,154 @@
|
||||
#include "sound_buffer.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct AudioParams
|
||||
{
|
||||
float mAudioDefaultMinDistance;
|
||||
float mAudioDefaultMaxDistance;
|
||||
float mAudioMinDistanceMult;
|
||||
float mAudioMaxDistanceMult;
|
||||
};
|
||||
|
||||
AudioParams makeAudioParams(const MWBase::World& world)
|
||||
{
|
||||
const auto& settings = world.getStore().get<ESM::GameSetting>();
|
||||
AudioParams params;
|
||||
params.mAudioDefaultMinDistance = settings.find("fAudioDefaultMinDistance")->mValue.getFloat();
|
||||
params.mAudioDefaultMaxDistance = settings.find("fAudioDefaultMaxDistance")->mValue.getFloat();
|
||||
params.mAudioMinDistanceMult = settings.find("fAudioMinDistanceMult")->mValue.getFloat();
|
||||
params.mAudioMaxDistanceMult = settings.find("fAudioMaxDistanceMult")->mValue.getFloat();
|
||||
return params;
|
||||
}
|
||||
}
|
||||
|
||||
SoundBufferPool::SoundBufferPool(const VFS::Manager& vfs, Sound_Output& output) :
|
||||
mVfs(&vfs),
|
||||
mOutput(&output),
|
||||
mBufferCacheMax(std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1) * 1024 * 1024),
|
||||
mBufferCacheMin(std::min(static_cast<std::size_t>(std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1)) * 1024 * 1024, mBufferCacheMax))
|
||||
{
|
||||
}
|
||||
|
||||
SoundBufferPool::~SoundBufferPool()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::lookup(const std::string& soundId) const
|
||||
{
|
||||
const auto it = mBufferNameMap.find(soundId);
|
||||
if (it != mBufferNameMap.end())
|
||||
{
|
||||
Sound_Buffer* sfx = it->second;
|
||||
if (sfx->getHandle() != nullptr)
|
||||
return sfx;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::load(const std::string& soundId)
|
||||
{
|
||||
if (mBufferNameMap.empty())
|
||||
{
|
||||
for (const ESM::Sound& sound : MWBase::Environment::get().getWorld()->getStore().get<ESM::Sound>())
|
||||
insertSound(Misc::StringUtils::lowerCase(sound.mId), sound);
|
||||
}
|
||||
|
||||
Sound_Buffer* sfx;
|
||||
const auto it = mBufferNameMap.find(soundId);
|
||||
if (it != mBufferNameMap.end())
|
||||
sfx = it->second;
|
||||
else
|
||||
{
|
||||
const ESM::Sound *sound = MWBase::Environment::get().getWorld()->getStore().get<ESM::Sound>().search(soundId);
|
||||
if (sound == nullptr)
|
||||
return {};
|
||||
sfx = insertSound(soundId, *sound);
|
||||
}
|
||||
|
||||
if (sfx->getHandle() == nullptr)
|
||||
{
|
||||
Sound_Handle handle;
|
||||
size_t size;
|
||||
std::tie(handle, size) = mOutput->loadSound(sfx->getResourceName());
|
||||
if (handle == nullptr)
|
||||
return {};
|
||||
|
||||
sfx->mHandle = handle;
|
||||
|
||||
mBufferCacheSize += size;
|
||||
if (mBufferCacheSize > mBufferCacheMax)
|
||||
{
|
||||
unloadUnused();
|
||||
if (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMax)
|
||||
Log(Debug::Warning) << "No unused sound buffers to free, using " << mBufferCacheSize << " bytes!";
|
||||
}
|
||||
mUnusedBuffers.push_front(sfx);
|
||||
}
|
||||
|
||||
return sfx;
|
||||
}
|
||||
|
||||
void SoundBufferPool::clear()
|
||||
{
|
||||
for (auto &sfx : mSoundBuffers)
|
||||
{
|
||||
if(sfx.mHandle)
|
||||
mOutput->unloadSound(sfx.mHandle);
|
||||
sfx.mHandle = nullptr;
|
||||
}
|
||||
mUnusedBuffers.clear();
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::insertSound(const std::string& soundId, const ESM::Sound& sound)
|
||||
{
|
||||
static const AudioParams audioParams = makeAudioParams(*MWBase::Environment::get().getWorld());
|
||||
|
||||
float volume = static_cast<float>(std::pow(10.0, (sound.mData.mVolume / 255.0 * 3348.0 - 3348.0) / 2000.0));
|
||||
float min = sound.mData.mMinRange;
|
||||
float max = sound.mData.mMaxRange;
|
||||
if (min == 0 && max == 0)
|
||||
{
|
||||
min = audioParams.mAudioDefaultMinDistance;
|
||||
max = audioParams.mAudioDefaultMaxDistance;
|
||||
}
|
||||
|
||||
min *= audioParams.mAudioMinDistanceMult;
|
||||
max *= audioParams.mAudioMaxDistanceMult;
|
||||
min = std::max(min, 1.0f);
|
||||
max = std::max(min, max);
|
||||
|
||||
Sound_Buffer& sfx = mSoundBuffers.emplace_back("Sound/" + sound.mSound, volume, min, max);
|
||||
mVfs->normalizeFilename(sfx.mResourceName);
|
||||
|
||||
mBufferNameMap.emplace(soundId, &sfx);
|
||||
return &sfx;
|
||||
}
|
||||
|
||||
void SoundBufferPool::unloadUnused()
|
||||
{
|
||||
while (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMin)
|
||||
{
|
||||
Sound_Buffer* const unused = mUnusedBuffers.back();
|
||||
|
||||
mBufferCacheSize -= mOutput->unloadSound(unused->getHandle());
|
||||
unused->mHandle = nullptr;
|
||||
|
||||
mUnusedBuffers.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue