Fade out sound sources that are no longer close

* Handle culling of all sound sources in a separate function cull3DSound
* Add two new settings Sound::sfx fade in duration and Sound::sfx fade out duration
macos-builds-only-for-openmw
Andreas Stöckel 3 years ago
parent 1583252dd8
commit 6f2e311c58

@ -33,6 +33,8 @@ namespace MWSound
namespace namespace
{ {
constexpr float sMinUpdateInterval = 1.0f / 30.0f; constexpr float sMinUpdateInterval = 1.0f / 30.0f;
constexpr float sSfxFadeInDuration = 1.0f;
constexpr float sSfxFadeOutDuration = 1.0f;
WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings() WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings()
{ {
@ -47,6 +49,17 @@ namespace MWSound
return settings; return settings;
} }
float initialFadeVolume(float squaredDist, Sound_Buffer *sfx, Type type, PlayMode mode)
{
// If a sound is farther away than its maximum distance, start playing it with a zero fade volume.
// It can still become audible once the player moves closer.
const float maxDist = sfx->getMaxDist();
if (squaredDist > (maxDist * maxDist))
return 0.0f;
return 1.0;
}
} }
// For combining PlayMode and Type flags // For combining PlayMode and Type flags
@ -517,7 +530,8 @@ namespace MWSound
return nullptr; return nullptr;
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
if ((mode & PlayMode::RemoveAtDistance) && (mListenerPos - objpos).length2() > 2000 * 2000) const float squaredDist = (mListenerPos - objpos).length2();
if ((mode & PlayMode::RemoveAtDistance) && squaredDist > 2000 * 2000)
return nullptr; return nullptr;
// Look up the sound in the ESM data // Look up the sound in the ESM data
@ -548,6 +562,7 @@ namespace MWSound
params.mPos = objpos; params.mPos = objpos;
params.mVolume = volume * sfx->getVolume(); params.mVolume = volume * sfx->getVolume();
params.mBaseVolume = volumeFromType(type); params.mBaseVolume = volumeFromType(type);
params.mFadeVolume = initialFadeVolume(squaredDist, sfx, type, mode);
params.mPitch = pitch; params.mPitch = pitch;
params.mMinDistance = sfx->getMinDist(); params.mMinDistance = sfx->getMinDist();
params.mMaxDistance = sfx->getMaxDist(); params.mMaxDistance = sfx->getMaxDist();
@ -576,12 +591,15 @@ namespace MWSound
Sound_Buffer *sfx = mSoundBuffers.load(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = mSoundBuffers.load(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr; if(!sfx) return nullptr;
const float squaredDist = (mListenerPos - initialPos).length2();
SoundPtr sound = getSoundRef(); SoundPtr sound = getSoundRef();
sound->init([&] { sound->init([&] {
SoundParams params; SoundParams params;
params.mPos = initialPos; params.mPos = initialPos;
params.mVolume = volume * sfx->getVolume(); params.mVolume = volume * sfx->getVolume();
params.mBaseVolume = volumeFromType(type); params.mBaseVolume = volumeFromType(type);
params.mFadeVolume = initialFadeVolume(squaredDist, sfx, type, mode);
params.mPitch = pitch; params.mPitch = pitch;
params.mMinDistance = sfx->getMinDist(); params.mMinDistance = sfx->getMinDist();
params.mMaxDistance = sfx->getMaxDist(); params.mMaxDistance = sfx->getMaxDist();
@ -830,6 +848,28 @@ namespace MWSound
return {WaterSoundAction::DoNothing, nullptr}; return {WaterSoundAction::DoNothing, nullptr};
} }
void SoundManager::cull3DSound(SoundBase *sound)
{
// Hard-coded distance of 2000.0f is from vanilla Morrowind
const float maxDist = sound->getDistanceCull() ? 2000.0f : sound->getMaxDistance();
const float squaredMaxDist = maxDist * maxDist;
const osg::Vec3f pos = sound->getPosition();
const float squaredDist = (mListenerPos - pos).length2();
if (squaredDist > squaredMaxDist)
{
// If getDistanceCull() is set, delete the sound after it has faded out
sound->setFade(sSfxFadeOutDuration, 0.0f, Play_FadeExponential | (sound->getDistanceCull() ? Play_StopAtFadeEnd : 0));
}
else
{
// Fade sounds back in once they are in range
sound->setFade(sSfxFadeInDuration, 1.0f, Play_FadeExponential);
}
}
void SoundManager::updateSounds(float duration) void SoundManager::updateSounds(float duration)
{ {
// We update active say sounds map for specific actors here // We update active say sounds map for specific actors here
@ -884,17 +924,12 @@ namespace MWSound
{ {
Sound *sound = sndidx->first.get(); Sound *sound = sndidx->first.get();
if(!ptr.isEmpty() && sound->getIs3D()) if (sound->getIs3D())
{ {
const ESM::Position &pos = ptr.getRefData().getPosition(); if (!ptr.isEmpty())
const osg::Vec3f objpos(pos.asVec3()); sound->setPosition(ptr.getRefData().getPosition().asVec3());
sound->setPosition(objpos);
cull3DSound(sound);
if(sound->getDistanceCull())
{
if((mListenerPos - objpos).length2() > 2000*2000)
mOutput->finishSound(sound);
}
} }
if(!sound->updateFade(duration) || !mOutput->isSoundPlaying(sound)) if(!sound->updateFade(duration) || !mOutput->isSoundPlaying(sound))
@ -924,17 +959,15 @@ namespace MWSound
{ {
MWWorld::ConstPtr ptr = sayiter->first; MWWorld::ConstPtr ptr = sayiter->first;
Stream *sound = sayiter->second.get(); Stream *sound = sayiter->second.get();
if(!ptr.isEmpty() && sound->getIs3D()) if (sound->getIs3D())
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); if (!ptr.isEmpty())
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
sound->setPosition(pos);
if(sound->getDistanceCull())
{ {
if((mListenerPos - pos).length2() > 2000*2000) MWBase::World *world = MWBase::Environment::get().getWorld();
mOutput->finishStream(sound); sound->setPosition(world->getActorHeadTransform(ptr).getTrans());
} }
cull3DSound(sound);
} }
if(!sound->updateFade(duration) || !mOutput->isStreamPlaying(sound)) if(!sound->updateFade(duration) || !mOutput->isStreamPlaying(sound))

@ -34,6 +34,7 @@ namespace MWSound
{ {
class Sound_Output; class Sound_Output;
struct Sound_Decoder; struct Sound_Decoder;
class SoundBase;
class Sound; class Sound;
class Stream; class Stream;
@ -111,6 +112,8 @@ namespace MWSound
void advanceMusic(const std::string& filename); void advanceMusic(const std::string& filename);
void startRandomTitle(); void startRandomTitle();
void cull3DSound(SoundBase *sound);
void updateSounds(float duration); void updateSounds(float duration);
void updateRegionSound(float duration); void updateRegionSound(float duration);
void updateWaterSound(); void updateWaterSound();

Loading…
Cancel
Save