Merge pull request #980 from scrawl/voice_fix

Voice fix
This commit is contained in:
scrawl 2016-07-02 21:55:46 +02:00 committed by GitHub
commit 343dccdbcc
12 changed files with 115 additions and 228 deletions

View file

@ -389,16 +389,6 @@ void FFmpeg_Decoder::readAll(std::vector<char> &output)
} }
} }
void FFmpeg_Decoder::rewind()
{
int stream_idx = mStream - mFormatCtx->streams;
if(av_seek_frame(mFormatCtx, stream_idx, 0, 0) < 0)
fail("Failed to seek in audio stream");
av_free_packet(&mPacket);
mFrameSize = mFramePos = 0;
mNextPts = 0.0;
}
size_t FFmpeg_Decoder::getSampleOffset() size_t FFmpeg_Decoder::getSampleOffset()
{ {
int delay = (mFrameSize-mFramePos) / av_get_channel_layout_nb_channels(mOutputChannelLayout) / int delay = (mFrameSize-mFramePos) / av_get_channel_layout_nb_channels(mOutputChannelLayout) /

View file

@ -74,7 +74,6 @@ namespace MWSound
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual void readAll(std::vector<char> &output); virtual void readAll(std::vector<char> &output);
virtual void rewind();
virtual size_t getSampleOffset(); virtual size_t getSampleOffset();
void fail(const std::string &msg); void fail(const std::string &msg);

View file

@ -8,15 +8,16 @@
namespace MWSound namespace MWSound
{ {
void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sampleRate, ChannelConfig chans, SampleType type, float valuesPerSecond) void Sound_Loudness::analyzeLoudness(const std::vector< char >& data)
{ {
int samplesPerSegment = static_cast<int>(sampleRate / valuesPerSecond); mQueue.insert( mQueue.end(), data.begin(), data.end() );
int numSamples = bytesToFrames(data.size(), chans, type); if (!mQueue.size())
int advance = framesToBytes(1, chans, type); return;
int samplesPerSegment = static_cast<int>(mSampleRate / mSamplesPerSec);
int numSamples = bytesToFrames(mQueue.size(), mChannelConfig, mSampleType);
int advance = framesToBytes(1, mChannelConfig, mSampleType);
mSamplesPerSec = valuesPerSecond;
mSamples.clear();
mSamples.reserve(numSamples/samplesPerSegment);
int segment=0; int segment=0;
int sample=0; int sample=0;
@ -28,16 +29,16 @@ void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sample
{ {
// get sample on a scale from -1 to 1 // get sample on a scale from -1 to 1
float value = 0; float value = 0;
if (type == SampleType_UInt8) if (mSampleType == SampleType_UInt8)
value = ((char)(data[sample*advance]^0x80))/128.f; value = ((char)(mQueue[sample*advance]^0x80))/128.f;
else if (type == SampleType_Int16) else if (mSampleType == SampleType_Int16)
{ {
value = *reinterpret_cast<const int16_t*>(&data[sample*advance]); value = *reinterpret_cast<const int16_t*>(&mQueue[sample*advance]);
value /= float(std::numeric_limits<int16_t>::max()); value /= float(std::numeric_limits<int16_t>::max());
} }
else if (type == SampleType_Float32) else if (mSampleType == SampleType_Float32)
{ {
value = *reinterpret_cast<const float*>(&data[sample*advance]); value = *reinterpret_cast<const float*>(&mQueue[sample*advance]);
value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already. value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already.
} }
@ -53,7 +54,7 @@ void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sample
++segment; ++segment;
} }
mReady = true; mQueue.erase(mQueue.begin(), mQueue.begin() + sample*advance);
} }

View file

@ -2,6 +2,7 @@
#define GAME_SOUND_LOUDNESS_H #define GAME_SOUND_LOUDNESS_H
#include <vector> #include <vector>
#include <deque>
#include "sound_decoder.hpp" #include "sound_decoder.hpp"
@ -9,29 +10,45 @@ namespace MWSound
{ {
class Sound_Loudness { class Sound_Loudness {
// Loudness sample info
float mSamplesPerSec; float mSamplesPerSec;
int mSampleRate;
ChannelConfig mChannelConfig;
SampleType mSampleType;
// Loudness sample info
std::vector<float> mSamples; std::vector<float> mSamples;
volatile bool mReady;
std::deque<char> mQueue;
public: public:
Sound_Loudness() : mSamplesPerSec(0.0f), mReady(false) { } /**
* @param samplesPerSecond How many loudness values per second of audio to compute.
* @param sampleRate the sample rate of the sound buffer
* @param chans channel layout of the buffer
* @param type sample type of the buffer
*/
Sound_Loudness(float samplesPerSecond, int sampleRate, ChannelConfig chans, SampleType type)
: mSamplesPerSec(samplesPerSecond)
, mSampleRate(sampleRate)
, mChannelConfig(chans)
, mSampleType(type)
{ }
/** /**
* Analyzes the energy (closely related to loudness) of a sound buffer. * Analyzes the energy (closely related to loudness) of a sound buffer.
* The buffer will be divided into segments according to \a valuesPerSecond, * The buffer will be divided into segments according to \a valuesPerSecond,
* and for each segment a loudness value in the range of [0,1] will be computed. * and for each segment a loudness value in the range of [0,1] will be computed.
* The computed values are then added to the mSamples vector. This method should be called continuously
* with chunks of audio until the whole audio file is processed.
* If the size of \a data does not exactly fit a number of loudness samples, the remainder
* will be kept in the mQueue and used in the next call to analyzeLoudness.
* @param data the sound buffer to analyze, containing raw samples * @param data the sound buffer to analyze, containing raw samples
* @param sampleRate the sample rate of the sound buffer
* @param chans channel layout of the buffer
* @param type sample type of the buffer
* @param valuesPerSecond How many loudness values per second of audio to compute.
*/ */
void analyzeLoudness(const std::vector<char>& data, int sampleRate, void analyzeLoudness(const std::vector<char>& data);
ChannelConfig chans, SampleType type,
float valuesPerSecond);
bool isReady() { return mReady; } /**
* Get loudness at a particular time. Before calling this, the stream has to be analyzed up to that point in time (see analyzeLoudness()).
*/
float getLoudnessAtTime(float sec) const; float getLoudnessAtTime(float sec) const;
}; };

View file

@ -27,7 +27,6 @@ namespace MWSound
virtual void open(const std::string &fname); virtual void open(const std::string &fname);
virtual void close(); virtual void close();
virtual void rewind();
virtual std::string getName(); virtual std::string getName();
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
@ -102,7 +101,6 @@ namespace MWSound
throw std::runtime_error("unimplemented"); throw std::runtime_error("unimplemented");
} }
void MWSoundDecoderBridge::close() {} void MWSoundDecoderBridge::close() {}
void MWSoundDecoderBridge::rewind() {}
std::string MWSoundDecoderBridge::getName() std::string MWSoundDecoderBridge::getName()
{ {

View file

@ -2,6 +2,7 @@
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <memory>
#include <stdint.h> #include <stdint.h>
@ -212,6 +213,8 @@ private:
DecoderPtr mDecoder; DecoderPtr mDecoder;
std::auto_ptr<Sound_Loudness> mLoudnessAnalyzer;
volatile bool mIsFinished; volatile bool mIsFinished;
void updateAll(bool local); void updateAll(bool local);
@ -222,13 +225,15 @@ private:
friend class OpenAL_Output; friend class OpenAL_Output;
public: public:
OpenAL_SoundStream(ALuint src, DecoderPtr decoder); OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData=false);
~OpenAL_SoundStream(); ~OpenAL_SoundStream();
bool isPlaying(); bool isPlaying();
double getStreamDelay() const; double getStreamDelay() const;
double getStreamOffset() const; double getStreamOffset() const;
float getCurrentLoudness() const;
bool process(); bool process();
ALint refillQueue(); ALint refillQueue();
}; };
@ -242,9 +247,6 @@ struct OpenAL_Output::StreamThread {
typedef std::vector<OpenAL_SoundStream*> StreamVec; typedef std::vector<OpenAL_SoundStream*> StreamVec;
StreamVec mStreams; StreamVec mStreams;
typedef std::vector<std::pair<DecoderPtr,Sound_Loudness*> > DecoderLoudnessVec;
DecoderLoudnessVec mDecoderLoudness;
volatile bool mQuitNow; volatile bool mQuitNow;
boost::mutex mMutex; boost::mutex mMutex;
boost::condition_variable mCondVar; boost::condition_variable mCondVar;
@ -277,32 +279,6 @@ struct OpenAL_Output::StreamThread {
++iter; ++iter;
} }
// Only do one loudness decode at a time, in case it takes particularly long we don't
// want to block up anything.
DecoderLoudnessVec::iterator dliter = mDecoderLoudness.begin();
if(dliter != mDecoderLoudness.end())
{
DecoderPtr decoder = dliter->first;
Sound_Loudness *loudness = dliter->second;
mDecoderLoudness.erase(dliter);
lock.unlock();
std::vector<char> data;
ChannelConfig chans = ChannelConfig_Mono;
SampleType type = SampleType_Int16;
int srate = 48000;
try {
decoder->getInfo(&srate, &chans, &type);
decoder->readAll(data);
}
catch(std::exception &e) {
std::cerr<< "Failed to decode audio: "<<e.what() <<std::endl;
}
loudness->analyzeLoudness(data, srate, chans, type, static_cast<float>(sLoudnessFPS));
lock.lock();
continue;
}
mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50));
} }
} }
@ -329,15 +305,6 @@ struct OpenAL_Output::StreamThread {
{ {
boost::lock_guard<boost::mutex> lock(mMutex); boost::lock_guard<boost::mutex> lock(mMutex);
mStreams.clear(); mStreams.clear();
mDecoderLoudness.clear();
}
void add(DecoderPtr decoder, Sound_Loudness *loudness)
{
boost::unique_lock<boost::mutex> lock(mMutex);
mDecoderLoudness.push_back(std::make_pair(decoder, loudness));
lock.unlock();
mCondVar.notify_all();
} }
private: private:
@ -346,7 +313,7 @@ private:
}; };
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData)
: mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false) : mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false)
{ {
alGenBuffers(sNumBuffers, mBuffers); alGenBuffers(sNumBuffers, mBuffers);
@ -371,6 +338,9 @@ OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
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;
if (getLoudnessData)
mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type));
} }
catch(std::exception&) catch(std::exception&)
{ {
@ -446,6 +416,15 @@ double OpenAL_SoundStream::getStreamOffset() const
return t; return t;
} }
float OpenAL_SoundStream::getCurrentLoudness() const
{
if (!mLoudnessAnalyzer.get())
return 0.f;
float time = getStreamOffset();
return mLoudnessAnalyzer->getLoudnessAtTime(time);
}
bool OpenAL_SoundStream::process() bool OpenAL_SoundStream::process()
{ {
try { try {
@ -493,6 +472,9 @@ ALint OpenAL_SoundStream::refillQueue()
} }
if(got > 0) if(got > 0)
{ {
if (mLoudnessAnalyzer.get())
mLoudnessAnalyzer->analyzeLoudness(data);
ALuint bufid = mBuffers[mCurrentBufIdx]; ALuint bufid = mBuffers[mCurrentBufIdx];
alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid); alSourceQueueBuffers(mSource, 1, &bufid);
@ -981,7 +963,7 @@ void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound
sound->mHandle = stream; sound->mHandle = stream;
} }
void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData)
{ {
OpenAL_SoundStream *stream = 0; OpenAL_SoundStream *stream = 0;
ALuint source; ALuint source;
@ -998,7 +980,7 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou
sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
throwALerror(); throwALerror();
stream = new OpenAL_SoundStream(source, decoder); stream = new OpenAL_SoundStream(source, decoder, getLoudnessData);
mStreamThread->add(stream); mStreamThread->add(stream);
mActiveStreams.push_back(sound); mActiveStreams.push_back(sound);
} }
@ -1045,6 +1027,14 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound)
return stream->getStreamOffset(); return stream->getStreamOffset();
} }
float OpenAL_Output::getStreamLoudness(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->getCurrentLoudness();
}
bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound)
{ {
if(!sound->mHandle) return false; if(!sound->mHandle) return false;
@ -1144,12 +1134,6 @@ void OpenAL_Output::resumeSounds(int types)
} }
void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness)
{
mStreamThread->add(decoder, loudness);
}
OpenAL_Output::OpenAL_Output(SoundManager &mgr) OpenAL_Output::OpenAL_Output(SoundManager &mgr)
: Sound_Output(mgr), mDevice(0), mContext(0) : Sound_Output(mgr), mDevice(0), mContext(0)
, mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal)

