From 054a176c8628f835a7d159e8a635f619deb8bf4f Mon Sep 17 00:00:00 2001 From: Michael Papageorgiou Date: Wed, 7 Mar 2012 17:46:51 +0200 Subject: [PATCH] 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 89cda8f7c..0e2189307 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 53da9040b..70118ea54 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 8f63cdb58..64cac7713 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 6bf7bacf4..c95efb37d 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 000000000..b896379d5 --- /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