llaudioengine_openal.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:13k
源码类别:
游戏引擎
开发平台:
C++ Builder
- /**
- * @file audioengine_openal.cpp
- * @brief implementation of audio engine using OpenAL
- * support as a OpenAL 3D implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "lldir.h"
- #include "llaudioengine_openal.h"
- #include "lllistener_openal.h"
- 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(const S32 num_channels, void* userdata)
- {
- mWindGen = NULL;
- LLAudioEngine::init(num_channels, userdata);
- if(!alutInit(NULL, NULL))
- {
- llwarns << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << llendl;
- return false;
- }
- llinfos << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << llendl;
- llinfos << "OpenAL version: "
- << ll_safe_string(alGetString(AL_VERSION)) << llendl;
- llinfos << "OpenAL vendor: "
- << ll_safe_string(alGetString(AL_VENDOR)) << llendl;
- llinfos << "OpenAL renderer: "
- << ll_safe_string(alGetString(AL_RENDERER)) << llendl;
- ALint major = alutGetMajorVersion ();
- ALint minor = alutGetMinorVersion ();
- llinfos << "ALUT version: " << major << "." << minor << llendl;
- ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
- alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
- alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor);
- llinfos << "ALC version: " << major << "." << minor << llendl;
- llinfos << "ALC default device: "
- << ll_safe_string(alcGetString(device,
- ALC_DEFAULT_DEVICE_SPECIFIER))
- << llendl;
- 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)
- {
- llwarns << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << llendl;
- }
- }
- // virtual
- void LLAudioEngine_OpenAL::shutdown()
- {
- llinfos << "About to LLAudioEngine::shutdown()" << llendl;
- LLAudioEngine::shutdown();
- llinfos << "About to alutExit()" << llendl;
- if(!alutExit())
- {
- llwarns << "Nuts." << llendl;
- llwarns << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << llendl;
- }
- llinfos << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << llendl;
- delete mListenerp;
- mListenerp = NULL;
- }
- LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer()
- {
- return new LLAudioBufferOpenAL();
- }
- LLAudioChannel *LLAudioEngine_OpenAL::createChannel()
- {
- return new LLAudioChannelOpenAL();
- }
- void LLAudioEngine_OpenAL::setInternalGain(F32 gain)
- {
- //llinfos << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << llendl;
- 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)
- {
- llwarns << "Playing without a mALSource, aborting" << llendl;
- 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);
- llinfos << "Syncing with master at " << master_offset
- << "sec" << llendl;
- // *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 (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->isAmbient())
- {
- 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))
- {
- llwarns <<
- "LLAudioBufferOpenAL::loadWAV() Error loading "
- << filename
- << " " << alutGetErrorString(error) << llendl;
- }
- else
- {
- // It's common for the file to not actually exist.
- lldebugs <<
- "LLAudioBufferOpenAL::loadWAV() Error loading "
- << filename
- << " " << alutGetErrorString(error) << llendl;
- }
- 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
- }
- // ------------
- void LLAudioEngine_OpenAL::initWind()
- {
- ALenum error;
- llinfos << "LLAudioEngine_OpenAL::initWind() start" << llendl;
- mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS;
- alGetError(); /* clear error */
- alGenSources(1,&mWindSource);
- if((error=alGetError()) != AL_NO_ERROR)
- {
- llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<llendl;
- }
- 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)
- {
- llerrs << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << llendl;
- mEnableWind=false;
- }
- llinfos << "LLAudioEngine_OpenAL::initWind() done" << llendl;
- }
- void LLAudioEngine_OpenAL::cleanupWind()
- {
- llinfos << "LLAudioEngine_OpenAL::cleanupWind()" << llendl;
- 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);
- //llinfos << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << llendl;
- while(processed--) // unqueue old buffers
- {
- ALuint buffer;
- ALenum error;
- alGetError(); /* clear error */
- alSourceUnqueueBuffers(mWindSource, 1, &buffer);
- error = alGetError();
- if(error != AL_NO_ERROR)
- {
- llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << llendl;
- }
- 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)
- {
- llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << llendl;
- break;
- }
- alBufferData(buffer,
- AL_FORMAT_STEREO16,
- mWindGen->windGenerate(mWindBuf,
- mWindBufSamples, 2),
- mWindBufBytes,
- mWindBufFreq);
- error = alGetError();
- if(error != AL_NO_ERROR)
- {
- llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << llendl;
- }
- alSourceQueueBuffers(mWindSource, 1, &buffer);
- error = alGetError();
- if(error != AL_NO_ERROR)
- {
- llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << llendl;
- }
- --mNumEmptyWindALBuffers;
- }
- ALint playing;
- alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing);
- if(playing != AL_PLAYING)
- {
- alSourcePlay(mWindSource);
- lldebugs << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << llendl;
- }
- }