Merge remote-tracking branch 'scrawl/videoplayback'

Conflicts:
	apps/openmw/mwscript/docs/vmformat.txt
actorid
Marc Zinnschlag 12 years ago
commit c6ff58d5b5

@ -37,8 +37,8 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
# Sound source selection # Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" ON)
option(USE_AUDIERE "use audiere for sound" OFF) option(USE_AUDIERE "use audiere for sound" ON)
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
# OS X deployment # OS X deployment
@ -137,30 +137,54 @@ set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER) set(OPENMW_LIBS_HEADER)
# Sound setup # Sound setup
set(GOT_SOUND_INPUT 0)
set(SOUND_INPUT_INCLUDES "") set(SOUND_INPUT_INCLUDES "")
set(SOUND_INPUT_LIBRARY "") set(SOUND_INPUT_LIBRARY "")
set(SOUND_DEFINE "") set(SOUND_DEFINE "")
if (USE_FFMPEG) if (USE_FFMPEG)
find_package(FFMPEG REQUIRED) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR}) find_package(FFmpeg)
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) if (FFMPEG_FOUND)
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
set(GOT_SOUND_INPUT 1)
endif (FFMPEG_FOUND)
endif (USE_FFMPEG) endif (USE_FFMPEG)
if (USE_AUDIERE) if (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
find_package(Audiere REQUIRED) find_package(Audiere)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR}) if (AUDIERE_FOUND)
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY}) set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE) set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
endif (USE_AUDIERE) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
set(GOT_SOUND_INPUT 1)
if (USE_MPG123) endif (AUDIERE_FOUND)
endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
if (USE_MPG123 AND NOT GOT_SOUND_INPUT)
find_package(MPG123 REQUIRED) find_package(MPG123 REQUIRED)
find_package(SNDFILE REQUIRED) find_package(SNDFILE REQUIRED)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) if (MPG123_FOUND AND SNDFILE_FOUND)
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY}) set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
endif (USE_MPG123) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
set(GOT_SOUND_INPUT 1)
endif (MPG123_FOUND AND SNDFILE_FOUND)
endif (USE_MPG123 AND NOT GOT_SOUND_INPUT)
if (NOT GOT_SOUND_INPUT)
message(WARNING "--------------------")
message(WARNING "Failed to find any sound input packages")
message(WARNING "--------------------")
endif (NOT GOT_SOUND_INPUT)
if (NOT FFMPEG_FOUND)
message(WARNING "--------------------")
message(WARNING "FFmpeg not found, video playback will be disabled")
message(WARNING "--------------------")
endif (NOT FFMPEG_FOUND)
# Platform specific # Platform specific
if (WIN32) if (WIN32)

@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
compositors characterpreview externalrendering globalmap compositors characterpreview externalrendering globalmap videoplayer
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

@ -128,12 +128,6 @@ float MWBase::Environment::getFrameDuration() const
void MWBase::Environment::cleanup() void MWBase::Environment::cleanup()
{ {
delete mInputManager;
mInputManager = 0;
delete mSoundManager;
mSoundManager = 0;
delete mMechanicsManager; delete mMechanicsManager;
mMechanicsManager = 0; mMechanicsManager = 0;
@ -146,11 +140,17 @@ void MWBase::Environment::cleanup()
delete mScriptManager; delete mScriptManager;
mScriptManager = 0; mScriptManager = 0;
delete mWorld;
mWorld = 0;
delete mSoundManager;
mSoundManager = 0;
delete mWindowManager; delete mWindowManager;
mWindowManager = 0; mWindowManager = 0;
delete mWorld; delete mInputManager;
mWorld = 0; mInputManager = 0;
} }
const MWBase::Environment& MWBase::Environment::get() const MWBase::Environment& MWBase::Environment::get()

@ -22,6 +22,8 @@ namespace MWWorld
namespace MWSound namespace MWSound
{ {
class Sound; class Sound;
class Sound_Decoder;
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
} }
namespace MWBase namespace MWBase
@ -32,7 +34,7 @@ namespace MWBase
class SoundManager class SoundManager
{ {
public: public:
/* These must all fit together */
enum PlayMode { enum PlayMode {
Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
@ -41,6 +43,13 @@ namespace MWBase
* but do not keep it updated (the sound will not move with * but do not keep it updated (the sound will not move with
* the object and will not stop when the object is deleted. */ * the object and will not stop when the object is deleted. */
}; };
enum PlayType {
Play_TypeSfx = 1<<3, /* Normal SFX sound */
Play_TypeVoice = 1<<4, /* Voice sound */
Play_TypeMusic = 1<<5, /* Music track */
Play_TypeMovie = 1<<6, /* Movie audio track */
Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeMusic|Play_TypeMovie
};
private: private:
@ -89,12 +98,15 @@ namespace MWBase
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0;
///< Stop an actor speaking ///< Stop an actor speaking
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
///< Play a 2D audio track, using a custom decoder
virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch,
int mode=Play_Normal) = 0; PlayMode mode=Play_Normal) = 0;
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
float volume, float pitch, int mode=Play_Normal) = 0; float volume, float pitch, PlayMode mode=Play_Normal) = 0;
///< Play a sound from an object ///< Play a sound from an object
virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0;
@ -112,15 +124,16 @@ namespace MWBase
virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0;
///< Is the given sound currently playing on the given object? ///< Is the given sound currently playing on the given object?
virtual void pauseSounds(int types=Play_TypeMask) = 0;
///< Pauses all currently playing sounds, including music.
virtual void resumeSounds(int types=Play_TypeMask) = 0;
///< Resumes all previously paused sounds.
virtual void update(float duration) = 0; virtual void update(float duration) = 0;
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
}; };
inline int operator|(SoundManager::PlayMode a, SoundManager::PlayMode b)
{ return static_cast<int> (a) | static_cast<int> (b); }
inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b)
{ return static_cast<int> (a) & static_cast<int> (b); }
} }
#endif #endif

@ -306,6 +306,11 @@ namespace MWBase
/// 1 - only waiting \n /// 1 - only waiting \n
/// 2 - player is underwater \n /// 2 - player is underwater \n
/// 3 - enemies are nearby (not implemented) /// 3 - enemies are nearby (not implemented)
/// \todo this does not belong here
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
virtual void stopVideo() = 0;
}; };
} }

@ -45,7 +45,9 @@ namespace MWGui
GM_Loading, GM_Loading,
GM_LoadingWallpaper, GM_LoadingWallpaper,
GM_QuickKeysMenu GM_QuickKeysMenu,
GM_Video
}; };
// Windows shown in inventory mode // Windows shown in inventory mode

@ -230,6 +230,8 @@ WindowManager::~WindowManager()
delete mSpellCreationDialog; delete mSpellCreationDialog;
delete mEnchantingDialog; delete mEnchantingDialog;
delete mTrainingWindow; delete mTrainingWindow;
delete mCountDialog;
delete mQuickKeysMenu;
cleanupGarbage(); cleanupGarbage();
@ -407,6 +409,10 @@ void WindowManager::updateVisible()
case GM_Loading: case GM_Loading:
MyGUI::PointerManager::getInstance().setVisible(false); MyGUI::PointerManager::getInstance().setVisible(false);
break; break;
case GM_Video:
MyGUI::PointerManager::getInstance().setVisible(false);
mHud->setVisible(false);
break;
default: default:
// Unsupported mode, switch back to game // Unsupported mode, switch back to game
break; break;

@ -515,6 +515,8 @@ namespace MWInput
{ {
if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))
mWindows.popGuiMode(); mWindows.popGuiMode();
else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video)
MWBase::Environment::get().getWorld ()->stopVideo ();
else else
mWindows.pushGuiMode (MWGui::GM_MainMenu); mWindows.pushGuiMode (MWGui::GM_MainMenu);
} }

@ -37,6 +37,7 @@
#include "npcanimation.hpp" #include "npcanimation.hpp"
#include "externalrendering.hpp" #include "externalrendering.hpp"
#include "globalmap.hpp" #include "globalmap.hpp"
#include "videoplayer.hpp"
using namespace MWRender; using namespace MWRender;
using namespace Ogre; using namespace Ogre;
@ -160,6 +161,9 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
mVideoPlayer = new VideoPlayer(mRendering.getScene ());
mVideoPlayer->setResolution (Settings::Manager::getInt ("resolution x", "Video"), Settings::Manager::getInt ("resolution y", "Video"));
mSun = 0; mSun = 0;
mDebugging = new Debugging(mMwRoot, engine); mDebugging = new Debugging(mMwRoot, engine);
@ -181,7 +185,7 @@ RenderingManager::~RenderingManager ()
delete mOcclusionQuery; delete mOcclusionQuery;
delete mCompositors; delete mCompositors;
delete mWater; delete mWater;
delete mVideoPlayer;
delete mFactory; delete mFactory;
} }
@ -332,6 +336,8 @@ void RenderingManager::update (float duration, bool paused)
} }
mOcclusionQuery->update(duration); mOcclusionQuery->update(duration);
mVideoPlayer->update ();
mRendering.update(duration); mRendering.update(duration);
if(paused) if(paused)
@ -838,6 +844,8 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw)
mCompositors->recreate(); mCompositors->recreate();
mWater->assignTextures(); mWater->assignTextures();
mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight());
const Settings::CategorySettingVector& changed = Settings::Manager::apply(); const Settings::CategorySettingVector& changed = Settings::Manager::apply();
MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME
MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME
@ -921,4 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend
rendering.setup (mRendering.getScene()); rendering.setup (mRendering.getScene());
} }
void RenderingManager::playVideo(const std::string& name, bool allowSkipping)
{
mVideoPlayer->playVideo ("video/" + name, allowSkipping);
}
void RenderingManager::stopVideo()
{
mVideoPlayer->stopVideo ();
}
} // namespace } // namespace

@ -45,6 +45,7 @@ namespace MWRender
class Compositors; class Compositors;
class ExternalRendering; class ExternalRendering;
class GlobalMap; class GlobalMap;
class VideoPlayer;
class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener {
@ -195,6 +196,9 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
void setupExternalRendering (MWRender::ExternalRendering& rendering); void setupExternalRendering (MWRender::ExternalRendering& rendering);
void playVideo(const std::string& name, bool allowSkipping);
void stopVideo();
protected: protected:
virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowResized(Ogre::RenderWindow* rw);
virtual void windowClosed(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw);
@ -248,6 +252,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
MWRender::Shadows* mShadows; MWRender::Shadows* mShadows;
MWRender::Compositors* mCompositors; MWRender::Compositors* mCompositors;
VideoPlayer* mVideoPlayer;
}; };
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,52 @@
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H
#include <OgreMaterial.h>
namespace Ogre
{
class SceneManager;
class SceneNode;
class Rectangle2D;
}
namespace MWRender
{
struct VideoState;
class VideoPlayer
{
public:
VideoPlayer(Ogre::SceneManager* sceneMgr);
~VideoPlayer();
void playVideo (const std::string& resourceName, bool allowSkipping);
void update();
void close();
void stopVideo();
bool isPlaying();
void setResolution (int w, int h) { mWidth = w; mHeight = h; }
private:
VideoState* mState;
bool mAllowSkipping;
Ogre::SceneManager* mSceneMgr;
Ogre::MaterialPtr mVideoMaterial;
Ogre::Rectangle2D* mRectangle;
Ogre::Rectangle2D* mBackgroundRectangle;
Ogre::SceneNode* mNode;
Ogre::SceneNode* mBackgroundNode;
int mWidth;
int mHeight;
};
}
#endif

@ -310,5 +310,5 @@ op 0x20001f3: AddSoulGem
op 0x20001f4: AddSoulGem, explicit reference op 0x20001f4: AddSoulGem, explicit reference
op 0x20001f5: RemoveSoulGem op 0x20001f5: RemoveSoulGem
op 0x20001f6: RemoveSoulGem, explicit reference op 0x20001f6: RemoveSoulGem, explicit reference
op 0x20001f7: PlayBink
opcodes 0x20001f7-0x3ffffff unused opcodes 0x20001f8-0x3ffffff unused

@ -27,6 +27,22 @@ namespace MWScript
{ {
namespace Misc namespace Misc
{ {
class OpPlayBink : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
bool allowSkipping = runtime[0].mInteger;
runtime.pop();
MWBase::Environment::get().getWorld ()->playVideo (name, allowSkipping);
}
};
class OpGetPcSleep : public Interpreter::Opcode0 class OpGetPcSleep : public Interpreter::Opcode0
{ {
public: public:
@ -257,7 +273,7 @@ namespace MWScript
static bool sActivate; static bool sActivate;
public: public:
virtual void execute(Interpreter::Runtime &runtime) virtual void execute(Interpreter::Runtime &runtime)
{ {
InterpreterContext& context = InterpreterContext& context =
@ -307,51 +323,51 @@ namespace MWScript
MWMechanics::EffectKey(key)).mMagnitude > 0); MWMechanics::EffectKey(key)).mMagnitude > 0);
} }
}; };
template<class R> template<class R>
class OpAddSoulGem : public Interpreter::Opcode0 class OpAddSoulGem : public Interpreter::Opcode0
{ {
public: public:
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
std::string creature = runtime.getStringLiteral (runtime[0].mInteger); std::string creature = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
std::string gem = runtime.getStringLiteral (runtime[0].mInteger); std::string gem = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem); MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem);
ref.getPtr().getRefData().setCount (1); ref.getPtr().getRefData().setCount (1);
ref.getPtr().getCellRef().mSoul = creature; ref.getPtr().getCellRef().mSoul = creature;
MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
} }
}; };
template<class R> template<class R>
class OpRemoveSoulGem : public Interpreter::Opcode0 class OpRemoveSoulGem : public Interpreter::Opcode0
{ {
public: public:
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
std::string soul = runtime.getStringLiteral (runtime[0].mInteger); std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{ {
@ -364,7 +380,7 @@ namespace MWScript
break; break;
} }
} }
} }
}; };
template <class R> template <class R>
@ -490,6 +506,8 @@ namespace MWScript
const int opcodeSetDeleteExplicit = 0x20001e6; const int opcodeSetDeleteExplicit = 0x20001e6;
const int opcodeGetSquareRoot = 0x20001e7; const int opcodeGetSquareRoot = 0x20001e7;
const int opcodePlayBink = 0x20001f7;
void registerExtensions (Compiler::Extensions& extensions) void registerExtensions (Compiler::Extensions& extensions)
{ {
extensions.registerFunction ("xbox", 'l', "", opcodeXBox); extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
@ -515,6 +533,7 @@ namespace MWScript
extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode);
extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep);
extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc); extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc);
extensions.registerInstruction ("playbink", "Sl", opcodePlayBink);
extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit);
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit);
@ -548,6 +567,7 @@ namespace MWScript
interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode);
interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep); interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep);
interpreter.installSegment5 (opcodeWakeUpPc, new OpWakeUpPc); interpreter.installSegment5 (opcodeWakeUpPc, new OpWakeUpPc);
interpreter.installSegment5 (opcodePlayBink, new OpPlayBink);
interpreter.installSegment5 (opcodeGetLocked, new OpGetLocked<ImplicitRef>); interpreter.installSegment5 (opcodeGetLocked, new OpGetLocked<ImplicitRef>);
interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked<ExplicitRef>); interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked<ExplicitRef>);
interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect<ImplicitRef>); interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect<ImplicitRef>);

@ -118,7 +118,8 @@ namespace MWScript
std::string sound = runtime.getStringLiteral (runtime[0].mInteger); std::string sound = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop : 0); MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop :
MWBase::SoundManager::Play_Normal);
} }
}; };
@ -144,7 +145,8 @@ namespace MWScript
Interpreter::Type_Float pitch = runtime[0].mFloat; Interpreter::Type_Float pitch = runtime[0].mFloat;
runtime.pop(); runtime.pop();
MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop : 0); MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop :
MWBase::SoundManager::Play_Normal);
} }
}; };

