Don't be so throw-happy in the sound manager

experimental
Chris Robinson 7 years ago
parent abe80f5868
commit c17edfd547

@ -39,6 +39,26 @@ const float UnitsPerMeter = 69.99125109f;
const int sLoudnessFPS = 20; // loudness values per second of audio
ALCenum checkALCError(ALCdevice *device, const char *func, int line)
{
ALCenum err = alcGetError(device);
if(err != ALC_NO_ERROR)
std::cerr<< ">>>>>>>>> ALC error "<<alcGetString(device, err)<<" ("<<err<<") @ "<<
func<<":"<<line <<std::endl;
return err;
}
#define getALCError(d) checkALCError((d), __FUNCTION__, __LINE__)
ALenum checkALError(const char *func, int line)
{
ALenum err = alGetError();
if(err != AL_NO_ERROR)
std::cerr<< ">>>>>>>>> AL error "<<alGetString(err)<<" ("<<err<<") @ "<<
func<<":"<<line <<std::endl;
return err;
}
#define getALError() checkALError(__FUNCTION__, __LINE__)
// Helper to get an OpenAL extension function
template<typename T, typename R>
void convertPointer(T& dest, R src)
@ -144,7 +164,7 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props)
alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor);
alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE);
}
alGetError();
getALError();
}
}
@ -152,30 +172,6 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props)
namespace MWSound
{
static void fail(const std::string &msg)
{ throw std::runtime_error("OpenAL exception: " + msg); }
static void throwALCerror(ALCdevice *device)
{
ALCenum err = alcGetError(device);
if(err != ALC_NO_ERROR)
{
const ALCchar *errstring = alcGetString(device, err);
fail(errstring ? errstring : "");
}
}
static void throwALerror()
{
ALenum err = alGetError();
if(err != AL_NO_ERROR)
{
const ALchar *errstring = alGetString(err);
fail(errstring ? errstring : "");
}
}
static ALenum getALFormat(ChannelConfig chans, SampleType type)
{
static const struct {
@ -268,7 +264,8 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
}
}
fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")");
std::cerr<< "Unsupported sound format ("<<getChannelConfigName(chans)<<", "<<
getSampleTypeName(type)<<")" <<std::endl;
return AL_NONE;
}
@ -307,9 +304,11 @@ private:
friend class OpenAL_Output;
public:
OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData=false);
OpenAL_SoundStream(ALuint src, DecoderPtr decoder);
~OpenAL_SoundStream();
bool init(bool getLoudnessData=false);
bool isPlaying();
double getStreamDelay() const;
double getStreamOffset() const;
@ -394,49 +393,52 @@ private:
};
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData)
: mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false)
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
: mSource(src), mBuffers{0}, mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0)
, mBufferSize(0), mFrameSize(0), mSilence(0), mDecoder(std::move(decoder))
, mLoudnessAnalyzer(nullptr)
{
alGenBuffers(sNumBuffers, mBuffers);
throwALerror();
try
{
int srate;
ChannelConfig chans;
SampleType type;
}
mDecoder->getInfo(&srate, &chans, &type);
mFormat = getALFormat(chans, type);
mSampleRate = srate;
OpenAL_SoundStream::~OpenAL_SoundStream()
{
if(mBuffers[0] && alIsBuffer(mBuffers[0]))
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
switch(type)
{
case SampleType_UInt8: mSilence = 0x80; break;
case SampleType_Int16: mSilence = 0x00; break;
case SampleType_Float32: mSilence = 0x00; break;
}
mDecoder->close();
}
bool OpenAL_SoundStream::init(bool getLoudnessData)
{
alGenBuffers(sNumBuffers, mBuffers);
ALenum err = getALError();
if(err != AL_NO_ERROR)
return false;
mFrameSize = framesToBytes(1, chans, type);
mBufferSize = static_cast<ALuint>(sBufferLength*srate);
mBufferSize *= mFrameSize;
ChannelConfig chans;
SampleType type;
if (getLoudnessData)
mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type));
}
catch(std::exception&)
mDecoder->getInfo(&mSampleRate, &chans, &type);
mFormat = getALFormat(chans, type);
if(!mFormat) return false;
switch(type)
{
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
throw;
case SampleType_UInt8: mSilence = 0x80; break;
case SampleType_Int16: mSilence = 0x00; break;
case SampleType_Float32: mSilence = 0x00; break;
}
mIsFinished = false;
}
OpenAL_SoundStream::~OpenAL_SoundStream()
{
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
mDecoder->close();
mFrameSize = framesToBytes(1, chans, type);
mBufferSize = static_cast<ALuint>(sBufferLength*mSampleRate);
mBufferSize *= mFrameSize;
if (getLoudnessData)
mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type));
mIsFinished = false;
return true;
}
bool OpenAL_SoundStream::isPlaying()
@ -444,7 +446,7 @@ bool OpenAL_SoundStream::isPlaying()
ALint state;
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
throwALerror();
getALError();
if(state == AL_PLAYING || state == AL_PAUSED)
return true;
@ -467,7 +469,7 @@ double OpenAL_SoundStream::getStreamDelay() const
d = (double)inqueue / (double)mSampleRate;
}
throwALerror();
getALError();
return d;
}
@ -493,7 +495,7 @@ double OpenAL_SoundStream::getStreamOffset() const
t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
}
throwALerror();
getALError();
return t;
}
@ -590,7 +592,7 @@ std::vector<std::string> OpenAL_Output::enumerate()
return devlist;
}
void OpenAL_Output::init(const std::string &devname)
bool OpenAL_Output::init(const std::string &devname)
{
deinit();
@ -598,9 +600,10 @@ void OpenAL_Output::init(const std::string &devname)
if(!mDevice)
{
if(devname.empty())
fail("Failed to open default device");
std::cerr<< "Failed to open default audio device" <<std::endl;
else
fail("Failed to open \""+devname+"\"");
std::cerr<< "Failed to open \""<<devname<<"\"" <<std::endl;
return false;
}
else
{
@ -615,42 +618,49 @@ void OpenAL_Output::init(const std::string &devname)
mContext = alcCreateContext(mDevice, NULL);
if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE)
{
std::cerr<< "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice)) <<std::endl;
if(mContext)
alcDestroyContext(mContext);
mContext = 0;
fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice)));
mContext = nullptr;
alcCloseDevice(mDevice);
mDevice = nullptr;
return false;
}
ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize");
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
throwALerror();
ALCint maxmono=0, maxstereo=0;
ALCuint maxtotal;
ALCint maxmono = 0, maxstereo = 0;
alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &maxmono);
alcGetIntegerv(mDevice, ALC_STEREO_SOURCES, 1, &maxstereo);
throwALCerror(mDevice);
try
if(getALCError(mDevice) != ALC_NO_ERROR)
maxtotal = 256;
else
{
ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
if (maxtotal == 0) // workaround for broken implementations
maxtotal = 256;
for(size_t i = 0;i < maxtotal;i++)
{
ALuint src = 0;
alGenSources(1, &src);
throwALerror();
mFreeSources.push_back(src);
}
}
catch(std::exception &e)
for(size_t i = 0;i < maxtotal;i++)
{
std::cout <<"Error: "<<e.what()<<", trying to continue"<< std::endl;
ALuint src = 0;
alGenSources(1, &src);
if(getALError() != AL_NO_ERROR)
break;
mFreeSources.push_back(src);
}
if(mFreeSources.empty())
fail("Could not allocate any sources");
{
std::cerr<< "Could not allocate any sound sources" <<std::endl;
alcMakeContextCurrent(nullptr);
alcDestroyContext(mContext);
mContext = nullptr;
alcCloseDevice(mDevice);
mDevice = nullptr;
return false;
}
std::cout<< "Allocated "<<mFreeSources.size()<<" sound sources" <<std::endl;
if(ALC.EXT_EFX)
{
@ -689,7 +699,11 @@ void OpenAL_Output::init(const std::string &devname)
LOAD_FUNC(alGetAuxiliaryEffectSlotf);
LOAD_FUNC(alGetAuxiliaryEffectSlotfv);
#undef LOAD_FUNC
throwALerror();
if(getALError() != AL_NO_ERROR)
{
ALC.EXT_EFX = false;
goto skip_efx;
}
alGenFilters(1, &mWaterFilter);
if(alGetError() == AL_NO_ERROR)
@ -743,12 +757,15 @@ void OpenAL_Output::init(const std::string &devname)
alListenerf(AL_METERS_PER_UNIT, 1.0f / UnitsPerMeter);
}
skip_efx:
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
// Speed of sound is in units per second. Given the default speed of sound is 343.3 (assumed
// meters per second), multiply by the units per meter to get the speed in u/s.
alSpeedOfSound(343.3f * UnitsPerMeter);
alGetError();
mInitialized = true;
return true;
}
void OpenAL_Output::deinit()
@ -786,11 +803,9 @@ void OpenAL_Output::deinit()
std::vector<std::string> OpenAL_Output::enumerateHrtf()
{
if(!mDevice)
fail("Device not initialized");
std::vector<std::string> ret;
if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"))
if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"))
return ret;
LPALCGETSTRINGISOFT alcGetStringiSOFT = 0;
@ -816,7 +831,6 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable)
return;
}
LPALCGETSTRINGISOFT alcGetStringiSOFT = 0;
getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT");
@ -891,7 +905,7 @@ void OpenAL_Output::disableHrtf()
Sound_Handle OpenAL_Output::loadSound(const std::string &fname)
{
throwALerror();
getALError();
DecoderPtr decoder = mManager.getDecoder();
// Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav.
@ -914,20 +928,20 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname)
decoder->getInfo(&srate, &chans, &type);
format = getALFormat(chans, type);
if(!format) return nullptr;
decoder->readAll(data);
decoder->close();
ALuint buf = 0;
try {
alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], data.size(), srate);
throwALerror();
}
catch(...) {
alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], data.size(), srate);
if(getALError() != AL_NO_ERROR)
{
if(buf && alIsBuffer(buf))
alDeleteBuffers(1, &buf);
throw;
getALError();
return nullptr;
}
return MAKE_PTRID(buf);
}
@ -952,6 +966,7 @@ void OpenAL_Output::unloadSound(Sound_Handle data)
}
}
alDeleteBuffers(1, &buffer);
getALError();
}
size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const
@ -960,7 +975,7 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const
ALint size = 0;
alGetBufferi(buffer, AL_SIZE, &size);
throwALerror();
getALError();
return (ALuint)size;
}
@ -1067,65 +1082,63 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m
}
void OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset)
bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset)
{
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
{
std::cerr<< "No free sources!" <<std::endl;
return false;
}
source = mFreeSources.front();
mFreeSources.pop_front();
try {
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();
initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
sound->getIsLooping(), sound->getUseEnv());
alSourcef(source, AL_SEC_OFFSET, offset);
if(getALError() != AL_NO_ERROR)
return false;
mActiveSounds.push_back(sound);
}
catch(std::exception&) {
mFreeSources.push_back(source);
throw;
}
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
if(getALError() != AL_NO_ERROR)
return false;
mFreeSources.pop_front();
sound->mHandle = MAKE_PTRID(source);
mActiveSounds.push_back(sound);
return true;
}
void OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset)
bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset)
{
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
{
std::cerr<< "No free sources!" <<std::endl;
return false;
}
source = mFreeSources.front();
mFreeSources.pop_front();
try {
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(),
sound->getUseEnv());
alSourcef(source, AL_SEC_OFFSET, offset);
throwALerror();
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(),
sound->getUseEnv());
alSourcef(source, AL_SEC_OFFSET, offset);
if(getALError() != AL_NO_ERROR)
return false;
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
throwALerror();
mActiveSounds.push_back(sound);
}
catch(std::exception&) {
mFreeSources.push_back(source);
throw;
}
alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcePlay(source);
if(getALError() != AL_NO_ERROR)
return false;
mFreeSources.pop_front();
sound->mHandle = MAKE_PTRID(source);
mActiveSounds.push_back(sound);
return true;
}
void OpenAL_Output::finishSound(Sound *sound)
@ -1139,6 +1152,7 @@ void OpenAL_Output::finishSound(Sound *sound)
// the initial queue already played when it hasn't.
alSourceRewind(source);
alSourcei(source, AL_BUFFER, 0);
getALError();
mFreeSources.push_back(source);
mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound));
@ -1148,10 +1162,10 @@ bool OpenAL_Output::isSoundPlaying(Sound *sound)
{
if(!sound->mHandle) return false;
ALuint source = GET_PTRID(sound->mHandle);
ALint state;
ALint state = AL_STOPPED;
alGetSourcei(source, AL_SOURCE_STATE, &state);
throwALerror();
getALError();
return state == AL_PLAYING || state == AL_PAUSED;
}
@ -1163,69 +1177,68 @@ void OpenAL_Output::updateSound(Sound *sound)
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
getALError();
}
void OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound)
bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound)
{
OpenAL_SoundStream *stream = 0;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
source = mFreeSources.front();
mFreeSources.pop_front();
{
std::cerr<< "No free sources!" <<std::endl;
return false;
}
ALuint source = mFreeSources.front();
if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try {
initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
false, sound->getUseEnv());
throwALerror();
initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
false, sound->getUseEnv());
if(getALError() != AL_NO_ERROR)
return false;
stream = new OpenAL_SoundStream(source, decoder);
mStreamThread->add(stream);
mActiveStreams.push_back(sound);
}
catch(std::exception&) {
mStreamThread->remove(stream);
OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder));
if(!stream->init())
{
delete stream;
mFreeSources.push_back(source);
throw;
return false;
}
mStreamThread->add(stream);
mFreeSources.pop_front();
sound->mHandle = stream;
mActiveStreams.push_back(sound);
return true;
}
void OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData)
bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData)
{
OpenAL_SoundStream *stream = 0;
ALuint source;
if(mFreeSources.empty())
fail("No free sources");
source = mFreeSources.front();
mFreeSources.pop_front();
{
std::cerr<< "No free sources!" <<std::endl;
return false;
}
ALuint source = mFreeSources.front();
if(sound->getIsLooping())
std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
try {
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
throwALerror();
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
if(getALError() != AL_NO_ERROR)
return false;
stream = new OpenAL_SoundStream(source, decoder, getLoudnessData);
mStreamThread->add(stream);
mActiveStreams.push_back(sound);
}
catch(std::exception&) {
mStreamThread->remove(stream);
OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder));
if(!stream->init(getLoudnessData))
{
delete stream;
mFreeSources.push_back(source);
throw;
return false;
}
mStreamThread->add(stream);
mFreeSources.pop_front();
sound->mHandle = stream;
mActiveStreams.push_back(sound);
return true;
}
void OpenAL_Output::finishStream(Stream *sound)
@ -1242,6 +1255,7 @@ void OpenAL_Output::finishStream(Stream *sound)
// the initial queue already played when it hasn't.
alSourceRewind(source);
alSourcei(source, AL_BUFFER, 0);
getALError();
mFreeSources.push_back(source);
mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound));
@ -1288,6 +1302,7 @@ void OpenAL_Output::updateStream(Stream *sound)
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
getALError();
}
@ -1346,7 +1361,7 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi
(env == Env_Underwater) ? mWaterEffect : mDefaultEffect
);
}
throwALerror();
getALError();
}
mListenerPos = pos;
@ -1374,8 +1389,8 @@ void OpenAL_Output::pauseSounds(int types)
}
if(!sources.empty())
{
alSourcePausev(sources.size(), &sources[0]);
throwALerror();
alSourcePausev(sources.size(), sources.data());
getALError();
}
}
@ -1399,8 +1414,8 @@ void OpenAL_Output::resumeSounds(int types)
}
if(!sources.empty())
{
alSourcePlayv(sources.size(), &sources[0]);
throwALerror();
alSourcePlayv(sources.size(), sources.data());
getALError();
}
}

@ -59,7 +59,7 @@ namespace MWSound
public:
virtual std::vector<std::string> enumerate();
virtual void init(const std::string &devname=std::string());
virtual bool init(const std::string &devname=std::string());
virtual void deinit();
virtual std::vector<std::string> enumerateHrtf();
@ -70,14 +70,14 @@ namespace MWSound
virtual void unloadSound(Sound_Handle data);
virtual size_t getSoundDataSize(Sound_Handle data) const;
virtual void playSound(Sound *sound, Sound_Handle data, float offset);
virtual void playSound3D(Sound *sound, Sound_Handle data, float offset);
virtual bool playSound(Sound *sound, Sound_Handle data, float offset);
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset);
virtual void finishSound(Sound *sound);
virtual bool isSoundPlaying(Sound *sound);
virtual void updateSound(Sound *sound);
virtual void streamSound(DecoderPtr decoder, Stream *sound);
virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData);
virtual bool streamSound(DecoderPtr decoder, Stream *sound);
virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData);
virtual void finishStream(Stream *sound);
virtual double getStreamDelay(Stream *sound);
virtual double getStreamOffset(Stream *sound);

@ -24,7 +24,7 @@ namespace MWSound
SoundManager &mManager;
virtual std::vector<std::string> enumerate() = 0;
virtual void init(const std::string &devname=std::string()) = 0;
virtual bool init(const std::string &devname=std::string()) = 0;
virtual void deinit() = 0;
virtual std::vector<std::string> enumerateHrtf() = 0;
@ -35,14 +35,14 @@ namespace MWSound
virtual void unloadSound(Sound_Handle data) = 0;
virtual size_t getSoundDataSize(Sound_Handle data) const = 0;
virtual void playSound(Sound *sound, Sound_Handle data, float offset) = 0;
virtual void playSound3D(Sound *sound, Sound_Handle data, float offset) = 0;
virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0;
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0;
virtual void finishSound(Sound *sound) = 0;
virtual bool isSoundPlaying(Sound *sound) = 0;
virtual void updateSound(Sound *sound) = 0;
virtual void streamSound(DecoderPtr decoder, Stream *sound) = 0;
virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0;
virtual bool streamSound(DecoderPtr decoder, Stream *sound) = 0;
virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0;
virtual void finishStream(Stream *sound) = 0;
virtual double getStreamDelay(Stream *sound) = 0;
virtual double getStreamOffset(Stream *sound) = 0;

@ -89,40 +89,42 @@ namespace MWSound
std::cout << "Sound output: " << SOUND_OUT << std::endl;
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
try {
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:"<< std::endl;
for(size_t i = 0;i < names.size();i++)
std::cout <<" "<<names[i]<< std::endl;
std::string devname = Settings::Manager::getString("device", "Sound");
try {
mOutput->init(devname);
}
catch(std::exception &e) {
if(devname.empty())
throw;
std::cerr <<"Failed to open device \""<<devname<<"\": " << e.what() << std::endl;
mOutput->init();
Settings::Manager::setString("device", "Sound", "");
}
names = mOutput->enumerateHrtf();
if(!names.empty())
{
std::cout <<"Enumerated HRTF names:"<< std::endl;
for(size_t i = 0;i < names.size();i++)
std::cout <<" "<<names[i]<< std::endl;
}
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
std::for_each(names.cbegin(), names.cend(),
[](const std::string &name) -> void
{ std::cout <<" "<<name<<"\n"; }
);
std::cout.flush();
if(hrtfstate == 0)
mOutput->disableHrtf();
else if(!hrtfname.empty())
mOutput->enableHrtf(hrtfname, hrtfstate<0);
std::string devname = Settings::Manager::getString("device", "Sound");
bool inited = mOutput->init(devname);
if(!inited && !devname.empty())
{
std::cerr<< "Failed to initialize device \""<<devname<<"\", trying default" <<std::endl;
inited = mOutput->init();
}
catch(std::exception &e) {
std::cout <<"Sound init failed: "<<e.what()<< std::endl;
if(!inited)
{
std::cerr<< "Failed to initialize default audio device, sound disabled" <<std::endl;
return;
}
names = mOutput->enumerateHrtf();
if(!names.empty())
{
std::cout<< "Enumerated HRTF names:\n";
std::for_each(names.cbegin(), names.cend(),
[](const std::string &name) -> void
{ std::cout<< " "<<name<<"\n"; }
);
std::cout.flush();
}
if(hrtfstate == 0)
mOutput->disableHrtf();
else if(!hrtfname.empty())
mOutput->enableHrtf(hrtfname, hrtfstate<0);
}
SoundManager::~SoundManager()
@ -186,8 +188,12 @@ namespace MWSound
Sound_Buffer *SoundManager::lookupSound(const std::string &soundId) const
{
NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId);
if(snd != mBufferNameMap.end()) return snd->second;
return 0;
if(snd != mBufferNameMap.end())
{
Sound_Buffer *sfx = snd->second;
if(sfx->mHandle) return sfx;
}
return nullptr;
}
// Lookup a soundId for its sound data (resource name, local volume,
@ -201,15 +207,17 @@ namespace MWSound
else
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const ESM::Sound *sound = world->getStore().get<ESM::Sound>().find(soundId);
const ESM::Sound *sound = world->getStore().get<ESM::Sound>().search(soundId);
if(!sound) return nullptr;
sfx = insertSound(soundId, sound);
}
if(!sfx->mHandle)
{
sfx->mHandle = mOutput->loadSound(sfx->mResourceName);
mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle);
if(!sfx->mHandle) return nullptr;
mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle);
if(mBufferCacheSize > mBufferCacheMax)
{
do {
@ -293,18 +301,24 @@ namespace MWSound
static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f);
static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance);
bool played;
float basevol = volumeFromType(Play_TypeVoice);
Stream *sound = getStreamRef();
if(playlocal)
{
sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D);
mOutput->streamSound(decoder, sound);
played = mOutput->streamSound(decoder, sound);
}
else
{
sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
Play_Normal|Play_TypeVoice|Play_3D);
mOutput->streamSound3D(decoder, sound, true);
played = mOutput->streamSound3D(decoder, sound, true);
}
if(!played)
{
mUnusedStreams.push_back(sound);
return nullptr;
}
return sound;
}
@ -351,23 +365,16 @@ namespace MWSound
return;
std::cout <<"Playing "<<filename<< std::endl;
mLastPlayedMusic = filename;
try {
stopMusic();
DecoderPtr decoder = getDecoder();
decoder->open(filename);
stopMusic();
mMusic = getStreamRef();
mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f,
Play_NoEnv|Play_TypeMusic|Play_2D);
mOutput->streamSound(decoder, mMusic);
}
catch(std::exception &e) {
std::cout << "Music Error: " << e.what() << "\n";
if(mMusic)
mUnusedStreams.push_back(mMusic);
mMusic = nullptr;
}
DecoderPtr decoder = getDecoder();
decoder->open(filename);
mMusic = getStreamRef();
mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f,
Play_NoEnv|Play_TypeMusic|Play_2D);
mOutput->streamSound(decoder, mMusic);
}
void SoundManager::advanceMusic(const std::string& filename)
@ -454,24 +461,20 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return;
try
{
std::string voicefile = "Sound/"+filename;
mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile);
std::string voicefile = "Sound/"+filename;
MWBase::World *world = MWBase::Environment::get().getWorld();
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile);
stopSay(ptr);
Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
mActiveSaySounds.insert(std::make_pair(ptr, sound));
}
catch(std::exception &e)
{
std::cout <<"Sound Error: "<<e.what()<< std::endl;
}
MWBase::World *world = MWBase::Environment::get().getWorld();
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
stopSay(ptr);
Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
if(!sound) return;
mActiveSaySounds.insert(std::make_pair(ptr, sound));
}
float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const
@ -490,21 +493,17 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return;
try
{
std::string voicefile = "Sound/"+filename;
mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile);
std::string voicefile = "Sound/"+filename;
stopSay(MWWorld::ConstPtr());
mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(),
playVoice(decoder, osg::Vec3f(), true)));
}
catch(std::exception &e)
{
std::cout <<"Sound Error: "<<e.what()<< std::endl;
}
mVFS->normalizeFilename(voicefile);
DecoderPtr decoder = loadVoice(voicefile);
stopSay(MWWorld::ConstPtr());
Stream *sound = playVoice(decoder, osg::Vec3f(), true);
if(!sound) return;
mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), sound));
}
bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const
@ -535,22 +534,18 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return nullptr;
Stream *track = getStreamRef();
try
{
track->init(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)
Stream *track = getStreamRef();
track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D);
if(!mOutput->streamSound(decoder, track))
{
std::cout <<"Sound Error: "<<e.what()<< std::endl;
if(track)
mUnusedStreams.push_back(track);
track = nullptr;
mUnusedStreams.push_back(track);
return nullptr;
}
mActiveTracks.insert(
std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track), track
);
return track;
}
@ -573,30 +568,25 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return nullptr;
Sound *sound = nullptr;
try
{
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
float basevol = volumeFromType(type);
sound = getSoundRef();
sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D);
mOutput->playSound(sound, sfx->mHandle, offset);
if(sfx->mUses++ == 0)
{
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
Sound *sound = getSoundRef();
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
if(!mOutput->playSound(sound, sfx->mHandle, offset))
{
mUnusedSounds.push_back(sound);
return nullptr;
}
catch(std::exception&)
if(sfx->mUses++ == 0)
{
//std::cout <<"Sound Error: "<<e.what()<< std::endl;
if(sound)
mUnusedSounds.push_back(sound);
sound = nullptr;
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
return sound;
}
@ -606,48 +596,44 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return nullptr;
Sound *sound = nullptr;
try
{
// Look up the sound in the ESM data
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
float basevol = volumeFromType(type);
const ESM::Position &pos = ptr.getRefData().getPosition();
const osg::Vec3f objpos(pos.asVec3());
if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000)
return nullptr;
// Look up the sound in the ESM data
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
// Only one copy of given sound can be played at time on ptr, so stop previous copy
stopSound3D(ptr, soundId);
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000)
return nullptr;
sound = getSoundRef();
if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer())
{
sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D);
mOutput->playSound(sound, sfx->mHandle, offset);
}
else
{
sound->init(objpos, volume * sfx->mVolume, basevol, pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
mOutput->playSound3D(sound, sfx->mHandle, offset);
}
if(sfx->mUses++ == 0)
{
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[ptr].push_back(std::make_pair(sound, sfx));
// Only one copy of given sound can be played at time on ptr, so stop previous copy
stopSound3D(ptr, soundId);
bool played;
Sound *sound = getSoundRef();
if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer())
{
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
played = mOutput->playSound(sound, sfx->mHandle, offset);
}
catch(std::exception&)
else
{
//std::cout <<"Sound Error: "<<e.what()<< std::endl;
if(sound)
mUnusedSounds.push_back(sound);
sound = nullptr;
sound->init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
played = mOutput->playSound3D(sound, sfx->mHandle, offset);
}
if(!played)
{
mUnusedSounds.push_back(sound);
return nullptr;
}
if(sfx->mUses++ == 0)
{
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[ptr].push_back(std::make_pair(sound, sfx));
return sound;
}
@ -657,32 +643,27 @@ namespace MWSound
{
if(!mOutput->isInitialized())
return nullptr;
Sound *sound = nullptr;
try
{
// Look up the sound in the ESM data
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
float basevol = volumeFromType(type);
sound = getSoundRef();
sound->init(initialPos, volume * sfx->mVolume, basevol, pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
mOutput->playSound3D(sound, sfx->mHandle, offset);
if(sfx->mUses++ == 0)
{
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
// Look up the sound in the ESM data
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
Sound *sound = getSoundRef();
sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
if(!mOutput->playSound3D(sound, sfx->mHandle, offset))
{
mUnusedSounds.push_back(sound);
return nullptr;
}
catch(std::exception &)
if(sfx->mUses++ == 0)
{
//std::cout <<"Sound Error: "<<e.what()<< std::endl;
if(sound)
mUnusedSounds.push_back(sound);
sound = nullptr;
SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx);
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
return sound;
}

Loading…
Cancel
Save