From 0261aac5184d961b9cfb8e5aaba8261ffdb3f5cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Mar 2012 10:34:36 -0700 Subject: [PATCH] Use Ogre's resource group manager to handle sound files --- apps/openmw/mwsound/mpgsnd_decoder.cpp | 79 +++++++++++++++- apps/openmw/mwsound/mpgsnd_decoder.hpp | 11 +++ apps/openmw/mwsound/sound_decoder.hpp | 12 ++- apps/openmw/mwsound/soundmanager.cpp | 122 ++++++------------------- apps/openmw/mwsound/soundmanager.hpp | 23 +---- 5 files changed, 125 insertions(+), 122 deletions(-) diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp index 1c13b5b1a..f9bef9774 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.cpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp @@ -12,12 +12,83 @@ static void fail(const std::string &msg) namespace MWSound { +// +// libSndFile io callbacks +// +sf_count_t MpgSnd_Decoder::ogresf_get_filelen(void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->size(); +} + +sf_count_t MpgSnd_Decoder::ogresf_seek(sf_count_t offset, int whence, void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + + if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + +sf_count_t MpgSnd_Decoder::ogresf_read(void *ptr, sf_count_t count, void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(ptr, count); +} + +sf_count_t MpgSnd_Decoder::ogresf_write(const void*, sf_count_t, void*) +{ return -1; } + +sf_count_t MpgSnd_Decoder::ogresf_tell(void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->tell(); +} + +// +// libmpg13 io callbacks +// +ssize_t MpgSnd_Decoder::ogrempg_read(void *user_data, void *ptr, size_t count) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(ptr, count); +} + +off_t MpgSnd_Decoder::ogrempg_lseek(void *user_data, off_t offset, int whence) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + + if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + + void MpgSnd_Decoder::open(const std::string &fname) { close(); + mDataStream = mResourceMgr.openResource(fname); SF_INFO info; - mSndFile = sf_open(fname.c_str(), SFM_READ, &info); + SF_VIRTUAL_IO streamIO = { + ogresf_get_filelen, ogresf_seek, + ogresf_read, ogresf_write, ogresf_tell + }; + mSndFile = sf_open_virtual(&streamIO, SFM_READ, &info, this); if(mSndFile) { if(info.channels == 1) @@ -33,9 +104,11 @@ void MpgSnd_Decoder::open(const std::string &fname) mSampleRate = info.samplerate; return; } + mDataStream->seek(0); mMpgFile = mpg123_new(NULL, NULL); - if(mMpgFile && mpg123_open(mMpgFile, fname.c_str()) == MPG123_OK) + if(mMpgFile && mpg123_replace_reader_handle(mMpgFile, ogrempg_read, ogrempg_lseek, NULL) == MPG123_OK && + mpg123_open_handle(mMpgFile, this) == MPG123_OK) { try { @@ -79,6 +152,8 @@ void MpgSnd_Decoder::close() mpg123_delete(mMpgFile); mMpgFile = NULL; } + + mDataStream.setNull(); } void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) diff --git a/apps/openmw/mwsound/mpgsnd_decoder.hpp b/apps/openmw/mwsound/mpgsnd_decoder.hpp index 19a6079b8..35c753ec8 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.hpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.hpp @@ -3,6 +3,8 @@ #include +#include + #include "mpg123.h" #include "sndfile.h" @@ -16,6 +18,15 @@ namespace MWSound SNDFILE *mSndFile; mpg123_handle *mMpgFile; + Ogre::DataStreamPtr mDataStream; + static sf_count_t ogresf_get_filelen(void *user_data); + static sf_count_t ogresf_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t ogresf_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t ogresf_write(const void*, sf_count_t, void*); + static sf_count_t ogresf_tell(void *user_data); + static ssize_t ogrempg_read(void*, void*, size_t); + static off_t ogrempg_lseek(void*, off_t, int); + ChannelConfig mChanConfig; int mSampleRate; diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 5abd4371d..858cc6353 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -3,6 +3,8 @@ #include +#include + namespace MWSound { enum SampleType { @@ -20,9 +22,10 @@ namespace MWSound size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type); size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type); - class Sound_Decoder + struct Sound_Decoder { - public: + Ogre::ResourceGroupManager &mResourceMgr; + virtual void open(const std::string &fname) = 0; virtual void close() = 0; @@ -31,10 +34,9 @@ namespace MWSound virtual size_t read(char *buffer, size_t bytes) = 0; virtual void rewind() = 0; + Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + { } virtual ~Sound_Decoder() { } - - friend class OpenAL_Output; - friend class SoundManager; }; } diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index e5449e09b..c0a1a8a83 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -39,7 +39,6 @@ namespace MWSound bool useSound, bool fsstrict, MWWorld::Environment& environment) : mFSStrict(fsstrict) , mEnvironment(environment) - , mCurrentPlaylist(NULL) { if(!useSound) return; @@ -59,24 +58,7 @@ namespace MWSound return; } - // 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"); - - // 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) - Files::FileLister(*it / std::string("Sound"), mSoundFiles, true); - - // 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); - - std::string anything = "anything"; // anything is better that a segfault - mCurrentPlaylist = mMusicLibrary.section(anything, mFSStrict); // now points to an empty path + mResourceMgr = Ogre::ResourceGroupManager::getSingletonPtr(); } SoundManager::~SoundManager() @@ -120,7 +102,14 @@ namespace MWSound max = std::max(min, max); } - return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false); + std::string fname = std::string("Sound\\")+snd->sound; + if(!mResourceMgr->resourceExistsInAnyGroup(fname)) + { + std::string::size_type pos = fname.rfind('.'); + if(pos != std::string::npos) + fname = fname.substr(0, pos)+".mp3"; + } + return fname; } // Add a sound to the list and play it @@ -163,53 +152,25 @@ namespace MWSound { if(mMusic) mMusic->stop(); - setPlaylist(); - } - - void SoundManager::streamMusicFull(const std::string& filename) - { - if(mMusic) - mMusic->stop(); - mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f)); + mMusic.reset(); } void SoundManager::streamMusic(const std::string& filename) { - std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string(); - if(!filePath.empty()) + try { - try - { - streamMusicFull(filePath); - } - catch(std::exception &e) - { - std::cout << "Music Error: " << e.what() << "\n"; - } + if(mMusic) + mMusic->stop(); + mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f)); + } + catch(std::exception &e) + { + std::cout << "Music Error: " << e.what() << "\n"; } } void SoundManager::startRandomTitle() { - if(mCurrentPlaylist && !mCurrentPlaylist->empty()) - { - Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin(); - srand( time(NULL) ); - int r = rand() % mCurrentPlaylist->size() + 1; //old random code - - std::advance(fileIter, r - 1); - std::string music = fileIter->string(); - //std::cout << "Playing " << music << "\n"; - - try - { - streamMusicFull(music); - } - catch (std::exception &e) - { - std::cout << "Music Error: " << e.what() << "\n"; - } - } } bool SoundManager::isMusicPlaying() @@ -217,52 +178,21 @@ namespace MWSound return mMusic && mMusic->isPlaying(); } - bool SoundManager::setPlaylist(std::string playlist) - { - const Files::PathContainer* previousPlaylist; - previousPlaylist = mCurrentPlaylist; - if (playlist == "") - { - mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); - } - else 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 - std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true); - if(!filePath.empty()) - play3d(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false); + std::string filePath = std::string("Sound\\")+filename; + if(!mResourceMgr->resourceExistsInAnyGroup(filePath)) + { + std::string::size_type pos = filePath.rfind('.'); + if(pos != std::string::npos) + filePath = filePath.substr(0, pos)+".mp3"; + } + play3d(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false); } bool SoundManager::sayDone(MWWorld::Ptr ptr) const diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 3c7826821..2a474e5f5 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include "../mwworld/ptr.hpp" @@ -29,6 +31,8 @@ namespace MWSound class SoundManager { + Ogre::ResourceGroupManager *mResourceMgr; + // 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 @@ -41,19 +45,6 @@ namespace MWSound boost::shared_ptr mMusic; - void streamMusicFull(const std::string& filename); - ///< Play a soundifle - /// \param absolute filename - - // 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; - typedef boost::shared_ptr SoundPtr; typedef std::map IDMap; typedef std::map SoundMap; @@ -92,12 +83,6 @@ namespace MWSound bool isMusicPlaying(); ///< Returns true if music is playing - 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