diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0c0f63475..ccdbff3af 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,14 +19,10 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif + #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace -{ - const int loudnessFPS = 20; // loudness values per second of audio -} - namespace MWSound { @@ -779,7 +775,7 @@ void OpenAL_Output::deinit() } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness *loudness) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { throwALerror(); @@ -806,9 +802,6 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness * decoder->readAll(data); decoder->close(); - if(loudness != 0) - loudness->analyzeLoudness(data, srate, chans, type, static_cast(loudnessFPS)); - ALuint buf = 0; try { alGenBuffers(1, &buf); @@ -975,7 +968,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec throw; } - sound->updateAll(true); + sound->updateAll(false); sound->play(); return sound; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index e6f438ad8..912bebb56 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -38,7 +38,7 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); + virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 8818ac23c..eb67908a2 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -20,7 +20,6 @@ namespace MWSound float mMinDist, mMaxDist; Sound_Handle mHandle; - Sound_Loudness mLoudness; size_t mReferences; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2326c64ba..86be94d33 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -26,7 +26,7 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b63e20395..bafd3aa1e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -30,6 +30,11 @@ #endif +namespace +{ + const int sLoudnessFPS = 20; // loudness values per second of audio +} + namespace MWSound { SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) @@ -103,13 +108,6 @@ namespace MWSound mOutput->unloadSound(sfxiter->second.mHandle); sfxiter->second.mHandle = 0; } - sfxiter = mVoiceSoundBuffers.begin(); - for(;sfxiter != mVoiceSoundBuffers.end();++sfxiter) - { - if(sfxiter->second.mHandle) - mOutput->unloadSound(sfxiter->second.mHandle); - sfxiter->second.mHandle = 0; - } } mOutput.reset(); } @@ -188,32 +186,37 @@ namespace MWSound return sfx; } - const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) + void SoundManager::loadVoice(const std::string &voicefile) { - NameBufferMap::iterator sfxiter = mVoiceSoundBuffers.find(voicefile); - if(sfxiter == mVoiceSoundBuffers.end()) + NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); + if(lipiter != mVoiceLipBuffers.end()) return; + + DecoderPtr decoder = getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(voicefile)) + decoder->open(voicefile); + else { - 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(); + std::string file = voicefile; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); + } - float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; - float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; - minDistance = std::max(minDistance, 1.f); - maxDistance = std::max(minDistance, maxDistance); + ChannelConfig chans; + SampleType type; + int srate; + decoder->getInfo(&srate, &chans, &type); - sfxiter = mVoiceSoundBuffers.insert(std::make_pair( - voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) - )).first; - mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); - } - else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); + std::vector data; + decoder->readAll(data); + decoder->close(); - return &sfxiter->second; + Sound_Loudness loudness; + loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); + + mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); } @@ -336,14 +339,25 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + 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(); + static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); + static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, - objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice ); mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); } @@ -358,12 +372,13 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - NameBufferMap::const_iterator sfxiter = mVoiceSoundBuffers.find(snditer->second.second); - if(sfxiter != mVoiceSoundBuffers.end()) + MWBase::SoundPtr sound = snditer->second.first; + NameLoudnessMap::const_iterator lipiter = mVoiceLipBuffers.find(snditer->second.second); + if(lipiter != mVoiceLipBuffers.end()) { - float sec = snditer->second.first->getTimeOffset(); - if(snditer->second.first->isPlaying()) - return sfxiter->second.mLoudness.getLoudnessAtTime(sec); + float sec = sound->getTimeOffset(); + if(sound->isPlaying()) + return lipiter->second.getLoudnessAtTime(sec); } } @@ -376,12 +391,15 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); - MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, - sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice ); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db5ced5c3..00c0af7b2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -9,6 +9,7 @@ #include +#include "loudness.hpp" #include "../mwbase/soundmanager.hpp" namespace VFS @@ -47,9 +48,9 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; size_t mBufferCacheSize; - // Should stream voices, but that requires handling the "lip" data - // separately from buffer loading. - NameBufferMap mVoiceSoundBuffers; + + typedef std::map NameLoudnessMap; + NameLoudnessMap mVoiceLipBuffers; typedef std::set SoundSet; SoundSet mUnusedBuffers; @@ -75,7 +76,8 @@ namespace MWSound int mPausedSoundTypes; Sound_Buffer *lookup(const std::string &soundId); - const Sound_Buffer *lookupVoice(const std::string &voicefile); + // Ensure the loudness/"lip" data is loaded + void loadVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration);