Use Ogre's resource group manager to handle sound files

This commit is contained in:
Chris Robinson 2012-03-20 10:34:36 -07:00
parent 80dbf82a74
commit 0261aac518
5 changed files with 125 additions and 122 deletions

View file

@ -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<MpgSnd_Decoder*>(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<MpgSnd_Decoder*>(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<MpgSnd_Decoder*>(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<MpgSnd_Decoder*>(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<MpgSnd_Decoder*>(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<MpgSnd_Decoder*>(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)

View file

@ -3,6 +3,8 @@
#include <string>
#include <OgreDataStream.h>
#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;

View file

@ -3,6 +3,8 @@
#include <string>
#include <OgreResourceGroupManager.h>
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;
};
}

View file

@ -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<std::string> 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

View file

@ -3,6 +3,8 @@
#include <string>
#include <OgreResourceGroupManager.h>
#include <components/files/filelibrary.hpp>
#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<Sound> 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<Sound> SoundPtr;
typedef std::map<std::string,SoundPtr> IDMap;
typedef std::map<MWWorld::Ptr,IDMap> 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