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
{
constexpr float sMinUpdateInterval = 1.0f / 30.0f;
constexpr float sSfxFadeInDuration = 1.0f;
constexpr float sSfxFadeOutDuration = 1.0f;
WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings()
{
@ -47,6 +49,17 @@ namespace MWSound
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
@ -517,7 +530,8 @@ namespace MWSound
return nullptr;
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;
// Look up the sound in the ESM data
@ -548,6 +562,7 @@ namespace MWSound
params.mPos = objpos;
params.mVolume = volume * sfx->getVolume();
params.mBaseVolume = volumeFromType(type);
params.mFadeVolume = initialFadeVolume(squaredDist, sfx, type, mode);
params.mPitch = pitch;
params.mMinDistance = sfx->getMinDist();
params.mMaxDistance = sfx->getMaxDist();
@ -576,12 +591,15 @@ namespace MWSound
Sound_Buffer *sfx = mSoundBuffers.load(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
const float squaredDist = (mListenerPos - initialPos).length2();
SoundPtr sound = getSoundRef();
sound->init([&] {
SoundParams params;
params.mPos = initialPos;
params.mVolume = volume * sfx->getVolume();
params.mBaseVolume = volumeFromType(type);
params.mFadeVolume = initialFadeVolume(squaredDist, sfx, type, mode);
params.mPitch = pitch;
params.mMinDistance = sfx->getMinDist();
params.mMaxDistance = sfx->getMaxDist();
@ -830,6 +848,28 @@ namespace MWSound
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)
{
// We update active say sounds map for specific actors here
@ -884,17 +924,12 @@ namespace MWSound
{
Sound *sound = sndidx->first.get();
if(!ptr.isEmpty() && sound->getIs3D())
if (sound->getIs3D())
{
const ESM::Position &pos = ptr.getRefData().getPosition();
const osg::Vec3f objpos(pos.asVec3());
sound->setPosition(objpos);
if(sound->getDistanceCull())
{
if((mListenerPos - objpos).length2() > 2000*2000)
mOutput->finishSound(sound);
}
if (!ptr.isEmpty())
sound->setPosition(ptr.getRefData().getPosition().asVec3());
cull3DSound(sound);
}
if(!sound->updateFade(duration) || !mOutput->isSoundPlaying(sound))
@ -924,17 +959,15 @@ namespace MWSound
{
MWWorld::ConstPtr ptr = sayiter->first;
Stream *sound = sayiter->second.get();
if(!ptr.isEmpty() && sound->getIs3D())
if (sound->getIs3D())
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
sound->setPosition(pos);
if(sound->getDistanceCull())
if (!ptr.isEmpty())
{
if((mListenerPos - pos).length2() > 2000*2000)
mOutput->finishStream(sound);
MWBase::World *world = MWBase::Environment::get().getWorld();
sound->setPosition(world->getActorHeadTransform(ptr).getTrans());
}
cull3DSound(sound);
}
if(!sound->updateFade(duration) || !mOutput->isStreamPlaying(sound))

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

Loading…
Cancel
Save