@ -53,6 +53,9 @@ public:
: mStream(stream), refs(1) : mStream(stream), refs(1)
{ } { }
virtual ~OgreFile() { } virtual ~OgreFile() { }
Ogre::String getName()
{ return mStream->getName(); }
}; };
@ -60,7 +63,7 @@ void Audiere_Decoder::open(const std::string &fname)
{ {
close(); close();
audiere::FilePtr file(new OgreFile(mResourceMgr.openResource(fname))); mSoundFile = audiere::FilePtr(new OgreFile(mResourceMgr.openResource(fname)));
mSoundSource = audiere::OpenSampleSource(file); mSoundSource = audiere::OpenSampleSource(file);
int channels, srate; int channels, srate;
@ -86,9 +89,15 @@ void Audiere_Decoder::open(const std::string &fname)
void Audiere_Decoder::close() void Audiere_Decoder::close()
{ {
mSoundFile = NULL;
mSoundSource = NULL; mSoundSource = NULL;
} }
std::string Audiere_Decoder::getName()
{
return mSoundFile->getName();
}
void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
{ {
*samplerate = mSampleRate; *samplerate = mSampleRate;
@ -108,6 +117,11 @@ void Audiere_Decoder::rewind()
mSoundSource->reset(); mSoundSource->reset();
} }
size_t Audiere_Decoder::getSampleOffset()
{
return 0;
}
Audiere_Decoder::Audiere_Decoder() Audiere_Decoder::Audiere_Decoder()
{ {
} }

@ -12,6 +12,7 @@ namespace MWSound
{ {
class Audiere_Decoder : public Sound_Decoder class Audiere_Decoder : public Sound_Decoder
{ {
audiere::FilePtr mSoundFile;
audiere::SampleSourcePtr mSoundSource; audiere::SampleSourcePtr mSoundSource;
int mSampleRate; int mSampleRate;
SampleType mSampleType; SampleType mSampleType;
@ -20,10 +21,12 @@ namespace MWSound
virtual void open(const std::string &fname); virtual void open(const std::string &fname);
virtual void close(); virtual void close();
virtual std::string getName();
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual void rewind(); virtual void rewind();
virtual size_t getSampleOffset();
Audiere_Decoder& operator=(const Audiere_Decoder &rhs); Audiere_Decoder& operator=(const Audiere_Decoder &rhs);
Audiere_Decoder(const Audiere_Decoder &rhs); Audiere_Decoder(const Audiere_Decoder &rhs);

@ -15,28 +15,6 @@ static void fail(const std::string &msg)
{ throw std::runtime_error("FFmpeg exception: "+msg); } { throw std::runtime_error("FFmpeg exception: "+msg); }
struct PacketList {
AVPacket pkt;
PacketList *next;
};
struct FFmpeg_Decoder::MyStream {
AVCodecContext *mCodecCtx;
int mStreamIdx;
PacketList *mPackets;
char *mDecodedData;
size_t mDecodedDataSize;
FFmpeg_Decoder *mParent;
void clearPackets();
void *getAVAudioData(size_t *length);
size_t readAVAudioData(void *data, size_t length);
};
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
{ {
Ogre::DataStreamPtr stream = static_cast<FFmpeg_Decoder*>(user_data)->mDataStream; Ogre::DataStreamPtr stream = static_cast<FFmpeg_Decoder*>(user_data)->mDataStream;
@ -72,166 +50,84 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence)
/* Used by getAV*Data to search for more compressed data, and buffer it in the /* Used by getAV*Data to search for more compressed data, and buffer it in the
* correct stream. It won't buffer data for streams that the app doesn't have a * correct stream. It won't buffer data for streams that the app doesn't have a
* handle for. */ * handle for. */
bool FFmpeg_Decoder::getNextPacket(int streamidx) bool FFmpeg_Decoder::getNextPacket()
{ {
PacketList *packet; if(!mStream)
return false;
packet = (PacketList*)av_malloc(sizeof(*packet)); int stream_idx = mStream - mFormatCtx->streams;
packet->next = NULL; while(av_read_frame(mFormatCtx, &mPacket) >= 0)
next_packet:
while(av_read_frame(mFormatCtx, &packet->pkt) >= 0)
{ {
std::vector<MyStream*>::iterator iter = mStreams.begin(); /* Check if the packet belongs to this stream */
if(stream_idx == mPacket.stream_index)
/* Check each stream the user has a handle for, looking for the one
* this packet belongs to */
while(iter != mStreams.end())
{ {
if((*iter)->mStreamIdx == packet->pkt.stream_index) if((uint64_t)mPacket.pts != AV_NOPTS_VALUE)
{ mNextPts = av_q2d((*mStream)->time_base)*mPacket.pts;
PacketList **last; return true;
last = &(*iter)->mPackets;
while(*last != NULL)
last = &(*last)->next;
*last = packet;
if((*iter)->mStreamIdx == streamidx)
return true;
packet = (PacketList*)av_malloc(sizeof(*packet));
packet->next = NULL;
goto next_packet;
}
iter++;
} }
/* Free the packet and look for another */ /* Free the packet and look for another */
av_free_packet(&packet->pkt); av_free_packet(&mPacket);
} }
av_free(packet);
return false; return false;
} }
void FFmpeg_Decoder::MyStream::clearPackets() bool FFmpeg_Decoder::getAVAudioData()
{ {
while(mPackets) int got_frame, len;
{
PacketList *self = mPackets;
mPackets = self->next;
av_free_packet(&self->pkt); if((*mStream)->codec->codec_type != AVMEDIA_TYPE_AUDIO)
av_free(self); return false;
}
}
void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length)
{
int size;
int len;
if(length) *length = 0;
if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
return NULL;
mDecodedDataSize = 0;
next_packet:
if(!mPackets && !mParent->getNextPacket(mStreamIdx))
return NULL;
/* Decode some data, and check for errors */
size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
while((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size,
&mPackets->pkt)) == 0)
{
PacketList *self;
if(size > 0) do {
break; if(mPacket.size == 0 && !getNextPacket())
return false;
/* Packet went unread and no data was given? Drop it and try the next, /* Decode some data, and check for errors */
* I guess... */ if((len=avcodec_decode_audio4((*mStream)->codec, mFrame, &got_frame, &mPacket)) < 0)
self = mPackets; return false;
mPackets = self->next;
av_free_packet(&self->pkt);
av_free(self);
if(!mPackets)
goto next_packet;
size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
}
if(len < 0)
return NULL;
if(len < mPackets->pkt.size)
{
/* Move the unread data to the front and clear the end bits */ /* Move the unread data to the front and clear the end bits */
int remaining = mPackets->pkt.size - len; int remaining = mPacket.size - len;
memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining); if(remaining <= 0)
memset(&mPackets->pkt.data[remaining], 0, mPackets->pkt.size - remaining); av_free_packet(&mPacket);
mPackets->pkt.size -= len; else
} {
else memmove(mPacket.data, &mPacket.data[len], remaining);
{ av_shrink_packet(&mPacket, remaining);
PacketList *self; }
} while(got_frame == 0 || mFrame->nb_samples == 0);
self = mPackets; mNextPts += (double)mFrame->nb_samples / (double)(*mStream)->codec->sample_rate;
mPackets = self->next;
av_free_packet(&self->pkt);
av_free(self);
}
if(size == 0)
goto next_packet;
/* Set the output buffer size */
mDecodedDataSize = size;
if(length) *length = mDecodedDataSize;
return mDecodedData; return true;
} }
size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
{ {
size_t dec = 0; size_t dec = 0;
while(dec < length) while(dec < length)
{ {
/* If there's no decoded data, find some */ /* If there's no decoded data, find some */
if(mDecodedDataSize == 0) if(mFramePos >= mFrameSize)
{ {
if(getAVAudioData(NULL) == NULL) if(!getAVAudioData())
break; break;
mFramePos = 0;
mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels *
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
} }
if(mDecodedDataSize > 0) /* Get the amount of bytes remaining to be written, and clamp to
{ * the amount of decoded data we have */
/* Get the amount of bytes remaining to be written, and clamp to size_t rem = std::min<size_t>(length-dec, mFrameSize-mFramePos);
* the amount of decoded data we have */
size_t rem = length-dec;
if(rem > mDecodedDataSize)
rem = mDecodedDataSize;
/* Copy the data to the app's buffer and increment */
if(data != NULL)
{
memcpy(data, mDecodedData, rem);
data = (char*)data + rem;
}
dec += rem;
/* If there's any decoded data left, move it to the front of the /* Copy the data to the app's buffer and increment */
* buffer for next time */ memcpy(data, mFrame->data[0]+mFramePos, rem);
if(rem < mDecodedDataSize) data = (char*)data + rem;
memmove(mDecodedData, &mDecodedData[rem], mDecodedDataSize - rem); dec += rem;
mDecodedDataSize -= rem; mFramePos += rem;
}
} }
/* Return the number of bytes we were able to get */ /* Return the number of bytes we were able to get */
@ -239,7 +135,6 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
} }
void FFmpeg_Decoder::open(const std::string &fname) void FFmpeg_Decoder::open(const std::string &fname)
{ {
close(); close();
@ -265,140 +160,155 @@ void FFmpeg_Decoder::open(const std::string &fname)
{ {
if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{ {
std::auto_ptr<MyStream> stream(new MyStream); mStream = &mFormatCtx->streams[j];
stream->mCodecCtx = mFormatCtx->streams[j]->codec;
stream->mStreamIdx = j;
stream->mPackets = NULL;
AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id);
if(!codec)
{
std::stringstream ss("No codec found for id ");
ss << stream->mCodecCtx->codec_id;
fail(ss.str());
}
if(avcodec_open(stream->mCodecCtx, codec) < 0)
fail("Failed to open audio codec " + std::string(codec->long_name));
stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
stream->mDecodedDataSize = 0;
stream->mParent = this;
mStreams.push_back(stream.release());
break; break;
} }
} }
if(mStreams.empty()) if(!mStream)
fail("No audio streams in "+fname); fail("No audio streams in "+fname);
AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
if(!codec)
{
std::stringstream ss("No codec found for id ");
ss << (*mStream)->codec->codec_id;
fail(ss.str());
}
if(avcodec_open2((*mStream)->codec, codec, NULL) < 0)
fail("Failed to open audio codec " + std::string(codec->long_name));
mFrame = avcodec_alloc_frame();
} }
catch(std::exception &e) catch(std::exception &e)
{ {
av_close_input_file(mFormatCtx); avformat_close_input(&mFormatCtx);
mFormatCtx = NULL;
throw; throw;
} }
} }
void FFmpeg_Decoder::close() void FFmpeg_Decoder::close()
{ {
while(!mStreams.empty()) if(mStream)
{ avcodec_close((*mStream)->codec);
MyStream *stream = mStreams.front(); mStream = NULL;
stream->clearPackets(); av_free_packet(&mPacket);
avcodec_close(stream->mCodecCtx); av_freep(&mFrame);
av_free(stream->mDecodedData);
delete stream;
mStreams.erase(mStreams.begin());
}
if(mFormatCtx) if(mFormatCtx)
{ {
AVIOContext* context = mFormatCtx->pb; AVIOContext* context = mFormatCtx->pb;
avformat_close_input(&mFormatCtx);
av_free(context); av_free(context);
mFormatCtx->pb = NULL;
av_close_input_file(mFormatCtx);
} }
mFormatCtx = NULL;
mDataStream.setNull(); mDataStream.setNull();
} }
std::string FFmpeg_Decoder::getName()
{
return mFormatCtx->filename;
}
void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
{ {
if(mStreams.empty()) if(!mStream)
fail("No audio stream info"); fail("No audio stream info");
MyStream *stream = mStreams[0]; if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8)
if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
*type = SampleType_UInt8; *type = SampleType_UInt8;
else if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16)
*type = SampleType_Int16; *type = SampleType_Int16;
else else
fail(std::string("Unsupported sample format: ")+ fail(std::string("Unsupported sample format: ")+
av_get_sample_fmt_name(stream->mCodecCtx->sample_fmt)); av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO)
*chans = ChannelConfig_Mono; *chans = ChannelConfig_Mono;
else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO)
*chans = ChannelConfig_Stereo; *chans = ChannelConfig_Stereo;
else if(stream->mCodecCtx->channel_layout == 0) else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_QUAD)
*chans = ChannelConfig_Quad;
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_5POINT1)
*chans = ChannelConfig_5point1;
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_7POINT1)
*chans = ChannelConfig_7point1;
else if((*mStream)->codec->channel_layout == 0)
{ {
/* Unknown channel layout. Try to guess. */ /* Unknown channel layout. Try to guess. */
if(stream->mCodecCtx->channels == 1) if((*mStream)->codec->channels == 1)
*chans = ChannelConfig_Mono; *chans = ChannelConfig_Mono;
else if(stream->mCodecCtx->channels == 2) else if((*mStream)->codec->channels == 2)
*chans = ChannelConfig_Stereo; *chans = ChannelConfig_Stereo;
else else
{ {
std::stringstream sstr("Unsupported raw channel count: "); std::stringstream sstr("Unsupported raw channel count: ");
sstr << stream->mCodecCtx->channels; sstr << (*mStream)->codec->channels;
fail(sstr.str()); fail(sstr.str());
} }
} }
else else
{ {
char str[1024]; char str[1024];
av_get_channel_layout_string(str, sizeof(str), stream->mCodecCtx->channels, av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels,
stream->mCodecCtx->channel_layout); (*mStream)->codec->channel_layout);
fail(std::string("Unsupported channel layout: ")+str); fail(std::string("Unsupported channel layout: ")+str);
} }
*samplerate = stream->mCodecCtx->sample_rate; *samplerate = (*mStream)->codec->sample_rate;
} }
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
{ {
if(mStreams.empty()) if(!mStream)
fail("No audio streams"); fail("No audio stream");
return readAVAudioData(buffer, bytes);
return mStreams.front()->readAVAudioData(buffer, bytes);
} }
void FFmpeg_Decoder::readAll(std::vector<char> &output) void FFmpeg_Decoder::readAll(std::vector<char> &output)
{ {
if(mStreams.empty()) if(!mStream)
fail("No audio streams"); fail("No audio stream");
MyStream *stream = mStreams.front();
char *inbuf;
size_t got;
while((inbuf=(char*)stream->getAVAudioData(&got)) != NULL && got > 0) while(getAVAudioData())
{
size_t got = mFrame->nb_samples * (*mStream)->codec->channels *
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
const char *inbuf = reinterpret_cast<char*>(mFrame->data[0]);
output.insert(output.end(), inbuf, inbuf+got); output.insert(output.end(), inbuf, inbuf+got);
}
} }
void FFmpeg_Decoder::rewind() void FFmpeg_Decoder::rewind()
{ {
av_seek_frame(mFormatCtx, -1, 0, 0); int stream_idx = mStream - mFormatCtx->streams;
std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets)); if(av_seek_frame(mFormatCtx, stream_idx, 0, 0) < 0)
fail("Failed to seek in audio stream");
av_free_packet(&mPacket);
mFrameSize = mFramePos = 0;
mNextPts = 0.0;
} }
FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL) size_t FFmpeg_Decoder::getSampleOffset()
{ {
static bool done_init = false; int delay = (mFrameSize-mFramePos) / (*mStream)->codec->channels /
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay;
}
FFmpeg_Decoder::FFmpeg_Decoder()
: mFormatCtx(NULL)
, mStream(NULL)
, mFrame(NULL)
, mFrameSize(0)
, mFramePos(0)
, mNextPts(0.0)
{
memset(&mPacket, 0, sizeof(mPacket));
/* We need to make sure ffmpeg is initialized. Optionally silence warning /* We need to make sure ffmpeg is initialized. Optionally silence warning
* output from the lib */ * output from the lib */
static bool done_init = false;
if(!done_init) if(!done_init)
{ {
av_register_all(); av_register_all();

@ -10,8 +10,8 @@
#include <stdint.h> #include <stdint.h>
extern "C" extern "C"
{ {
#include <avcodec.h> #include <libavcodec/avcodec.h>
#include <avformat.h> #include <libavformat/avformat.h>
} }
#include "sound_decoder.hpp" #include "sound_decoder.hpp"
@ -22,25 +22,36 @@ namespace MWSound
class FFmpeg_Decoder : public Sound_Decoder class FFmpeg_Decoder : public Sound_Decoder
{ {
AVFormatContext *mFormatCtx; AVFormatContext *mFormatCtx;
AVStream **mStream;
struct MyStream; AVPacket mPacket;
std::vector<MyStream*> mStreams; AVFrame *mFrame;
bool getNextPacket(int streamidx); int mFrameSize;
int mFramePos;
double mNextPts;
bool getNextPacket();
Ogre::DataStreamPtr mDataStream; Ogre::DataStreamPtr mDataStream;
static int readPacket(void *user_data, uint8_t *buf, int buf_size); static int readPacket(void *user_data, uint8_t *buf, int buf_size);
static int writePacket(void *user_data, uint8_t *buf, int buf_size); static int writePacket(void *user_data, uint8_t *buf, int buf_size);
static int64_t seek(void *user_data, int64_t offset, int whence); static int64_t seek(void *user_data, int64_t offset, int whence);
bool getAVAudioData();
size_t readAVAudioData(void *data, size_t length);
virtual void open(const std::string &fname); virtual void open(const std::string &fname);
virtual void close(); virtual void close();
virtual std::string getName();
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual void readAll(std::vector<char> &output); virtual void readAll(std::vector<char> &output);
virtual void rewind(); virtual void rewind();
virtual size_t getSampleOffset();
FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
FFmpeg_Decoder(const FFmpeg_Decoder &rhs); FFmpeg_Decoder(const FFmpeg_Decoder &rhs);

@ -155,6 +155,11 @@ void MpgSnd_Decoder::close()
mDataStream.setNull(); mDataStream.setNull();
} }
std::string MpgSnd_Decoder::getName()
{
return mDataStream->getName();
}
void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
{ {
if(!mSndFile && !mMpgFile) if(!mSndFile && !mMpgFile)
@ -213,6 +218,11 @@ void MpgSnd_Decoder::rewind()
} }
} }
size_t MpgSnd_Decoder::getSampleOffset()
{
return 0;
}
MpgSnd_Decoder::MpgSnd_Decoder() MpgSnd_Decoder::MpgSnd_Decoder()
: mSndInfo() : mSndInfo()
, mSndFile(NULL) , mSndFile(NULL)

@ -34,11 +34,13 @@ namespace MWSound
virtual void open(const std::string &fname); virtual void open(const std::string &fname);
virtual void close(); virtual void close();
virtual std::string getName();
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual void readAll(std::vector<char> &output); virtual void readAll(std::vector<char> &output);
virtual void rewind(); virtual void rewind();
virtual size_t getSampleOffset();
MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs); MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs);
MpgSnd_Decoder(const MpgSnd_Decoder &rhs); MpgSnd_Decoder(const MpgSnd_Decoder &rhs);

@ -61,10 +61,50 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
if(fmtlist[i].chans == chans && fmtlist[i].type == type) if(fmtlist[i].chans == chans && fmtlist[i].type == type)
return fmtlist[i].format; return fmtlist[i].format;
} }
if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
static const struct {
char name[32];
ChannelConfig chans;
SampleType type;
} mcfmtlist[] = {
{ "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 },
{ "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 },
{ "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 },
{ "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 },
{ "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 },
{ "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 },
};
static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]);
for(size_t i = 0;i < mcfmtlistsize;i++)
{
if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type)
{
ALenum format = alGetEnumValue(mcfmtlist[i].name);
if(format != 0 && format != -1)
return format;
}
}
}
fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")");
return AL_NONE; return AL_NONE;
} }
static ALint getBufferSampleCount(ALuint buf)
{
ALint size, bits, channels;
alGetBufferi(buf, AL_SIZE, &size);
alGetBufferi(buf, AL_BITS, &bits);
alGetBufferi(buf, AL_CHANNELS, &channels);
throwALerror();
return size / channels * 8 / bits;
}
// //
// A streaming OpenAL sound. // A streaming OpenAL sound.
// //
@ -82,19 +122,26 @@ class OpenAL_SoundStream : public Sound
ALsizei mSampleRate; ALsizei mSampleRate;
ALuint mBufferSize; ALuint mBufferSize;
ALuint mSamplesQueued;
DecoderPtr mDecoder; DecoderPtr mDecoder;
volatile bool mIsFinished; volatile bool mIsFinished;
void updateAll(bool local);
OpenAL_SoundStream(const OpenAL_SoundStream &rhs); OpenAL_SoundStream(const OpenAL_SoundStream &rhs);
OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs); OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs);
friend class OpenAL_Output;
public: public:
OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder); OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags);
virtual ~OpenAL_SoundStream(); virtual ~OpenAL_SoundStream();
virtual void stop(); virtual void stop();
virtual bool isPlaying(); virtual bool isPlaying();
virtual double getTimeOffset();
virtual void update(); virtual void update();
void play(); void play();
@ -109,7 +156,7 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
struct OpenAL_Output::StreamThread { struct OpenAL_Output::StreamThread {
typedef std::vector<OpenAL_SoundStream*> StreamVec; typedef std::vector<OpenAL_SoundStream*> StreamVec;
StreamVec mStreams; StreamVec mStreams;
boost::mutex mMutex; boost::recursive_mutex mMutex;
boost::thread mThread; boost::thread mThread;
StreamThread() StreamThread()
@ -170,8 +217,9 @@ private:
}; };
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder) OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags)
: mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true) : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)
, mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true)
{ {
throwALerror(); throwALerror();
@ -189,6 +237,8 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
mBufferSize = static_cast<ALuint>(sBufferLength*srate); mBufferSize = static_cast<ALuint>(sBufferLength*srate);
mBufferSize = framesToBytes(mBufferSize, chans, type); mBufferSize = framesToBytes(mBufferSize, chans, type);
mOutput.mActiveSounds.push_back(this);
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -209,22 +259,20 @@ OpenAL_SoundStream::~OpenAL_SoundStream()
alGetError(); alGetError();
mDecoder->close(); mDecoder->close();
mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(),
mOutput.mActiveSounds.end(), this));
} }
void OpenAL_SoundStream::play() void OpenAL_SoundStream::play()
{ {
std::vector<char> data(mBufferSize);
alSourceStop(mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
throwALerror(); throwALerror();
mSamplesQueued = 0;
for(ALuint i = 0;i < sNumBuffers;i++) for(ALuint i = 0;i < sNumBuffers;i++)
{ alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate);
size_t got;
got = mDecoder->read(&data[0], data.size());
alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate);
}
throwALerror(); throwALerror();
alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); alSourceQueueBuffers(mSource, sNumBuffers, mBuffers);
@ -243,6 +291,7 @@ void OpenAL_SoundStream::stop()
alSourceStop(mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
throwALerror(); throwALerror();
mSamplesQueued = 0;
mDecoder->rewind(); mDecoder->rewind();
} }
@ -254,11 +303,49 @@ bool OpenAL_SoundStream::isPlaying()
alGetSourcei(mSource, AL_SOURCE_STATE, &state); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror(); throwALerror();
if(state == AL_PLAYING) if(state == AL_PLAYING || state == AL_PAUSED)
return true; return true;
return !mIsFinished; return !mIsFinished;
} }
double OpenAL_SoundStream::getTimeOffset()
{
ALint state = AL_STOPPED;
ALfloat offset = 0.0f;
double t;
mOutput.mStreamThread->mMutex.lock();
alGetSourcef(mSource, AL_SEC_OFFSET, &offset);
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
if(state == AL_PLAYING || state == AL_PAUSED)
t = (double)(mDecoder->getSampleOffset() - mSamplesQueued)/(double)mSampleRate + offset;
else
t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
mOutput.mStreamThread->mMutex.unlock();
throwALerror();
return t;
}
void OpenAL_SoundStream::updateAll(bool local)
{
alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance);
alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance);
if(local)
{
alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE);
}
else
{
alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f);
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE);
}
alSourcei(mSource, AL_LOOPING, AL_FALSE);
update();
}
void OpenAL_SoundStream::update() void OpenAL_SoundStream::update()
{ {
ALfloat gain = mVolume*mBaseVolume; ALfloat gain = mVolume*mBaseVolume;
@ -279,52 +366,58 @@ void OpenAL_SoundStream::update()
bool OpenAL_SoundStream::process() bool OpenAL_SoundStream::process()
{ {
bool finished = mIsFinished; try {
ALint processed, state; bool finished = mIsFinished;
ALint processed, state;
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
throwALerror();
if(processed > 0)
{
std::vector<char> data(mBufferSize);
do {
ALuint bufid;
size_t got;
alSourceUnqueueBuffers(mSource, 1, &bufid); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
processed--; alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
if(finished)
continue;
got = mDecoder->read(&data[0], data.size());
finished = (got < data.size());
if(got > 0)
{
alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid);
}
} while(processed > 0);
throwALerror(); throwALerror();
}
if(state != AL_PLAYING && state != AL_PAUSED) if(processed > 0)
{ {
ALint queued; std::vector<char> data(mBufferSize);
do {
ALuint bufid = 0;
size_t got;
alSourceUnqueueBuffers(mSource, 1, &bufid);
mSamplesQueued -= getBufferSampleCount(bufid);
processed--;
if(finished)
continue;
got = mDecoder->read(&data[0], data.size());
finished = (got < data.size());
if(got > 0)
{
alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid);
mSamplesQueued += getBufferSampleCount(bufid);
}
} while(processed > 0);
throwALerror();
}
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); if(state != AL_PLAYING && state != AL_PAUSED)
throwALerror();
if(queued > 0)
{ {
alSourcePlay(mSource); ALint queued = 0;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
if(queued > 0)
alSourcePlay(mSource);
throwALerror(); throwALerror();
} }
}
mIsFinished = finished; mIsFinished = finished;
return !finished; }
catch(std::exception &e) {
std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl;
mSamplesQueued = 0;
mIsFinished = true;
}
return !mIsFinished;
} }
// //
@ -338,16 +431,21 @@ protected:
ALuint mSource; ALuint mSource;
ALuint mBuffer; ALuint mBuffer;
friend class OpenAL_Output;
void updateAll(bool local);
private: private:
OpenAL_Sound(const OpenAL_Sound &rhs); OpenAL_Sound(const OpenAL_Sound &rhs);
OpenAL_Sound& operator=(const OpenAL_Sound &rhs); OpenAL_Sound& operator=(const OpenAL_Sound &rhs);
public: public:
OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf); OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags);
virtual ~OpenAL_Sound(); virtual ~OpenAL_Sound();
virtual void stop(); virtual void stop();
virtual bool isPlaying(); virtual bool isPlaying();
virtual double getTimeOffset();
virtual void update(); virtual void update();
}; };
@ -360,16 +458,18 @@ class OpenAL_Sound3D : public OpenAL_Sound
OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs);
public: public:
OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf) OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: OpenAL_Sound(output, src, buf) : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags)
{ } { }
virtual void update(); virtual void update();
}; };
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: mOutput(output), mSource(src), mBuffer(buf) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)
, mOutput(output), mSource(src), mBuffer(buf)
{ {
mOutput.mActiveSounds.push_back(this);
} }
OpenAL_Sound::~OpenAL_Sound() OpenAL_Sound::~OpenAL_Sound()
{ {
@ -378,6 +478,9 @@ OpenAL_Sound::~OpenAL_Sound()
mOutput.mFreeSources.push_back(mSource); mOutput.mFreeSources.push_back(mSource);
mOutput.bufferFinished(mBuffer); mOutput.bufferFinished(mBuffer);
mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(),
mOutput.mActiveSounds.end(), this));
} }
void OpenAL_Sound::stop() void OpenAL_Sound::stop()
@ -393,13 +496,43 @@ bool OpenAL_Sound::isPlaying()
alGetSourcei(mSource, AL_SOURCE_STATE, &state); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror(); throwALerror();
return state==AL_PLAYING; return state==AL_PLAYING || state==AL_PAUSED;
}
double OpenAL_Sound::getTimeOffset()
{
ALfloat t;
alGetSourcef(mSource, AL_SEC_OFFSET, &t);
throwALerror();
return t;
}
void OpenAL_Sound::updateAll(bool local)
{
alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance);
alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance);
if(local)
{
alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE);
}
else
{
alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f);
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE);
}
alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
update();
} }
void OpenAL_Sound::update() void OpenAL_Sound::update()
{ {
ALfloat gain = mVolume*mBaseVolume; ALfloat gain = mVolume*mBaseVolume;
ALfloat pitch = mPitch; ALfloat pitch = mPitch;
if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
{ {
gain *= 0.9f; gain *= 0.9f;
@ -521,11 +654,9 @@ void OpenAL_Output::deinit()
{ {
mStreamThread->removeAll(); mStreamThread->removeAll();
while(!mFreeSources.empty()) for(size_t i = 0;i < mFreeSources.size();i++)
{ alDeleteSources(1, &mFreeSources[i]);
alDeleteSources(1, &mFreeSources.front()); mFreeSources.clear();
mFreeSources.pop_front();
}
mBufferRefs.clear(); mBufferRefs.clear();
mUnusedBuffers.clear(); mUnusedBuffers.clear();
@ -642,7 +773,7 @@ void OpenAL_Output::bufferFinished(ALuint buf)
} }
MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags) MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags)
{ {
boost::shared_ptr<OpenAL_Sound> sound; boost::shared_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0; ALuint src=0, buf=0;
@ -655,7 +786,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
try try
{ {
buf = getBuffer(fname); buf = getBuffer(fname);
sound.reset(new OpenAL_Sound(*this, src, buf)); sound.reset(new OpenAL_Sound(*this, src, buf, Ogre::Vector3(0.0f), vol, basevol, pitch, 1.0f, 1000.0f, flags));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -666,25 +797,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
throw; throw;
} }
alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); sound->updateAll(true);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
{
volume *= 0.9f;
pitch *= 0.7f;
}
alSourcef(src, AL_GAIN, volume);
alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
throwALerror();
alSourcei(src, AL_BUFFER, buf); alSourcei(src, AL_BUFFER, buf);
alSourcePlay(src); alSourcePlay(src);
@ -693,8 +806,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
return sound; return sound;
} }
MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch,
float min, float max, int flags) float min, float max, int flags)
{ {
boost::shared_ptr<OpenAL_Sound> sound; boost::shared_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0; ALuint src=0, buf=0;
@ -707,7 +820,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
try try
{ {
buf = getBuffer(fname); buf = getBuffer(fname);
sound.reset(new OpenAL_Sound3D(*this, src, buf)); sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -718,26 +831,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
throw; throw;
} }
alSource3f(src, AL_POSITION, pos.x, pos.z, -pos.y); sound->updateAll(false);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(src, AL_REFERENCE_DISTANCE, min);
alSourcef(src, AL_MAX_DISTANCE, max);
alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
{
volume *= 0.9f;
pitch *= 0.7f;
}
alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ?
0.0f : volume);
alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
throwALerror();
alSourcei(src, AL_BUFFER, buf); alSourcei(src, AL_BUFFER, buf);
alSourcePlay(src); alSourcePlay(src);
@ -747,7 +841,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
} }
MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags) MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, float pitch, int flags)
{ {
boost::shared_ptr<OpenAL_SoundStream> sound; boost::shared_ptr<OpenAL_SoundStream> sound;
ALuint src; ALuint src;
@ -757,13 +851,11 @@ MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volu
src = mFreeSources.front(); src = mFreeSources.front();
mFreeSources.pop_front(); mFreeSources.pop_front();
if((flags&MWBase::SoundManager::Play_Loop))
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try try
{ {
if((flags&MWBase::SoundManager::Play_Loop)) sound.reset(new OpenAL_SoundStream(*this, src, decoder, volume, pitch, flags));
std::cout <<"Warning: cannot loop stream "<<fname<< std::endl;
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
sound.reset(new OpenAL_SoundStream(*this, src, decoder));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -771,25 +863,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volu
throw; throw;
} }
alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); sound->updateAll(true);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
{
volume *= 0.9f;
pitch *= 0.7f;
}
alSourcef(src, AL_GAIN, volume);
alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(src, AL_LOOPING, AL_FALSE);
throwALerror();
sound->play(); sound->play();
return sound; return sound;
@ -814,6 +888,61 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3
} }
void OpenAL_Output::pauseSounds(int types)
{
std::vector<ALuint> sources;
SoundVec::const_iterator iter = mActiveSounds.begin();
while(iter != mActiveSounds.end())
{
const OpenAL_SoundStream *stream = dynamic_cast<OpenAL_SoundStream*>(*iter);
if(stream)
{
if(stream->mSource && (stream->getPlayType()&types))
sources.push_back(stream->mSource);
}
else
{
const OpenAL_Sound *sound = dynamic_cast<OpenAL_Sound*>(*iter);
if(sound && sound->mSource && (sound->getPlayType()&types))
sources.push_back(sound->mSource);
}
iter++;
}
if(sources.size() > 0)
{
alSourcePausev(sources.size(), &sources[0]);
throwALerror();
}
}
void OpenAL_Output::resumeSounds(int types)
{
std::vector<ALuint> sources;
SoundVec::const_iterator iter = mActiveSounds.begin();
while(iter != mActiveSounds.end())
{
const OpenAL_SoundStream *stream = dynamic_cast<OpenAL_SoundStream*>(*iter);
if(stream)
{
if(stream->mSource && (stream->getPlayType()&types))
sources.push_back(stream->mSource);
}
else
{
const OpenAL_Sound *sound = dynamic_cast<OpenAL_Sound*>(*iter);
if(sound && sound->mSource && (sound->getPlayType()&types))
sources.push_back(sound->mSource);
}
iter++;
}
if(sources.size() > 0)
{
alSourcePlayv(sources.size(), &sources[0]);
throwALerror();
}
}
OpenAL_Output::OpenAL_Output(SoundManager &mgr) OpenAL_Output::OpenAL_Output(SoundManager &mgr)
: Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0),
mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) mLastEnvironment(Env_Normal), mStreamThread(new StreamThread)

@ -33,6 +33,9 @@ namespace MWSound
uint64_t mBufferCacheMemSize; uint64_t mBufferCacheMemSize;
typedef std::vector<Sound*> SoundVec;
SoundVec mActiveSounds;
ALuint getBuffer(const std::string &fname); ALuint getBuffer(const std::string &fname);
void bufferFinished(ALuint buffer); void bufferFinished(ALuint buffer);
@ -42,13 +45,16 @@ namespace MWSound
virtual void init(const std::string &devname=""); virtual void init(const std::string &devname="");
virtual void deinit(); virtual void deinit();
virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags);
virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
float volume, float pitch, float min, float max, int flags); float vol, float basevol, float pitch, float min, float max, int flags);
virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags);
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env);
virtual void pauseSounds(int types);
virtual void resumeSounds(int types);
OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output& operator=(const OpenAL_Output &rhs);
OpenAL_Output(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs);
@ -64,7 +70,7 @@ namespace MWSound
friend class SoundManager; friend class SoundManager;
}; };
#ifndef DEFAULT_OUTPUT #ifndef DEFAULT_OUTPUT
#define DEFAULT_OUTPUT (::MWSound::OpenAL_Output) #define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x))
#endif #endif
} }

@ -26,16 +26,22 @@ namespace MWSound
public: public:
virtual void stop() = 0; virtual void stop() = 0;
virtual bool isPlaying() = 0; virtual bool isPlaying() = 0;
virtual double getTimeOffset() = 0;
void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } void setPosition(const Ogre::Vector3 &pos) { mPos = pos; }
void setVolume(float volume) { mVolume = volume; } void setVolume(float volume) { mVolume = volume; }
Sound() : mPos(0.0f, 0.0f, 0.0f) MWBase::SoundManager::PlayType getPlayType() const
, mVolume(1.0f) { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); }
, mBaseVolume(1.0f)
, mPitch(1.0f)
, mMinDistance(20.0f) /* 1 * min_range_scale */ Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
, mMaxDistance(12750.0f) /* 255 * max_range_scale */ : mPos(pos)
, mFlags(MWBase::SoundManager::Play_Normal) , mVolume(vol)
, mBaseVolume(basevol)
, mPitch(pitch)
, mMinDistance(mindist)
, mMaxDistance(maxdist)
, mFlags(flags)
{ } { }
virtual ~Sound() { } virtual ~Sound() { }