View file

@ -63,10 +63,11 @@ namespace MWSound
virtual void updateSound(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound);
virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound);
virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData);
virtual void finishStream(MWBase::SoundStreamPtr sound); virtual void finishStream(MWBase::SoundStreamPtr sound);
virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamDelay(MWBase::SoundStreamPtr sound);
virtual double getStreamOffset(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound);
virtual float getStreamLoudness(MWBase::SoundStreamPtr sound);
virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound);
virtual void updateStream(MWBase::SoundStreamPtr sound); virtual void updateStream(MWBase::SoundStreamPtr sound);
@ -78,8 +79,6 @@ namespace MWSound
virtual void pauseSounds(int types); virtual void pauseSounds(int types);
virtual void resumeSounds(int types); virtual void resumeSounds(int types);
virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness);
OpenAL_Output(SoundManager &mgr); OpenAL_Output(SoundManager &mgr);
virtual ~OpenAL_Output(); virtual ~OpenAL_Output();
}; };

View file

@ -3,11 +3,7 @@
#include <string> #include <string>
#include "soundmanagerimp.hpp"
#include "sound_output.hpp" #include "sound_output.hpp"
#include "loudness.hpp"
#include "../mwworld/ptr.hpp"
namespace MWSound namespace MWSound
{ {

View file

@ -42,7 +42,6 @@ namespace MWSound
virtual size_t read(char *buffer, size_t bytes) = 0; virtual size_t read(char *buffer, size_t bytes) = 0;
virtual void readAll(std::vector<char> &output); virtual void readAll(std::vector<char> &output);
virtual void rewind() = 0;
virtual size_t getSampleOffset() = 0; virtual size_t getSampleOffset() = 0;
Sound_Decoder(const VFS::Manager* resourceMgr) : mResourceMgr(resourceMgr) Sound_Decoder(const VFS::Manager* resourceMgr) : mResourceMgr(resourceMgr)

View file

@ -12,7 +12,6 @@ namespace MWSound
class SoundManager; class SoundManager;
struct Sound_Decoder; struct Sound_Decoder;
class Sound; class Sound;
class Sound_Loudness;
// 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;
@ -42,10 +41,11 @@ namespace MWSound
virtual void updateSound(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0;
virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0;
virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData) = 0;
virtual void finishStream(MWBase::SoundStreamPtr sound) = 0; virtual void finishStream(MWBase::SoundStreamPtr sound) = 0;
virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0;
virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0;
virtual float getStreamLoudness(MWBase::SoundStreamPtr sound) = 0;
virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0;
virtual void updateStream(MWBase::SoundStreamPtr sound) = 0; virtual void updateStream(MWBase::SoundStreamPtr sound) = 0;
@ -57,11 +57,6 @@ namespace MWSound
virtual void pauseSounds(int types) = 0; virtual void pauseSounds(int types) = 0;
virtual void resumeSounds(int types) = 0; virtual void resumeSounds(int types) = 0;
// HACK: The sound output implementation really shouldn't be handling
// asynchronous loudness data loading, but it's currently where we have
// a background processing thread.
virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness) = 0;
Sound_Output& operator=(const Sound_Output &rhs); Sound_Output& operator=(const Sound_Output &rhs);
Sound_Output(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs);

View file

@ -219,7 +219,7 @@ namespace MWSound
return sfx; return sfx;
} }
DecoderPtr SoundManager::loadVoice(const std::string &voicefile, Sound_Loudness **lipdata) DecoderPtr SoundManager::loadVoice(const std::string &voicefile)
{ {
DecoderPtr decoder = getDecoder(); DecoderPtr decoder = getDecoder();
// Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav.
@ -234,21 +234,6 @@ namespace MWSound
decoder->open(file); decoder->open(file);
} }
NameLoudnessRefMap::iterator lipiter = mVoiceLipNameMap.find(voicefile);
if(lipiter != mVoiceLipNameMap.end())
{
*lipdata = lipiter->second;
return decoder;
}
mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), Sound_Loudness());
lipiter = mVoiceLipNameMap.insert(
std::make_pair(voicefile, &mVoiceLipBuffers.back())
).first;
mOutput->loadLoudnessAsync(decoder, lipiter->second);
*lipdata = lipiter->second;
return decoder; return decoder;
} }
@ -273,7 +258,7 @@ namespace MWSound
{ {
sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
Play_Normal|Play_TypeVoice|Play_3D)); Play_Normal|Play_TypeVoice|Play_3D));
mOutput->streamSound3D(decoder, sound); mOutput->streamSound3D(decoder, sound, true);
} }
return sound; return sound;
} }
@ -400,28 +385,22 @@ namespace MWSound
{ {
std::string voicefile = "Sound/"+filename; std::string voicefile = "Sound/"+filename;
Sound_Loudness *loudness;
mVFS->normalizeFilename(voicefile); mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile, &loudness); DecoderPtr decoder = loadVoice(voicefile);
if(!loudness->isReady()) MWBase::World *world = MWBase::Environment::get().getWorld();
mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
else
SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr);
if (oldIt != mActiveSaySounds.end())
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); mOutput->finishStream(oldIt->second);
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); mActiveSaySounds.erase(oldIt);
SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr);
if (oldIt != mActiveSaySounds.end())
{
mOutput->finishStream(oldIt->second.first);
mActiveSaySounds.erase(oldIt);
}
MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness)));
} }
MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
mActiveSaySounds.insert(std::make_pair(ptr, sound));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -434,10 +413,8 @@ 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::SoundStreamPtr sound = snditer->second.first; MWBase::SoundStreamPtr sound = snditer->second;
Sound_Loudness *loudness = snditer->second.second; return mOutput->getStreamLoudness(sound);
float sec = mOutput->getStreamOffset(sound);
return loudness->getLoudnessAtTime(sec);
} }
return 0.0f; return 0.0f;
@ -451,24 +428,18 @@ namespace MWSound
{ {
std::string voicefile = "Sound/"+filename; std::string voicefile = "Sound/"+filename;
Sound_Loudness *loudness;
mVFS->normalizeFilename(voicefile); mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile, &loudness); DecoderPtr decoder = loadVoice(voicefile);
if(!loudness->isReady()) SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr());
mPendingSaySounds[MWWorld::ConstPtr()] = std::make_pair(decoder, loudness); if (oldIt != mActiveSaySounds.end())
else
{ {
SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr()); mOutput->finishStream(oldIt->second);
if (oldIt != mActiveSaySounds.end()) mActiveSaySounds.erase(oldIt);
{
mOutput->finishStream(oldIt->second.first);
mActiveSaySounds.erase(oldIt);
}
mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(),
std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness)));
} }
mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(),
playVoice(decoder, osg::Vec3f(), true)));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -481,11 +452,11 @@ 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(mOutput->isStreamPlaying(snditer->second.first)) if(mOutput->isStreamPlaying(snditer->second))
return false; return false;
return true; return true;
} }
return mPendingSaySounds.find(ptr) == mPendingSaySounds.end(); return true;
} }
void SoundManager::stopSay(const MWWorld::ConstPtr &ptr) void SoundManager::stopSay(const MWWorld::ConstPtr &ptr)
@ -493,10 +464,9 @@ namespace MWSound
SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end()) if(snditer != mActiveSaySounds.end())
{ {
mOutput->finishStream(snditer->second.first); mOutput->finishStream(snditer->second);
mActiveSaySounds.erase(snditer); mActiveSaySounds.erase(snditer);
} }
mPendingSaySounds.erase(ptr);
} }
@ -691,7 +661,7 @@ namespace MWSound
sayiter->first != MWMechanics::getPlayer() && sayiter->first != MWMechanics::getPlayer() &&
sayiter->first.getCell() == cell) sayiter->first.getCell() == cell)
{ {
mOutput->finishStream(sayiter->second.first); mOutput->finishStream(sayiter->second);
} }
++sayiter; ++sayiter;
} }
@ -901,51 +871,11 @@ namespace MWSound
++snditer; ++snditer;
} }
SayDecoderMap::iterator penditer = mPendingSaySounds.begin();
while(penditer != mPendingSaySounds.end())
{
Sound_Loudness *loudness = penditer->second.second;
if(loudness->isReady())
{
try {
DecoderPtr decoder = penditer->second.first;
decoder->rewind();
MWBase::SoundStreamPtr sound;
MWWorld::ConstPtr ptr = penditer->first;
SaySoundMap::iterator old = mActiveSaySounds.find(ptr);
if (old != mActiveSaySounds.end())
{
mOutput->finishStream(old->second.first);
mActiveSaySounds.erase(old);
}
if(ptr == MWWorld::ConstPtr())
sound = playVoice(decoder, osg::Vec3f(), true);
else
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
}
mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness)));
}
catch(std::exception &e) {
std::cerr<< "Sound Error: "<<e.what() <<std::endl;
}
mPendingSaySounds.erase(penditer++);
}
else
++penditer;
}
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
while(sayiter != mActiveSaySounds.end()) while(sayiter != mActiveSaySounds.end())
{ {
MWWorld::ConstPtr ptr = sayiter->first; MWWorld::ConstPtr ptr = sayiter->first;
MWBase::SoundStreamPtr sound = sayiter->second.first; MWBase::SoundStreamPtr sound = sayiter->second;
if(!ptr.isEmpty() && sound->getIs3D()) if(!ptr.isEmpty() && sound->getIs3D())
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -1040,7 +970,7 @@ namespace MWSound
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter) for(;sayiter != mActiveSaySounds.end();++sayiter)
{ {
MWBase::SoundStreamPtr sound = sayiter->second.first; MWBase::SoundStreamPtr sound = sayiter->second;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound); mOutput->updateStream(sound);
} }
@ -1080,16 +1010,9 @@ namespace MWSound
SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); SaySoundMap::iterator sayiter = mActiveSaySounds.find(old);
if(sayiter != mActiveSaySounds.end()) if(sayiter != mActiveSaySounds.end())
{ {
SoundLoudnessPair sndlist = sayiter->second; MWBase::SoundStreamPtr stream = sayiter->second;
mActiveSaySounds.erase(sayiter); mActiveSaySounds.erase(sayiter);
mActiveSaySounds[updated] = sndlist; mActiveSaySounds[updated] = stream;
}
SayDecoderMap::iterator penditer = mPendingSaySounds.find(old);
if(penditer != mPendingSaySounds.end())
{
DecoderLoudnessPair dl = penditer->second;
mPendingSaySounds.erase(penditer);
mPendingSaySounds[updated] = dl;
} }
} }
@ -1175,13 +1098,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)
mOutput->finishStream(sayiter->second.first); mOutput->finishStream(sayiter->second);
mActiveSaySounds.clear(); mActiveSaySounds.clear();
TrackList::iterator trkiter = mActiveTracks.begin(); TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter) for(;trkiter != mActiveTracks.end();++trkiter)
mOutput->finishStream(*trkiter); mOutput->finishStream(*trkiter);
mActiveTracks.clear(); mActiveTracks.clear();
mPendingSaySounds.clear();
mUnderwaterSound.reset(); mUnderwaterSound.reset();
stopMusic(); stopMusic();
} }

View file

@ -11,7 +11,6 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "loudness.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
namespace VFS namespace VFS
@ -69,12 +68,6 @@ namespace MWSound
typedef std::map<std::string,Sound_Buffer*> NameBufferMap; typedef std::map<std::string,Sound_Buffer*> NameBufferMap;
NameBufferMap mBufferNameMap; NameBufferMap mBufferNameMap;
typedef std::deque<Sound_Loudness> LoudnessList;
LoudnessList mVoiceLipBuffers;
typedef std::map<std::string,Sound_Loudness*> NameLoudnessRefMap;
NameLoudnessRefMap mVoiceLipNameMap;
// NOTE: unused buffers are stored in front-newest order. // NOTE: unused buffers are stored in front-newest order.
typedef std::deque<Sound_Buffer*> SoundList; typedef std::deque<Sound_Buffer*> SoundList;
SoundList mUnusedBuffers; SoundList mUnusedBuffers;
@ -84,14 +77,9 @@ namespace MWSound
typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap; typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap;
SoundMap mActiveSounds; SoundMap mActiveSounds;
typedef std::pair<MWBase::SoundStreamPtr,Sound_Loudness*> SoundLoudnessPair; typedef std::map<MWWorld::ConstPtr,MWBase::SoundStreamPtr> SaySoundMap;
typedef std::map<MWWorld::ConstPtr,SoundLoudnessPair> SaySoundMap;
SaySoundMap mActiveSaySounds; SaySoundMap mActiveSaySounds;
typedef std::pair<DecoderPtr,Sound_Loudness*> DecoderLoudnessPair;
typedef std::map<MWWorld::ConstPtr,DecoderLoudnessPair> SayDecoderMap;
SayDecoderMap mPendingSaySounds;
typedef std::vector<MWBase::SoundStreamPtr> TrackList; typedef std::vector<MWBase::SoundStreamPtr> TrackList;
TrackList mActiveTracks; TrackList mActiveTracks;
@ -112,9 +100,8 @@ namespace MWSound
Sound_Buffer *lookupSound(const std::string &soundId) const; Sound_Buffer *lookupSound(const std::string &soundId) const;
Sound_Buffer *loadSound(const std::string &soundId); Sound_Buffer *loadSound(const std::string &soundId);
// Ensures the loudness/"lip" data gets loaded, and returns a decoder // returns a decoder to start streaming
// to start streaming DecoderPtr loadVoice(const std::string &voicefile);
DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata);
MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal);