mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-02 07:45:35 +00:00
Use Ogre's resource group manager to handle sound files
This commit is contained in:
parent
80dbf82a74
commit
0261aac518
5 changed files with 125 additions and 122 deletions
|
@ -12,12 +12,83 @@ static void fail(const std::string &msg)
|
||||||
namespace MWSound
|
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)
|
void MpgSnd_Decoder::open(const std::string &fname)
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
mDataStream = mResourceMgr.openResource(fname);
|
||||||
|
|
||||||
SF_INFO info;
|
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(mSndFile)
|
||||||
{
|
{
|
||||||
if(info.channels == 1)
|
if(info.channels == 1)
|
||||||
|
@ -33,9 +104,11 @@ void MpgSnd_Decoder::open(const std::string &fname)
|
||||||
mSampleRate = info.samplerate;
|
mSampleRate = info.samplerate;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mDataStream->seek(0);
|
||||||
|
|
||||||
mMpgFile = mpg123_new(NULL, NULL);
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -79,6 +152,8 @@ void MpgSnd_Decoder::close()
|
||||||
mpg123_delete(mMpgFile);
|
mpg123_delete(mMpgFile);
|
||||||
mMpgFile = NULL;
|
mMpgFile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDataStream.setNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <OgreDataStream.h>
|
||||||
|
|
||||||
#include "mpg123.h"
|
#include "mpg123.h"
|
||||||
#include "sndfile.h"
|
#include "sndfile.h"
|
||||||
|
|
||||||
|
@ -16,6 +18,15 @@ namespace MWSound
|
||||||
SNDFILE *mSndFile;
|
SNDFILE *mSndFile;
|
||||||
mpg123_handle *mMpgFile;
|
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;
|
ChannelConfig mChanConfig;
|
||||||
int mSampleRate;
|
int mSampleRate;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
enum SampleType {
|
enum SampleType {
|
||||||
|
@ -20,9 +22,10 @@ namespace MWSound
|
||||||
size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type);
|
size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type);
|
||||||
size_t bytesToFrames(size_t bytes, 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 open(const std::string &fname) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
@ -31,10 +34,9 @@ namespace MWSound
|
||||||
virtual size_t read(char *buffer, size_t bytes) = 0;
|
virtual size_t read(char *buffer, size_t bytes) = 0;
|
||||||
virtual void rewind() = 0;
|
virtual void rewind() = 0;
|
||||||
|
|
||||||
|
Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
|
||||||
|
{ }
|
||||||
virtual ~Sound_Decoder() { }
|
virtual ~Sound_Decoder() { }
|
||||||
|
|
||||||
friend class OpenAL_Output;
|
|
||||||
friend class SoundManager;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ namespace MWSound
|
||||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||||
: mFSStrict(fsstrict)
|
: mFSStrict(fsstrict)
|
||||||
, mEnvironment(environment)
|
, mEnvironment(environment)
|
||||||
, mCurrentPlaylist(NULL)
|
|
||||||
{
|
{
|
||||||
if(!useSound)
|
if(!useSound)
|
||||||
return;
|
return;
|
||||||
|
@ -59,24 +58,7 @@ namespace MWSound
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The music library will accept these filetypes
|
mResourceMgr = Ogre::ResourceGroupManager::getSingletonPtr();
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundManager::~SoundManager()
|
SoundManager::~SoundManager()
|
||||||
|
@ -120,7 +102,14 @@ namespace MWSound
|
||||||
max = std::max(min, max);
|
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
|
// Add a sound to the list and play it
|
||||||
|
@ -163,53 +152,25 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
if(mMusic)
|
if(mMusic)
|
||||||
mMusic->stop();
|
mMusic->stop();
|
||||||
setPlaylist();
|
mMusic.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::streamMusicFull(const std::string& filename)
|
void SoundManager::streamMusic(const std::string& filename)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if(mMusic)
|
if(mMusic)
|
||||||
mMusic->stop();
|
mMusic->stop();
|
||||||
mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f));
|
mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::streamMusic(const std::string& filename)
|
|
||||||
{
|
|
||||||
std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string();
|
|
||||||
if(!filePath.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
streamMusicFull(filePath);
|
|
||||||
}
|
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
std::cout << "Music Error: " << e.what() << "\n";
|
std::cout << "Music Error: " << e.what() << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SoundManager::startRandomTitle()
|
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()
|
bool SoundManager::isMusicPlaying()
|
||||||
|
@ -217,51 +178,20 @@ namespace MWSound
|
||||||
return mMusic && mMusic->isPlaying();
|
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)
|
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)
|
void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename)
|
||||||
{
|
{
|
||||||
// The range values are not tested
|
// The range values are not tested
|
||||||
std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true);
|
std::string filePath = std::string("Sound\\")+filename;
|
||||||
if(!filePath.empty())
|
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);
|
play3d(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
|
|
||||||
#include <components/files/filelibrary.hpp>
|
#include <components/files/filelibrary.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
@ -29,6 +31,8 @@ namespace MWSound
|
||||||
|
|
||||||
class SoundManager
|
class SoundManager
|
||||||
{
|
{
|
||||||
|
Ogre::ResourceGroupManager *mResourceMgr;
|
||||||
|
|
||||||
// This is used for case insensitive and slash-type agnostic file
|
// This is used for case insensitive and slash-type agnostic file
|
||||||
// finding. It takes DOS paths (any case, \\ slashes or / slashes)
|
// finding. It takes DOS paths (any case, \\ slashes or / slashes)
|
||||||
// relative to the sound dir, and translates them into full paths
|
// relative to the sound dir, and translates them into full paths
|
||||||
|
@ -41,19 +45,6 @@ namespace MWSound
|
||||||
|
|
||||||
boost::shared_ptr<Sound> mMusic;
|
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 boost::shared_ptr<Sound> SoundPtr;
|
||||||
typedef std::map<std::string,SoundPtr> IDMap;
|
typedef std::map<std::string,SoundPtr> IDMap;
|
||||||
typedef std::map<MWWorld::Ptr,IDMap> SoundMap;
|
typedef std::map<MWWorld::Ptr,IDMap> SoundMap;
|
||||||
|
@ -92,12 +83,6 @@ namespace MWSound
|
||||||
bool isMusicPlaying();
|
bool isMusicPlaying();
|
||||||
///< Returns true if music is playing
|
///< 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="");
|
void playPlaylist(std::string playlist="");
|
||||||
///< Start playing music from the selected folder
|
///< Start playing music from the selected folder
|
||||||
/// \param name of the folder that contains the playlist
|
/// \param name of the folder that contains the playlist
|
||||||
|
|
Loading…
Reference in a new issue