Avoid inheriting from Sound for sound types

openmw-38
Chris Robinson 9 years ago
parent 77965501d4
commit 816015d6e6

@ -107,6 +107,14 @@ namespace MWBase
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
///< Play a 2D audio track, using a custom decoder
virtual void stopTrack(SoundPtr sound) = 0;
///< Stop the given audio track from playing
virtual double getTrackTimeDelay(SoundPtr sound) = 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,
PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal,
float offset=0) = 0;
@ -123,6 +131,9 @@ namespace MWBase
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.
virtual void stopSound(SoundPtr sound) = 0;
///< Stop the given sound from playing
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
///< Stop the given object from playing the given sound,

@ -61,7 +61,7 @@ namespace MWSound
virtual double getAudioClock()
{
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)
@ -86,6 +86,8 @@ namespace MWSound
public:
~MovieAudioDecoder()
{
if(mAudioTrack.get())
MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack);
mAudioTrack.reset();
mDecoderBridge.reset();
}

@ -157,17 +157,14 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
//
// A streaming OpenAL sound.
//
class OpenAL_SoundStream : public Sound
class OpenAL_SoundStream
{
static const ALuint sNumBuffers = 6;
static const ALfloat sBufferLength;
protected:
OpenAL_Output &mOutput;
private:
ALuint mSource;
private:
ALuint mBuffers[sNumBuffers];
ALint mCurrentBufIdx;
@ -189,34 +186,18 @@ private:
friend class OpenAL_Output;
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);
virtual ~OpenAL_SoundStream();
OpenAL_SoundStream(ALuint src, DecoderPtr decoder);
~OpenAL_SoundStream();
virtual void stop();
virtual bool isPlaying();
virtual double getTimeOffset();
virtual double getStreamDelay() const;
virtual void applyUpdates();
bool isPlaying();
double getStreamDelay() const;
double getStreamOffset() const;
void play();
bool process();
ALint refillQueue();
};
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)
@ -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)
: Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)
, mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0)
, mDecoder(decoder), mIsFinished(true)
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
: mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false)
{
throwALerror();
alGenBuffers(sNumBuffers, mBuffers);
throwALerror();
try
@ -358,8 +335,6 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
mFrameSize = framesToBytes(1, chans, type);
mBufferSize = static_cast<ALuint>(sBufferLength*srate);
mBufferSize *= mFrameSize;
mOutput.mActiveStreams.push_back(this);
}
catch(std::exception&)
{
@ -367,51 +342,20 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
alGetError();
throw;
}
mIsFinished = false;
}
OpenAL_SoundStream::~OpenAL_SoundStream()
{
mOutput.mStreamThread->remove(this);
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
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()
{
ALint state;
boost::lock_guard<boost::mutex> lock(mOutput.mStreamThread->mMutex);
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror();
@ -420,13 +364,12 @@ bool OpenAL_SoundStream::isPlaying()
return !mIsFinished;
}
double OpenAL_SoundStream::getTimeOffset()
double OpenAL_SoundStream::getStreamDelay() const
{
ALint state = AL_STOPPED;
double d = 0.0;
ALint offset;
double t;
boost::lock_guard<boost::mutex> lock(mOutput.mStreamThread->mMutex);
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
if(state == AL_PLAYING || state == AL_PAUSED)
@ -434,24 +377,18 @@ double OpenAL_SoundStream::getTimeOffset()
ALint queued;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
ALint inqueue = mBufferSize/mFrameSize*queued - offset;
t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate;
}
else
{
/* Underrun, or not started yet. The decoder offset is where we'll play
* next. */
t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
d = (double)inqueue / (double)mSampleRate;
}
throwALerror();
return t;
return d;
}
double OpenAL_SoundStream::getStreamDelay() const
double OpenAL_SoundStream::getStreamOffset() const
{
ALint state = AL_STOPPED;
double d = 0.0;
ALint offset;
double t;
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
@ -460,48 +397,17 @@ double OpenAL_SoundStream::getStreamDelay() const
ALint queued;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
ALint inqueue = mBufferSize/mFrameSize*queued - offset;
d = (double)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);
t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate;
}
else
{
alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f);
alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE);
}
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;
/* Underrun, or not started yet. The decoder offset is where we'll play
* next. */
t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
}
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();
return t;
}
bool OpenAL_SoundStream::process()
@ -562,172 +468,6 @@ ALint OpenAL_SoundStream::refillQueue()
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
@ -881,15 +621,16 @@ void OpenAL_Output::unloadSound(Sound_Handle data)
SoundVec::const_iterator iter = mActiveSounds.begin();
for(;iter != mActiveSounds.end();++iter)
{
if(!(*iter)->mSource)
if(!(*iter)->mHandle)
continue;
ALuint source = GET_PTRID((*iter)->mHandle);
ALint srcbuf;
alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf);
alGetSourcei(source, AL_BUFFER, &srcbuf);
if((ALuint)srcbuf == buffer)
{
alSourceStop((*iter)->mSource);
alSourcei((*iter)->mSource, AL_BUFFER, 0);
alSourceStop(source);
alSourcei(source, AL_BUFFER, 0);
}
}
alDeleteBuffers(1, &buffer);
@ -907,123 +648,281 @@ 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)
MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset)
{
boost::shared_ptr<OpenAL_Sound> sound;
ALuint src;
boost::shared_ptr<Sound> sound;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.front();
source = mFreeSources.front();
mFreeSources.pop_front();
try {
sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags));
alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
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, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
ALfloat gain = vol*basevol;
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(source, AL_GAIN, gain);
alSourcef(source, AL_PITCH, pitch);
alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(source, AL_SEC_OFFSET, offset/pitch);
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
throwALerror();
sound.reset(new Sound(osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags));
sound->mHandle = MAKE_PTRID(source);
mActiveSounds.push_back(sound);
}
catch(std::exception&)
{
mFreeSources.push_back(src);
catch(std::exception&) {
mFreeSources.push_back(source);
throw;
}
sound->updateAll(true);
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,
float min, float max, int flags, float offset)
float mindist, float maxdist, int flags, float offset)
{
boost::shared_ptr<OpenAL_Sound> sound;
ALuint src;
boost::shared_ptr<Sound> sound;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.front();
source = mFreeSources.front();
mFreeSources.pop_front();
try {
sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags));
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, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
ALfloat gain = vol*basevol;
if((pos - mPos).length2() > maxdist*maxdist)
gain = 0.0f;
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == 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);
alSourcef(source, AL_SEC_OFFSET, offset/pitch);
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
throwALerror();
sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags));
sound->mHandle = MAKE_PTRID(source);
mActiveSounds.push_back(sound);
}
catch(std::exception&)
{
mFreeSources.push_back(src);
catch(std::exception&) {
mFreeSources.push_back(source);
throw;
}
sound->updateAll(false);
alSourcei(src, AL_BUFFER, GET_PTRID(data));
alSourcef(src, AL_SEC_OFFSET, offset/pitch);
return sound;
}
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);
mFreeSources.push_back(source);
mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound));
}
alSourcePlay(src);
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();
return sound;
return state == AL_PLAYING || state == AL_PAUSED;
}
MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags)
{
boost::shared_ptr<OpenAL_SoundStream> sound;
ALuint src;
boost::shared_ptr<Sound> sound;
OpenAL_SoundStream *stream = 0;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.front();
source = mFreeSources.front();
mFreeSources.pop_front();
if((flags&MWBase::SoundManager::Play_Loop))
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try
{
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));
try {
alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
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, AL_FALSE);
ALfloat gain = basevol;
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
{
gain *= 0.9f;
pitch *= 0.7f;
}
alSourcef(source, AL_GAIN, gain);
alSourcef(source, AL_PITCH, pitch);
alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror();
sound.reset(new Sound(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags));
stream = new OpenAL_SoundStream(source, decoder);
mStreamThread->add(stream);
sound->mHandle = stream;
mActiveStreams.push_back(sound);
}
catch(std::exception&)
{
mFreeSources.push_back(src);
catch(std::exception&) {
mStreamThread->remove(stream);
delete stream;
mFreeSources.push_back(source);
throw;
}
sound->updateAll(true);
sound->play();
return sound;
}
MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags)
MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags)
{
boost::shared_ptr<OpenAL_SoundStream> sound;
ALuint src;
boost::shared_ptr<Sound> sound;
OpenAL_SoundStream *stream = 0;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.front();
source = mFreeSources.front();
mFreeSources.pop_front();
if((flags&MWBase::SoundManager::Play_Loop))
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try
{
sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags));
try {
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, AL_FALSE);
ALfloat gain = volume*basevol;
if((pos - mPos).length2() > maxdist*maxdist)
gain = 0.0f;
if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == 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);
throwALerror();
sound.reset(new Sound(pos, volume, basevol, pitch, mindist, maxdist, flags));
stream = new OpenAL_SoundStream(source, decoder);
mStreamThread->add(stream);
sound->mHandle = stream;
mActiveStreams.push_back(sound);
}
catch(std::exception&)
{
mFreeSources.push_back(src);
catch(std::exception&) {
mStreamThread->remove(stream);
delete stream;
mFreeSources.push_back(source);
throw;
}
sound->updateAll(false);
sound->play();
return sound;
}
void OpenAL_Output::stopStream(MWBase::SoundPtr 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::SoundPtr sound)
{
if(!sound->mHandle)
return 0.0;
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
return stream->getStreamDelay();
}
double OpenAL_Output::getStreamOffset(MWBase::SoundPtr 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::SoundPtr 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();
}
void OpenAL_Output::startUpdate()
{
@ -1060,14 +959,17 @@ void OpenAL_Output::pauseSounds(int types)
SoundVec::const_iterator sound = mActiveSounds.begin();
for(;sound != mActiveSounds.end();++sound)
{
if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types))
sources.push_back((*sound)->mSource);
if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types))
sources.push_back(GET_PTRID((*sound)->mHandle));
}
StreamVec::const_iterator stream = mActiveStreams.begin();
for(;stream != mActiveStreams.end();++stream)
{
if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types))
sources.push_back((*stream)->mSource);
if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types))
{
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>((*stream)->mHandle);
sources.push_back(strm->mSource);
}
}
if(!sources.empty())
{
@ -1082,14 +984,17 @@ void OpenAL_Output::resumeSounds(int types)
SoundVec::const_iterator sound = mActiveSounds.begin();
for(;sound != mActiveSounds.end();++sound)
{
if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types))
sources.push_back((*sound)->mSource);
if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types))
sources.push_back(GET_PTRID((*sound)->mHandle));
}
StreamVec::const_iterator stream = mActiveStreams.begin();
for(;stream != mActiveStreams.end();++stream)
{
if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types))
sources.push_back((*stream)->mSource);
if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types))
{
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>((*stream)->mHandle);
sources.push_back(strm->mSource);
}
}
if(!sources.empty())
{

@ -16,9 +16,6 @@ namespace MWSound
class SoundManager;
class Sound;
class OpenAL_Sound;
class OpenAL_SoundStream;
class OpenAL_Output : public Sound_Output
{
ALCdevice *mDevice;
@ -27,9 +24,9 @@ namespace MWSound
typedef std::deque<ALuint> IDDq;
IDDq mFreeSources;
typedef std::vector<OpenAL_Sound*> SoundVec;
typedef std::vector<MWBase::SoundPtr> SoundVec;
SoundVec mActiveSounds;
typedef std::vector<OpenAL_SoundStream*> StreamVec;
typedef std::vector<MWBase::SoundPtr> StreamVec;
StreamVec mActiveStreams;
Environment mLastEnvironment;
@ -45,9 +42,16 @@ namespace MWSound
virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset);
virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos,
float vol, float basevol, float pitch, float min, float max, int flags, float offset);
virtual void stopSound(MWBase::SoundPtr sound);
virtual bool isSoundPlaying(MWBase::SoundPtr sound);
virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags);
virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos,
float vol, float basevol, float pitch, float min, float max, int flags);
virtual void stopStream(MWBase::SoundPtr sound);
virtual double getStreamDelay(MWBase::SoundPtr sound);
virtual double getStreamOffset(MWBase::SoundPtr sound);
virtual bool isStreamPlaying(MWBase::SoundPtr sound);
virtual void startUpdate();
virtual void finishUpdate();

@ -10,7 +10,6 @@ namespace MWSound
Sound& operator=(const Sound &rhs);
Sound(const Sound &rhs);
protected:
osg::Vec3f mPos;
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
float mBaseVolume;
@ -21,12 +20,13 @@ namespace MWSound
float mFadeOutTime;
protected:
void *mHandle;
friend class Sound_Output;
friend class OpenAL_Output;
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 setVolume(float volume) { mVolume = volume; }
void setBaseVolume(float volume) { mBaseVolume = volume; }
@ -47,16 +47,11 @@ namespace MWSound
bool getIs3D() const { return mFlags&Play_3D; }
Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
: mPos(pos)
, mVolume(vol)
, mBaseVolume(basevol)
, mPitch(pitch)
, mMinDistance(mindist)
, mMaxDistance(maxdist)
, mFlags(flags)
, mFadeOutTime(0.0f)
: mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch)
, mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags)
, mFadeOutTime(0.0f), mHandle(0)
{ }
virtual ~Sound() { }
~Sound() { }
};
}

@ -35,9 +35,16 @@ namespace MWSound
/// @param offset Number of seconds into the sound to start playback.
virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos,
float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0;
virtual void stopSound(MWBase::SoundPtr sound) = 0;
virtual bool isSoundPlaying(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,
float vol, float basevol, float pitch, float min, float max, int flags) = 0;
virtual void stopStream(MWBase::SoundPtr sound) = 0;
virtual double getStreamDelay(MWBase::SoundPtr sound) = 0;
virtual double getStreamOffset(MWBase::SoundPtr sound) = 0;
virtual bool isStreamPlaying(MWBase::SoundPtr sound) = 0;
virtual void startUpdate() = 0;
virtual void finishUpdate() = 0;

@ -293,7 +293,7 @@ namespace MWSound
void SoundManager::stopMusic()
{
if(mMusic)
mMusic->stop();
mOutput->stopStream(mMusic);
mMusic.reset();
}
@ -303,8 +303,7 @@ namespace MWSound
return;
std::cout <<"Playing "<<filename<< std::endl;
mLastPlayedMusic = filename;
try
{
try {
stopMusic();
DecoderPtr decoder = getDecoder();
@ -313,8 +312,7 @@ namespace MWSound
mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic),
1.0f, Play_NoEnv|Play_TypeMusic|Play_2D);
}
catch(std::exception &e)
{
catch(std::exception &e) {
std::cout << "Music Error: " << e.what() << "\n";
}
}
@ -366,7 +364,7 @@ namespace MWSound
bool SoundManager::isMusicPlaying()
{
return mMusic && mMusic->isPlaying();
return mMusic && mOutput->isStreamPlaying(mMusic);
}
void SoundManager::playPlaylist(const std::string &playlist)
@ -411,9 +409,8 @@ namespace MWSound
{
MWBase::SoundPtr sound = snditer->second.first;
Sound_Loudness *loudness = snditer->second.second;
float sec = sound->getTimeOffset();
if(sound->isPlaying())
return loudness->getLoudnessAtTime(sec);
float sec = mOutput->getStreamOffset(sound);
return loudness->getLoudnessAtTime(sec);
}
return 0.0f;
@ -450,7 +447,7 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
if(snditer->second.first->isPlaying())
if(mOutput->isStreamPlaying(snditer->second.first))
return false;
return true;
}
@ -462,7 +459,7 @@ namespace MWSound
SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
snditer->second.first->stop();
mOutput->stopStream(snditer->second.first);
mActiveSaySounds.erase(snditer);
}
mPendingSaySounds.erase(ptr);
@ -485,6 +482,16 @@ namespace MWSound
return track;
}
void SoundManager::stopTrack(MWBase::SoundPtr sound)
{
mOutput->stopStream(sound);
}
double SoundManager::getTrackTimeDelay(MWBase::SoundPtr sound)
{
return mOutput->getStreamDelay(sound);
}
MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset)
{
@ -586,6 +593,11 @@ namespace MWSound
return sound;
}
void SoundManager::stopSound(MWBase::SoundPtr sound)
{
mOutput->stopSound(sound);
}
void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId)
{
SoundMap::iterator snditer = mActiveSounds.find(ptr);
@ -596,7 +608,7 @@ namespace MWSound
for(;sndidx != snditer->second.end();++sndidx)
{
if(sndidx->second == sfx)
sndidx->first->stop();
mOutput->stopSound(sndidx->first);
}
}
}
@ -608,7 +620,7 @@ namespace MWSound
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
sndidx->first->stop();
mOutput->stopSound(sndidx->first);
}
}
@ -623,7 +635,7 @@ namespace MWSound
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
sndidx->first->stop();
mOutput->stopSound(sndidx->first);
}
++snditer;
}
@ -634,7 +646,7 @@ namespace MWSound
sayiter->first != MWMechanics::getPlayer() &&
sayiter->first.getCell() == cell)
{
sayiter->second.first->stop();
mOutput->stopStream(sayiter->second.first);
}
++sayiter;
}
@ -650,7 +662,7 @@ namespace MWSound
for(;sndidx != snditer->second.end();++sndidx)
{
if(sndidx->second == sfx)
sndidx->first->stop();
mOutput->stopSound(sndidx->first);
}
}
}
@ -680,7 +692,7 @@ namespace MWSound
SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
{
if(sndidx->second == sfx && sndidx->first->isPlaying())
if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first))
return true;
}
}
@ -788,7 +800,7 @@ namespace MWSound
env = Env_Underwater;
else if(mUnderwaterSound)
{
mUnderwaterSound->stop();
mOutput->stopSound(mUnderwaterSound);
mUnderwaterSound.reset();
}
@ -803,7 +815,7 @@ namespace MWSound
if(mListenerUnderwater)
{
// 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);
}
@ -814,15 +826,35 @@ namespace MWSound
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
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;
if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx);
sndidx = snditer->second.erase(sndidx);
}
else
{
sound->updateFade(duration);
++sndidx;
}
}
if(snditer->second.empty())
mActiveSounds.erase(snditer++);
@ -862,36 +894,34 @@ namespace MWSound
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
while(sayiter != mActiveSaySounds.end())
{
if(!updateSound(sayiter->second.first, sayiter->first, duration))
mActiveSaySounds.erase(sayiter++);
else
++sayiter;
}
mOutput->finishUpdate();
}
MWWorld::Ptr ptr = sayiter->first;
MWBase::SoundPtr 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);
bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration)
{
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(sound->getDistanceCull())
if(!mOutput->isStreamPlaying(sound))
{
if((mListenerPos - objpos).length2() > 2000*2000)
sound->stop();
mOutput->stopStream(sound);
mActiveSaySounds.erase(sayiter++);
}
}
if(!sound->isPlaying())
return false;
sound->updateFade(duration);
else
{
sound->updateFade(duration);
sound->applyUpdates();
return true;
++sayiter;
}
}
mOutput->finishUpdate();
}
@ -928,7 +958,6 @@ namespace MWSound
{
MWBase::SoundPtr sound = sndidx->first;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
sound->applyUpdates();
}
}
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
@ -936,12 +965,10 @@ namespace MWSound
{
MWBase::SoundPtr sound = sayiter->second.first;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
sound->applyUpdates();
}
if(mMusic)
{
mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType()));
mMusic->applyUpdates();
}
mOutput->finishUpdate();
}
@ -1056,7 +1083,7 @@ namespace MWSound
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
{
sndidx->first->stop();
mOutput->stopSound(sndidx->first);
Sound_Buffer *sfx = sndidx->second;
if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx);
@ -1065,7 +1092,7 @@ namespace MWSound
mActiveSounds.clear();
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter)
sayiter->second.first->stop();
mOutput->stopStream(sayiter->second.first);
mActiveSaySounds.clear();
mPendingSaySounds.clear();
mUnderwaterSound.reset();

@ -116,7 +116,6 @@ namespace MWSound
MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal);
void streamMusicFull(const std::string& filename);
bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration);
void updateSounds(float duration);
void updateRegionSound(float duration);
@ -174,6 +173,14 @@ namespace MWSound
virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type);
///< Play a 2D audio track, using a custom decoder
virtual void stopTrack(MWBase::SoundPtr sound);
///< Stop the given audio track from playing
virtual double getTrackTimeDelay(MWBase::SoundPtr sound);
///< 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);
///< Play a sound, independently of 3D-position
///< @param offset Number of seconds into the sound to start playback.
@ -189,6 +196,9 @@ namespace MWSound
///< 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.
virtual void stopSound(MWBase::SoundPtr sound);
///< Stop the given sound from playing
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId);
///< 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);
it->mSound->stop();
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
mParent->removeChild(it->mNode);
it = mMagicBolts.erase(it);
@ -264,7 +264,7 @@ namespace MWWorld
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
{
mParent->removeChild(it->mNode);
it->mSound->stop();
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
}
mMagicBolts.clear();
}

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

Loading…
Cancel
Save