diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 2a3ef980c..e1ca8e745 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -103,13 +103,16 @@ namespace MWBase ///< Play a 2D audio track, using a custom decoder virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, - PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal) = 0; + PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, + float offset=0) = 0; ///< Play a sound, independently of 3D-position + ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal) = 0; + PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a sound from an object + ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, @@ -123,6 +126,12 @@ namespace MWBase virtual void stopSound(const std::string& soundId) = 0; ///< Stop a non-3d looping sound + virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration) = 0; + ///< Fade out given sound (that is already playing) of given object + ///< @param reference Reference to object, whose sound is faded out + ///< @param soundId ID of the sound to fade out. + ///< @param duration Time until volume reaches 0. + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 91d38b8ef..381ffa233 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -6,6 +6,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/ptr.hpp" @@ -142,9 +143,23 @@ namespace MWClass // animated door boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); if (MWBase::Environment::get().getWorld()->getOpenOrCloseDoor(ptr)) + { + MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, + closeSound, 0.5); + float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + action->setSoundOffset(offset); action->setSound(openSound); + } else + { + MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, + openSound, 0.5); + float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + //most if not all door have closing bang somewhere in the middle of the sound, + //so we divide offset by two + action->setSoundOffset(offset * 0.5); action->setSound(closeSound); + } return action; } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 690b07331..734a5e42a 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -491,6 +491,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); + virtual double getLength(); virtual void update(); }; @@ -554,6 +555,17 @@ double OpenAL_Sound::getTimeOffset() return t; } +double OpenAL_Sound::getLength() +{ + ALint bufferSize, frequency, channels, bitsPerSample; + alGetBufferi(mBuffer, AL_SIZE, &bufferSize); + alGetBufferi(mBuffer, AL_FREQUENCY, &frequency); + alGetBufferi(mBuffer, AL_CHANNELS, &channels); + alGetBufferi(mBuffer, AL_BITS, &bitsPerSample); + + return (8.0*bufferSize)/(frequency*channels*bitsPerSample); +} + void OpenAL_Sound::updateAll(bool local) { alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); @@ -817,8 +829,7 @@ void OpenAL_Output::bufferFinished(ALuint buf) } } - -MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags,float offset) { boost::shared_ptr sound; ALuint src=0, buf=0; @@ -843,8 +854,13 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f } sound->updateAll(true); + if(offset<0) + offset=0; + if(offset>1) + offset=1; alSourcei(src, AL_BUFFER, buf); + alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); alSourcePlay(src); throwALerror(); @@ -852,7 +868,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f } MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch, - float min, float max, int flags) + float min, float max, int flags, float offset) { boost::shared_ptr sound; ALuint src=0, buf=0; @@ -878,7 +894,14 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre sound->updateAll(false); + if(offset<0) + offset=0; + if(offset>1) + offset=1; + alSourcei(src, AL_BUFFER, buf); + alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 02706b50c..31edf7359 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -45,9 +45,11 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags); + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset); + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float vol, float basevol, float pitch, float min, float max, int flags); + float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 8deaf26a6..670002a30 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -22,6 +22,7 @@ namespace MWSound float mMinDistance; float mMaxDistance; int mFlags; + float mFadeOutTime; public: virtual void stop() = 0; @@ -29,7 +30,7 @@ namespace MWSound virtual double getTimeOffset() = 0; void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } - + void setFadeout(float duration) { mFadeOutTime=duration; } MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } @@ -42,6 +43,7 @@ namespace MWSound , mMinDistance(mindist) , mMaxDistance(maxdist) , mFlags(flags) + , mFadeOutTime(0) { } virtual ~Sound() { } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index b5ccc946a..91e25db52 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,9 +24,11 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) = 0; + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset) = 0; + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float vol, float basevol, float pitch, float min, float max, int flags) = 0; + float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c820a7e16..3081842ea 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -255,7 +255,7 @@ namespace MWSound const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, - 20.0f, 12750.0f, Play_Normal|Play_TypeVoice); + 20.0f, 12750.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); } catch(std::exception &e) @@ -273,7 +273,7 @@ namespace MWSound float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; - MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice); + MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); } catch(std::exception &e) @@ -320,7 +320,7 @@ namespace MWSound } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode) + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) @@ -331,7 +331,7 @@ namespace MWSound float min, max; std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound(file, volume, basevol, pitch, mode|type); + sound = mOutput->playSound(file, volume, basevol, pitch, mode|type, offset); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &e) @@ -342,7 +342,7 @@ namespace MWSound } MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode) + float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) @@ -353,10 +353,10 @@ namespace MWSound float basevol = volumeFromType(type); float min, max; std::string file = lookup(soundId, volume, min, max); - const ESM::Position &pos = ptr.getRefData().getPosition();; + const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); - sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type); + 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); else @@ -431,6 +431,20 @@ namespace MWSound } } + void SoundManager::fadeOutSound3D(const MWWorld::Ptr &ptr, + const std::string& soundId, float duration) + { + SoundMap::iterator snditer = mActiveSounds.begin(); + while(snditer != mActiveSounds.end()) + { + if(snditer->second.first == ptr && snditer->second.second == soundId) + { + snditer->first->setFadeout(duration); + } + snditer++; + } + } + bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const { return isPlaying(ptr, soundId); @@ -520,6 +534,7 @@ namespace MWSound timePassed += duration; if(timePassed < (1.0f/30.0f)) return; + duration = timePassed; timePassed = 0.0f; // Make sure music is still playing @@ -542,6 +557,7 @@ namespace MWSound ); // Check if any sounds are finished playing, and trash them + // Lower volume on fading out sounds SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { @@ -556,6 +572,16 @@ namespace MWSound const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); snditer->first->setPosition(objpos); } + //update fade out + if(snditer->first->mFadeOutTime>0) + { + float soundDuration=duration; + if(soundDuration>snditer->first->mFadeOutTime) + soundDuration=snditer->first->mFadeOutTime; + snditer->first->setVolume(snditer->first->mVolume + - soundDuration / snditer->first->mFadeOutTime * snditer->first->mVolume); + snditer->first->mFadeOutTime -= soundDuration; + } snditer->first->update(); snditer++; } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5fcab14e2..2450ba5c3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -106,13 +106,15 @@ namespace MWSound virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal); + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position + ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal); + PlayMode mode=Play_Normal, float offset=0); ///< Play a sound from an object + ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, @@ -126,6 +128,12 @@ namespace MWSound virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound + virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration); + ///< Fade out given sound (that is already playing) of given object + ///< @param reference Reference to object, whose sound is faded out + ///< @param soundId ID of the sound to fade out. + ///< @param duration Time until volume reaches 0. + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index a37d00727..0fe061e5c 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -11,7 +11,7 @@ const MWWorld::Ptr& MWWorld::Action::getTarget() const return mTarget; } -MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSound), mTarget (target) +MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSound), mTarget (target), mSoundOffset(0) {} MWWorld::Action::~Action() {} @@ -21,14 +21,16 @@ void MWWorld::Action::execute (const Ptr& actor) if (!mSoundId.empty()) { if (mKeepSound && actor.getRefData().getHandle()=="player") - MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else { bool local = mTarget.isEmpty() || !mTarget.isInCell(); // no usable target MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal); + mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal, + mSoundOffset); } } @@ -39,3 +41,8 @@ void MWWorld::Action::setSound (const std::string& id) { mSoundId = id; } + +void MWWorld::Action::setSoundOffset(float offset) +{ + mSoundOffset=offset; +} diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index d8e5d93bb..3e0e8ad1b 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -12,6 +12,7 @@ namespace MWWorld { std::string mSoundId; bool mKeepSound; + float mSoundOffset; Ptr mTarget; // not implemented @@ -34,6 +35,7 @@ namespace MWWorld void execute (const Ptr& actor); void setSound (const std::string& id); + void setSoundOffset(float offset); }; }