From 9f90a1e44bba06c581eb423172fe0648d4a646e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Dec 2014 22:37:50 +0100 Subject: [PATCH 1/5] Remove script access to deleted references that have no content file In original MW these objects are permanently deleted and can not be accessed anymore. --- apps/openmw/mwworld/cellreflist.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index cf1289654..037de8645 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -27,7 +27,9 @@ namespace MWWorld LiveRef *find (const std::string& name) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mRef.getRefId() == name) + if (!iter->mData.isDeletedByContentFile() + && (iter->mRef.getRefNum().mContentFile != -1 || iter->mData.getCount() > 0) + && iter->mRef.getRefId() == name) return &*iter; return 0; From fbed429b257503417ecc32ef26f03c90a728a0d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Dec 2014 17:24:45 +0100 Subject: [PATCH 2/5] Use GMSTs for sound fading distance --- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 781bfb5d5..251b05890 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -103,24 +103,31 @@ namespace MWSound std::string SoundManager::lookup(const std::string &soundId, float &volume, float &min, float &max) { - const ESM::Sound *snd = - MWBase::Environment::get().getWorld()->getStore().get().find(soundId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + const ESM::Sound *snd = world->getStore().get().find(soundId); volume *= pow(10.0, (snd->mData.mVolume/255.0*3348.0 - 3348.0) / 2000.0); if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) { - min = 100.0f; - max = 2000.0f; + static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); + min = fAudioDefaultMinDistance; + max = fAudioDefaultMaxDistance; } else { - min = snd->mData.mMinRange * 20.0f; - max = snd->mData.mMaxRange * 50.0f; - min = std::max(min, 1.0f); - max = std::max(min, max); + min = snd->mData.mMinRange; + max = snd->mData.mMaxRange; } + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + min *= fAudioMinDistanceMult; + max *= fAudioMaxDistanceMult; + min = std::max(min, 1.0f); + max = std::max(min, max); + return "Sound/"+snd->mSound; } @@ -250,8 +257,19 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos); + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + + float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; + float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; + minDistance = std::max(minDistance, 1.f); + maxDistance = std::max(minDistance, maxDistance); + MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, - 20.0f, 1500.0f, Play_Normal|Play_TypeVoice, 0, true); + minDistance, maxDistance, Play_Normal|Play_TypeVoice, 0, true); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); } catch(std::exception &e) From cf85cbbc8e48f790e41faad5a765d94219debaef Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Dec 2014 17:43:56 +0100 Subject: [PATCH 3/5] Switch sound distance model to AL_INVERSE_DISTANCE --- apps/openmw/mwsound/openal_output.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3d2795ce1..fcdc60ee3 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -628,9 +628,7 @@ void OpenAL_Sound3D::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) - gain = 0.0f; - else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -696,7 +694,7 @@ void OpenAL_Output::init(const std::string &devname) fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); } - alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); + alDistanceModel(AL_INVERSE_DISTANCE); throwALerror(); ALCint maxmono=0, maxstereo=0; From f6960debcbf5d6b3758a6dca8da35c4e89daee1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Dec 2014 23:26:09 +0100 Subject: [PATCH 4/5] Attach sound listener to the player head instead of camera --- apps/openmw/mwrender/camera.cpp | 11 ----------- apps/openmw/mwrender/camera.hpp | 3 --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 1850df904..c7a27dfe8 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -7,7 +7,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/refdata.hpp" @@ -120,15 +119,6 @@ namespace MWRender setPosition(Ogre::Vector3(x,y,z)); } - void Camera::updateListener() - { - Ogre::Vector3 pos = mCamera->getRealPosition(); - Ogre::Vector3 dir = mCamera->getRealDirection(); - Ogre::Vector3 up = mCamera->getRealUp(); - - MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); - } - void Camera::update(float duration, bool paused) { if (mAnimation->upperBodyReady()) @@ -148,7 +138,6 @@ namespace MWRender } } - updateListener(); if (paused) return; diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index c542dc96c..691a80862 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -50,9 +50,6 @@ namespace MWRender bool mVanityToggleQueued; bool mViewModeToggleQueued; - /// Updates sound manager listener data - void updateListener(); - void setPosition(const Ogre::Vector3& position); void setPosition(float x, float y, float z); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d783857f1..1b5d6e002 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1560,6 +1560,8 @@ namespace MWWorld updateWindowManager (); + updateSoundListener(); + if (!paused && mPlayer->getPlayer().getCell()->isExterior()) { ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); @@ -1567,6 +1569,17 @@ namespace MWWorld } } + void World::updateSoundListener() + { + Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); + if(actor) playerPos.z += 1.85*actor->getHalfExtents().z; + Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * + Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); + MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(), + playerOrient.zAxis()); + } + void World::updateWindowManager () { // inform the GUI about focused object diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2da6a6e05..555ed7fb7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -109,6 +109,7 @@ namespace MWWorld Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); + void updateSoundListener(); void updateWindowManager (); void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); From 855fe33c59458b2abc05887ace95733ebc44e1cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Dec 2014 23:26:54 +0100 Subject: [PATCH 5/5] Add vanilla-compatible range limiting for playloopsound (Fixes #244, Fixes #1342) --- apps/openmw/mwbase/soundmanager.hpp | 20 +++++++++++++------- apps/openmw/mwscript/soundextensions.cpp | 8 ++++---- apps/openmw/mwsound/openal_output.cpp | 6 ++++-- apps/openmw/mwsound/soundmanagerimp.cpp | 12 ++++++++++++ 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a02a463dd..bc2f3f1c6 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -42,15 +42,21 @@ namespace MWBase Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position * but do not keep it updated (the sound will not move with * the object and will not stop when the object is deleted. */ - - Play_LoopNoEnv = Play_Loop | Play_NoEnv + Play_RemoveAtDistance = 1<<3, /* (3D only) If the listener gets further than 2000 units away + from the sound source, the sound is removed. + This is weird stuff but apparently how vanilla works for sounds + played by the PlayLoopSound family of script functions. Perhaps we + can make this cut off a more subtle fade later, but have to + be careful to not change the overall volume of areas by too much. */ + Play_LoopNoEnv = Play_Loop | Play_NoEnv, + Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance }; enum PlayType { - Play_TypeSfx = 1<<3, /* Normal SFX sound */ - Play_TypeVoice = 1<<4, /* Voice sound */ - Play_TypeFoot = 1<<5, /* Footstep sound */ - Play_TypeMusic = 1<<6, /* Music track */ - Play_TypeMovie = 1<<7, /* Movie audio track */ + Play_TypeSfx = 1<<4, /* Normal SFX sound */ + Play_TypeVoice = 1<<5, /* Voice sound */ + Play_TypeFoot = 1<<6, /* Footstep sound */ + Play_TypeMusic = 1<<7, /* Music track */ + Play_TypeMovie = 1<<8, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie }; diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 73c3ec93a..606de7aa0 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -121,8 +121,8 @@ namespace MWScript MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_Loop : - MWBase::SoundManager::Play_Normal); + mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance + : MWBase::SoundManager::Play_Normal); } }; @@ -150,8 +150,8 @@ namespace MWScript MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, volume, pitch, MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_Loop : - MWBase::SoundManager::Play_Normal); + mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance + : MWBase::SoundManager::Play_Normal); } }; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index fcdc60ee3..bc9478945 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -628,7 +628,9 @@ void OpenAL_Sound3D::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) + gain = 0.0f; + else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -694,7 +696,7 @@ void OpenAL_Output::init(const std::string &devname) fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); } - alDistanceModel(AL_INVERSE_DISTANCE); + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); throwALerror(); ALCint maxmono=0, maxstereo=0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 251b05890..d856f41ee 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -385,6 +385,11 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos); + if ((mode & Play_RemoveAtDistance) && mListenerPos.squaredDistance(objpos) > 2000*2000) + { + return MWBase::SoundPtr(); + } + sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); @@ -650,6 +655,13 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos); snditer->first->setPosition(objpos); + + if ((snditer->first->mFlags & Play_RemoveAtDistance) + && mListenerPos.squaredDistance(Ogre::Vector3(ptr.getRefData().getPosition().pos)) > 2000*2000) + { + mActiveSounds.erase(snditer++); + continue; + } } //update fade out if(snditer->first->mFadeOutTime>0)