From 03ea3bb62f9f1eb2905d47360e2f31090da59aa5 Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Tue, 6 Mar 2012 01:21:00 +0200 Subject: [PATCH 1/7] SoundManager: first attempt at refactoring. BROKEN --- apps/openmw/engine.cpp | 1 - apps/openmw/mwsound/soundmanager.cpp | 225 +++++++++------------------ apps/openmw/mwsound/soundmanager.hpp | 72 +++++++-- 3 files changed, 139 insertions(+), 159 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4765ceadc5..89cda8f7c9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -341,7 +341,6 @@ void OMW::Engine::go() // Create sound system mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(), mOgre->getCamera(), - mEnvironment.mWorld->getStore(), mDataDirs, mUseSound, mFSStrict, mEnvironment); diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 6795eff195..c269c02368 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -45,7 +45,7 @@ using namespace Mangle::Sound; typedef OEngine::Sound::SoundManager OEManager; -typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; +////typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; // Set the position on a sound based on a Ptr. static void setPos(SoundPtr &snd, const MWWorld::Ptr ref) @@ -60,73 +60,53 @@ static void setPos(SoundPtr &snd, const MWWorld::Ptr ref) namespace MWSound { - struct SoundManager::SoundImpl - { - /* This is the sound manager. It loades, stores and deletes - sounds based on the sound factory it is given. - */ - OEManagerPtr mgr; - SoundPtr music; - /* This class calls update() on the sound manager each frame - using and Ogre::FrameListener - */ - Mangle::Sound::OgreOutputUpdater updater; - - /* This class tracks the movement of an Ogre::Camera and moves - a sound listener automatically to follow it. - */ - Mangle::Sound::OgreListenerMover cameraTracker; - - const ESMS::ESMStore &store; - - typedef std::map IDMap; - typedef std::map PtrMap; - PtrMap sounds; - - // This is used for case insensitive and slash-type agnostic file - // finding. It takes DOS paths (any case, \\ slashes or / slashes) - // relative to the sound dir, and translates them into full paths - // of existing files in the filesystem, if they exist. - bool FSstrict; - FileFinder::LessTreeFileFinder files; - FileFinder::StrictTreeFileFinder strict; - FileFinder::LessTreeFileFinder musicpath; - FileFinder::StrictTreeFileFinder musicpathStrict; - - SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str, - const Files::PathContainer& soundDir, - const Files::PathContainer& musicDir, - bool fsstrict) - : mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) - , updater(mgr) - , cameraTracker(mgr) - , store(str) - , FSstrict(fsstrict) - , files(soundDir) - , strict(soundDir) - , musicpath(musicDir) - , musicpathStrict(musicDir) + SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, + const Files::PathContainer& dataDirs, + bool useSound, bool fsstrict, MWWorld::Environment& environment) + : fsStrict(fsstrict) + , mEnvironment(environment) + , mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) + , updater(mgr) + , cameraTracker(mgr) { + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + MP3Lookup((*it) / "Music/Explore/"); + } - std::cout << "Sound output: " << SOUND_OUT << std::endl; - std::cout << "Sound decoder: " << SOUND_IN << std::endl; - // Attach the camera to the camera tracker - cameraTracker.followCamera(camera); + if(useSound) + { + Files::PathContainer soundDirs;; + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + soundDirs.push_back( *it / std::string("Sound")); + } + soundfiles = soundDirs; + strict = soundDirs; + musicpath = dataDirs; + musicpathStrict = dataDirs; + std::cout << "Sound output: " << SOUND_OUT << std::endl; + std::cout << "Sound decoder: " << SOUND_IN << std::endl; + // Attach the camera to the camera tracker + cameraTracker.followCamera(camera); - // Tell Ogre to update the sound system each frame - root->addFrameListener(&updater); - } + // Tell Ogre to update the sound system each frame + root->addFrameListener(&updater); + } - ~SoundImpl() + test.name = ""; + total = 0; + } + + SoundManager::~SoundManager() { Ogre::Root::getSingleton().removeFrameListener(&updater); cameraTracker.unfollowCamera(); } - - static std::string toMp3(std::string str) + static std::string SoundManager::toMp3(std::string str) { std::string::size_type i = str.rfind('.'); if(str.find('/', i) == std::string::npos && @@ -137,10 +117,10 @@ namespace MWSound return str; } - bool hasFile(const std::string &str, bool music = false) + bool SoundManager::hasFile(const std::string &str, bool music) { bool found = false; - if(!FSstrict) + if(!fsStrict) { if(music) { @@ -153,10 +133,10 @@ namespace MWSound } else { - found = files.has(str); + found = soundfiles.has(str); if (!found) { - found = files.has(toMp3(str)); + found = soundfiles.has(toMp3(str)); } } } @@ -186,22 +166,22 @@ namespace MWSound // Convert a Morrowind sound path (eg. Fx\funny.wav) to full path // with proper slash conversion (eg. datadir/Sound/Fx/funny.wav) - std::string convertPath(const std::string &str, bool music = false) + std::string SoundManager::convertPath(const std::string &str, bool music) { - if(FSstrict == false) + if(fsStrict == false) { // Search and return if(music && musicpath.has(str)) return musicpath.lookup(str); - else if(files.has(str)) - return files.lookup(str); + else if(soundfiles.has(str)) + return soundfiles.lookup(str); // Try mp3 if the wav wasn't found std::string mp3 = toMp3(str); if(music && musicpath.has(mp3)) return musicpath.lookup(mp3); - else if(files.has(mp3)) - return files.lookup(mp3); + else if(soundfiles.has(mp3)) + return soundfiles.lookup(mp3); } else { @@ -225,10 +205,10 @@ namespace MWSound // Convert a soundId to file name, and modify the volume // according to the sounds local volume setting, minRange and // maxRange. - std::string lookup(const std::string &soundId, + std::string SoundManager::lookup(const std::string &soundId, float &volume, float &min, float &max) { - const ESM::Sound *snd = store.sounds.search(soundId); + const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId); if(snd == NULL) return ""; if(snd->data.volume == 0) @@ -253,7 +233,7 @@ namespace MWSound } // Add a sound to the list and play it - void add(const std::string &file, + void SoundManager::add(const std::string &file, MWWorld::Ptr ptr, const std::string &id, float volume, float pitch, @@ -280,7 +260,7 @@ namespace MWSound // Clears all the sub-elements of a given iterator, and then // removes it from 'sounds'. - void clearAll(PtrMap::iterator& it) + void SoundManager::clearAll(PtrMap::iterator& it) { IDMap::iterator sit = it->second.begin(); @@ -301,7 +281,7 @@ namespace MWSound // Stop a sound and remove it from the list. If id="" then // remove the entire object and stop all its sounds. - void remove(MWWorld::Ptr ptr, const std::string &id = "") + void SoundManager::remove(MWWorld::Ptr ptr, const std::string &id) { PtrMap::iterator it = sounds.find(ptr); if(it != sounds.end()) @@ -324,7 +304,7 @@ namespace MWSound } } - bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const + bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const { PtrMap::const_iterator it = sounds.find(ptr); if(it != sounds.end()) @@ -348,7 +328,7 @@ namespace MWSound } // Remove all references to objects belonging to a given cell - void removeCell(const MWWorld::Ptr::CellStore *cell) + void SoundManager::removeCell(const MWWorld::Ptr::CellStore *cell) { PtrMap::iterator it2, it = sounds.begin(); while(it != sounds.end()) @@ -360,7 +340,7 @@ namespace MWSound } } - void updatePositions(MWWorld::Ptr ptr) + void SoundManager::updatePositions(MWWorld::Ptr ptr) { // Find the reference (if any) PtrMap::iterator it = sounds.find(ptr); @@ -378,61 +358,27 @@ namespace MWSound } } } - }; /* SoundImpl */ + void SoundManager::streamMusicFull(const std::string& filename) { - if(!mData) return; - // Play the sound and tell it to stream, if possible. TODO: // Store the reference, the jukebox will need to check status, // control volume etc. - if (mData->music) - mData->music->stop(); - mData->music = mData->mgr->load(filename); - mData->music->setStreaming(true); - mData->music->setVolume(0.4); - mData->music->play(); + if (music) + music->stop(); + music = mgr->load(filename); + music->setStreaming(true); + music->setVolume(0.4); + music->play(); } - SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, - const ESMS::ESMStore &store, const Files::PathContainer& dataDirs, - bool useSound, bool fsstrict, MWWorld::Environment& environment) - : mData(NULL) - , fsStrict(fsstrict) - , mEnvironment(environment) - { - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - MP3Lookup((*it) / "Music/Explore/"); - } - - if(useSound) - { - Files::PathContainer soundDirs;; - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - soundDirs.push_back( *it / std::string("Sound")); - } - mData = new SoundImpl(root, camera, store, soundDirs /* Sound */, dataDirs /* Music */, fsstrict); - } - - test.name = ""; - total = 0; - } - - SoundManager::~SoundManager() - { - if(mData) - delete mData; - } - void SoundManager::streamMusic(const std::string& filename) { - if(mData->hasFile(filename, true)) + if(hasFile(filename, true)) { - streamMusicFull(mData->convertPath(filename, true)); + streamMusicFull(convertPath(filename, true)); } } @@ -476,45 +422,36 @@ namespace MWSound bool SoundManager::isMusicPlaying() { bool test = false; - if(mData && mData->music) + if(music) { - test = mData->music->isPlaying(); + test = music->isPlaying(); } return test; } - SoundManager::SoundImpl SoundManager::getMData() - { - // bool test = mData->music->isPlaying(); - return *mData; - } - void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { // The range values are not tested - if(!mData) return; - if(mData->hasFile(filename)) - mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false); + if(hasFile(filename)) + add(convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false); else std::cout << "Sound file " << filename << " not found, skipping.\n"; } bool SoundManager::sayDone (MWWorld::Ptr ptr) const { - if(!mData) return false; - return !mData->isPlaying(ptr, "_say_sound"); + return !isPlaying(ptr, "_say_sound"); } void SoundManager::playSound(const std::string& soundId, float volume, float pitch) { - if(!mData) return; // Play and forget float min, max; - const std::string &file = mData->lookup(soundId, volume, min, max); + const std::string &file = ookup(soundId, volume, min, max); if (file != "") { - SoundPtr snd = mData->mgr->load(file); + SoundPtr snd = mgr->load(file); snd->setVolume(volume); snd->setRange(min,max); snd->setPitch(pitch); @@ -525,42 +462,34 @@ namespace MWSound void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId, float volume, float pitch, bool loop) { - if(!mData) return; - // Look up the sound in the ESM data float min, max; - const std::string &file = mData->lookup(soundId, volume, min, max); + const std::string &file = lookup(soundId, volume, min, max); if (file != "") - mData->add(file, ptr, soundId, volume, pitch, min, max, loop); + add(file, ptr, soundId, volume, pitch, min, max, loop); } void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId) { - if(!mData) return; - mData->remove(ptr, soundId); + remove(ptr, soundId); } void SoundManager::stopSound (MWWorld::Ptr::CellStore *cell) { - if(!mData) return; - mData->removeCell(cell); + removeCell(cell); } bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const { // Mark all sounds as playing, otherwise the scripts will just // keep trying to play them every frame. - if(!mData) return true; - return mData->isPlaying(ptr, soundId); + return isPlaying(ptr, soundId); } void SoundManager::updateObject(MWWorld::Ptr ptr) { - if (mData != NULL) - { - mData->updatePositions(ptr); - } + updatePositions(ptr); } void SoundManager::update (float duration) diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 5c3f473f2e..cde8475e94 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -6,10 +6,14 @@ #include #include -#include "../mwworld/ptr.hpp" +#include +#include + #include #include +#include +#include "../mwworld/ptr.hpp" namespace Ogre @@ -18,6 +22,17 @@ namespace Ogre class Camera; } +namespace Mangle +{ + namespace Sound + { + typedef boost::shared_ptr SoundPtr; + //struct OgreOutputUpdater; + } +} + +typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; + namespace ESMS { struct ESMStore; @@ -30,14 +45,8 @@ namespace MWWorld namespace MWSound { - //SoundPtr *music; class SoundManager { - // Hide implementation details - engine.cpp is compiling - // enough as it is. - struct SoundImpl; - - SoundImpl *mData; Files::PathContainer files; bool fsStrict; MWWorld::Environment& mEnvironment; @@ -50,9 +59,54 @@ namespace MWSound ///< Play a soundifle /// \param absolute filename + /* This is the sound manager. It loades, stores and deletes + sounds based on the sound factory it is given. + */ + OEManagerPtr mgr; + Mangle::Sound::SoundPtr music; + + /* This class calls update() on the sound manager each frame + using and Ogre::FrameListener + */ + Mangle::Sound::OgreOutputUpdater updater; + + /* This class tracks the movement of an Ogre::Camera and moves + a sound listener automatically to follow it. + */ + Mangle::Sound::OgreListenerMover cameraTracker; + + typedef std::map IDMap; + typedef std::map PtrMap; + PtrMap sounds; + + // This is used for case insensitive and slash-type agnostic file + // finding. It takes DOS paths (any case, \\ slashes or / slashes) + // relative to the sound dir, and translates them into full paths + // of existing files in the filesystem, if they exist. + bool FSstrict; + FileFinder::LessTreeFileFinder soundfiles; + FileFinder::StrictTreeFileFinder strict; + FileFinder::LessTreeFileFinder musicpath; + FileFinder::StrictTreeFileFinder musicpathStrict; + + static std::string toMp3(std::string str); + bool hasFile(const std::string &str, bool music = false); + std::string convertPath(const std::string &str, bool music = false); + std::string lookup(const std::string &soundId, + float &volume, float &min, float &max); + void add(const std::string &file, + MWWorld::Ptr ptr, const std::string &id, + float volume, float pitch, float min, float max, + bool loop); + void clearAll(PtrMap::iterator& it); + void remove(MWWorld::Ptr ptr, const std::string &id = ""); + bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; + void removeCell(const MWWorld::Ptr::CellStore *cell); + void updatePositions(MWWorld::Ptr ptr); + public: - SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, + SoundManager(Ogre::Root*, Ogre::Camera*, const Files::PathContainer& dataDir, bool useSound, bool fsstrict, MWWorld::Environment& environment); ~SoundManager(); @@ -66,8 +120,6 @@ namespace MWSound bool isMusicPlaying(); - SoundImpl getMData(); - void say (MWWorld::Ptr reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/Vo/" in the data directory. From 54353794e580248b1a7638e38fe31371a20dd59b Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Wed, 7 Mar 2012 02:20:15 +0200 Subject: [PATCH 2/7] SoundManager: Completely rewrote the file management --- apps/openmw/mwsound/soundmanager.cpp | 161 +++++---------------------- apps/openmw/mwsound/soundmanager.hpp | 27 ++--- components/files/fileops.cpp | 87 +++++++++++++++ components/files/fileops.hpp | 24 ++++ 4 files changed, 152 insertions(+), 147 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index c269c02368..53da9040bc 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -64,28 +64,36 @@ namespace MWSound SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, const Files::PathContainer& dataDirs, bool useSound, bool fsstrict, MWWorld::Environment& environment) - : fsStrict(fsstrict) + : mFSStrict(fsstrict) , mEnvironment(environment) , mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) , updater(mgr) , cameraTracker(mgr) { - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - MP3Lookup((*it) / "Music/Explore/"); - } - if(useSound) { - Files::PathContainer soundDirs;; + // Make a list of all the sounds + Files::PathContainer soundDirs; for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { soundDirs.push_back( *it / std::string("Sound")); } - soundfiles = soundDirs; - strict = soundDirs; - musicpath = dataDirs; - musicpathStrict = dataDirs; + for (Files::PathContainer::const_iterator it = soundDirs.begin(); it != soundDirs.end(); ++it) + { + Files::FileLister(*it, mSoundFiles, true); + } + + // Make a list of all the music tracks + Files::PathContainer musicDirs; + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + musicDirs.push_back( *it / std::string("Music") / std::string("Explore")); + } + for (Files::PathContainer::const_iterator it = musicDirs.begin(); it != musicDirs.end(); ++it) + { + Files::FileLister(*it, mMusicFiles, true); + } + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; // Attach the camera to the camera tracker @@ -105,103 +113,6 @@ namespace MWSound cameraTracker.unfollowCamera(); } - - static std::string SoundManager::toMp3(std::string str) - { - std::string::size_type i = str.rfind('.'); - if(str.find('/', i) == std::string::npos && - str.find('\\', i) == std::string::npos) - str = str.substr(0, i) + ".mp3"; - else - str += ".mp3"; - return str; - } - - bool SoundManager::hasFile(const std::string &str, bool music) - { - bool found = false; - if(!fsStrict) - { - if(music) - { - found = musicpath.has(str); - // Not found? Try with .mp3 - if (!found) - { - found = musicpath.has(toMp3(str)); - } - } - else - { - found = soundfiles.has(str); - if (!found) - { - found = soundfiles.has(toMp3(str)); - } - } - } - else - { - if(music) - { - found = musicpathStrict.has(str); - // Not found? Try with .mp3 - if (!found) - { - found = musicpathStrict.has(toMp3(str)); - } - } - else - { - found = strict.has(str); - if (!found) - { - found = strict.has(toMp3(str)); - } - } - } - - return found; - } - - // Convert a Morrowind sound path (eg. Fx\funny.wav) to full path - // with proper slash conversion (eg. datadir/Sound/Fx/funny.wav) - std::string SoundManager::convertPath(const std::string &str, bool music) - { - if(fsStrict == false) - { - // Search and return - if(music && musicpath.has(str)) - return musicpath.lookup(str); - else if(soundfiles.has(str)) - return soundfiles.lookup(str); - - // Try mp3 if the wav wasn't found - std::string mp3 = toMp3(str); - if(music && musicpath.has(mp3)) - return musicpath.lookup(mp3); - else if(soundfiles.has(mp3)) - return soundfiles.lookup(mp3); - } - else - { - if(music && musicpathStrict.has(str)) - return musicpathStrict.lookup(str); - else if(strict.has(str)) - return strict.lookup(str); - - // Try mp3 if the wav wasn't found - std::string mp3 = toMp3(str); - if(music && musicpathStrict.has(mp3)) - return musicpathStrict.lookup(mp3); - else if(strict.has(str)) - return strict.lookup(mp3); - } - - // Give up - return ""; - } - // Convert a soundId to file name, and modify the volume // according to the sounds local volume setting, minRange and // maxRange. @@ -229,7 +140,7 @@ namespace MWSound max = std::max(min, max); } - return convertPath(snd->sound); + return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict); } // Add a sound to the list and play it @@ -376,33 +287,20 @@ namespace MWSound void SoundManager::streamMusic(const std::string& filename) { - if(hasFile(filename, true)) + std::string filePath = Files::FileListLocator(mMusicFiles, filename, mFSStrict); + if(!filePath.empty()) { - streamMusicFull(convertPath(filename, true)); + streamMusicFull(filePath); } } - void SoundManager::MP3Lookup(const boost::filesystem::path& dir) - { - boost::filesystem::directory_iterator dir_iter(dir), dir_end; - - std::string mp3extension = ".mp3"; - for(;dir_iter != dir_end; dir_iter++) - { - if(boost::filesystem::extension(*dir_iter) == mp3extension) - { - files.push_back(*dir_iter); - } - } - } - void SoundManager::startRandomTitle() { - if(!files.empty()) + if(!mMusicFiles.empty()) { - Files::PathContainer::iterator fileIter = files.begin(); + Files::PathContainer::iterator fileIter = mMusicFiles.begin(); srand( time(NULL) ); - int r = rand() % files.size() + 1; //old random code + int r = rand() % mMusicFiles.size() + 1; //old random code std::advance(fileIter, r - 1); std::string music = fileIter->string(); @@ -432,8 +330,9 @@ namespace MWSound void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { // The range values are not tested - if(hasFile(filename)) - add(convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false); + std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict); + if(!filePath.empty()) + add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false); else std::cout << "Sound file " << filename << " not found, skipping.\n"; } @@ -448,7 +347,7 @@ namespace MWSound { // Play and forget float min, max; - const std::string &file = ookup(soundId, volume, min, max); + const std::string &file = lookup(soundId, volume, min, max); if (file != "") { SoundPtr snd = mgr->load(file); diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index cde8475e94..8f63cdb58a 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include "../mwworld/ptr.hpp" @@ -47,8 +47,13 @@ namespace MWSound { class SoundManager { - Files::PathContainer files; - bool fsStrict; + + // This is used for case insensitive and slash-type agnostic file + // finding. It takes DOS paths (any case, \\ slashes or / slashes) + // relative to the sound dir, and translates them into full paths + // of existing files in the filesystem, if they exist. + bool mFSStrict; + MWWorld::Environment& mEnvironment; int total; @@ -79,19 +84,10 @@ namespace MWSound typedef std::map PtrMap; PtrMap sounds; - // This is used for case insensitive and slash-type agnostic file - // finding. It takes DOS paths (any case, \\ slashes or / slashes) - // relative to the sound dir, and translates them into full paths - // of existing files in the filesystem, if they exist. - bool FSstrict; - FileFinder::LessTreeFileFinder soundfiles; - FileFinder::StrictTreeFileFinder strict; - FileFinder::LessTreeFileFinder musicpath; - FileFinder::StrictTreeFileFinder musicpathStrict; + Files::PathContainer mSoundFiles; + + Files::PathContainer mMusicFiles; - static std::string toMp3(std::string str); - bool hasFile(const std::string &str, bool music = false); - std::string convertPath(const std::string &str, bool music = false); std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void add(const std::string &file, @@ -116,7 +112,6 @@ namespace MWSound /// \param filename name of a sound file in "Music/" in the data directory. void startRandomTitle(); - void MP3Lookup(const boost::filesystem::path& dir); bool isMusicPlaying(); diff --git a/components/files/fileops.cpp b/components/files/fileops.cpp index 329e4eb05f..d6365e7534 100644 --- a/components/files/fileops.cpp +++ b/components/files/fileops.cpp @@ -1,5 +1,6 @@ #include "fileops.hpp" #include +#include namespace Files { @@ -9,4 +10,90 @@ bool isFile(const char *name) return boost::filesystem::exists(boost::filesystem::path(name)); } + // Makes a list of files from a directory + void FileLister( boost::filesystem::path currentPath, Files::PathContainer& list, bool recursive) + { + if (!boost::filesystem::exists(currentPath)) + { + std::cout << "WARNING: " << currentPath.string() << " does not exist.\n"; + return ; + } + if (recursive) + { + for ( boost::filesystem::recursive_directory_iterator end, itr(currentPath.string()); + itr != end; ++itr ) + { + if ( boost::filesystem::is_regular_file(*itr)) + list.push_back(itr->path()); + } + } + else + { + for ( boost::filesystem::directory_iterator end, itr(currentPath.string()); + itr != end; ++itr ) + { + if ( boost::filesystem::is_regular_file(*itr)) + list.push_back(itr->path()); + } + } + } + + // Locates path in path container + boost::filesystem::path FileListLocator (const Files::PathContainer& list, const boost::filesystem::path& toFind, bool strict) + { + boost::filesystem::path result(""); + if (list.empty()) + return result; + + std::string toFindStr = toFind.string(); + + std::string fullPath; + + // The filesystems slash sets the default slash + std::string slash; + std::string wrongslash; + if(list[0].string().find("\\") != std::string::npos) + { + slash = "\\"; + wrongslash = "/"; + } + else + { + slash = "/"; + wrongslash = "\\"; + } + + // The file being looked for is converted to the new slash + if(toFindStr.find(wrongslash) != std::string::npos ) + { + boost::replace_all(toFindStr, wrongslash, slash); + } + + if (!strict) + { + boost::algorithm::to_lower(toFindStr); + } + + for (Files::PathContainer::const_iterator it = list.begin(); it != list.end(); ++it) + { + fullPath = it->string(); + if (!strict) + { + boost::algorithm::to_lower(fullPath); + } + if(fullPath.find(toFindStr) != std::string::npos) + { + result = *it; + break; + } + } + return result; + } + + // Overloaded form of the locator that takes a string and returns a string + std::string FileListLocator (const Files::PathContainer& list,const std::string& toFind, bool strict) + { + return FileListLocator(list, boost::filesystem::path(toFind), strict).string(); + } + } diff --git a/components/files/fileops.hpp b/components/files/fileops.hpp index a541beffc2..49ef7b9472 100644 --- a/components/files/fileops.hpp +++ b/components/files/fileops.hpp @@ -1,6 +1,12 @@ #ifndef COMPONENTS_FILES_FILEOPS_HPP #define COMPONENTS_FILES_FILEOPS_HPP +#include +#include +#include + +#include + namespace Files { @@ -8,6 +14,24 @@ namespace Files ///\param [in] name - filename bool isFile(const char *name); + /// A vector of Boost Paths, very handy + typedef std::vector PathContainer; + + /// Makes a list of files from a directory by taking a boost + /// path and a Path Container and adds to the Path container + /// all files in the path. It has a recursive option. + void FileLister( boost::filesystem::path currentPath, Files::PathContainer& list, bool recursive); + + /// Locates boost path in path container + /// returns the path from the container + /// that contains the searched path. + /// If it's not found it returns and empty path + /// Takes care of slashes, backslashes and it has a strict option. + boost::filesystem::path FileListLocator (const Files::PathContainer& list, const boost::filesystem::path& toFind, bool strict); + + /// Overloaded form of the locator that takes a string and returns a string + std::string FileListLocator (const Files::PathContainer& list,const std::string& toFind, bool strict); + } #endif /* COMPONENTS_FILES_FILEOPS_HPP */ From 054a176c8628f835a7d159e8a635f619deb8bf4f Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Wed, 7 Mar 2012 17:46:51 +0200 Subject: [PATCH 3/7] Added new FileLibrary class to handle music, this fixes a number of issues. --- apps/openmw/engine.cpp | 5 +- apps/openmw/mwsound/soundmanager.cpp | 70 +++++++++++++---- apps/openmw/mwsound/soundmanager.hpp | 16 +++- components/CMakeLists.txt | 1 + components/files/filelibrary.cpp | 113 +++++++++++++++++++++++++++ components/files/filelibrary.hpp | 48 ++++++++++++ 6 files changed, 235 insertions(+), 18 deletions(-) create mode 100644 components/files/filelibrary.cpp create mode 100644 components/files/filelibrary.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 89cda8f7c9..0e21893070 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -118,8 +118,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // sound if (mUseSound) { - if (!mEnvironment.mSoundManager->isMusicPlaying()) - mEnvironment.mSoundManager->startRandomTitle(); + mEnvironment.mSoundManager->playPlaylist(); mEnvironment.mSoundManager->update (evt.timeSinceLastFrame); } @@ -389,7 +388,7 @@ void OMW::Engine::go() mOgre->getRoot()->addFrameListener (this); // Play some good 'ol tunes - mEnvironment.mSoundManager->startRandomTitle(); + mEnvironment.mSoundManager->playPlaylist(std::string("Explore")); // scripts if (mCompileAll) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 53da9040bc..70118ea547 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -13,7 +13,6 @@ #include #include - #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -45,7 +44,6 @@ using namespace Mangle::Sound; typedef OEngine::Sound::SoundManager OEManager; -////typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; // Set the position on a sound based on a Ptr. static void setPos(SoundPtr &snd, const MWWorld::Ptr ref) @@ -69,11 +67,21 @@ namespace MWSound , mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) , updater(mgr) , cameraTracker(mgr) + , mCurrentPlaylist(NULL) { if(useSound) { - // Make a list of all the sounds + // Temporary list of all sound directories Files::PathContainer soundDirs; + + // The music library will accept these filetypes + // If none is given then it will accept all filetypes + std::vector acceptableExtensions; + acceptableExtensions.push_back(".mp3"); + acceptableExtensions.push_back(".wav"); + acceptableExtensions.push_back(".ogg"); + acceptableExtensions.push_back(".flac"); + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { soundDirs.push_back( *it / std::string("Sound")); @@ -83,17 +91,14 @@ namespace MWSound Files::FileLister(*it, mSoundFiles, true); } - // Make a list of all the music tracks - Files::PathContainer musicDirs; for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { - musicDirs.push_back( *it / std::string("Music") / std::string("Explore")); - } - for (Files::PathContainer::const_iterator it = musicDirs.begin(); it != musicDirs.end(); ++it) - { - Files::FileLister(*it, mMusicFiles, true); + mMusicLibrary.add(*it / std::string("Music"), true, mFSStrict, acceptableExtensions); } + std::string anything = "anything"; // anything is better that a segfault + mCurrentPlaylist = mMusicLibrary.section(anything, mFSStrict); // now points to an empty path + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; // Attach the camera to the camera tracker @@ -287,7 +292,8 @@ namespace MWSound void SoundManager::streamMusic(const std::string& filename) { - std::string filePath = Files::FileListLocator(mMusicFiles, filename, mFSStrict); + std::cout << filename << std::endl; + std::string filePath = mMusicLibrary.locate(filename, mFSStrict).string(); if(!filePath.empty()) { streamMusicFull(filePath); @@ -296,11 +302,11 @@ namespace MWSound void SoundManager::startRandomTitle() { - if(!mMusicFiles.empty()) + if(mCurrentPlaylist && !mCurrentPlaylist->empty()) { - Files::PathContainer::iterator fileIter = mMusicFiles.begin(); + Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin(); srand( time(NULL) ); - int r = rand() % mMusicFiles.size() + 1; //old random code + int r = rand() % mCurrentPlaylist->size() + 1; //old random code std::advance(fileIter, r - 1); std::string music = fileIter->string(); @@ -327,6 +333,42 @@ namespace MWSound return test; } + bool SoundManager::setPlaylist(std::string playlist) + { + const Files::PathContainer* previousPlaylist; + previousPlaylist = mCurrentPlaylist; + if(mMusicLibrary.containsSection(playlist, mFSStrict)) + { + mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); + } + else + { + std::cout << "Warning: playlist named " << playlist << " does not exist.\n"; + } + return previousPlaylist == mCurrentPlaylist; + } + + void SoundManager::playPlaylist(std::string playlist) + { + if (playlist == "") + { + if(!isMusicPlaying()) + { + startRandomTitle(); + } + return; + } + + if(!setPlaylist(playlist)) + { + startRandomTitle(); + } + else if (!isMusicPlaying()) + { + startRandomTitle(); + } + } + void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { // The range values are not tested diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 8f63cdb58a..64cac77135 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "../mwworld/ptr.hpp" @@ -86,7 +87,9 @@ namespace MWSound Files::PathContainer mSoundFiles; - Files::PathContainer mMusicFiles; + Files::FileLibrary mMusicLibrary; + + const Files::PathContainer* mCurrentPlaylist; std::string lookup(const std::string &soundId, float &volume, float &min, float &max); @@ -115,6 +118,17 @@ namespace MWSound bool isMusicPlaying(); + bool setPlaylist(std::string playlist=""); + ///< Set the playlist to an existing folder + /// \param name of the folder that contains the playlist + /// if none is set then it is set to an empty playlist + /// \return Return true if the previous playlist was the same + + void playPlaylist(std::string playlist=""); + ///< Start playing music from the selected folder + /// \param name of the folder that contains the playlist + /// if none is set then it plays from the current playlist + void say (MWWorld::Ptr reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/Vo/" in the data directory. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6bf7bacf40..c95efb37df 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -44,6 +44,7 @@ add_component_dir (misc add_component_dir (files linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager + filelibrary ) add_component_dir (compiler diff --git a/components/files/filelibrary.cpp b/components/files/filelibrary.cpp new file mode 100644 index 0000000000..b896379d50 --- /dev/null +++ b/components/files/filelibrary.cpp @@ -0,0 +1,113 @@ +#include "filelibrary.hpp" + +#include + +#include + +namespace Files +{ + // Looks for a string in a vector of strings + bool containsVectorString(const StringVector& list, const std::string& str) + { + for (StringVector::const_iterator iter = list.begin(); + iter != list.end(); iter++) + { + if (*iter == str) + return true; + } + return false; + } + + // Searches a path and adds the results to the library + void FileLibrary::add(const boost::filesystem::path &root, bool recursive, bool strict, + const StringVector &acceptableExtensions) + { + PathContainer list; + std::string fileExtension; + std::string type; + FileLister(root, list, recursive); + + for (PathContainer::iterator listIter = list.begin(); + listIter != list.end(); ++listIter) + { + if( !acceptableExtensions.empty() ) + { + fileExtension = listIter->extension().string(); + boost::algorithm::to_lower(fileExtension); + if(!containsVectorString(acceptableExtensions, fileExtension)) + continue; + } + + type = listIter->parent_path().leaf().string(); + if (!strict) + boost::algorithm::to_lower(type); + + mMap[type].push_back(*listIter); + //std::cout << "Added path: " << listIter->string() << " in section "<< type <second); + } + } + + // Searches the library for an item and returns a boost path to it + boost::filesystem::path FileLibrary::locate(std::string item, bool strict, std::string sectionName) + { + boost::filesystem::path result(""); + if (sectionName == "") + { + for(StringPathContMap::iterator iter = mMap.begin(); iter != mMap.end(); iter++) + { + result = FileListLocator(iter->second, boost::filesystem::path(item), strict); + if (result != boost::filesystem::path("")) + return result; + } + } + else + { + if (!containsSection(sectionName, strict)) + { + std::cout << "Warning: There is no section named " << sectionName << "\n"; + return result; + } + result = FileListLocator(mMap[sectionName], boost::filesystem::path(item), strict); + } + return result; + } + + // Prints all the available sections, used for debugging + void FileLibrary::printSections() + { + for(StringPathContMap::const_iterator mapIter = mMap.begin(); + mapIter != mMap.end(); mapIter++) + { + std::cout << mapIter->first < + +namespace Files +{ + typedef std::map StringPathContMap; + typedef std::vector StringVector; + + /// Looks for a string in a vector of strings + bool containsVectorString(const StringVector& list, const std::string& str); + + /// \brief Searches directories and makes lists of files according to folder name + class FileLibrary + { + private: + StringPathContMap mMap; + PathContainer mEmptyPath; + + public: + /// Searches a path and adds the results to the library + /// Recursive search and fs strict options are available + /// Takes a vector of acceptable files extensions, if none is given it lists everything. + void add(const boost::filesystem::path &root, bool recursive, bool strict, + const StringVector &acceptableExtensions); + + /// Returns true if the named section exists + /// You can run this check before running section() + bool containsSection(std::string sectionName, bool strict); + + /// Returns a pointer to const for a section of the library + /// which is essentially a PathContainer. + /// If the section does not exists it returns a pointer to an empty path. + const PathContainer* section(std::string sectionName, bool strict); + + /// Searches the library for an item and returns a boost path to it + /// Optionally you can provide a specific section + /// The result is the first that comes up according to alphabetical + /// section naming + boost::filesystem::path locate(std::string item, bool strict, std::string sectionName=""); + + /// Prints all the available sections, used for debugging + void printSections(); + }; +} + +#endif From ad6175c78a809f0acd5d547a1444bfebd99cb80b Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Thu, 8 Mar 2012 23:06:52 +0200 Subject: [PATCH 4/7] SoundManager: Set up the priority for file look up right and take care of a corner case --- apps/openmw/mwsound/soundmanager.cpp | 16 +++++---------- components/files/filelibrary.cpp | 29 +++++++++++++++++----------- components/files/filelibrary.hpp | 1 + 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 70118ea547..5f48081f22 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -71,9 +71,6 @@ namespace MWSound { if(useSound) { - // Temporary list of all sound directories - Files::PathContainer soundDirs; - // The music library will accept these filetypes // If none is given then it will accept all filetypes std::vector acceptableExtensions; @@ -82,16 +79,14 @@ namespace MWSound acceptableExtensions.push_back(".ogg"); acceptableExtensions.push_back(".flac"); - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + // Makes a list of all sound files, searches in reverse for priority reasons + for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it) { - soundDirs.push_back( *it / std::string("Sound")); - } - for (Files::PathContainer::const_iterator it = soundDirs.begin(); it != soundDirs.end(); ++it) - { - Files::FileLister(*it, mSoundFiles, true); + Files::FileLister(*it / std::string("Sound"), mSoundFiles, true); } - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + // Makes a FileLibrary of all music files, searches in reverse for priority reasons + for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it) { mMusicLibrary.add(*it / std::string("Music"), true, mFSStrict, acceptableExtensions); } @@ -292,7 +287,6 @@ namespace MWSound void SoundManager::streamMusic(const std::string& filename) { - std::cout << filename << std::endl; std::string filePath = mMusicLibrary.locate(filename, mFSStrict).string(); if(!filePath.empty()) { diff --git a/components/files/filelibrary.cpp b/components/files/filelibrary.cpp index b896379d50..baefd79ebc 100644 --- a/components/files/filelibrary.cpp +++ b/components/files/filelibrary.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace Files @@ -22,13 +23,24 @@ namespace Files void FileLibrary::add(const boost::filesystem::path &root, bool recursive, bool strict, const StringVector &acceptableExtensions) { - PathContainer list; + if (!boost::filesystem::exists(root)) + { + std::cout << "Warning " << root.string() << " does not exist.\n"; + return; + } + std::string fileExtension; std::string type; - FileLister(root, list, recursive); - for (PathContainer::iterator listIter = list.begin(); - listIter != list.end(); ++listIter) + // remember the last location of the priority list when listing new items + int length = mPriorityList.size(); + + // First makes a list of all candidate files + FileLister(root, mPriorityList, recursive); + + // Then sort these files into sections according to the folder they belong to + for (PathContainer::iterator listIter = mPriorityList.begin() + length; + listIter != mPriorityList.end(); ++listIter) { if( !acceptableExtensions.empty() ) { @@ -43,7 +55,7 @@ namespace Files boost::algorithm::to_lower(type); mMap[type].push_back(*listIter); - //std::cout << "Added path: " << listIter->string() << " in section "<< type <string() << " in section "<< type <second, boost::filesystem::path(item), strict); - if (result != boost::filesystem::path("")) - return result; - } + return FileListLocator(mPriorityList, boost::filesystem::path(item), strict); } else { diff --git a/components/files/filelibrary.hpp b/components/files/filelibrary.hpp index 9013dbb37a..55978084f9 100644 --- a/components/files/filelibrary.hpp +++ b/components/files/filelibrary.hpp @@ -17,6 +17,7 @@ namespace Files private: StringPathContMap mMap; PathContainer mEmptyPath; + PathContainer mPriorityList; public: /// Searches a path and adds the results to the library From 44620ada861e9060f5eb6e0dd1817bd7bd0614d9 Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Fri, 9 Mar 2012 03:22:16 +0200 Subject: [PATCH 5/7] SoundManager: Finish up with Task #172, plus cleanup --- apps/openmw/mwsound/soundmanager.cpp | 27 +++++++++++++++------------ apps/openmw/mwsound/soundmanager.hpp | 21 ++++++--------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 5f48081f22..105dc5a3d0 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include "../mwworld/environment.hpp" @@ -102,9 +101,6 @@ namespace MWSound // Tell Ogre to update the sound system each frame root->addFrameListener(&updater); } - - test.name = ""; - total = 0; } SoundManager::~SoundManager() @@ -430,15 +426,22 @@ namespace MWSound void SoundManager::update (float duration) { MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); + static int total = 0; + static std::string regionName = ""; + static float timePassed = 0.0; + timePassed += duration; //If the region has changed - if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10) + if(!(current->cell->data.flags & current->cell->Interior) && timePassed >= 10) { - timer.restart(); - if (test.name != current->cell->region) + + ESM::Region test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region)); + + timePassed = 0; + if (regionName != current->cell->region) { + regionName = current->cell->region; total = 0; - test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region)); } if(test.soundList.size() > 0) @@ -462,15 +465,15 @@ namespace MWSound soundIter = test.soundList.begin(); while (soundIter != test.soundList.end()) { - const ESM::NAME32 go = soundIter->sound; + const std::string go = soundIter->sound.toString(); int chance = (int) soundIter->chance; //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; soundIter++; if( r - pos < chance) { //play sound - std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0); + std::cout << "Sound: " << go <<" Chance:" << chance << "\n"; + mEnvironment.mSoundManager->playSound(go, 20.0, 1.0); break; } @@ -480,7 +483,7 @@ namespace MWSound } else if(current->cell->data.flags & current->cell->Interior) { - test.name = ""; + regionName = ""; } } diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 64cac77135..39370d755d 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -3,15 +3,11 @@ #include -#include -#include - #include #include #include -#include -#include + #include #include "../mwworld/ptr.hpp" @@ -28,17 +24,11 @@ namespace Mangle namespace Sound { typedef boost::shared_ptr SoundPtr; - //struct OgreOutputUpdater; } } typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; -namespace ESMS -{ - struct ESMStore; -} - namespace MWWorld { struct Environment; @@ -57,10 +47,6 @@ namespace MWSound MWWorld::Environment& mEnvironment; - int total; - ESM::Region test; - boost::timer timer; - void streamMusicFull (const std::string& filename); ///< Play a soundifle /// \param absolute filename @@ -85,10 +71,13 @@ namespace MWSound typedef std::map PtrMap; PtrMap sounds; + // A list of all sound files used to lookup paths Files::PathContainer mSoundFiles; + // A library of all Music file paths stored by the folder they are contained in Files::FileLibrary mMusicLibrary; + // Points to the current playlist of music files stored in the music library const Files::PathContainer* mCurrentPlaylist; std::string lookup(const std::string &soundId, @@ -115,8 +104,10 @@ namespace MWSound /// \param filename name of a sound file in "Music/" in the data directory. void startRandomTitle(); + ///< Starts a random track from the current playlist bool isMusicPlaying(); + ///< Returns true if music is playing bool setPlaylist(std::string playlist=""); ///< Set the playlist to an existing folder From a309ef7b55bbf7dfc73e3851cd0e2edabe931ce2 Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Fri, 9 Mar 2012 03:56:29 +0200 Subject: [PATCH 6/7] Corrected setPlaylist and added stopMusic --- apps/openmw/mwsound/soundmanager.cpp | 13 ++++++++++++- apps/openmw/mwsound/soundmanager.hpp | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 105dc5a3d0..270a45656b 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -266,6 +266,13 @@ namespace MWSound } } + void SoundManager::stopMusic() + { + if (music) + music->stop(); + setPlaylist(); + } + void SoundManager::streamMusicFull(const std::string& filename) { @@ -327,7 +334,11 @@ namespace MWSound { const Files::PathContainer* previousPlaylist; previousPlaylist = mCurrentPlaylist; - if(mMusicLibrary.containsSection(playlist, mFSStrict)) + if (playlist == "") + { + mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); + } + else if(mMusicLibrary.containsSection(playlist, mFSStrict)) { mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); } diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 39370d755d..29aacb373e 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -99,6 +99,9 @@ namespace MWSound MWWorld::Environment& environment); ~SoundManager(); + void stopMusic(); + ///< Stops music if it's playing + void streamMusic(const std::string& filename); ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. From 6f46f2b7a0d5fd16ba89a843aae82fa8b48d46e0 Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Fri, 9 Mar 2012 18:10:23 +0200 Subject: [PATCH 7/7] SoundManager: add the ability to play non-3d looping sounds --- apps/openmw/mwsound/soundmanager.cpp | 25 +++++++++++++++++++++++-- apps/openmw/mwsound/soundmanager.hpp | 7 ++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 270a45656b..2440eda238 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -386,18 +386,28 @@ namespace MWSound } - void SoundManager::playSound(const std::string& soundId, float volume, float pitch) + void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop) { - // Play and forget float min, max; const std::string &file = lookup(soundId, volume, min, max); if (file != "") { SoundPtr snd = mgr->load(file); + snd->setRepeat(loop); snd->setVolume(volume); snd->setRange(min,max); snd->setPitch(pitch); snd->play(); + + if (loop) + { + // Only add the looping sound once + IDMap::iterator it = mLoopedSounds.find(soundId); + if(it == mLoopedSounds.end()) + { + mLoopedSounds[soundId] = WSoundPtr(snd); + } + } } } @@ -421,6 +431,17 @@ namespace MWSound removeCell(cell); } + void SoundManager::stopSound(const std::string& soundId) + { + IDMap::iterator it = mLoopedSounds.find(soundId); + if(it != mLoopedSounds.end()) + { + SoundPtr snd = it->second.lock(); + if(snd) snd->stop(); + mLoopedSounds.erase(it); + } + } + bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const { // Mark all sounds as playing, otherwise the scripts will just diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 29aacb373e..03c19ce774 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -80,6 +80,8 @@ namespace MWSound // Points to the current playlist of music files stored in the music library const Files::PathContainer* mCurrentPlaylist; + IDMap mLoopedSounds; + std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void add(const std::string &file, @@ -130,7 +132,7 @@ namespace MWSound bool sayDone (MWWorld::Ptr reference) const; ///< Is actor not speaking? - void playSound (const std::string& soundId, float volume, float pitch); + void playSound (const std::string& soundId, float volume, float pitch, bool loop=false); ///< Play a sound, independently of 3D-position void playSound3D (MWWorld::Ptr reference, const std::string& soundId, @@ -144,6 +146,9 @@ namespace MWSound void stopSound (MWWorld::Ptr::CellStore *cell); ///< Stop all sounds for the given cell. + void stopSound(const std::string& soundId); + ///< Stop a non-3d looping sound + bool getSoundPlaying (MWWorld::Ptr reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object?