@ -15,7 +15,10 @@ namespace MWSound
enum ChannelConfig { enum ChannelConfig {
ChannelConfig_Mono, ChannelConfig_Mono,
ChannelConfig_Stereo ChannelConfig_Stereo,
ChannelConfig_Quad,
ChannelConfig_5point1,
ChannelConfig_7point1
}; };
const char *getChannelConfigName(ChannelConfig config); const char *getChannelConfigName(ChannelConfig config);
@ -29,11 +32,13 @@ namespace MWSound
virtual void open(const std::string &fname) = 0; virtual void open(const std::string &fname) = 0;
virtual void close() = 0; virtual void close() = 0;
virtual std::string getName() = 0;
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
virtual size_t read(char *buffer, size_t bytes) = 0; virtual size_t read(char *buffer, size_t bytes) = 0;
virtual void readAll(std::vector<char> &output); virtual void readAll(std::vector<char> &output);
virtual void rewind() = 0; virtual void rewind() = 0;
virtual size_t getSampleOffset() = 0;
Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
{ } { }

@ -24,13 +24,16 @@ namespace MWSound
virtual void init(const std::string &devname="") = 0; virtual void init(const std::string &devname="") = 0;
virtual void deinit() = 0; virtual void deinit() = 0;
virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) = 0;
virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
float volume, float pitch, float min, float max, int flags) = 0; float vol, float basevol, float pitch, float min, float max, int flags) = 0;
virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0;
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0;
virtual void pauseSounds(int types) = 0;
virtual void resumeSounds(int types) = 0;
Sound_Output& operator=(const Sound_Output &rhs); Sound_Output& operator=(const Sound_Output &rhs);
Sound_Output(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs);

@ -52,6 +52,7 @@ namespace MWSound
, mMusicVolume(1.0f) , mMusicVolume(1.0f)
, mFootstepsVolume(1.0f) , mFootstepsVolume(1.0f)
, mVoiceVolume(1.0f) , mVoiceVolume(1.0f)
, mPausedSoundTypes(0)
{ {
if(!useSound) if(!useSound)
return; return;
@ -86,7 +87,7 @@ namespace MWSound
{ {
if(devname.empty()) if(devname.empty())
throw; throw;
std::cout <<"Failed to open device \""<<devname<<"\", trying default."<< std::endl << "The error given was: " << e.what() << std::endl; std::cerr <<"Failed to open device \""<<devname<<"\": " << e.what() << std::endl;
mOutput->init(); mOutput->init();
Settings::Manager::setString("device", "Sound", ""); Settings::Manager::setString("device", "Sound", "");
} }
@ -137,6 +138,27 @@ namespace MWSound
return "Sound/"+snd->mSound; return "Sound/"+snd->mSound;
} }
// Gets the combined volume settings for the given sound type
float SoundManager::volumeFromType(PlayType type) const
{
float volume = mMasterVolume;
switch(type)
{
case Play_TypeSfx:
volume *= mSFXVolume;
break;
case Play_TypeVoice:
volume *= mVoiceVolume;
break;
case Play_TypeMusic:
case Play_TypeMovie:
volume *= mMusicVolume;
break;
case Play_TypeMask:
break;
}
return volume;
}
bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
{ {
@ -165,11 +187,13 @@ namespace MWSound
std::cout <<"Playing "<<filename<< std::endl; std::cout <<"Playing "<<filename<< std::endl;
try try
{ {
float basevol = mMasterVolume * mMusicVolume;
stopMusic(); stopMusic();
mMusic = mOutput->streamSound(filename, basevol, 1.0f, Play_NoEnv);
mMusic->mBaseVolume = basevol; DecoderPtr decoder = getDecoder();
mMusic->mFlags = Play_NoEnv; decoder->open(filename);
mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic),
1.0f, Play_NoEnv|Play_TypeMusic);
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -212,16 +236,13 @@ namespace MWSound
try try
{ {
// The range values are not tested // The range values are not tested
float basevol = mMasterVolume * mVoiceVolume; float basevol = volumeFromType(Play_TypeVoice);
std::string filePath = "Sound/"+filename; std::string filePath = "Sound/"+filename;
const ESM::Position &pos = ptr.getRefData().getPosition(); const ESM::Position &pos = ptr.getRefData().getPosition();
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f, MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f,
20.0f, 12750.0f, Play_Normal); 20.0f, 12750.0f, Play_Normal|Play_TypeVoice);
sound->mPos = objpos;
sound->mBaseVolume = basevol;
mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound"));
} }
catch(std::exception &e) catch(std::exception &e)
@ -236,12 +257,10 @@ namespace MWSound
return; return;
try try
{ {
float basevol = mMasterVolume * mVoiceVolume; float basevol = volumeFromType(Play_TypeVoice);
std::string filePath = "Sound/"+filename; std::string filePath = "Sound/"+filename;
MWBase::SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice);
sound->mBaseVolume = basevol;
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound"));
} }
catch(std::exception &e) catch(std::exception &e)
@ -271,26 +290,35 @@ namespace MWSound
} }
MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type)
{
MWBase::SoundPtr track;
if(!mOutput->isInitialized())
return track;
try
{
track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type);
}
catch(std::exception &e)
{
std::cout <<"Sound Error: "<<e.what()<< std::endl;
}
return track;
}
MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayMode mode)
{ {
MWBase::SoundPtr sound; MWBase::SoundPtr sound;
if(!mOutput->isInitialized()) if(!mOutput->isInitialized())
return sound; return sound;
try try
{ {
float basevol = mMasterVolume * mSFXVolume; float basevol = volumeFromType(Play_TypeSfx);
float min, max; float min, max;
std::string file = lookup(soundId, basevol, min, max); std::string file = lookup(soundId, volume, min, max);
sound = mOutput->playSound(file, volume*basevol, pitch, mode);
sound->mVolume = volume;
sound->mBaseVolume = basevol;
sound->mPitch = pitch;
sound->mMinDistance = min;
sound->mMaxDistance = max;
sound->mFlags = mode;
sound = mOutput->playSound(file, volume, basevol, pitch, mode|Play_TypeSfx);
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
} }
catch(std::exception &e) catch(std::exception &e)
@ -301,7 +329,7 @@ namespace MWSound
} }
MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId,
float volume, float pitch, int mode) float volume, float pitch, PlayMode mode)
{ {
MWBase::SoundPtr sound; MWBase::SoundPtr sound;
if(!mOutput->isInitialized()) if(!mOutput->isInitialized())
@ -309,21 +337,13 @@ namespace MWSound
try try
{ {
// Look up the sound in the ESM data // Look up the sound in the ESM data
float basevol = mMasterVolume * mSFXVolume; float basevol = volumeFromType(Play_TypeSfx);
float min, max; float min, max;
std::string file = lookup(soundId, basevol, min, max); std::string file = lookup(soundId, volume, min, max);
const ESM::Position &pos = ptr.getRefData().getPosition();; const ESM::Position &pos = ptr.getRefData().getPosition();;
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
sound = mOutput->playSound3D(file, objpos, volume*basevol, pitch, min, max, mode); sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|Play_TypeSfx);
sound->mPos = objpos;
sound->mVolume = volume;
sound->mBaseVolume = basevol;
sound->mPitch = pitch;
sound->mMinDistance = min;
sound->mMaxDistance = max;
sound->mFlags = mode;
if((mode&Play_NoTrack)) if((mode&Play_NoTrack))
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
else else
@ -404,6 +424,27 @@ namespace MWSound
} }
void SoundManager::pauseSounds(int types)
{
if(mOutput->isInitialized())
{
types &= Play_TypeMask;
mOutput->pauseSounds(types);
mPausedSoundTypes |= types;
}
}
void SoundManager::resumeSounds(int types)
{
if(mOutput->isInitialized())
{
types &= types&Play_TypeMask&mPausedSoundTypes;
mOutput->resumeSounds(types);
mPausedSoundTypes &= ~types;
}
}
void SoundManager::updateRegionSound(float duration) void SoundManager::updateRegionSound(float duration)
{ {
MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell();
@ -525,24 +566,13 @@ namespace MWSound
SoundMap::iterator snditer = mActiveSounds.begin(); SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
{ {
if(snditer->second.second != "_say_sound") snditer->first->mBaseVolume = volumeFromType(snditer->first->getPlayType());
{
float basevol = mMasterVolume * mSFXVolume;
float min, max;
lookup(snditer->second.second, basevol, min, max);
snditer->first->mBaseVolume = basevol;
}
else
{
float basevol = mMasterVolume * mVoiceVolume;
snditer->first->mBaseVolume = basevol;
}
snditer->first->update(); snditer->first->update();
snditer++; snditer++;
} }
if(mMusic) if(mMusic)
{ {
mMusic->mBaseVolume = mMasterVolume * mMusicVolume; mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType());
mMusic->update(); mMusic->update();
} }
} }
@ -585,8 +615,11 @@ namespace MWSound
{ {
switch(config) switch(config)
{ {
case ChannelConfig_Mono: return "Mono"; case ChannelConfig_Mono: return "Mono";
case ChannelConfig_Stereo: return "Stereo"; case ChannelConfig_Stereo: return "Stereo";
case ChannelConfig_Quad: return "Quad";
case ChannelConfig_5point1: return "5.1 Surround";
case ChannelConfig_7point1: return "7.1 Surround";
} }
return "(unknown channel config)"; return "(unknown channel config)";
} }
@ -595,8 +628,11 @@ namespace MWSound
{ {
switch(config) switch(config)
{ {
case ChannelConfig_Mono: frames *= 1; break; case ChannelConfig_Mono: frames *= 1; break;
case ChannelConfig_Stereo: frames *= 2; break; case ChannelConfig_Stereo: frames *= 2; break;
case ChannelConfig_Quad: frames *= 4; break;
case ChannelConfig_5point1: frames *= 6; break;
case ChannelConfig_7point1: frames *= 8; break;
} }
switch(type) switch(type)
{ {

@ -22,8 +22,6 @@ namespace MWSound
struct Sound_Decoder; struct Sound_Decoder;
class Sound; class Sound;
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
enum Environment { enum Environment {
Env_Normal, Env_Normal,
Env_Underwater Env_Underwater
@ -54,6 +52,8 @@ namespace MWSound
Ogre::Vector3 mListenerDir; Ogre::Vector3 mListenerDir;
Ogre::Vector3 mListenerUp; Ogre::Vector3 mListenerUp;
int mPausedSoundTypes;
std::string lookup(const std::string &soundId, std::string lookup(const std::string &soundId,
float &volume, float &min, float &max); float &volume, float &min, float &max);
void streamMusicFull(const std::string& filename); void streamMusicFull(const std::string& filename);
@ -61,6 +61,8 @@ namespace MWSound
void updateSounds(float duration); void updateSounds(float duration);
void updateRegionSound(float duration); void updateRegionSound(float duration);
float volumeFromType(PlayType type) const;
SoundManager(const SoundManager &rhs); SoundManager(const SoundManager &rhs);
SoundManager& operator=(const SoundManager &rhs); SoundManager& operator=(const SoundManager &rhs);
@ -105,11 +107,14 @@ namespace MWSound
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr());
///< Stop an actor speaking ///< Stop an actor speaking
virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type);
///< Play a 2D audio track, using a custom decoder
virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal);
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
float volume, float pitch, int mode=Play_Normal); float volume, float pitch, PlayMode mode=Play_Normal);
///< Play a sound from an object ///< Play a sound from an object
virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId);
@ -127,6 +132,12 @@ namespace MWSound
virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const;
///< Is the given sound currently playing on the given object? ///< Is the given sound currently playing on the given object?
virtual void pauseSounds(int types=Play_TypeMask);
///< Pauses all currently playing sounds, including music.
virtual void resumeSounds(int types=Play_TypeMask);
///< Resumes all previously paused sounds.
virtual void update(float duration); virtual void update(float duration);
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up);

@ -738,7 +738,7 @@ void WeatherManager::update(float duration)
if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end())
{ {
mSoundsPlaying.push_back(ambientSnd); mSoundsPlaying.push_back(ambientSnd);
MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, true); MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop);
} }
} }
@ -749,7 +749,7 @@ void WeatherManager::update(float duration)
if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end())
{ {
mSoundsPlaying.push_back(rainSnd); mSoundsPlaying.push_back(rainSnd);
MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, true); MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop);
} }
} }

@ -1300,4 +1300,14 @@ namespace MWWorld
return 0; return 0;
} }
void World::playVideo (const std::string &name, bool allowSkipping)
{
mRendering->playVideo(name, allowSkipping);
}
void World::stopVideo ()
{
mRendering->stopVideo();
}
} }

@ -336,6 +336,10 @@ namespace MWWorld
/// 1 - only waiting \n /// 1 - only waiting \n
/// 2 - player is underwater \n /// 2 - player is underwater \n
/// 3 - enemies are nearby (not implemented) /// 3 - enemies are nearby (not implemented)
/// \todo this does not belong here
virtual void playVideo(const std::string& name, bool allowSkipping);
virtual void stopVideo();
}; };
} }

@ -1,105 +0,0 @@
# Find the FFmpeg library
#
# Sets
# FFMPEG_FOUND. If false, don't try to use ffmpeg
# FFMPEG_INCLUDE_DIR
# FFMPEG_LIBRARIES
#
# Modified by Nicolay Korslund for OpenMW
SET( FFMPEG_FOUND "NO" )
FIND_PATH( FFMPEG_general_INCLUDE_DIR libavcodec/avcodec.h libavformat/avformat.h
HINTS
PATHS
/usr/include
/usr/local/include
/usr/include/ffmpeg
/usr/local/include/ffmpeg
/usr/include/ffmpeg/libavcodec
/usr/local/include/ffmpeg/libavcodec
/usr/include/libavcodec
/usr/local/include/libavcodec
)
FIND_PATH( FFMPEG_avcodec_INCLUDE_DIR avcodec.h
HINTS
PATHS
${FFMPEG_general_INCLUDE_DIR}/libavcodec
/usr/include
/usr/local/include
/usr/include/ffmpeg
/usr/local/include/ffmpeg
/usr/include/ffmpeg/libavcodec
/usr/local/include/ffmpeg/libavcodec
/usr/include/libavcodec
/usr/local/include/libavcodec
)
FIND_PATH( FFMPEG_avformat_INCLUDE_DIR avformat.h
HINTS
PATHS
${FFMPEG_general_INCLUDE_DIR}/libavformat
/usr/include
/usr/local/include
/usr/include/ffmpeg
/usr/local/include/ffmpeg
/usr/include/ffmpeg/libavformat
/usr/local/include/ffmpeg/libavformat
/usr/include/libavformat
/usr/local/include/libavformat
)
set(FFMPEG_INCLUDE_DIR ${FFMPEG_general_INCLUDE_DIR} ${FFMPEG_avcodec_INCLUDE_DIR} ${FFMPEG_avformat_INCLUDE_DIR})
IF( FFMPEG_INCLUDE_DIR )
FIND_PROGRAM( FFMPEG_CONFIG ffmpeg-config
/usr/bin
/usr/local/bin
${HOME}/bin
)
IF( FFMPEG_CONFIG )
EXEC_PROGRAM( ${FFMPEG_CONFIG} ARGS "--libs avformat" OUTPUT_VARIABLE FFMPEG_LIBS )
SET( FFMPEG_FOUND "YES" )
SET( FFMPEG_LIBRARIES "${FFMPEG_LIBS}" )
ELSE( FFMPEG_CONFIG )
FIND_LIBRARY( FFMPEG_avcodec_LIBRARY avcodec
/usr/lib
/usr/local/lib
/usr/lib64
/usr/local/lib64
)
FIND_LIBRARY( FFMPEG_avformat_LIBRARY avformat
/usr/lib
/usr/local/lib
/usr/lib64
/usr/local/lib64
)
FIND_LIBRARY( FFMPEG_avutil_LIBRARY avutil
/usr/lib
/usr/local/lib
/usr/lib64
/usr/local/lib64
)
IF( FFMPEG_avcodec_LIBRARY )
IF( FFMPEG_avformat_LIBRARY )
SET( FFMPEG_FOUND "YES" )
SET( FFMPEG_LIBRARIES ${FFMPEG_avformat_LIBRARY} ${FFMPEG_avcodec_LIBRARY} )
IF( FFMPEG_avutil_LIBRARY )
SET( FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${FFMPEG_avutil_LIBRARY} )
ENDIF( FFMPEG_avutil_LIBRARY )
ENDIF( FFMPEG_avformat_LIBRARY )
ENDIF( FFMPEG_avcodec_LIBRARY )
ENDIF( FFMPEG_CONFIG )
ENDIF( FFMPEG_INCLUDE_DIR )

@ -0,0 +1,148 @@
# vim: ts=2 sw=2
# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC)
#
# Once done this will define
# FFMPEG_FOUND - System has the all required components.
# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers.
# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components.
# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components.
#
# For each of the components it will additionaly set.
# - AVCODEC
# - AVDEVICE
# - AVFORMAT
# - AVUTIL
# - POSTPROCESS
# - SWSCALE
# the following variables will be defined
# <component>_FOUND - System has <component>
# <component>_INCLUDE_DIRS - Include directory necessary for using the <component> headers
# <component>_LIBRARIES - Link these to use <component>
# <component>_DEFINITIONS - Compiler switches required for using <component>
# <component>_VERSION - The components version
#
# Copyright (c) 2006, Matthias Kretz, <kretz@kde.org>
# Copyright (c) 2008, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2011, Michael Jansen, <kde@michael-jansen.biz>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
include(FindPackageHandleStandardArgs)
# The default components were taken from a survey over other FindFFMPEG.cmake files
if (NOT FFmpeg_FIND_COMPONENTS)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
endif ()
#
### Macro: set_component_found
#
# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present.
#
macro(set_component_found _component )
if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS)
# message(STATUS " - ${_component} found.")
set(${_component}_FOUND TRUE)
else ()
# message(STATUS " - ${_component} not found.")
endif ()
endmacro()
#
### Macro: find_component
#
# Checks for the given component by invoking pkgconfig and then looking up the libraries and
# include directories.
#
macro(find_component _component _pkgconfig _library _header)
if (NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_${_component} ${_pkgconfig})
endif ()
endif (NOT WIN32)
find_path(${_component}_INCLUDE_DIRS ${_header}
HINTS
${PC_LIB${_component}_INCLUDEDIR}
${PC_LIB${_component}_INCLUDE_DIRS}
PATH_SUFFIXES
ffmpeg
)
find_library(${_component}_LIBRARIES NAMES ${_library}
HINTS
${PC_LIB${_component}_LIBDIR}
${PC_LIB${_component}_LIBRARY_DIRS}
)
set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.")
set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.")
set_component_found(${_component})
mark_as_advanced(
${_component}_INCLUDE_DIRS
${_component}_LIBRARIES
${_component}_DEFINITIONS
${_component}_VERSION)
endmacro()
# Check for cached results. If there are skip the costly part.
if (NOT FFMPEG_LIBRARIES)
# Check for all possible component.
find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h)
find_component(AVFORMAT libavformat avformat libavformat/avformat.h)
find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h)
find_component(AVUTIL libavutil avutil libavutil/avutil.h)
find_component(SWSCALE libswscale swscale libswscale/swscale.h)
find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
# Check if the required components were found and add their stuff to the FFMPEG_* vars.
foreach (_component ${FFmpeg_FIND_COMPONENTS})
if (${_component}_FOUND)
# message(STATUS "Required component ${_component} present.")
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES})
set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS})
list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS})
else ()
# message(STATUS "Required component ${_component} missing.")
endif ()
endforeach ()
# Build the include path with duplicates removed.
if (FFMPEG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS)
endif ()
# cache the vars.
set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE)
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE)
set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE)
mark_as_advanced(FFMPEG_INCLUDE_DIRS
FFMPEG_LIBRARIES
FFMPEG_DEFINITIONS)
endif ()
# Now set the noncached _FOUND vars for the components.
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE)
set_component_found(${_component})
endforeach ()
# Compile the list of required vars
set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS)
foreach (_component ${FFmpeg_FIND_COMPONENTS})
list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS)
endforeach ()
# Give a nice error message if some of the required vars are missing.
find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS})

@ -0,0 +1,177 @@
# Locate SDL library
# This module defines
# SDL_LIBRARY, the name of the library to link against
# SDL_FOUND, if false, do not try to link to SDL
# SDL_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL_BUILDING_LIBRARY
# If this is defined, then no SDL_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL_LIBRARY variable.
#
# Don't forget to include SDLmain.h and SDLmain.m your project for the
# OS X framework based version. (Other versions link to -lSDLmain which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL_LIBRARY_TEMP in your configuration
# and no SDL_LIBRARY, it means CMake did not find your SDL library
# (SDL.dll, libsdl.so, SDL.framework, etc).
# Set SDL_LIBRARY_TEMP to point to your SDL library, and configure again.
# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL_LIBRARY
# variable, but when these values are unset, SDL_LIBRARY does not get created.
#
#
# $SDLDIR is an environment variable that would
# correspond to the ./configure --prefix=$SDLDIR
# used in building SDL.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL guidelines.
# Added a search for SDLmain which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL/SDL.h to just SDL.h
# This needed to change because "proper" SDL convention
# is #include "SDL.h", not <SDL/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL/ (see FreeBSD).
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PATH(SDL_INCLUDE_DIR SDL.h
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES include/SDL include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL12
/usr/local/include/SDL11 # FreeBSD ports
/usr/include/SDL12
/usr/include/SDL11
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
#MESSAGE("SDL_INCLUDE_DIR is ${SDL_INCLUDE_DIR}")
# SDL-1.1 is the name used by FreeBSD ports...
# don't confuse it for the version number.
FIND_LIBRARY(SDL_LIBRARY_TEMP
NAMES SDL SDL-1.1
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
#MESSAGE("SDL_LIBRARY_TEMP is ${SDL_LIBRARY_TEMP}")
IF(NOT SDL_BUILDING_LIBRARY)
IF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDLmain for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDLMAIN_LIBRARY
NAMES SDLmain SDLmain-1.1
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL_BUILDING_LIBRARY)
# SDL may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
SET(SDL_FOUND "NO")
IF(SDL_LIBRARY_TEMP)
# For SDLmain
IF(NOT SDL_BUILDING_LIBRARY)
IF(SDLMAIN_LIBRARY)
SET(SDL_LIBRARY_TEMP ${SDLMAIN_LIBRARY} ${SDL_LIBRARY_TEMP})
ENDIF(SDLMAIN_LIBRARY)
ENDIF(NOT SDL_BUILDING_LIBRARY)
# For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL_FOUND "YES")
ENDIF(SDL_LIBRARY_TEMP)
#MESSAGE("SDL_LIBRARY is ${SDL_LIBRARY}")

@ -72,7 +72,7 @@ compositor gbufferFinalizer
pass render_scene pass render_scene
{ {
first_render_queue 51 first_render_queue 51
last_render_queue 100 last_render_queue 105
} }
} }
target_output target_output

Loading…
Cancel
Save