Merge remote-tracking branch 'origin/master'

openmw-38
Marc Zinnschlag 9 years ago
commit e0c9265148

@ -15,6 +15,7 @@ namespace MWWorld
namespace MWSound namespace MWSound
{ {
class Sound; class Sound;
class Stream;
struct Sound_Decoder; struct Sound_Decoder;
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr; typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
} }
@ -22,6 +23,7 @@ namespace MWSound
namespace MWBase namespace MWBase
{ {
typedef boost::shared_ptr<MWSound::Sound> SoundPtr; typedef boost::shared_ptr<MWSound::Sound> SoundPtr;
typedef boost::shared_ptr<MWSound::Stream> SoundStreamPtr;
/// \brief Interface for sound manager (implemented in MWSound) /// \brief Interface for sound manager (implemented in MWSound)
class SoundManager class SoundManager
@ -104,9 +106,17 @@ namespace MWBase
/// and get an average loudness value (scale [0,1]) at the current time position. /// and get an average loudness value (scale [0,1]) at the current time position.
/// If the actor is not saying anything, returns 0. /// If the actor is not saying anything, returns 0.
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
///< Play a 2D audio track, using a custom decoder ///< Play a 2D audio track, using a custom decoder
virtual void stopTrack(SoundStreamPtr stream) = 0;
///< Stop the given audio track from playing
virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0;
///< Retives the time delay, in seconds, of the audio track (must be a sound
/// returned by \ref playTrack). Only intended to be called by the track
/// decoder's read method.
virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch,
PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal,
float offset=0) = 0; float offset=0) = 0;
@ -123,6 +133,9 @@ namespace MWBase
float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0;
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition.
virtual void stopSound(SoundPtr sound) = 0;
///< Stop the given sound from playing
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
///< Stop the given object from playing the given sound, ///< Stop the given object from playing the given sound,
@ -155,7 +168,7 @@ namespace MWBase
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0; virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0;
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; virtual void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;
virtual void clear() = 0; virtual void clear() = 0;
}; };

@ -61,7 +61,7 @@ namespace MWSound
virtual double getAudioClock() virtual double getAudioClock()
{ {
return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate - return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate -
mAudioTrack->getStreamDelay(); MWBase::Environment::get().getSoundManager()->getTrackTimeDelay(mAudioTrack);
} }
virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate)
@ -86,11 +86,13 @@ namespace MWSound
public: public:
~MovieAudioDecoder() ~MovieAudioDecoder()
{ {
if(mAudioTrack.get())
MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack);
mAudioTrack.reset(); mAudioTrack.reset();
mDecoderBridge.reset(); mDecoderBridge.reset();
} }
MWBase::SoundPtr mAudioTrack; MWBase::SoundStreamPtr mAudioTrack;
boost::shared_ptr<MWSoundDecoderBridge> mDecoderBridge; boost::shared_ptr<MWSoundDecoderBridge> mDecoderBridge;
}; };
@ -161,7 +163,8 @@ namespace MWSound
boost::shared_ptr<MWSound::MovieAudioDecoder> decoder(new MWSound::MovieAudioDecoder(videoState)); boost::shared_ptr<MWSound::MovieAudioDecoder> decoder(new MWSound::MovieAudioDecoder(videoState));
decoder->setupFormat(); decoder->setupFormat();
MWBase::SoundPtr sound = MWBase::Environment::get().getSoundManager()->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
MWBase::SoundStreamPtr sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie);
if (!sound.get()) if (!sound.get())
{ {
decoder.reset(); decoder.reset();

@ -157,17 +157,14 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
// //
// A streaming OpenAL sound. // A streaming OpenAL sound.
// //
class OpenAL_SoundStream : public Sound class OpenAL_SoundStream
{ {
static const ALuint sNumBuffers = 6; static const ALuint sNumBuffers = 6;
static const ALfloat sBufferLength; static const ALfloat sBufferLength;
protected: private:
OpenAL_Output &mOutput;
ALuint mSource; ALuint mSource;
private:
ALuint mBuffers[sNumBuffers]; ALuint mBuffers[sNumBuffers];
ALint mCurrentBufIdx; ALint mCurrentBufIdx;
@ -189,34 +186,18 @@ private:
friend class OpenAL_Output; friend class OpenAL_Output;
public: public:
OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); OpenAL_SoundStream(ALuint src, DecoderPtr decoder);
virtual ~OpenAL_SoundStream(); ~OpenAL_SoundStream();
virtual void stop(); bool isPlaying();
virtual bool isPlaying(); double getStreamDelay() const;
virtual double getTimeOffset(); double getStreamOffset() const;
virtual double getStreamDelay() const;
virtual void applyUpdates();
void play();
bool process(); bool process();
ALint refillQueue(); ALint refillQueue();
}; };
const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
class OpenAL_SoundStream3D : public OpenAL_SoundStream
{
OpenAL_SoundStream3D(const OpenAL_SoundStream3D &rhs);
OpenAL_SoundStream3D& operator=(const OpenAL_SoundStream3D &rhs);
public:
OpenAL_SoundStream3D(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags)
{ }
virtual void applyUpdates();
};
// //
// A background streaming thread (keeps active streams processed) // A background streaming thread (keeps active streams processed)
@ -329,13 +310,9 @@ private:
}; };
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
: Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) : mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false)
, mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0)
, mDecoder(decoder), mIsFinished(true)
{ {
throwALerror();
alGenBuffers(sNumBuffers, mBuffers); alGenBuffers(sNumBuffers, mBuffers);
throwALerror(); throwALerror();
try try
@ -358,8 +335,6 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
mFrameSize = framesToBytes(1, chans, type); mFrameSize = framesToBytes(1, chans, type);
mBufferSize = static_cast<ALuint>(sBufferLength*srate); mBufferSize = static_cast<ALuint>(sBufferLength*srate);
mBufferSize *= mFrameSize; mBufferSize *= mFrameSize;
mOutput.mActiveStreams.push_back(this);
} }
catch(std::exception&) catch(std::exception&)
{ {
@ -367,51 +342,20 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
alGetError(); alGetError();
throw; throw;
} }
mIsFinished = false;
} }
OpenAL_SoundStream::~OpenAL_SoundStream() OpenAL_SoundStream::~OpenAL_SoundStream()
{ {
mOutput.mStreamThread->remove(this);
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers); alDeleteBuffers(sNumBuffers, mBuffers);
alGetError(); alGetError();
mDecoder->close(); mDecoder->close();
mOutput.mActiveStreams.erase(std::find(mOutput.mActiveStreams.begin(),
mOutput.mActiveStreams.end(), this));
}
void OpenAL_SoundStream::play()
{
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
throwALerror();
mIsFinished = false;
mOutput.mStreamThread->add(this);
}
void OpenAL_SoundStream::stop()
{
mOutput.mStreamThread->remove(this);
mIsFinished = true;
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
throwALerror();
mDecoder->rewind();
} }
bool OpenAL_SoundStream::isPlaying() bool OpenAL_SoundStream::isPlaying()
{ {
ALint state; ALint state;
boost::lock_guard<boost::mutex> lock(mOutput.mStreamThread->mMutex);
alGetSourcei(mSource, AL_SOURCE_STATE, &state); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror(); throwALerror();
@ -420,13 +364,12 @@ bool OpenAL_SoundStream::isPlaying()
return !mIsFinished; return !mIsFinished;
} }
double OpenAL_SoundStream::getTimeOffset() double OpenAL_SoundStream::getStreamDelay() const
{ {
ALint state = AL_STOPPED; ALint state = AL_STOPPED;
double d = 0.0;
ALint offset; ALint offset;
double t;
boost::lock_guard<boost::mutex> lock(mOutput.mStreamThread->mMutex);
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
alGetSourcei(mSource, AL_SOURCE_STATE, &state); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
if(state == AL_PLAYING || state == AL_PAUSED) if(state == AL_PLAYING || state == AL_PAUSED)
@ -434,24 +377,18 @@ double OpenAL_SoundStream::getTimeOffset()
ALint queued; ALint queued;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
ALint inqueue = mBufferSize/mFrameSize*queued - offset; ALint inqueue = mBufferSize/mFrameSize*queued - offset;
t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; d = (double)inqueue / (double)mSampleRate;
}
else
{
/* Underrun, or not started yet. The decoder offset is where we'll play
* next. */
t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
} }
throwALerror(); throwALerror();
return t; return d;
} }
double OpenAL_SoundStream::getStreamDelay() const double OpenAL_SoundStream::getStreamOffset() const
{ {
ALint state = AL_STOPPED; ALint state = AL_STOPPED;
double d = 0.0;
ALint offset; ALint offset;
double t;
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
alGetSourcei(mSource, AL_SOURCE_STATE, &state); alGetSourcei(mSource, AL_SOURCE_STATE, &state);
@ -460,48 +397,17 @@ double OpenAL_SoundStream::getStreamDelay() const
ALint queued; ALint queued;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
ALint inqueue = mBufferSize/mFrameSize*queued - offset; ALint inqueue = mBufferSize/mFrameSize*queued - offset;
d = (double)inqueue / (double)mSampleRate; t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate;
}
throwALerror();
return d;
}
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 else
{ {
alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); /* Underrun, or not started yet. The decoder offset is where we'll play
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); * next. */
} t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
alSourcei(mSource, AL_LOOPING, AL_FALSE);
applyUpdates();
}
void OpenAL_SoundStream::applyUpdates()
{
ALfloat gain = mVolume*mBaseVolume;
ALfloat pitch = mPitch;
if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
} }
alSourcef(mSource, AL_GAIN, gain);
alSourcef(mSource, AL_PITCH, pitch);
alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]);
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror(); throwALerror();
return t;
} }
bool OpenAL_SoundStream::process() bool OpenAL_SoundStream::process()
@ -562,172 +468,6 @@ ALint OpenAL_SoundStream::refillQueue()
return queued; return queued;
} }
void OpenAL_SoundStream3D::applyUpdates()
{
ALfloat gain = mVolume*mBaseVolume;
ALfloat pitch = mPitch;
if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance)
gain = 0.0f;
else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(mSource, AL_GAIN, gain);
alSourcef(mSource, AL_PITCH, pitch);
alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]);
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror();
}
//
// A regular 2D OpenAL sound
//
class OpenAL_Sound : public Sound
{
protected:
OpenAL_Output &mOutput;
ALuint mSource;
friend class OpenAL_Output;
void updateAll(bool local);
private:
OpenAL_Sound(const OpenAL_Sound &rhs);
OpenAL_Sound& operator=(const OpenAL_Sound &rhs);
public:
OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags);
virtual ~OpenAL_Sound();
virtual void stop();
virtual bool isPlaying();
virtual double getTimeOffset();
virtual void applyUpdates();
};
//
// A regular 3D OpenAL sound
//
class OpenAL_Sound3D : public OpenAL_Sound
{
OpenAL_Sound3D(const OpenAL_Sound &rhs);
OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs);
public:
OpenAL_Sound3D(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags)
{ }
virtual void applyUpdates();
};
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)
, mOutput(output), mSource(src)
{
mOutput.mActiveSounds.push_back(this);
}
OpenAL_Sound::~OpenAL_Sound()
{
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(),
mOutput.mActiveSounds.end(), this));
}
void OpenAL_Sound::stop()
{
alSourceStop(mSource);
throwALerror();
}
bool OpenAL_Sound::isPlaying()
{
ALint state;
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror();
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);
applyUpdates();
}
void OpenAL_Sound::applyUpdates()
{
ALfloat gain = mVolume*mBaseVolume;
ALfloat pitch = mPitch;
if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(mSource, AL_GAIN, gain);
alSourcef(mSource, AL_PITCH, pitch);
alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]);
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror();
}
void OpenAL_Sound3D::applyUpdates()
{
ALfloat gain = mVolume*mBaseVolume;
ALfloat pitch = mPitch;
if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance)
gain = 0.0f;
else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(mSource, AL_GAIN, gain);
alSourcef(mSource, AL_PITCH, pitch);
alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]);
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror();
}
// //
// An OpenAL output device // An OpenAL output device
@ -881,15 +621,16 @@ void OpenAL_Output::unloadSound(Sound_Handle data)
SoundVec::const_iterator iter = mActiveSounds.begin(); SoundVec::const_iterator iter = mActiveSounds.begin();
for(;iter != mActiveSounds.end();++iter) for(;iter != mActiveSounds.end();++iter)
{ {
if(!(*iter)->mSource) if(!(*iter)->mHandle)
continue; continue;
ALuint source = GET_PTRID((*iter)->mHandle);
ALint srcbuf; ALint srcbuf;
alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf); alGetSourcei(source, AL_BUFFER, &srcbuf);
if((ALuint)srcbuf == buffer) if((ALuint)srcbuf == buffer)
{ {
alSourceStop((*iter)->mSource); alSourceStop(source);
alSourcei((*iter)->mSource, AL_BUFFER, 0); alSourcei(source, AL_BUFFER, 0);
} }
} }
alDeleteBuffers(1, &buffer); alDeleteBuffers(1, &buffer);
@ -907,121 +648,278 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const
} }
MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv)
{ {
boost::shared_ptr<OpenAL_Sound> sound; alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
ALuint src; alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
if(useenv && mListenerEnv == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(source, AL_GAIN, gain);
alSourcef(source, AL_PITCH, pitch);
alSourcefv(source, AL_POSITION, pos.ptr());
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
}
void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv)
{
alSourcef(source, AL_REFERENCE_DISTANCE, mindist);
alSourcef(source, AL_MAX_DISTANCE, maxdist);
alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f);
alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
if((pos - mListenerPos).length2() > maxdist*maxdist)
gain = 0.0f;
if(useenv && mListenerEnv == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(source, AL_GAIN, gain);
alSourcef(source, AL_PITCH, pitch);
alSourcefv(source, AL_POSITION, pos.ptr());
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
}
void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d)
{
if(is3d)
{
if((pos - mListenerPos).length2() > maxdist*maxdist)
gain = 0.0f;
}
if(useenv && mListenerEnv == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(source, AL_GAIN, gain);
alSourcef(source, AL_PITCH, pitch);
alSourcefv(source, AL_POSITION, pos.ptr());
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
}
void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset)
{
ALuint source;
if(mFreeSources.empty()) if(mFreeSources.empty())
fail("No free sources"); fail("No free sources");
src = mFreeSources.front(); source = mFreeSources.front();
mFreeSources.pop_front(); mFreeSources.pop_front();
try { try {
sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
sound->getIsLooping(), sound->getUseEnv());
alSourcef(source, AL_SEC_OFFSET, offset);
throwALerror();
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
throwALerror();
mActiveSounds.push_back(sound);
} }
catch(std::exception&) catch(std::exception&) {
{ mFreeSources.push_back(source);
mFreeSources.push_back(src);
throw; throw;
} }
sound->updateAll(true); sound->mHandle = MAKE_PTRID(source);
alSourcei(src, AL_BUFFER, GET_PTRID(data));
alSourcef(src, AL_SEC_OFFSET, offset/pitch);
alSourcePlay(src);
throwALerror();
return sound;
} }
MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset)
float min, float max, int flags, float offset)
{ {
boost::shared_ptr<OpenAL_Sound> sound; ALuint source;
ALuint src;
if(mFreeSources.empty()) if(mFreeSources.empty())
fail("No free sources"); fail("No free sources");
src = mFreeSources.front(); source = mFreeSources.front();
mFreeSources.pop_front(); mFreeSources.pop_front();
try { try {
sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags)); initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(),
sound->getUseEnv());
alSourcef(source, AL_SEC_OFFSET, offset);
throwALerror();
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
throwALerror();
mActiveSounds.push_back(sound);
} }
catch(std::exception&) catch(std::exception&) {
{ mFreeSources.push_back(source);
mFreeSources.push_back(src);
throw; throw;
} }
sound->updateAll(false); sound->mHandle = MAKE_PTRID(source);
alSourcei(src, AL_BUFFER, GET_PTRID(data)); }
alSourcef(src, AL_SEC_OFFSET, offset/pitch);
void OpenAL_Output::stopSound(MWBase::SoundPtr sound)
{
if(!sound->mHandle) return;
ALuint source = GET_PTRID(sound->mHandle);
sound->mHandle = 0;
alSourceStop(source);
alSourcei(source, AL_BUFFER, 0);
alSourcePlay(src); mFreeSources.push_back(source);
mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound));
}
bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound)
{
if(!sound->mHandle) return false;
ALuint source = GET_PTRID(sound->mHandle);
ALint state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
throwALerror(); throwALerror();
return sound; return state == AL_PLAYING || state == AL_PAUSED;
}
void OpenAL_Output::updateSound(MWBase::SoundPtr sound)
{
if(!sound->mHandle) return;
ALuint source = GET_PTRID(sound->mHandle);
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
} }
MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound)
{ {
boost::shared_ptr<OpenAL_SoundStream> sound; OpenAL_SoundStream *stream = 0;
ALuint src; ALuint source;
if(mFreeSources.empty()) if(mFreeSources.empty())
fail("No free sources"); fail("No free sources");
src = mFreeSources.front(); source = mFreeSources.front();
mFreeSources.pop_front(); mFreeSources.pop_front();
if((flags&MWBase::SoundManager::Play_Loop)) if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl; std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try try {
{ initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
sound.reset(new OpenAL_SoundStream(*this, src, decoder, osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); false, sound->getUseEnv());
throwALerror();
stream = new OpenAL_SoundStream(source, decoder);
mStreamThread->add(stream);
mActiveStreams.push_back(sound);
} }
catch(std::exception&) catch(std::exception&) {
{ mStreamThread->remove(stream);
mFreeSources.push_back(src); delete stream;
mFreeSources.push_back(source);
throw; throw;
} }
sound->updateAll(true); sound->mHandle = stream;
sound->play();
return sound;
} }
void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound)
MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags)
{ {
boost::shared_ptr<OpenAL_SoundStream> sound; OpenAL_SoundStream *stream = 0;
ALuint src; ALuint source;
if(mFreeSources.empty()) if(mFreeSources.empty())
fail("No free sources"); fail("No free sources");
src = mFreeSources.front(); source = mFreeSources.front();
mFreeSources.pop_front(); mFreeSources.pop_front();
if((flags&MWBase::SoundManager::Play_Loop)) if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl; std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try try {
{ initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags)); sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
throwALerror();
stream = new OpenAL_SoundStream(source, decoder);
mStreamThread->add(stream);
mActiveStreams.push_back(sound);
} }
catch(std::exception&) catch(std::exception&) {
{ mStreamThread->remove(stream);
mFreeSources.push_back(src); delete stream;
mFreeSources.push_back(source);
throw; throw;
} }
sound->updateAll(false); sound->mHandle = stream;
}
void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound)
{
if(!sound->mHandle) return;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
ALuint source = stream->mSource;
sound->mHandle = 0;
mStreamThread->remove(stream);
alSourceStop(source);
alSourcei(source, AL_BUFFER, 0);
mFreeSources.push_back(source);
mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound));
delete stream;
}
double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound)
{
if(!sound->mHandle) return 0.0;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
return stream->getStreamDelay();
}
double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound)
{
if(!sound->mHandle) return 0.0;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
boost::lock_guard<boost::mutex> lock(mStreamThread->mMutex);
return stream->getStreamOffset();
}
bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound)
{
if(!sound->mHandle) return false;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
boost::lock_guard<boost::mutex> lock(mStreamThread->mMutex);
return stream->isPlaying();
}
sound->play(); void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound)
return sound; {
if(!sound->mHandle) return;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
ALuint source = stream->mSource;
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
} }
@ -1038,19 +936,19 @@ void OpenAL_Output::finishUpdate()
void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env)
{ {
mPos = pos;
mLastEnvironment = env;
if(mContext) if(mContext)
{ {
ALfloat orient[6] = { ALfloat orient[6] = {
atdir.x(), atdir.y(), atdir.z(), atdir.x(), atdir.y(), atdir.z(),
updir.x(), updir.y(), updir.z() updir.x(), updir.y(), updir.z()
}; };
alListener3f(AL_POSITION, mPos.x(), mPos.y(), mPos.z()); alListenerfv(AL_POSITION, pos.ptr());
alListenerfv(AL_ORIENTATION, orient); alListenerfv(AL_ORIENTATION, orient);
throwALerror(); throwALerror();
} }
mListenerPos = pos;
mListenerEnv = env;
} }
@ -1060,14 +958,17 @@ void OpenAL_Output::pauseSounds(int types)
SoundVec::const_iterator sound = mActiveSounds.begin(); SoundVec::const_iterator sound = mActiveSounds.begin();
for(;sound != mActiveSounds.end();++sound) for(;sound != mActiveSounds.end();++sound)
{ {
if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types))
sources.push_back((*sound)->mSource); sources.push_back(GET_PTRID((*sound)->mHandle));
} }
StreamVec::const_iterator stream = mActiveStreams.begin(); StreamVec::const_iterator stream = mActiveStreams.begin();
for(;stream != mActiveStreams.end();++stream) for(;stream != mActiveStreams.end();++stream)
{ {
if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types))
sources.push_back((*stream)->mSource); {
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>((*stream)->mHandle);
sources.push_back(strm->mSource);
}
} }
if(!sources.empty()) if(!sources.empty())
{ {
@ -1082,14 +983,17 @@ void OpenAL_Output::resumeSounds(int types)
SoundVec::const_iterator sound = mActiveSounds.begin(); SoundVec::const_iterator sound = mActiveSounds.begin();
for(;sound != mActiveSounds.end();++sound) for(;sound != mActiveSounds.end();++sound)
{ {
if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types))
sources.push_back((*sound)->mSource); sources.push_back(GET_PTRID((*sound)->mHandle));
} }
StreamVec::const_iterator stream = mActiveStreams.begin(); StreamVec::const_iterator stream = mActiveStreams.begin();
for(;stream != mActiveStreams.end();++stream) for(;stream != mActiveStreams.end();++stream)
{ {
if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types))
sources.push_back((*stream)->mSource); {
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>((*stream)->mHandle);
sources.push_back(strm->mSource);
}
} }
if(!sources.empty()) if(!sources.empty())
{ {
@ -1106,8 +1010,9 @@ void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudne
OpenAL_Output::OpenAL_Output(SoundManager &mgr) OpenAL_Output::OpenAL_Output(SoundManager &mgr)
: Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), : Sound_Output(mgr), mDevice(0), mContext(0)
mStreamThread(new StreamThread) , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal)
, mStreamThread(new StreamThread)
{ {
} }

@ -16,9 +16,6 @@ namespace MWSound
class SoundManager; class SoundManager;
class Sound; class Sound;
class OpenAL_Sound;
class OpenAL_SoundStream;
class OpenAL_Output : public Sound_Output class OpenAL_Output : public Sound_Output
{ {
ALCdevice *mDevice; ALCdevice *mDevice;
@ -27,13 +24,26 @@ namespace MWSound
typedef std::deque<ALuint> IDDq; typedef std::deque<ALuint> IDDq;
IDDq mFreeSources; IDDq mFreeSources;
typedef std::vector<OpenAL_Sound*> SoundVec; typedef std::vector<MWBase::SoundPtr> SoundVec;
SoundVec mActiveSounds; SoundVec mActiveSounds;
typedef std::vector<OpenAL_SoundStream*> StreamVec; typedef std::vector<MWBase::SoundStreamPtr> StreamVec;
StreamVec mActiveStreams; StreamVec mActiveStreams;
Environment mLastEnvironment; osg::Vec3f mListenerPos;
Environment mListenerEnv;
struct StreamThread;
std::auto_ptr<StreamThread> mStreamThread;
void initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv);
void initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv);
void updateCommon(ALuint source, const osg::Vec3f &pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d);
OpenAL_Output& operator=(const OpenAL_Output &rhs);
OpenAL_Output(const OpenAL_Output &rhs);
public:
virtual std::vector<std::string> enumerate(); virtual std::vector<std::string> enumerate();
virtual void init(const std::string &devname=""); virtual void init(const std::string &devname="");
virtual void deinit(); virtual void deinit();
@ -42,12 +52,19 @@ namespace MWSound
virtual void unloadSound(Sound_Handle data); virtual void unloadSound(Sound_Handle data);
virtual size_t getSoundDataSize(Sound_Handle data) const; virtual size_t getSoundDataSize(Sound_Handle data) const;
virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset);
virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset);
float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual void stopSound(MWBase::SoundPtr sound);
virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); virtual bool isSoundPlaying(MWBase::SoundPtr sound);
virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, virtual void updateSound(MWBase::SoundPtr sound);
float vol, float basevol, float pitch, float min, float max, int flags);
virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound);
virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound);
virtual void stopStream(MWBase::SoundStreamPtr sound);
virtual double getStreamDelay(MWBase::SoundStreamPtr sound);
virtual double getStreamOffset(MWBase::SoundStreamPtr sound);
virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound);
virtual void updateStream(MWBase::SoundStreamPtr sound);
virtual void startUpdate(); virtual void startUpdate();
virtual void finishUpdate(); virtual void finishUpdate();
@ -59,20 +76,8 @@ namespace MWSound
virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness); virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness);
OpenAL_Output& operator=(const OpenAL_Output &rhs);
OpenAL_Output(const OpenAL_Output &rhs);
OpenAL_Output(SoundManager &mgr); OpenAL_Output(SoundManager &mgr);
virtual ~OpenAL_Output(); virtual ~OpenAL_Output();
struct StreamThread;
std::auto_ptr<StreamThread> mStreamThread;
friend class OpenAL_Sound;
friend class OpenAL_Sound3D;
friend class OpenAL_SoundStream;
friend class OpenAL_SoundStream3D;
friend class SoundManager;
}; };
#ifndef DEFAULT_OUTPUT #ifndef DEFAULT_OUTPUT
#define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x)) #define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x))

@ -1,16 +1,14 @@
#ifndef GAME_SOUND_SOUND_H #ifndef GAME_SOUND_SOUND_H
#define GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H
#include "soundmanagerimp.hpp" #include "sound_output.hpp"
namespace MWSound namespace MWSound
{ {
class Sound class Sound {
{
Sound& operator=(const Sound &rhs); Sound& operator=(const Sound &rhs);
Sound(const Sound &rhs); Sound(const Sound &rhs);
protected:
osg::Vec3f mPos; osg::Vec3f mPos;
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
float mBaseVolume; float mBaseVolume;
@ -21,12 +19,12 @@ namespace MWSound
float mFadeOutTime; float mFadeOutTime;
protected:
Sound_Instance mHandle;
friend class OpenAL_Output;
public: public:
virtual void stop() = 0;
virtual bool isPlaying() = 0;
virtual double getTimeOffset() = 0;
virtual double getStreamDelay() const { return 0.0; }
virtual void applyUpdates() = 0;
void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setPosition(const osg::Vec3f &pos) { mPos = pos; }
void setVolume(float volume) { mVolume = volume; } void setVolume(float volume) { mVolume = volume; }
void setBaseVolume(float volume) { mBaseVolume = volume; } void setBaseVolume(float volume) { mBaseVolume = volume; }
@ -41,22 +39,43 @@ namespace MWSound
} }
} }
const osg::Vec3f &getPosition() const { return mPos; }
float getRealVolume() const { return mVolume * mBaseVolume; }
float getPitch() const { return mPitch; }
float getMinDistance() const { return mMinDistance; }
float getMaxDistance() const { return mMaxDistance; }
MWBase::SoundManager::PlayType getPlayType() const MWBase::SoundManager::PlayType getPlayType() const
{ return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); }
bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); }
bool getIsLooping() const { return mFlags&MWBase::SoundManager::Play_Loop; }
bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; }
bool getIs3D() const { return mFlags&Play_3D; } bool getIs3D() const { return mFlags&Play_3D; }
Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: mPos(pos) : mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch)
, mVolume(vol) , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags)
, mBaseVolume(basevol) , mFadeOutTime(0.0f), mHandle(0)
, mPitch(pitch) { }
, mMinDistance(mindist) Sound(float vol, float basevol, float pitch, int flags)
, mMaxDistance(maxdist) : mPos(0.0f, 0.0f, 0.0f), mVolume(vol), mBaseVolume(basevol), mPitch(pitch)
, mFlags(flags) , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(flags)
, mFadeOutTime(0.0f) , mFadeOutTime(0.0f), mHandle(0)
{ }
};
// Same as above, but it's a different type since the output handles them differently
class Stream : public Sound {
Stream& operator=(const Stream &rhs);
Stream(const Stream &rhs);
public:
Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)
{ }
Stream(float vol, float basevol, float pitch, int flags)
: Sound(vol, basevol, pitch, flags)
{ } { }
virtual ~Sound() { }
}; };
} }

@ -3,11 +3,10 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector>
#include "soundmanagerimp.hpp" #include "soundmanagerimp.hpp"
#include "../mwworld/ptr.hpp"
namespace MWSound namespace MWSound
{ {
class SoundManager; class SoundManager;
@ -17,6 +16,8 @@ namespace MWSound
// An opaque handle for the implementation's sound buffers. // An opaque handle for the implementation's sound buffers.
typedef void *Sound_Handle; typedef void *Sound_Handle;
// An opaque handle for the implementation's sound instances.
typedef void *Sound_Instance;
class Sound_Output class Sound_Output
{ {
@ -30,14 +31,19 @@ namespace MWSound
virtual void unloadSound(Sound_Handle data) = 0; virtual void unloadSound(Sound_Handle data) = 0;
virtual size_t getSoundDataSize(Sound_Handle data) const = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0;
/// @param offset Number of seconds into the sound to start playback. virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0;
virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0;
/// @param offset Number of seconds into the sound to start playback. virtual void stopSound(MWBase::SoundPtr sound) = 0;
virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0;
float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0;
virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0;
virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0;
float vol, float basevol, float pitch, float min, float max, int flags) = 0; virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0;
virtual void stopStream(MWBase::SoundStreamPtr sound) = 0;
virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0;
virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0;
virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0;
virtual void updateStream(MWBase::SoundStreamPtr sound) = 0;
virtual void startUpdate() = 0; virtual void startUpdate() = 0;
virtual void finishUpdate() = 0; virtual void finishUpdate() = 0;
@ -57,12 +63,9 @@ namespace MWSound
protected: protected:
bool mInitialized; bool mInitialized;
osg::Vec3f mPos;
Sound_Output(SoundManager &mgr) Sound_Output(SoundManager &mgr)
: mManager(mgr) : mManager(mgr), mInitialized(false)
, mInitialized(false)
, mPos(0.0f, 0.0f, 0.0f)
{ } { }
public: public:
virtual ~Sound_Output() { } virtual ~Sound_Output() { }

@ -241,7 +241,7 @@ namespace MWSound
return decoder; return decoder;
} }
MWBase::SoundPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) MWBase::SoundStreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal)
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
static const float fAudioMinDistanceMult = world->getStore().get<ESM::GameSetting>().find("fAudioMinDistanceMult")->getFloat(); static const float fAudioMinDistanceMult = world->getStore().get<ESM::GameSetting>().find("fAudioMinDistanceMult")->getFloat();
@ -251,15 +251,20 @@ namespace MWSound
static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f);
static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance);
MWBase::SoundStreamPtr sound;
float basevol = volumeFromType(Play_TypeVoice); float basevol = volumeFromType(Play_TypeVoice);
if(playlocal) if(playlocal)
return mOutput->streamSound(decoder, {
basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D sound.reset(new Stream(1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D));
); mOutput->streamSound(decoder, sound);
return mOutput->streamSound3D(decoder, }
pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, else
Play_Normal|Play_TypeVoice|Play_3D {
); sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
Play_Normal|Play_TypeVoice|Play_3D));
mOutput->streamSound3D(decoder, sound);
}
return sound;
} }
@ -293,7 +298,7 @@ namespace MWSound
void SoundManager::stopMusic() void SoundManager::stopMusic()
{ {
if(mMusic) if(mMusic)
mMusic->stop(); mOutput->stopStream(mMusic);
mMusic.reset(); mMusic.reset();
} }
@ -303,19 +308,19 @@ namespace MWSound
return; return;
std::cout <<"Playing "<<filename<< std::endl; std::cout <<"Playing "<<filename<< std::endl;
mLastPlayedMusic = filename; mLastPlayedMusic = filename;
try try {
{
stopMusic(); stopMusic();
DecoderPtr decoder = getDecoder(); DecoderPtr decoder = getDecoder();
decoder->open(filename); decoder->open(filename);
mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), mMusic.reset(new Stream(1.0f, volumeFromType(Play_TypeMusic), 1.0f,
1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); Play_NoEnv|Play_TypeMusic|Play_2D));
mOutput->streamSound(decoder, mMusic);
} }
catch(std::exception &e) catch(std::exception &e) {
{
std::cout << "Music Error: " << e.what() << "\n"; std::cout << "Music Error: " << e.what() << "\n";
mMusic.reset();
} }
} }
@ -366,7 +371,7 @@ namespace MWSound
bool SoundManager::isMusicPlaying() bool SoundManager::isMusicPlaying()
{ {
return mMusic && mMusic->isPlaying(); return mMusic && mOutput->isStreamPlaying(mMusic);
} }
void SoundManager::playPlaylist(const std::string &playlist) void SoundManager::playPlaylist(const std::string &playlist)
@ -394,7 +399,7 @@ namespace MWSound
mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); mPendingSaySounds[ptr] = std::make_pair(decoder, loudness);
else else
{ {
MWBase::SoundPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer()));
mActiveSaySounds[ptr] = std::make_pair(sound, loudness); mActiveSaySounds[ptr] = std::make_pair(sound, loudness);
} }
} }
@ -409,11 +414,10 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end()) if(snditer != mActiveSaySounds.end())
{ {
MWBase::SoundPtr sound = snditer->second.first; MWBase::SoundStreamPtr sound = snditer->second.first;
Sound_Loudness *loudness = snditer->second.second; Sound_Loudness *loudness = snditer->second.second;
float sec = sound->getTimeOffset(); float sec = mOutput->getStreamOffset(sound);
if(sound->isPlaying()) return loudness->getLoudnessAtTime(sec);
return loudness->getLoudnessAtTime(sec);
} }
return 0.0f; return 0.0f;
@ -435,7 +439,7 @@ namespace MWSound
mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness);
else else
{ {
MWBase::SoundPtr sound = playVoice(decoder, osg::Vec3f(), true); MWBase::SoundStreamPtr sound = playVoice(decoder, osg::Vec3f(), true);
mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness);
} }
} }
@ -450,7 +454,7 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end()) if(snditer != mActiveSaySounds.end())
{ {
if(snditer->second.first->isPlaying()) if(mOutput->isStreamPlaying(snditer->second.first))
return false; return false;
return true; return true;
} }
@ -462,21 +466,25 @@ namespace MWSound
SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end()) if(snditer != mActiveSaySounds.end())
{ {
snditer->second.first->stop(); mOutput->stopStream(snditer->second.first);
mActiveSaySounds.erase(snditer); mActiveSaySounds.erase(snditer);
} }
mPendingSaySounds.erase(ptr); mPendingSaySounds.erase(ptr);
} }
MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) MWBase::SoundStreamPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type)
{ {
MWBase::SoundPtr track; MWBase::SoundStreamPtr track;
if(!mOutput->isInitialized()) if(!mOutput->isInitialized())
return track; return track;
try try
{ {
track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); track.reset(new Stream(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D));
mOutput->streamSound(decoder, track);
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track);
mActiveTracks.insert(iter, track);
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -485,6 +493,19 @@ namespace MWSound
return track; return track;
} }
void SoundManager::stopTrack(MWBase::SoundStreamPtr stream)
{
mOutput->stopStream(stream);
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream);
if(iter != mActiveTracks.end() && *iter == stream)
mActiveTracks.erase(iter);
}
double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream)
{
return mOutput->getStreamDelay(stream);
}
MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset)
{ {
@ -496,9 +517,8 @@ namespace MWSound
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
float basevol = volumeFromType(type); float basevol = volumeFromType(type);
sound = mOutput->playSound(sfx->mHandle, sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D));
volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset mOutput->playSound(sound, sfx->mHandle, offset);
);
if(sfx->mUses++ == 0) if(sfx->mUses++ == 0)
{ {
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
@ -510,6 +530,7 @@ namespace MWSound
catch(std::exception&) catch(std::exception&)
{ {
//std::cout <<"Sound Error: "<<e.what()<< std::endl; //std::cout <<"Sound Error: "<<e.what()<< std::endl;
sound.reset();
} }
return sound; return sound;
} }
@ -532,14 +553,16 @@ namespace MWSound
return MWBase::SoundPtr(); return MWBase::SoundPtr();
if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer())
sound = mOutput->playSound(sfx->mHandle, {
volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D));
); mOutput->playSound(sound, sfx->mHandle, offset);
}
else else
sound = mOutput->playSound3D(sfx->mHandle, {
objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, sound.reset(new Sound(objpos, volume * sfx->mVolume, basevol, pitch,
mode|type|Play_3D, offset sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D));
); mOutput->playSound3D(sound, sfx->mHandle, offset);
}
if(sfx->mUses++ == 0) if(sfx->mUses++ == 0)
{ {
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
@ -551,6 +574,7 @@ namespace MWSound
catch(std::exception&) catch(std::exception&)
{ {
//std::cout <<"Sound Error: "<<e.what()<< std::endl; //std::cout <<"Sound Error: "<<e.what()<< std::endl;
sound.reset();
} }
return sound; return sound;
} }
@ -567,10 +591,9 @@ namespace MWSound
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
float basevol = volumeFromType(type); float basevol = volumeFromType(type);
sound = mOutput->playSound3D(sfx->mHandle, sound.reset(new Sound(initialPos, volume * sfx->mVolume, basevol, pitch,
initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D));
mode|type|Play_3D, offset mOutput->playSound3D(sound, sfx->mHandle, offset);
);
if(sfx->mUses++ == 0) if(sfx->mUses++ == 0)
{ {
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
@ -582,10 +605,16 @@ namespace MWSound
catch(std::exception &) catch(std::exception &)
{ {
//std::cout <<"Sound Error: "<<e.what()<< std::endl; //std::cout <<"Sound Error: "<<e.what()<< std::endl;
sound.reset();
} }
return sound; return sound;
} }
void SoundManager::stopSound(MWBase::SoundPtr sound)
{
mOutput->stopSound(sound);
}
void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId)
{ {
SoundMap::iterator snditer = mActiveSounds.find(ptr); SoundMap::iterator snditer = mActiveSounds.find(ptr);
@ -596,7 +625,7 @@ namespace MWSound
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx) if(sndidx->second == sfx)
sndidx->first->stop(); mOutput->stopSound(sndidx->first);
} }
} }
} }
@ -608,7 +637,7 @@ namespace MWSound
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
sndidx->first->stop(); mOutput->stopSound(sndidx->first);
} }
} }
@ -623,7 +652,7 @@ namespace MWSound
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
sndidx->first->stop(); mOutput->stopSound(sndidx->first);
} }
++snditer; ++snditer;
} }
@ -634,7 +663,7 @@ namespace MWSound
sayiter->first != MWMechanics::getPlayer() && sayiter->first != MWMechanics::getPlayer() &&
sayiter->first.getCell() == cell) sayiter->first.getCell() == cell)
{ {
sayiter->second.first->stop(); mOutput->stopStream(sayiter->second.first);
} }
++sayiter; ++sayiter;
} }
@ -650,7 +679,7 @@ namespace MWSound
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx) if(sndidx->second == sfx)
sndidx->first->stop(); mOutput->stopSound(sndidx->first);
} }
} }
} }
@ -680,7 +709,7 @@ namespace MWSound
SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx && sndidx->first->isPlaying()) if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first))
return true; return true;
} }
} }
@ -788,7 +817,7 @@ namespace MWSound
env = Env_Underwater; env = Env_Underwater;
else if(mUnderwaterSound) else if(mUnderwaterSound)
{ {
mUnderwaterSound->stop(); mOutput->stopSound(mUnderwaterSound);
mUnderwaterSound.reset(); mUnderwaterSound.reset();
} }
@ -803,7 +832,7 @@ namespace MWSound
if(mListenerUnderwater) if(mListenerUnderwater)
{ {
// Play underwater sound (after updating listener) // Play underwater sound (after updating listener)
if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound)))
mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv);
} }
@ -814,15 +843,36 @@ namespace MWSound
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
while(sndidx != snditer->second.end()) while(sndidx != snditer->second.end())
{ {
if(!updateSound(sndidx->first, snditer->first, duration)) MWWorld::Ptr ptr = snditer->first;
MWBase::SoundPtr sound = sndidx->first;
if(!ptr.isEmpty() && sound->getIs3D())
{ {
const ESM::Position &pos = ptr.getRefData().getPosition();
const osg::Vec3f objpos(pos.asVec3());
sound->setPosition(objpos);
if(sound->getDistanceCull())
{
if((mListenerPos - objpos).length2() > 2000*2000)
mOutput->stopSound(sound);
}
}
if(!mOutput->isSoundPlaying(sound))
{
mOutput->stopSound(sound);
Sound_Buffer *sfx = sndidx->second; Sound_Buffer *sfx = sndidx->second;
if(sfx->mUses-- == 1) if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx); mUnusedBuffers.push_front(sfx);
sndidx = snditer->second.erase(sndidx); sndidx = snditer->second.erase(sndidx);
} }
else else
{
sound->updateFade(duration);
mOutput->updateSound(sound);
++sndidx; ++sndidx;
}
} }
if(snditer->second.empty()) if(snditer->second.empty())
mActiveSounds.erase(snditer++); mActiveSounds.erase(snditer++);
@ -840,13 +890,17 @@ namespace MWSound
DecoderPtr decoder = penditer->second.first; DecoderPtr decoder = penditer->second.first;
decoder->rewind(); decoder->rewind();
MWBase::SoundStreamPtr sound;
MWWorld::Ptr ptr = penditer->first; MWWorld::Ptr ptr = penditer->first;
const ESM::Position &pos = ptr.getRefData().getPosition(); if(ptr == MWWorld::Ptr())
const osg::Vec3f objpos(pos.asVec3()); sound = playVoice(decoder, osg::Vec3f(), true);
else
{
const ESM::Position &pos = ptr.getRefData().getPosition();
const osg::Vec3f objpos(pos.asVec3());
MWBase::SoundPtr sound = playVoice(decoder, sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer()));
objpos, (ptr == MWMechanics::getPlayer()) }
);
mActiveSaySounds[ptr] = std::make_pair(sound, loudness); mActiveSaySounds[ptr] = std::make_pair(sound, loudness);
} }
catch(std::exception &e) { catch(std::exception &e) {
@ -862,36 +916,53 @@ namespace MWSound
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
while(sayiter != mActiveSaySounds.end()) while(sayiter != mActiveSaySounds.end())
{ {
if(!updateSound(sayiter->second.first, sayiter->first, duration)) MWWorld::Ptr ptr = sayiter->first;
MWBase::SoundStreamPtr sound = sayiter->second.first;
if(!ptr.isEmpty() && sound->getIs3D())
{
const ESM::Position &pos = ptr.getRefData().getPosition();
const osg::Vec3f objpos(pos.asVec3());
sound->setPosition(objpos);
if(sound->getDistanceCull())
{
if((mListenerPos - objpos).length2() > 2000*2000)
mOutput->stopStream(sound);
}
}
if(!mOutput->isStreamPlaying(sound))
{
mOutput->stopStream(sound);
mActiveSaySounds.erase(sayiter++); mActiveSaySounds.erase(sayiter++);
}
else else
{
sound->updateFade(duration);
mOutput->updateStream(sound);
++sayiter; ++sayiter;
}
} }
mOutput->finishUpdate();
}
bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) TrackList::iterator trkiter = mActiveTracks.begin();
{ for(;trkiter != mActiveTracks.end();++trkiter)
if(!ptr.isEmpty() && sound->getIs3D())
{ {
const ESM::Position &pos = ptr.getRefData().getPosition(); MWBase::SoundStreamPtr sound = *trkiter;
const osg::Vec3f objpos(pos.asVec3()); if(!mOutput->isStreamPlaying(sound))
sound->setPosition(objpos);
if(sound->getDistanceCull())
{ {
if((mListenerPos - objpos).length2() > 2000*2000) mOutput->stopStream(sound);
sound->stop(); trkiter = mActiveTracks.erase(trkiter);
} }
} else
{
if(!sound->isPlaying()) sound->updateFade(duration);
return false;
sound->updateFade(duration);
sound->applyUpdates(); mOutput->updateStream(sound);
return true; ++trkiter;
}
}
mOutput->finishUpdate();
} }
@ -928,20 +999,27 @@ namespace MWSound
{ {
MWBase::SoundPtr sound = sndidx->first; MWBase::SoundPtr sound = sndidx->first;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
sound->applyUpdates(); mOutput->updateSound(sound);
} }
} }
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter) for(;sayiter != mActiveSaySounds.end();++sayiter)
{ {
MWBase::SoundPtr sound = sayiter->second.first; MWBase::SoundStreamPtr sound = sayiter->second.first;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
}
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter)
{
MWBase::SoundStreamPtr sound = *trkiter;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
sound->applyUpdates(); mOutput->updateStream(sound);
} }
if(mMusic) if(mMusic)
{ {
mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType()));
mMusic->applyUpdates(); mOutput->updateStream(mMusic);
} }
mOutput->finishUpdate(); mOutput->finishUpdate();
} }
@ -1053,7 +1131,7 @@ namespace MWSound
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx) for(;sndidx != snditer->second.end();++sndidx)
{ {
sndidx->first->stop(); mOutput->stopSound(sndidx->first);
Sound_Buffer *sfx = sndidx->second; Sound_Buffer *sfx = sndidx->second;
if(sfx->mUses-- == 1) if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx); mUnusedBuffers.push_front(sfx);
@ -1062,8 +1140,12 @@ namespace MWSound
mActiveSounds.clear(); mActiveSounds.clear();
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter) for(;sayiter != mActiveSaySounds.end();++sayiter)
sayiter->second.first->stop(); mOutput->stopStream(sayiter->second.first);
mActiveSaySounds.clear(); mActiveSaySounds.clear();
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter)
mOutput->stopStream(*trkiter);
mActiveTracks.clear();
mPendingSaySounds.clear(); mPendingSaySounds.clear();
mUnderwaterSound.reset(); mUnderwaterSound.reset();
stopMusic(); stopMusic();

@ -79,15 +79,12 @@ namespace MWSound
typedef std::deque<Sound_Buffer*> SoundList; typedef std::deque<Sound_Buffer*> SoundList;
SoundList mUnusedBuffers; SoundList mUnusedBuffers;
boost::shared_ptr<Sound> mMusic;
std::string mCurrentPlaylist;
typedef std::pair<MWBase::SoundPtr,Sound_Buffer*> SoundBufferRefPair; typedef std::pair<MWBase::SoundPtr,Sound_Buffer*> SoundBufferRefPair;
typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList; typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList;
typedef std::map<MWWorld::Ptr,SoundBufferRefPairList> SoundMap; typedef std::map<MWWorld::Ptr,SoundBufferRefPairList> SoundMap;
SoundMap mActiveSounds; SoundMap mActiveSounds;
typedef std::pair<MWBase::SoundPtr,Sound_Loudness*> SoundLoudnessPair; typedef std::pair<MWBase::SoundStreamPtr,Sound_Loudness*> SoundLoudnessPair;
typedef std::map<MWWorld::Ptr,SoundLoudnessPair> SaySoundMap; typedef std::map<MWWorld::Ptr,SoundLoudnessPair> SaySoundMap;
SaySoundMap mActiveSaySounds; SaySoundMap mActiveSaySounds;
@ -95,7 +92,11 @@ namespace MWSound
typedef std::map<MWWorld::Ptr,DecoderLoudnessPair> SayDecoderMap; typedef std::map<MWWorld::Ptr,DecoderLoudnessPair> SayDecoderMap;
SayDecoderMap mPendingSaySounds; SayDecoderMap mPendingSaySounds;
MWBase::SoundPtr mUnderwaterSound; typedef std::vector<MWBase::SoundStreamPtr> TrackList;
TrackList mActiveTracks;
MWBase::SoundStreamPtr mMusic;
std::string mCurrentPlaylist;
bool mListenerUnderwater; bool mListenerUnderwater;
osg::Vec3f mListenerPos; osg::Vec3f mListenerPos;
@ -104,6 +105,8 @@ namespace MWSound
int mPausedSoundTypes; int mPausedSoundTypes;
MWBase::SoundPtr mUnderwaterSound;
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
Sound_Buffer *lookupSound(const std::string &soundId) const; Sound_Buffer *lookupSound(const std::string &soundId) const;
@ -113,10 +116,9 @@ namespace MWSound
// to start streaming // to start streaming
DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata);
MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal);
void streamMusicFull(const std::string& filename); void streamMusicFull(const std::string& filename);
bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration);
void updateSounds(float duration); void updateSounds(float duration);
void updateRegionSound(float duration); void updateRegionSound(float duration);
@ -171,9 +173,17 @@ namespace MWSound
/// and get an average loudness value (scale [0,1]) at the current time position. /// and get an average loudness value (scale [0,1]) at the current time position.
/// If the actor is not saying anything, returns 0. /// If the actor is not saying anything, returns 0.
virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); virtual MWBase::SoundStreamPtr playTrack(const DecoderPtr& decoder, PlayType type);
///< Play a 2D audio track, using a custom decoder ///< Play a 2D audio track, using a custom decoder
virtual void stopTrack(MWBase::SoundStreamPtr stream);
///< Stop the given audio track from playing
virtual double getTrackTimeDelay(MWBase::SoundStreamPtr stream);
///< Retives the time delay, in seconds, of the audio track (must be a sound
/// returned by \ref playTrack). Only intended to be called by the track
/// decoder's read method.
virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0);
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
///< @param offset Number of seconds into the sound to start playback. ///< @param offset Number of seconds into the sound to start playback.
@ -189,6 +199,9 @@ namespace MWSound
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition.
///< @param offset Number of seconds into the sound to start playback. ///< @param offset Number of seconds into the sound to start playback.
virtual void stopSound(MWBase::SoundPtr sound);
///< Stop the given sound from playing
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId);
///< Stop the given object from playing the given sound, ///< Stop the given object from playing the given sound,

@ -190,7 +190,7 @@ namespace MWWorld
{ {
MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName);
it->mSound->stop(); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
mParent->removeChild(it->mNode); mParent->removeChild(it->mNode);
it = mMagicBolts.erase(it); it = mMagicBolts.erase(it);
@ -264,7 +264,7 @@ namespace MWWorld
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
{ {
mParent->removeChild(it->mNode); mParent->removeChild(it->mNode);
it->mSound->stop(); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
} }
mMagicBolts.clear(); mMagicBolts.clear();
} }

@ -738,7 +738,7 @@ void WeatherManager::update(float duration, bool paused)
void WeatherManager::stopSounds() void WeatherManager::stopSounds()
{ {
if (mAmbientSound.get()) if (mAmbientSound.get())
mAmbientSound->stop(); MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound);
mAmbientSound.reset(); mAmbientSound.reset();
mPlayingSoundID.clear(); mPlayingSoundID.clear();
} }

Loading…
Cancel
Save