diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 59a523023f..48d10e2028 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp new file mode 100644 index 0000000000..fcef7963ab --- /dev/null +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_SOUND_SOUND_BUFFER_H +#define GAME_SOUND_SOUND_BUFFER_H + +#include + +#include "soundmanagerimp.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWSound +{ + class Sound_Buffer + { + public: + std::string mResourceName; + + float mVolume; + float mMinDist, mMaxDist; + + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist) + { } + }; +} + +#endif /* GAME_SOUND_SOUND_BUFFER_H */ diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6e309e28e3..0845240744 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/actorutil.hpp" #include "sound_output.hpp" +#include "sound_buffer.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -103,38 +104,48 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - // Convert a soundId to file name, and modify the volume - // according to the sounds local volume setting, minRange and - // maxRange. - std::string SoundManager::lookup(const std::string &soundId, - float &volume, float &min, float &max) + // Lookup a soundid for its sound data (resource name, local volume, + // minRange and maxRange. The returned pointer is only valid temporarily. + const Sound_Buffer *SoundManager::lookup(const std::string &soundId) { - MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Sound *snd = world->getStore().get().find(soundId); - - volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - - if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); + if(sfxiter == mSoundBuffers.end()) { - 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; - max = snd->mData.mMaxRange; - } + // TODO: We could process all available ESM::Sound records on init + // to pre-fill a non-resizing list, which would allow subsystems to + // reference sounds by index instead of string. + MWBase::World* world = MWBase::Environment::get().getWorld(); + const ESM::Sound *snd = world->getStore().get().find(soundId); - 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); + float volume, min, max; + volume = static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - return "Sound/"+snd->mSound; + if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + { + 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; + 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); + + sfxiter = mSoundBuffers.insert(std::make_pair( + soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) + )).first; + mVFS->normalizeFilename(sfxiter->second.mResourceName); + } + return &sfxiter->second; } // Gets the combined volume settings for the given sound type @@ -268,7 +279,7 @@ namespace MWSound try { float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "Sound/"+filename; + std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -371,11 +382,12 @@ namespace MWSound return sound; try { + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound(file, volume, basevol, pitch, mode|type, offset); + sound = mOutput->playSound(sfx->mResourceName, + volume * sfx->mVolume, basevol, pitch, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception&) @@ -394,18 +406,17 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - if ((mode & Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - { + if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - } - sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); else @@ -427,11 +438,12 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound3D(file, initialPos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index f79bfce155..d9eb7ff3df 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -21,6 +21,7 @@ namespace MWSound class Sound_Output; struct Sound_Decoder; class Sound; + class Sound_Buffer; enum Environment { Env_Normal, @@ -43,6 +44,9 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + typedef std::map NameBufferMap; + NameBufferMap mSoundBuffers; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -59,8 +63,8 @@ namespace MWSound int mPausedSoundTypes; - std::string lookup(const std::string &soundId, - float &volume, float &min, float &max); + const Sound_Buffer *lookup(const std::string &soundId); + void streamMusicFull(const std::string& filename); bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration);