diff options
Diffstat (limited to 'indra/llaudio/llaudioengine_openal.cpp')
-rw-r--r-- | indra/llaudio/llaudioengine_openal.cpp | 1120 |
1 files changed, 560 insertions, 560 deletions
diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index 4a17b12532..9e62e9bfec 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -1,560 +1,560 @@ -/** - * @file audioengine_openal.cpp - * @brief implementation of audio engine using OpenAL - * support as a OpenAL 3D implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "lldir.h" - -#include "llaudioengine_openal.h" -#include "lllistener_openal.h" - - -const float LLAudioEngine_OpenAL::WIND_BUFFER_SIZE_SEC = 0.05f; - -LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() - : - mWindGen(NULL), - mWindBuf(NULL), - mWindBufFreq(0), - mWindBufSamples(0), - mWindBufBytes(0), - mWindSource(AL_NONE), - mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) -{ -} - -// virtual -LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() -{ -} - -// virtual -bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title) -{ - mWindGen = NULL; - LLAudioEngine::init(userdata, app_title); - - if(!alutInit(NULL, NULL)) - { - LL_WARNS() << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; - return false; - } - - LL_INFOS() << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; - - LL_INFOS() << "OpenAL version: " - << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; - LL_INFOS() << "OpenAL vendor: " - << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; - LL_INFOS() << "OpenAL renderer: " - << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; - - ALint major = alutGetMajorVersion (); - ALint minor = alutGetMinorVersion (); - LL_INFOS() << "ALUT version: " << major << "." << minor << LL_ENDL; - - ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); - - alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); - LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL; - - LL_INFOS() << "ALC default device: " - << ll_safe_string(alcGetString(device, - ALC_DEFAULT_DEVICE_SPECIFIER)) - << LL_ENDL; - - return true; -} - -// virtual -std::string LLAudioEngine_OpenAL::getDriverName(bool verbose) -{ - ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); - std::ostringstream version; - - version << - "OpenAL"; - - if (verbose) - { - version << - ", version " << - ll_safe_string(alGetString(AL_VERSION)) << - " / " << - ll_safe_string(alGetString(AL_VENDOR)) << - " / " << - ll_safe_string(alGetString(AL_RENDERER)); - - if (device) - version << - ": " << - ll_safe_string(alcGetString(device, - ALC_DEFAULT_DEVICE_SPECIFIER)); - } - - return version.str(); -} - -// virtual -void LLAudioEngine_OpenAL::allocateListener() -{ - mListenerp = (LLListener *) new LLListener_OpenAL(); - if(!mListenerp) - { - LL_WARNS() << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; - } -} - -// virtual -void LLAudioEngine_OpenAL::shutdown() -{ - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - // If a subsequent error occurs while there is still an error recorded - // internally, the second error will simply be ignored. - // Clear previous error to make sure we will captuare a valid failure reason - ALenum error = alutGetError(); - if (error != ALUT_ERROR_NO_ERROR) - { - LL_WARNS() << "Uncleared error state prior to shutdown: " - << alutGetErrorString(error) << LL_ENDL; - } - - LL_INFOS() << "About to alutExit()" << LL_ENDL; - if(!alutExit()) - { - LL_WARNS() << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; - } - - LL_INFOS() << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; - - delete mListenerp; - mListenerp = NULL; -} - -LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer() -{ - return new LLAudioBufferOpenAL(); -} - -LLAudioChannel *LLAudioEngine_OpenAL::createChannel() -{ - return new LLAudioChannelOpenAL(); -} - -void LLAudioEngine_OpenAL::setInternalGain(F32 gain) -{ - //LL_INFOS() << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; - alListenerf(AL_GAIN, gain); -} - -LLAudioChannelOpenAL::LLAudioChannelOpenAL() - : - mALSource(AL_NONE), - mLastSamplePos(0) -{ - alGenSources(1, &mALSource); -} - -LLAudioChannelOpenAL::~LLAudioChannelOpenAL() -{ - cleanup(); - alDeleteSources(1, &mALSource); -} - -void LLAudioChannelOpenAL::cleanup() -{ - alSourceStop(mALSource); - mCurrentBufferp = NULL; -} - -void LLAudioChannelOpenAL::play() -{ - if (mALSource == AL_NONE) - { - LL_WARNS() << "Playing without a mALSource, aborting" << LL_ENDL; - return; - } - - if(!isPlaying()) - { - alSourcePlay(mALSource); - getSource()->setPlayedOnce(true); - } -} - -void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) -{ - if (channelp) - { - LLAudioChannelOpenAL *masterchannelp = - (LLAudioChannelOpenAL*)channelp; - if (mALSource != AL_NONE && - masterchannelp->mALSource != AL_NONE) - { - // we have channels allocated to master and slave - ALfloat master_offset; - alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, - &master_offset); - - LL_INFOS() << "Syncing with master at " << master_offset - << "sec" << LL_ENDL; - // *TODO: detect when this fails, maybe use AL_SAMPLE_ - alSourcef(mALSource, AL_SEC_OFFSET, master_offset); - } - } - play(); -} - -bool LLAudioChannelOpenAL::isPlaying() -{ - if (mALSource != AL_NONE) - { - ALint state; - alGetSourcei(mALSource, AL_SOURCE_STATE, &state); - if(state == AL_PLAYING) - { - return true; - } - } - - return false; -} - -bool LLAudioChannelOpenAL::updateBuffer() -{ - if (!mCurrentSourcep) - { - // This channel isn't associated with any source, nothing - // to be updated - return false; - } - - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the source for a different buffer. - LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); - ALuint buffer = bufferp->getBuffer(); - alSourcei(mALSource, AL_BUFFER, buffer); - mLastSamplePos = 0; - } - - if (mCurrentSourcep) - { - alSourcef(mALSource, AL_GAIN, - mCurrentSourcep->getGain() * getSecondaryGain()); - alSourcei(mALSource, AL_LOOPING, - mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); - alSourcef(mALSource, AL_ROLLOFF_FACTOR, - gAudiop->mListenerp->getRolloffFactor()); - } - - return true; -} - - -void LLAudioChannelOpenAL::updateLoop() -{ - if (mALSource == AL_NONE) - { - return; - } - - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - ALint cur_pos; - alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); - if (cur_pos < mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelOpenAL::update3DPosition() -{ - if(!mCurrentSourcep) - { - return; - } - if (mCurrentSourcep->isForcedPriority()) - { - alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); - alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); - } else { - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - alSourcefv(mALSource, AL_POSITION, float_pos.mV); - alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); - alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - - alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); -} - -LLAudioBufferOpenAL::LLAudioBufferOpenAL() -{ - mALBuffer = AL_NONE; -} - -LLAudioBufferOpenAL::~LLAudioBufferOpenAL() -{ - cleanup(); -} - -void LLAudioBufferOpenAL::cleanup() -{ - if(mALBuffer != AL_NONE) - { - alDeleteBuffers(1, &mALBuffer); - mALBuffer = AL_NONE; - } -} - -bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) -{ - cleanup(); - mALBuffer = alutCreateBufferFromFile(filename.c_str()); - if(mALBuffer == AL_NONE) - { - ALenum error = alutGetError(); - if (gDirUtilp->fileExists(filename)) - { - LL_WARNS() << - "LLAudioBufferOpenAL::loadWAV() Error loading " - << filename - << " " << alutGetErrorString(error) << LL_ENDL; - } - else - { - // It's common for the file to not actually exist. - LL_DEBUGS() << - "LLAudioBufferOpenAL::loadWAV() Error loading " - << filename - << " " << alutGetErrorString(error) << LL_ENDL; - } - return false; - } - - return true; -} - -U32 LLAudioBufferOpenAL::getLength() -{ - if(mALBuffer == AL_NONE) - { - return 0; - } - ALint length; - alGetBufferi(mALBuffer, AL_SIZE, &length); - return length / 2; // convert size in bytes to size in (16-bit) samples -} - -// ------------ - -bool LLAudioEngine_OpenAL::initWind() -{ - ALenum error; - LL_INFOS() << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; - - mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; - - alGetError(); /* clear error */ - - alGenSources(1,&mWindSource); - - if((error=alGetError()) != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL; - } - - mWindGen = new LLWindGen<WIND_SAMPLE_T>; - - mWindBufFreq = mWindGen->getInputSamplingRate(); - mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); - mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); - - mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; - - if(mWindBuf==NULL) - { - LL_ERRS() << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL; - return false; - } - - LL_INFOS() << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL; - - return true; -} - -void LLAudioEngine_OpenAL::cleanupWind() -{ - LL_INFOS() << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL; - - if (mWindSource != AL_NONE) - { - // detach and delete all outstanding buffers on the wind source - alSourceStop(mWindSource); - ALint processed; - alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); - while (processed--) - { - ALuint buffer = AL_NONE; - alSourceUnqueueBuffers(mWindSource, 1, &buffer); - alDeleteBuffers(1, &buffer); - } - - // delete the wind source itself - alDeleteSources(1, &mWindSource); - - mWindSource = AL_NONE; - } - - delete[] mWindBuf; - mWindBuf = NULL; - - delete mWindGen; - mWindGen = NULL; -} - -void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - ALenum error; - - if (!mEnableWind) - return; - - if(!mWindBuf) - return; - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - - alSourcei(mWindSource, AL_LOOPING, AL_FALSE); - alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); - alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); - alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); - } - - // ok lets make a wind buffer now - - ALint processed, queued, unprocessed; - alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); - alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); - unprocessed = queued - processed; - - // ensure that there are always at least 3x as many filled buffers - // queued as we managed to empty since last time. - mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); - mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); - - //LL_INFOS() << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; - - while(processed--) // unqueue old buffers - { - ALuint buffer; - ALenum error; - alGetError(); /* clear error */ - alSourceUnqueueBuffers(mWindSource, 1, &buffer); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; - } - else - { - alDeleteBuffers(1, &buffer); - } - } - - unprocessed += mNumEmptyWindALBuffers; - while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers - { - ALuint buffer; - alGetError(); /* clear error */ - alGenBuffers(1,&buffer); - if((error=alGetError()) != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << LL_ENDL; - break; - } - - alBufferData(buffer, - AL_FORMAT_STEREO_FLOAT32, - mWindGen->windGenerate(mWindBuf, - mWindBufSamples), - mWindBufBytes, - mWindBufFreq); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; - } - - alSourceQueueBuffers(mWindSource, 1, &buffer); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; - } - - --mNumEmptyWindALBuffers; - } - - ALint playing; - alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); - if(playing != AL_PLAYING) - { - alSourcePlay(mWindSource); - - LL_DEBUGS() << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; - } -} - +/**
+ * @file audioengine_openal.cpp
+ * @brief implementation of audio engine using OpenAL
+ * support as a OpenAL 3D implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "lldir.h"
+
+#include "llaudioengine_openal.h"
+#include "lllistener_openal.h"
+
+
+const float LLAudioEngine_OpenAL::WIND_BUFFER_SIZE_SEC = 0.05f;
+
+LLAudioEngine_OpenAL::LLAudioEngine_OpenAL()
+ :
+ mWindGen(NULL),
+ mWindBuf(NULL),
+ mWindBufFreq(0),
+ mWindBufSamples(0),
+ mWindBufBytes(0),
+ mWindSource(AL_NONE),
+ mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS)
+{
+}
+
+// virtual
+LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL()
+{
+}
+
+// virtual
+bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title)
+{
+ mWindGen = NULL;
+ LLAudioEngine::init(userdata, app_title);
+
+ if(!alutInit(NULL, NULL))
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL;
+ return false;
+ }
+
+ LL_INFOS() << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL;
+
+ LL_INFOS() << "OpenAL version: "
+ << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL;
+ LL_INFOS() << "OpenAL vendor: "
+ << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL;
+ LL_INFOS() << "OpenAL renderer: "
+ << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL;
+
+ ALint major = alutGetMajorVersion ();
+ ALint minor = alutGetMinorVersion ();
+ LL_INFOS() << "ALUT version: " << major << "." << minor << LL_ENDL;
+
+ ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
+
+ alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
+ alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor);
+ LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL;
+
+ LL_INFOS() << "ALC default device: "
+ << ll_safe_string(alcGetString(device,
+ ALC_DEFAULT_DEVICE_SPECIFIER))
+ << LL_ENDL;
+
+ return true;
+}
+
+// virtual
+std::string LLAudioEngine_OpenAL::getDriverName(bool verbose)
+{
+ ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
+ std::ostringstream version;
+
+ version <<
+ "OpenAL";
+
+ if (verbose)
+ {
+ version <<
+ ", version " <<
+ ll_safe_string(alGetString(AL_VERSION)) <<
+ " / " <<
+ ll_safe_string(alGetString(AL_VENDOR)) <<
+ " / " <<
+ ll_safe_string(alGetString(AL_RENDERER));
+
+ if (device)
+ version <<
+ ": " <<
+ ll_safe_string(alcGetString(device,
+ ALC_DEFAULT_DEVICE_SPECIFIER));
+ }
+
+ return version.str();
+}
+
+// virtual
+void LLAudioEngine_OpenAL::allocateListener()
+{
+ mListenerp = (LLListener *) new LLListener_OpenAL();
+ if(!mListenerp)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL;
+ }
+}
+
+// virtual
+void LLAudioEngine_OpenAL::shutdown()
+{
+ LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL;
+ LLAudioEngine::shutdown();
+
+ // If a subsequent error occurs while there is still an error recorded
+ // internally, the second error will simply be ignored.
+ // Clear previous error to make sure we will captuare a valid failure reason
+ ALenum error = alutGetError();
+ if (error != ALUT_ERROR_NO_ERROR)
+ {
+ LL_WARNS() << "Uncleared error state prior to shutdown: "
+ << alutGetErrorString(error) << LL_ENDL;
+ }
+
+ LL_INFOS() << "About to alutExit()" << LL_ENDL;
+ if(!alutExit())
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL;
+ }
+
+ LL_INFOS() << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL;
+
+ delete mListenerp;
+ mListenerp = NULL;
+}
+
+LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer()
+{
+ return new LLAudioBufferOpenAL();
+}
+
+LLAudioChannel *LLAudioEngine_OpenAL::createChannel()
+{
+ return new LLAudioChannelOpenAL();
+}
+
+void LLAudioEngine_OpenAL::setInternalGain(F32 gain)
+{
+ //LL_INFOS() << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL;
+ alListenerf(AL_GAIN, gain);
+}
+
+LLAudioChannelOpenAL::LLAudioChannelOpenAL()
+ :
+ mALSource(AL_NONE),
+ mLastSamplePos(0)
+{
+ alGenSources(1, &mALSource);
+}
+
+LLAudioChannelOpenAL::~LLAudioChannelOpenAL()
+{
+ cleanup();
+ alDeleteSources(1, &mALSource);
+}
+
+void LLAudioChannelOpenAL::cleanup()
+{
+ alSourceStop(mALSource);
+ mCurrentBufferp = NULL;
+}
+
+void LLAudioChannelOpenAL::play()
+{
+ if (mALSource == AL_NONE)
+ {
+ LL_WARNS() << "Playing without a mALSource, aborting" << LL_ENDL;
+ return;
+ }
+
+ if(!isPlaying())
+ {
+ alSourcePlay(mALSource);
+ getSource()->setPlayedOnce(true);
+ }
+}
+
+void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp)
+{
+ if (channelp)
+ {
+ LLAudioChannelOpenAL *masterchannelp =
+ (LLAudioChannelOpenAL*)channelp;
+ if (mALSource != AL_NONE &&
+ masterchannelp->mALSource != AL_NONE)
+ {
+ // we have channels allocated to master and slave
+ ALfloat master_offset;
+ alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET,
+ &master_offset);
+
+ LL_INFOS() << "Syncing with master at " << master_offset
+ << "sec" << LL_ENDL;
+ // *TODO: detect when this fails, maybe use AL_SAMPLE_
+ alSourcef(mALSource, AL_SEC_OFFSET, master_offset);
+ }
+ }
+ play();
+}
+
+bool LLAudioChannelOpenAL::isPlaying()
+{
+ if (mALSource != AL_NONE)
+ {
+ ALint state;
+ alGetSourcei(mALSource, AL_SOURCE_STATE, &state);
+ if(state == AL_PLAYING)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LLAudioChannelOpenAL::updateBuffer()
+{
+ if (!mCurrentSourcep)
+ {
+ // This channel isn't associated with any source, nothing
+ // to be updated
+ return false;
+ }
+
+ if (LLAudioChannel::updateBuffer())
+ {
+ // Base class update returned true, which means that we need to actually
+ // set up the source for a different buffer.
+ LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer();
+ ALuint buffer = bufferp->getBuffer();
+ alSourcei(mALSource, AL_BUFFER, buffer);
+ mLastSamplePos = 0;
+ }
+
+ if (mCurrentSourcep)
+ {
+ alSourcef(mALSource, AL_GAIN,
+ mCurrentSourcep->getGain() * getSecondaryGain());
+ alSourcei(mALSource, AL_LOOPING,
+ mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE);
+ alSourcef(mALSource, AL_ROLLOFF_FACTOR,
+ gAudiop->mListenerp->getRolloffFactor());
+ }
+
+ return true;
+}
+
+
+void LLAudioChannelOpenAL::updateLoop()
+{
+ if (mALSource == AL_NONE)
+ {
+ return;
+ }
+
+ // Hack: We keep track of whether we looped or not by seeing when the
+ // sample position looks like it's going backwards. Not reliable; may
+ // yield false negatives.
+ //
+ ALint cur_pos;
+ alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos);
+ if (cur_pos < mLastSamplePos)
+ {
+ mLoopedThisFrame = true;
+ }
+ mLastSamplePos = cur_pos;
+}
+
+
+void LLAudioChannelOpenAL::update3DPosition()
+{
+ if(!mCurrentSourcep)
+ {
+ return;
+ }
+ if (mCurrentSourcep->isForcedPriority())
+ {
+ alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0);
+ alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0);
+ alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ } else {
+ LLVector3 float_pos;
+ float_pos.setVec(mCurrentSourcep->getPositionGlobal());
+ alSourcefv(mALSource, AL_POSITION, float_pos.mV);
+ alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV);
+ alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE);
+ }
+
+ alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain());
+}
+
+LLAudioBufferOpenAL::LLAudioBufferOpenAL()
+{
+ mALBuffer = AL_NONE;
+}
+
+LLAudioBufferOpenAL::~LLAudioBufferOpenAL()
+{
+ cleanup();
+}
+
+void LLAudioBufferOpenAL::cleanup()
+{
+ if(mALBuffer != AL_NONE)
+ {
+ alDeleteBuffers(1, &mALBuffer);
+ mALBuffer = AL_NONE;
+ }
+}
+
+bool LLAudioBufferOpenAL::loadWAV(const std::string& filename)
+{
+ cleanup();
+ mALBuffer = alutCreateBufferFromFile(filename.c_str());
+ if(mALBuffer == AL_NONE)
+ {
+ ALenum error = alutGetError();
+ if (gDirUtilp->fileExists(filename))
+ {
+ LL_WARNS() <<
+ "LLAudioBufferOpenAL::loadWAV() Error loading "
+ << filename
+ << " " << alutGetErrorString(error) << LL_ENDL;
+ }
+ else
+ {
+ // It's common for the file to not actually exist.
+ LL_DEBUGS() <<
+ "LLAudioBufferOpenAL::loadWAV() Error loading "
+ << filename
+ << " " << alutGetErrorString(error) << LL_ENDL;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+U32 LLAudioBufferOpenAL::getLength()
+{
+ if(mALBuffer == AL_NONE)
+ {
+ return 0;
+ }
+ ALint length;
+ alGetBufferi(mALBuffer, AL_SIZE, &length);
+ return length / 2; // convert size in bytes to size in (16-bit) samples
+}
+
+// ------------
+
+bool LLAudioEngine_OpenAL::initWind()
+{
+ ALenum error;
+ LL_INFOS() << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL;
+
+ mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS;
+
+ alGetError(); /* clear error */
+
+ alGenSources(1,&mWindSource);
+
+ if((error=alGetError()) != AL_NO_ERROR)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL;
+ }
+
+ mWindGen = new LLWindGen<WIND_SAMPLE_T>;
+
+ mWindBufFreq = mWindGen->getInputSamplingRate();
+ mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC);
+ mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T);
+
+ mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/];
+
+ if(mWindBuf==NULL)
+ {
+ LL_ERRS() << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL;
+ return false;
+ }
+
+ LL_INFOS() << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL;
+
+ return true;
+}
+
+void LLAudioEngine_OpenAL::cleanupWind()
+{
+ LL_INFOS() << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL;
+
+ if (mWindSource != AL_NONE)
+ {
+ // detach and delete all outstanding buffers on the wind source
+ alSourceStop(mWindSource);
+ ALint processed;
+ alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed);
+ while (processed--)
+ {
+ ALuint buffer = AL_NONE;
+ alSourceUnqueueBuffers(mWindSource, 1, &buffer);
+ alDeleteBuffers(1, &buffer);
+ }
+
+ // delete the wind source itself
+ alDeleteSources(1, &mWindSource);
+
+ mWindSource = AL_NONE;
+ }
+
+ delete[] mWindBuf;
+ mWindBuf = NULL;
+
+ delete mWindGen;
+ mWindGen = NULL;
+}
+
+void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude)
+{
+ LLVector3 wind_pos;
+ F64 pitch;
+ F64 center_freq;
+ ALenum error;
+
+ if (!mEnableWind)
+ return;
+
+ if(!mWindBuf)
+ return;
+
+ if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
+ {
+
+ // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
+ // need to convert this to the conventional orientation DS3D and OpenAL use
+ // where +X = right, +Y = up, +Z = backwards
+
+ wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
+
+ pitch = 1.0 + mapWindVecToPitch(wind_vec);
+ center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
+
+ mWindGen->mTargetFreq = (F32)center_freq;
+ mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
+ mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
+
+ alSourcei(mWindSource, AL_LOOPING, AL_FALSE);
+ alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0);
+ alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0);
+ alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0);
+ alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ }
+
+ // ok lets make a wind buffer now
+
+ ALint processed, queued, unprocessed;
+ alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed);
+ alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued);
+ unprocessed = queued - processed;
+
+ // ensure that there are always at least 3x as many filled buffers
+ // queued as we managed to empty since last time.
+ mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed);
+ mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0);
+
+ //LL_INFOS() << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL;
+
+ while(processed--) // unqueue old buffers
+ {
+ ALuint buffer;
+ ALenum error;
+ alGetError(); /* clear error */
+ alSourceUnqueueBuffers(mWindSource, 1, &buffer);
+ error = alGetError();
+ if(error != AL_NO_ERROR)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL;
+ }
+ else
+ {
+ alDeleteBuffers(1, &buffer);
+ }
+ }
+
+ unprocessed += mNumEmptyWindALBuffers;
+ while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers
+ {
+ ALuint buffer;
+ alGetError(); /* clear error */
+ alGenBuffers(1,&buffer);
+ if((error=alGetError()) != AL_NO_ERROR)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << LL_ENDL;
+ break;
+ }
+
+ alBufferData(buffer,
+ AL_FORMAT_STEREO_FLOAT32,
+ mWindGen->windGenerate(mWindBuf,
+ mWindBufSamples),
+ mWindBufBytes,
+ mWindBufFreq);
+ error = alGetError();
+ if(error != AL_NO_ERROR)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL;
+ }
+
+ alSourceQueueBuffers(mWindSource, 1, &buffer);
+ error = alGetError();
+ if(error != AL_NO_ERROR)
+ {
+ LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL;
+ }
+
+ --mNumEmptyWindALBuffers;
+ }
+
+ ALint playing;
+ alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing);
+ if(playing != AL_PLAYING)
+ {
+ alSourcePlay(mWindSource);
+
+ LL_DEBUGS() << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL;
+ }
+}
+
|