123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "audio/audio.h"
- #include "audio/audioDataBlock.h"
- #include "audio/audioDescriptions.h"
- #include "collection/vector.h"
- #include "console/console.h"
- #include "console/consoleTypes.h"
- #include "game/gameConnection.h"
- #include "io/fileStream.h"
- #include "audio/audioStreamSourceFactory.h"
- #ifdef TORQUE_OS_IOS
- #include "platformiOS/SoundEngine.h"
- #endif
- #ifdef TORQUE_OS_OSX
- //#define REL_WORKAROUND
- #endif
- //-------------------------------------------------------------------------
- #ifdef TORQUE_OS_IOS
- extern ALvoid alcMacOSXMixerOutputRateProc(const ALdouble value);
- #endif
- #define MAX_AUDIOSOURCES 16 // maximum number of concurrent sources
- #define MIN_GAIN 0.05f // anything with lower gain will not be started
- #define MIN_UNCULL_PERIOD 500 // time before buffer is checked to be unculled
- #define MIN_UNCULL_GAIN 0.1f // min gain of source to be unculled
- #define ALX_DEF_SAMPLE_RATE 44100 // default values for mixer
- #define ALX_DEF_SAMPLE_BITS 16
- #define ALX_DEF_CHANNELS 2
- #define FORCED_OUTER_FALLOFF 10000.f // forced falloff distance
- #ifdef TORQUE_OS_OSX
- static ALCdevice *mDevice = NULL; // active OpenAL device
- static ALCcontext *mContext = NULL; // active OpenAL context
- #elif TORQUE_OS_IOS
- static ALCdevice *mDevice = NULL; // active OpenAL device
- static ALCcontext *mContext = NULL; // active OpenAL context
- #else
- static ALCvoid *mDevice = NULL; // active OpenAL device
- static ALCvoid *mContext = NULL; // active OpenAL context
- #endif
- F32 mAudioChannelVolumes[Audio::AudioVolumeChannels]; // the attenuation for each of the channel types
- //-------------------------------------------------------------------------
- struct LoopingImage
- {
- AUDIOHANDLE mHandle;
- Resource<AudioBuffer> mBuffer;
- Audio::Description mDescription;
- AudioSampleEnvironment *mEnvironment;
- Point3F mPosition;
- Point3F mDirection;
- F32 mPitch;
- F32 mScore;
- U32 mCullTime;
- LoopingImage() { clear(); }
- void clear()
- {
- mHandle = NULL_AUDIOHANDLE;
- mBuffer = NULL;
- dMemset(&mDescription, 0, sizeof(Audio::Description));
- mEnvironment = 0;
- mPosition.set(0.f,0.f,0.f);
- mDirection.set(0.f,1.f,0.f);
- mPitch = 1.f;
- mScore = 0.f;
- mCullTime = 0;
- }
- };
- //-------------------------------------------------------------------------
- static F32 mMasterVolume = 1.f; // traped from AL_LISTENER gain (miles has difficulties with 3d sources)
- static ALuint mSource[MAX_AUDIOSOURCES]; // ALSources
- static ALint mResumePosition[MAX_AUDIOSOURCES]; // Ensures Pause resumes from the correct position
- static AUDIOHANDLE mHandle[MAX_AUDIOSOURCES]; // unique handles
- static Resource<AudioBuffer> mBuffer[MAX_AUDIOSOURCES]; // each of the playing buffers (needed for AudioThread)
- static F32 mScore[MAX_AUDIOSOURCES]; // for figuring out which sources to cull/uncull
- static F32 mSourceVolume[MAX_AUDIOSOURCES]; // the samples current un-attenuated gain (not scaled by master/channel gains)
- static U32 mType[MAX_AUDIOSOURCES]; // the channel which this source belongs
- static AudioSampleEnvironment* mSampleEnvironment[MAX_AUDIOSOURCES]; // currently playing sample environments
- static bool mEnvironmentEnabled = false; // environment enabled?
- static SimObjectPtr<AudioEnvironment> mCurrentEnvironment; // the last environment set
- struct LoopingList : VectorPtr<LoopingImage*>
- {
- LoopingList() : VectorPtr<LoopingImage*>(__FILE__, __LINE__) { }
- LoopingList::iterator findImage(AUDIOHANDLE handle);
- void sort();
- };
- struct StreamingList : VectorPtr<AudioStreamSource*>
- {
- StreamingList() : VectorPtr<AudioStreamSource*>(__FILE__, __LINE__) { }
- StreamingList::iterator findImage(AUDIOHANDLE handle);
- void sort();
- };
- // LoopingList and LoopingFreeList own the images
- static LoopingList mLoopingList; // all the looping sources
- static LoopingList mLoopingFreeList; // free store
- static LoopingList mLoopingInactiveList; // sources which have not been played yet
- static LoopingList mLoopingCulledList; // sources which have been culled (alxPlay called)
- // StreamingList and StreamingFreeList own the images
- static StreamingList mStreamingList; // all the streaming sources
- //static StreamingList mStreamingFreeList; // free store
- static StreamingList mStreamingInactiveList; // sources which have not been played yet
- static StreamingList mStreamingCulledList; // sources which have been culled (alxPlay called)
- #define AUDIOHANDLE_LOOPING_BIT (0x80000000)
- #define AUDIOHANDLE_STREAMING_BIT (0x40000000)
- #define AUDIOHANDLE_INACTIVE_BIT (0x20000000)
- #define AUDIOHANDLE_LOADING_BIT (0x10000000)
- #define HANDLE_MASK ~(AUDIOHANDLE_LOOPING_BIT | AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT)
- // keep the 'AUDIOHANDLE_LOOPING_BIT' on the handle returned to the caller so that
- // the handle can quickly be rejected from looping list queries
- #define RETURN_MASK ~(AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT)
- static AUDIOHANDLE mLastHandle = NULL_AUDIOHANDLE;
- // force gain setting for 3d distances
- static U32 mNumSources = 0; // total number of sources to work with
- static U32 mRequestSources = MAX_AUDIOSOURCES; // number of sources to request from openAL
- #define INVALID_SOURCE 0xffffffff
- inline bool areEqualHandles(AUDIOHANDLE a, AUDIOHANDLE b)
- {
- return((a & HANDLE_MASK) == (b & HANDLE_MASK));
- }
- //-------------------------------------------------------------------------
- // Looping image
- //-------------------------------------------------------------------------
- inline LoopingList::iterator LoopingList::findImage(AUDIOHANDLE handle)
- {
- if(handle & AUDIOHANDLE_LOOPING_BIT)
- {
- LoopingList::iterator itr = begin();
- while(itr != end())
- {
- if(areEqualHandles((*itr)->mHandle, handle))
- return(itr);
- itr++;
- }
- }
- return(0);
- }
- inline S32 QSORT_CALLBACK loopingImageSort(const void * p1, const void * p2)
- {
- const LoopingImage * ip1 = *(const LoopingImage**)p1;
- const LoopingImage * ip2 = *(const LoopingImage**)p2;
- // min->max
- return (S32)(ip2->mScore - ip1->mScore);
- }
- void LoopingList::sort()
- {
- dQsort(address(), size(), sizeof(LoopingImage*), loopingImageSort);
- }
- //-------------------------------------------------------------------------
- // StreamingList
- //-------------------------------------------------------------------------
- inline StreamingList::iterator StreamingList::findImage(AUDIOHANDLE handle)
- {
- if(handle & AUDIOHANDLE_STREAMING_BIT)
- {
- StreamingList::iterator itr = begin();
- while(itr != end())
- {
- if(areEqualHandles((*itr)->mHandle, handle))
- return(itr);
- itr++;
- }
- }
- return(0);
- }
- inline S32 QSORT_CALLBACK streamingSourceSort(const void * p1, const void * p2)
- {
- const AudioStreamSource * ip1 = *(const AudioStreamSource**)p1;
- const AudioStreamSource * ip2 = *(const AudioStreamSource**)p2;
- // min->max
- return (S32)(ip2->mScore - ip1->mScore);
- }
- void StreamingList::sort()
- {
- dQsort(address(), size(), sizeof(AudioStreamSource*), streamingSourceSort);
- }
- //-------------------------------------------------------------------------
- LoopingImage * createLoopingImage()
- {
- LoopingImage *image;
- if (mLoopingFreeList.size())
- {
- image = mLoopingFreeList.last();
- mLoopingFreeList.pop_back();
- }
- else
- image = new LoopingImage;
- return(image);
- }
- //-------------------------------------------------------------------------
- AudioStreamSource * createStreamingSource(const char* filename)
- {
- AudioStreamSource *streamSource = AudioStreamSourceFactory::getNewInstance(filename);
- return(streamSource);
- }
- //-------------------------------------------------------------------------
- static AUDIOHANDLE getNewHandle()
- {
- mLastHandle++;
- mLastHandle &= HANDLE_MASK;
- if (mLastHandle == NULL_AUDIOHANDLE)
- mLastHandle++;
- return mLastHandle;
- }
- //-------------------------------------------------------------------------
- // function declarations
- void alxLoopingUpdate();
- void alxStreamingUpdate();
- void alxUpdateScores(bool);
- static bool findFreeSource(U32 *index)
- {
- for(U32 i = 0; i < mNumSources; i++)
- if(mHandle[i] == NULL_AUDIOHANDLE)
- {
- *index = i;
- return(true);
- }
- return(false);
- }
- //--------------------------------------------------------------------------
- // - cull out the min source that is below volume
- // - streams/voice/loading streams are all scored > 2
- // - volumes are attenuated by channel only
- static bool cullSource(U32 *index, F32 volume)
- {
- alGetError();
- F32 minVolume = volume;
- S32 best = -1;
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mScore[i] < minVolume)
- {
- minVolume = mScore[i];
- best = i;
- }
- }
- if(best == -1)
- return(false);
- // check if culling a looper
- LoopingList::iterator itr = mLoopingList.findImage(mHandle[best]);
- if(itr)
- {
- // check if culling an inactive looper
- if(mHandle[best] & AUDIOHANDLE_INACTIVE_BIT)
- {
- AssertFatal(!mLoopingInactiveList.findImage(mHandle[best]), "cullSource: image already in inactive list");
- AssertFatal(!mLoopingCulledList.findImage(mHandle[best]), "cullSource: image should not be in culled list");
- mLoopingInactiveList.push_back(*itr);
- }
- else
- {
- (*itr)->mHandle |= AUDIOHANDLE_INACTIVE_BIT;
- AssertFatal(!mLoopingCulledList.findImage(mHandle[best]), "cullSource: image already in culled list");
- AssertFatal(!mLoopingInactiveList.findImage(mHandle[best]), "cullSource: image should no be in inactive list");
- (*itr)->mCullTime = Platform::getRealMilliseconds();
- mLoopingCulledList.push_back(*itr);
- }
- }
- // check if culling a streamer
- StreamingList::iterator itr2 = mStreamingList.findImage(mHandle[best]);
- if(itr2)
- {
- // check if culling an inactive streamer
- if(mHandle[best] & AUDIOHANDLE_INACTIVE_BIT)
- {
- AssertFatal(!mStreamingInactiveList.findImage(mHandle[best]), "cullSource: image already in inactive list");
- AssertFatal(!mStreamingCulledList.findImage(mHandle[best]), "cullSource: image should not be in culled list");
- mStreamingInactiveList.push_back(*itr2);
- }
- else
- {
- (*itr2)->mHandle |= AUDIOHANDLE_INACTIVE_BIT;
- AssertFatal(!mStreamingCulledList.findImage(mHandle[best]), "cullSource: image already in culled list");
- AssertFatal(!mStreamingInactiveList.findImage(mHandle[best]), "cullSource: image should no be in inactive list");
- (*itr2)->freeStream();
- (*itr2)->mCullTime = Platform::getRealMilliseconds();
- mStreamingCulledList.push_back(*itr2);
- }
- }
- alSourceStop(mSource[best]);
- mHandle[best] = NULL_AUDIOHANDLE;
- mBuffer[best] = 0;
- *index = best;
- return(true);
- }
- //--------------------------------------------------------------------------
- /** Compute approximate max volume at a particular distance
- ignore cone volume influnces
- */
- static F32 approximate3DVolume(const Audio::Description& desc, const Point3F &position)
- {
- Point3F p1;
- alxGetListenerPoint3F(AL_POSITION, &p1);
- p1 -= position;
- F32 distance = p1.magnitudeSafe();
- if(distance >= desc.mMaxDistance)
- return(0.f);
- else if(distance < desc.mReferenceDistance)
- return 1.0f;
- else
- return 1.0f - (distance - desc.mReferenceDistance) / (desc.mMaxDistance - desc.mReferenceDistance);
- }
- //--------------------------------------------------------------------------
- inline U32 alxFindIndex(AUDIOHANDLE handle)
- {
- for (U32 i=0; i<mNumSources; i++)
- if(mHandle[i] && areEqualHandles(mHandle[i], handle))
- return i;
- return MAX_AUDIOSOURCES;
- }
- //--------------------------------------------------------------------------
- ALuint alxFindSource(AUDIOHANDLE handle)
- {
- for (U32 i=0; i<mNumSources; i++)
- if(mHandle[i] && areEqualHandles(mHandle[i], handle))
- return mSource[i];
- return(INVALID_SOURCE);
- }
- //--------------------------------------------------------------------------
- /** Determmine if an AUDIOHANDLE is valid.
- An AUDIOHANDLE is valid if it is a currently playing source, inactive source,
- or a looping source (basically anything where a alxSource??? call will succeed)
- */
- bool alxIsValidHandle(AUDIOHANDLE handle)
- {
- if(handle == NULL_AUDIOHANDLE)
- return(false);
- // inactive sources are valid
- U32 idx = alxFindIndex(handle);
- if(idx != MAX_AUDIOSOURCES)
- {
- if(mHandle[idx] & AUDIOHANDLE_INACTIVE_BIT)
- return(true);
- // if it is active but not playing then it has stopped...
- ALint state = AL_STOPPED;
- alGetSourcei(mSource[idx], AL_SOURCE_STATE, &state);
- return(state == AL_PLAYING);
- }
- if(mLoopingList.findImage(handle))
- return(true);
- if(mStreamingList.findImage(handle))
- return(true);
- return(false);
- }
- //--------------------------------------------------------------------------
- /** Determmine if an AUDIOHANDLE is currently playing
- */
- bool alxIsPlaying(AUDIOHANDLE handle)
- {
- if(handle == NULL_AUDIOHANDLE)
- return(false);
- U32 idx = alxFindIndex(handle);
- if(idx == MAX_AUDIOSOURCES)
- return(false);
- ALint state = 0;
- alGetSourcei(mSource[idx], AL_SOURCE_STATE, &state);
- return(state == AL_PLAYING);
- }
- //--------------------------------------------------------------------------
- void alxEnvironmentDestroy()
- {
- /* todo
- if(mEnvironment)
- {
- alDeleteEnvironmentIASIG(1, &mEnvironment);
- mEnvironment = 0;
- }
- */
- }
- void alxEnvironmentInit()
- {
- /* todo
- alxEnvironmentDestroy();
- if(alIsExtensionPresent((const ALubyte *)"AL_EXT_IASIG"))
- {
- alGenEnvironmentIASIG(1, &mEnvironment);
- if(alGetError() != AL_NO_ERROR)
- mEnvironment = 0;
- }
- */
- }
- //--------------------------------------------------------------------------
- // - setup a sources environmental effect settings
- static void alxSourceEnvironment(ALuint source, F32 environmentLevel, AudioSampleEnvironment * env)
- {
- // environment level is on the AudioDatablock
- /* todo
- alSourcef(source, AL_ENV_SAMPLE_REVERB_MIX_EXT, environmentLevel);
- */
- if(!env)
- return;
- /* todo
- alSourcei(source, AL_ENV_SAMPLE_DIRECT_EXT, env->mDirect);
- alSourcei(source, AL_ENV_SAMPLE_DIRECT_HF_EXT, env->mDirectHF);
- alSourcei(source, AL_ENV_SAMPLE_ROOM_EXT, env->mRoom);
- alSourcei(source, AL_ENV_SAMPLE_ROOM_HF_EXT, env->mRoomHF);
- alSourcei(source, AL_ENV_SAMPLE_OUTSIDE_VOLUME_HF_EXT, env->mOutsideVolumeHF);
- alSourcei(source, AL_ENV_SAMPLE_FLAGS_EXT, env->mFlags);
- alSourcef(source, AL_ENV_SAMPLE_OBSTRUCTION_EXT, env->mObstruction);
- alSourcef(source, AL_ENV_SAMPLE_OBSTRUCTION_LF_RATIO_EXT, env->mObstructionLFRatio);
- alSourcef(source, AL_ENV_SAMPLE_OCCLUSION_EXT, env->mOcclusion);
- alSourcef(source, AL_ENV_SAMPLE_OCCLUSION_LF_RATIO_EXT, env->mOcclusionLFRatio);
- alSourcef(source, AL_ENV_SAMPLE_OCCLUSION_ROOM_RATIO_EXT, env->mOcclusionRoomRatio);
- alSourcef(source, AL_ENV_SAMPLE_ROOM_ROLLOFF_EXT, env->mRoomRolloff);
- alSourcef(source, AL_ENV_SAMPLE_AIR_ABSORPTION_EXT, env->mAirAbsorption);
- */
- }
- static void alxSourceEnvironment(ALuint source, LoopingImage * image)
- {
- AssertFatal(image, "alxSourceEnvironment: invalid looping image");
- if(image->mDescription.mIs3D)
- alxSourceEnvironment(source, image->mDescription.mEnvironmentLevel, image->mEnvironment);
- }
- static void alxSourceEnvironment(ALuint source, AudioStreamSource * image)
- {
- AssertFatal(image, "alxSourceEnvironment: invalid looping image");
- if(image->mDescription.mIs3D)
- alxSourceEnvironment(source, image->mDescription.mEnvironmentLevel, image->mEnvironment);
- }
- //--------------------------------------------------------------------------
- // setup a source to play... loopers have pitch cached
- // - by default, pitch is 1x (settings not defined in description)
- // - all the settings are cached by openAL (miles version), so no worries setting them here
- static void alxSourcePlay(ALuint source, Resource<AudioBuffer> buffer, const Audio::Description& desc, const MatrixF *transform)
- {
- alSourcei(source, AL_BUFFER, buffer->getALBuffer());
- alSourcef(source, AL_GAIN, Audio::linearToDB(desc.mVolume * mAudioChannelVolumes[desc.mVolumeChannel] * mMasterVolume));
- alSourcei(source, AL_LOOPING, desc.mIsLooping ? AL_TRUE : AL_FALSE);
- alSourcef(source, AL_PITCH, 1.f);
- alSourcei(source, AL_CONE_INNER_ANGLE, desc.mConeInsideAngle);
- alSourcei(source, AL_CONE_OUTER_ANGLE, desc.mConeOutsideAngle);
- alSourcef(source, AL_CONE_OUTER_GAIN, desc.mConeOutsideVolume);
- if(transform != NULL)
- {
- #ifdef REL_WORKAROUND
- alSourcei(source, AL_SOURCE_ABSOLUTE, AL_TRUE);
- #else
- alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
- #endif
- Point3F p;
- transform->getColumn(3, &p);
- alSource3f(source, AL_POSITION, p.x, p.y, p.z);
- //Always use ConeVector (which is tied to transform)
- alSource3f(source, AL_DIRECTION, desc.mConeVector.x, desc.mConeVector.y, desc.mConeVector.z);
- }
- else
- {
- // 2D sound
- alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
- alSource3f(source, AL_POSITION, 0.0f, 0.0f, 1.0f);
- }
- alSourcef(source, AL_REFERENCE_DISTANCE, desc.mReferenceDistance);
- alSourcef(source, AL_MAX_DISTANCE, desc.mMaxDistance);
- /* todo
- // environmental audio stuff:
- alSourcef(source, AL_ENV_SAMPLE_REVERB_MIX_EXT, desc.mEnvironmentLevel);
- if(desc.mEnvironmentLevel != 0.f)
- alSourceResetEnvironment_EXT(source);
- */
- }
- // helper for looping images
- static void alxSourcePlay(ALuint source, LoopingImage * image)
- {
- AssertFatal(image, "alxSourcePlay: invalid looping image");
- // 3d source? need position/direction
- if(image->mDescription.mIs3D)
- {
- MatrixF transform(true);
- transform.setColumn(3, image->mPosition);
- transform.setRow(1, image->mDirection);
- alxSourcePlay(source, image->mBuffer, image->mDescription, &transform);
- }
- else
- {
- // 2d source
- alxSourcePlay(source, image->mBuffer, image->mDescription, 0);
- }
- }
- //--------------------------------------------------------------------------
- // setup a streaming source to play
- static void alxSourcePlay(AudioStreamSource *streamSource)
- {
- ALuint source = streamSource->mSource;
- Audio::Description& desc = streamSource->mDescription;
- streamSource->initStream();
- alSourcef(source, AL_GAIN, Audio::linearToDB(desc.mVolume * mAudioChannelVolumes[desc.mVolumeChannel] * mMasterVolume));
- // alSourcei(source, AL_LOOPING, AL_FALSE);
- alSourcef(source, AL_PITCH, 1.f);
- alSourcei(source, AL_CONE_INNER_ANGLE, desc.mConeInsideAngle);
- alSourcei(source, AL_CONE_OUTER_ANGLE, desc.mConeOutsideAngle);
- alSourcef(source, AL_CONE_OUTER_GAIN, desc.mConeOutsideVolume);
- if(streamSource->mDescription.mIs3D)
- {
- MatrixF transform(true);
- transform.setColumn(3, streamSource->mPosition);
- transform.setRow(1, streamSource->mDirection);
- #ifdef REL_WORKAROUND
- alSourcei(source, AL_SOURCE_ABSOLUTE, AL_TRUE);
- #else
- alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
- #endif
- Point3F p;
- transform.getColumn(3, &p);
- alSource3f(source, AL_POSITION, p.x, p.y, p.z);
- //Always use ConeVector (which is tied to transform)
- alSource3f(source, AL_DIRECTION, desc.mConeVector.x, desc.mConeVector.y, desc.mConeVector.z);
- }
- else
- {
- // 2D sound
- // JMQ: slam the stream source's position to our desired value
- streamSource->mPosition = Point3F(0.0f, 0.0f, 1.0f);
- alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
- alSource3f(source, AL_POSITION,
- streamSource->mPosition.x,
- streamSource->mPosition.y,
- streamSource->mPosition.z);
- }
- alSourcef(source, AL_REFERENCE_DISTANCE, desc.mReferenceDistance);
- alSourcef(source, AL_MAX_DISTANCE, desc.mMaxDistance);
- /* todo
- // environmental audio stuff:
- alSourcef(source, AL_ENV_SAMPLE_REVERB_MIX_EXT, desc.mEnvironmentLevel);
- if(desc.mEnvironmentLevel != 0.f)
- alSourceResetEnvironment_EXT(source);
- */
- }
- //--------------------------------------------------------------------------
- AUDIOHANDLE alxCreateSource(const Audio::Description& desc,
- const char *filename,
- const MatrixF *transform,
- AudioSampleEnvironment *sampleEnvironment)
- {
- if (!mContext)
- return NULL_AUDIOHANDLE;
- if( filename == NULL || filename == StringTable->EmptyString )
- return NULL_AUDIOHANDLE;
- F32 volume = desc.mVolume;
- // calculate an approximate attenuation for 3d sounds
- if(transform && desc.mIs3D)
- {
- Point3F position;
- transform->getColumn(3, &position);
- volume *= approximate3DVolume(desc, position);
- }
- // check the type specific volume
- AssertFatal(desc.mVolumeChannel < Audio::AudioVolumeChannels, "alxCreateSource: invalid volume channel for source");
- if(desc.mVolumeChannel >= Audio::AudioVolumeChannels)
- return(NULL_AUDIOHANDLE);
- // done if channel is muted (and not a looper)
- if(!desc.mIsLooping && !desc.mIsStreaming && (mAudioChannelVolumes[desc.mVolumeChannel] == 0.f))
- return(NULL_AUDIOHANDLE);
- // scale volume by channel attenuation
- volume *= mAudioChannelVolumes[desc.mVolumeChannel];
- // non-loopers don't add if < minvolume
- if(!desc.mIsLooping && !desc.mIsStreaming && (volume <= MIN_GAIN))
- return(NULL_AUDIOHANDLE);
- U32 index = MAX_AUDIOSOURCES;
- // try and find an available source: 0 volume loopers get added to inactive list
- if(volume > MIN_GAIN)
- {
- if(!findFreeSource(&index))
- {
- alxUpdateScores(true);
- // scores do not include master volume
- if(!cullSource(&index, volume))
- index = MAX_AUDIOSOURCES;
- }
- }
- // make sure that loopers are added
- if(index == MAX_AUDIOSOURCES)
- {
- if(desc.mIsLooping && !(desc.mIsStreaming))
- {
- Resource<AudioBuffer> buffer = AudioBuffer::find(filename);
- if(!(bool)buffer)
- return(NULL_AUDIOHANDLE);
- // create the inactive looping image
- LoopingImage * image = createLoopingImage();
- image->mHandle = getNewHandle() | AUDIOHANDLE_LOOPING_BIT | AUDIOHANDLE_INACTIVE_BIT;
- image->mBuffer = buffer;
- image->mDescription = desc;
- image->mScore = volume;
- image->mEnvironment = sampleEnvironment;
- // grab position/direction if 3d source
- if(transform)
- {
- transform->getColumn(3, &image->mPosition);
- transform->getColumn(1, &image->mDirection);
- }
- AssertFatal(!mLoopingInactiveList.findImage(image->mHandle), "alxCreateSource: handle in inactive list");
- AssertFatal(!mLoopingCulledList.findImage(image->mHandle), "alxCreateSource: handle in culled list");
- // add to the looping and inactive lists
- mLoopingList.push_back(image);
- mLoopingInactiveList.push_back(image);
- return(image->mHandle & RETURN_MASK);
- }
- else
- return(NULL_AUDIOHANDLE);
- }
- // make sure that streamers are added
- if(index == MAX_AUDIOSOURCES)
- {
- if(desc.mIsStreaming)
- {
- // create the inactive audio stream
- AudioStreamSource * streamSource = createStreamingSource(filename);
- if (streamSource)
- {
- streamSource->mHandle = getNewHandle() | AUDIOHANDLE_STREAMING_BIT | AUDIOHANDLE_INACTIVE_BIT;
- streamSource->mSource = 0;
- streamSource->mDescription = desc;
- streamSource->mScore = volume;
- streamSource->mEnvironment = sampleEnvironment;
- // grab position/direction if 3d source
- if(transform)
- {
- transform->getColumn(3, &streamSource->mPosition);
- transform->getColumn(1, &streamSource->mDirection);
- }
- AssertFatal(!mStreamingInactiveList.findImage(streamSource->mHandle), "alxCreateSource: handle in inactive list");
- AssertFatal(!mStreamingCulledList.findImage(streamSource->mHandle), "alxCreateSource: handle in culled list");
- // add to the streaming and inactive lists
- mStreamingList.push_back(streamSource);
- mStreamingInactiveList.push_back(streamSource);
- return(streamSource->mHandle & RETURN_MASK);
- }
- else
- return NULL_AUDIOHANDLE;
- }
- else
- return(NULL_AUDIOHANDLE);
- }
- // clear the error state
- alGetError();
- // grab the buffer
- Resource<AudioBuffer> buffer;
- if(!(desc.mIsStreaming)) {
- buffer = AudioBuffer::find(filename);
- if((bool)buffer == false)
- return NULL_AUDIOHANDLE;
- }
- // init the source (created inactive) and store needed values
- mHandle[index] = getNewHandle() | AUDIOHANDLE_INACTIVE_BIT;
- mType[index] = desc.mVolumeChannel;
- if(!(desc.mIsStreaming)) {
- mBuffer[index] = buffer;
- }
- mScore[index] = volume;
- mSourceVolume[index] = desc.mVolume;
- mSampleEnvironment[index] = sampleEnvironment;
- ALuint source = mSource[index];
- // setup play info
- if(!desc.mIsStreaming)
- alxSourcePlay(source, buffer, desc, desc.mIs3D ? transform : 0);
- if(mEnvironmentEnabled)
- alxSourceEnvironment(source, desc.mEnvironmentLevel, sampleEnvironment);
- // setup a LoopingImage ONLY if the sound is a looper:
- if(desc.mIsLooping && !(desc.mIsStreaming))
- {
- mHandle[index] |= AUDIOHANDLE_LOOPING_BIT;
- LoopingImage * image = createLoopingImage();
- image->mHandle = mHandle[index];
- image->mBuffer = buffer;
- image->mDescription = desc;
- image->mScore = volume;
- image->mEnvironment = sampleEnvironment;
- // grab position/direction
- if(transform)
- {
- transform->getColumn(3, &image->mPosition);
- transform->getColumn(1, &image->mDirection);
- }
- AssertFatal(!mLoopingInactiveList.findImage(image->mHandle), "alxCreateSource: handle in inactive list");
- AssertFatal(!mLoopingCulledList.findImage(image->mHandle), "alxCreateSource: handle in culled list");
- // add to the looping list
- mLoopingList.push_back(image);
- }
- // setup a AudioStreamSource ONLY if the sound is a streamer:
- if(desc.mIsStreaming)
- {
- // Intangir> why is loading bit never used anywhere else?
- // comes in handy for my oggmixedstream
- // (prevents it from being deleted before it is loaded)
- mHandle[index] |= AUDIOHANDLE_STREAMING_BIT | AUDIOHANDLE_LOADING_BIT;
- AudioStreamSource * streamSource = createStreamingSource(filename);
- if (streamSource)
- {
- streamSource->mHandle = mHandle[index];
- streamSource->mSource = mSource[index];
- streamSource->mDescription = desc;
- streamSource->mScore = volume;
- streamSource->mEnvironment = sampleEnvironment;
- // grab position/direction
- if(transform)
- {
- transform->getColumn(3, &streamSource->mPosition);
- transform->getColumn(1, &streamSource->mDirection);
- }
- AssertFatal(!mStreamingInactiveList.findImage(streamSource->mHandle), "alxCreateSource: handle in inactive list");
- AssertFatal(!mStreamingCulledList.findImage(streamSource->mHandle), "alxCreateSource: handle in culled list");
- alxSourcePlay(streamSource);
- // add to the looping list
- mStreamingList.push_back(streamSource);
- }
- else
- {
- mSampleEnvironment[index] = 0;
- mHandle[index] = NULL_AUDIOHANDLE;
- mBuffer[index] = 0;
- return NULL_AUDIOHANDLE;
- }
- }
- // clear off all but looping bit
- return(mHandle[index] & RETURN_MASK);
- }
- //--------------------------------------------------------------------------
- AUDIOHANDLE alxCreateSource(const AudioAsset *profile, const MatrixF *transform)
- {
- if (profile == NULL)
- return NULL_AUDIOHANDLE;
- return alxCreateSource(profile->getAudioDescription(), profile->getAudioFile(), transform, NULL );
- }
- //--------------------------------------------------------------------------
- AUDIOHANDLE alxCreateSource_AD(const AudioAsset *profile, const AudioDescription* description, const MatrixF *transform)
- {
- //Since we don't want to modify AudioAssets all the time
- //here is a version which accepts a script-defined AudioDescription
- if (profile == NULL)
- return NULL_AUDIOHANDLE;
-
- Audio::Description newAD;
- newAD.mVolume = description->mVolume;
- newAD.mVolumeChannel = description->mVolumeChannel;
- newAD.mConeInsideAngle = description->mConeInsideAngle;
- newAD.mConeOutsideAngle = description->mConeOutsideAngle;
- newAD.mConeOutsideVolume = description->mConeOutsideVolume;
- newAD.mConeVector = description->mConeVector;
- newAD.mEnvironmentLevel = description->mEnvironmentLevel;
- newAD.mIs3D = description->mIs3D;
- newAD.mIsLooping = description->mIsLooping;
- newAD.mIsStreaming = description->mIsStreaming;
- newAD.mMaxDistance = description->mMaxDistance;
- newAD.mReferenceDistance = description->mReferenceDistance;
-
- return alxCreateSource(newAD, profile->getAudioFile(), transform, NULL);
- }
- //--------------------------------------------------------------------------
- extern void threadPlay(AudioBuffer * buffer, AUDIOHANDLE handle);
- AUDIOHANDLE alxPlay(AUDIOHANDLE handle)
- {
- U32 index = alxFindIndex(handle);
- if(index != MAX_AUDIOSOURCES)
- {
- // play if not already playing
- if(mHandle[index] & AUDIOHANDLE_INACTIVE_BIT)
- {
- mHandle[index] &= ~(AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT);
- // make sure the looping image also clears it's inactive bit
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- (*itr)->mHandle &= ~(AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT);
- // make sure the streaming image also clears it's inactive bit
- StreamingList::iterator itr2 = mStreamingList.findImage(handle);
- if(itr2)
- (*itr2)->mHandle &= ~(AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT);
- alSourcePlay(mSource[index]);
- return(handle);
- }
- }
- else
- {
- // move inactive loopers to the culled list, try to start the sound
- LoopingList::iterator itr = mLoopingInactiveList.findImage(handle);
- if(itr)
- {
- AssertFatal(!mLoopingCulledList.findImage(handle), "alxPlay: image already in culled list");
- mLoopingCulledList.push_back(*itr);
- mLoopingInactiveList.erase_fast(itr);
- alxLoopingUpdate();
- return(handle);
- }
- else if(mLoopingCulledList.findImage(handle))
- {
- alxLoopingUpdate();
- return(handle);
- }
- else
- return(NULL_AUDIOHANDLE);
- #if 0
- // move inactive streamers to the culled list, try to start the sound
- StreamingList::iterator itr2 = mStreamingInactiveList.findImage(handle);
- if(itr2)
- {
- AssertFatal(!mStreamingCulledList.findImage(handle), "alxPlay: image already in culled list");
- (*itr2)->freeStream();
- mStreamingCulledList.push_back(*itr2);
- mStreamingInactiveList.erase_fast(itr2);
- alxStreamingUpdate();
- return(handle);
- }
- else if(mStreamingCulledList.findImage(handle))
- {
- alxStreamingUpdate();
- return(handle);
- }
- else
- return(NULL_AUDIOHANDLE);
- #endif
- }
- return(handle);
- }
- //--------------------------------------------------------------------------
- // helper function.. create a source and play it
- AUDIOHANDLE alxPlay(const AudioAsset *profile, const MatrixF *transform, const Point3F* /*velocity*/)
- {
- if(profile == NULL)
- return NULL_AUDIOHANDLE;
- AUDIOHANDLE handle = alxCreateSource(profile->getAudioDescription(), profile->getAudioFile(), transform, NULL);
- if(handle != NULL_AUDIOHANDLE)
- return(alxPlay(handle));
- return(handle);
- }
- bool alxPause( AUDIOHANDLE handle )
- {
- if(handle == NULL_AUDIOHANDLE)
- return false;
- U32 index = alxFindIndex( handle );
- alSourcePause( mSource[index] );
- ALint state;
- alGetSourcei(mSource[index], AL_SOURCE_STATE, &state);
- if( state==AL_PAUSED)
- {
- mResumePosition[index] = -1;
- return true;
- }
- alGetSourcei(mSource[index], AL_SAMPLE_OFFSET, &mResumePosition[index]);
- return alxCheckError("alxPause()","alGetSourcei");
- }
- void alxUnPause( AUDIOHANDLE handle )
- {
- if(handle == NULL_AUDIOHANDLE)
- return;
-
- U32 index = alxFindIndex(handle);
- ALuint source = mSource[index];
- if( mResumePosition[index] != -1 )
- {
- alSourcei( source, AL_SAMPLE_OFFSET, mResumePosition[index]);
- mResumePosition[index] = -1;
- }
- alxCheckError("alxUnPause()","alSourcei");
- alSourcePlay( source );
- alxCheckError("alxUnPause()","alSourcePlay");
- }
- //--------------------------------------------------------------------------
- void alxStop(AUDIOHANDLE handle)
- {
- U32 index = alxFindIndex(handle);
- // stop it
- if(index != MAX_AUDIOSOURCES)
- {
- if(!(mHandle[index] & AUDIOHANDLE_INACTIVE_BIT))
- {
- alSourceStop(mSource[index]);
- }
- alSourcei(mSource[index], AL_BUFFER, AL_NONE);
- mSampleEnvironment[index] = 0;
- mHandle[index] = NULL_AUDIOHANDLE;
- mBuffer[index] = 0;
- }
- // remove loopingImage and add it to the free list
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- // remove from inactive/culled list
- if((*itr)->mHandle & AUDIOHANDLE_INACTIVE_BIT)
- {
- LoopingList::iterator tmp = mLoopingInactiveList.findImage(handle);
- // inactive?
- if(tmp)
- mLoopingInactiveList.erase_fast(tmp);
- else
- {
- //culled?
- tmp = mLoopingCulledList.findImage(handle);
- AssertFatal(tmp, "alxStop: failed to find inactive looping source");
- mLoopingCulledList.erase_fast(tmp);
- }
- }
- AssertFatal(!mLoopingInactiveList.findImage((*itr)->mHandle), "alxStop: handle in inactive list");
- AssertFatal(!mLoopingCulledList.findImage((*itr)->mHandle), "alxStop: handle in culled list");
- // remove it
- (*itr)->clear();
- mLoopingFreeList.push_back(*itr);
- mLoopingList.erase_fast(itr);
- }
- // remove streamingImage and add it to the free list
- StreamingList::iterator itr2 = mStreamingList.findImage(handle);
- if(itr2)
- {
- // remove from inactive/culled list
- if((*itr2)->mHandle & AUDIOHANDLE_INACTIVE_BIT)
- {
- StreamingList::iterator tmp = mStreamingInactiveList.findImage(handle);
- // inactive?
- if(tmp)
- mStreamingInactiveList.erase_fast(tmp);
- else
- {
- //culled?
- tmp = mStreamingCulledList.findImage(handle);
- AssertFatal(tmp, "alxStop: failed to find inactive looping source");
- mStreamingCulledList.erase_fast(tmp);
- }
- }
- AssertFatal(!mStreamingInactiveList.findImage((*itr2)->mHandle), "alxStop: handle in inactive list");
- AssertFatal(!mStreamingCulledList.findImage((*itr2)->mHandle), "alxStop: handle in culled list");
- // remove it
- (*itr2)->freeStream();
- delete(*itr2);
- mStreamingList.erase_fast(itr2);
- }
- }
- //--------------------------------------------------------------------------
- void alxStopAll()
- {
- // stop all open sources
- for(S32 i = mNumSources - 1; i >= 0; i--)
- if(mHandle[i] != NULL_AUDIOHANDLE)
- alxStop(mHandle[i]);
- // stop all looping sources
- while(mLoopingList.size())
- alxStop(mLoopingList.last()->mHandle);
- // stop all streaming sources
- while(mStreamingList.size())
- alxStop(mStreamingList.last()->mHandle);
- }
- void alxLoopSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat value)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_GAIN:
- (*itr)->mDescription.mVolume = Audio::DBToLinear(value);
- break;
- case AL_GAIN_LINEAR:
- (*itr)->mDescription.mVolume = value;
- break;
- case AL_PITCH:
- (*itr)->mPitch = value;
- break;
- case AL_REFERENCE_DISTANCE:
- (*itr)->mDescription.mReferenceDistance = value;
- break;
- case AL_CONE_OUTER_GAIN:
- (*itr)->mDescription.mMaxDistance = value;
- break;
- }
- }
- }
- void alxLoopSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat value1, ALfloat value2, ALfloat value3)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_POSITION:
- (*itr)->mPosition.x = value1;
- (*itr)->mPosition.y = value2;
- (*itr)->mPosition.z = value3;
- break;
- case AL_DIRECTION:
- (*itr)->mDirection.x = value1;
- (*itr)->mDirection.y = value2;
- (*itr)->mDirection.z = value3;
- break;
- }
- }
- }
- void alxLoopSourcei(AUDIOHANDLE handle, ALenum pname, ALint value)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- //case AL_SOURCE_AMBIENT:
- // (*itr)->mDescription.mIs3D = value;
- // break;
- case AL_CONE_INNER_ANGLE:
- (*itr)->mDescription.mConeInsideAngle = value;
- break;
- case AL_CONE_OUTER_ANGLE:
- (*itr)->mDescription.mConeOutsideAngle = value;
- break;
- }
- }
- }
- void alxLoopGetSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat *value)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_GAIN:
- *value = Audio::linearToDB((*itr)->mDescription.mVolume);
- break;
- case AL_GAIN_LINEAR:
- *value = (*itr)->mDescription.mVolume;
- break;
- case AL_PITCH:
- *value = (*itr)->mPitch;
- break;
- case AL_REFERENCE_DISTANCE:
- *value = (*itr)->mDescription.mReferenceDistance;
- break;
- case AL_CONE_OUTER_GAIN:
- *value = (*itr)->mDescription.mMaxDistance;
- break;
- }
- }
- }
- void alxLoopGetSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat *value1, ALfloat *value2, ALfloat *value3)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_POSITION:
- *value1 = (*itr)->mPosition.x;
- *value2 = (*itr)->mPosition.y;
- *value3 = (*itr)->mPosition.z;
- break;
- case AL_DIRECTION:
- *value1 = (*itr)->mDirection.x;
- *value2 = (*itr)->mDirection.y;
- *value3 = (*itr)->mDirection.z;
- break;
- }
- }
- }
- void alxLoopGetSourcei(AUDIOHANDLE handle, ALenum pname, ALint *value)
- {
- LoopingList::iterator itr = mLoopingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- //case AL_SOURCE_AMBIENT:
- // *value = (*itr)->mDescription.mIs3D;
- // break;
- case AL_LOOPING:
- *value = true;
- break;
- case AL_CONE_INNER_ANGLE:
- *value = (*itr)->mDescription.mConeInsideAngle;
- break;
- case AL_CONE_OUTER_ANGLE:
- *value = (*itr)->mDescription.mConeOutsideAngle;
- break;
- }
- }
- }
- //------------------------------------------------------
- void alxStreamSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat value)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_GAIN:
- (*itr)->mDescription.mVolume = Audio::DBToLinear(value);
- break;
- case AL_GAIN_LINEAR:
- (*itr)->mDescription.mVolume = value;
- break;
- case AL_PITCH:
- (*itr)->mPitch = value;
- break;
- case AL_REFERENCE_DISTANCE:
- (*itr)->mDescription.mReferenceDistance = value;
- break;
- case AL_CONE_OUTER_GAIN:
- (*itr)->mDescription.mMaxDistance = value;
- break;
- }
- }
- }
- void alxStreamSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat value1, ALfloat value2, ALfloat value3)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_POSITION:
- (*itr)->mPosition.x = value1;
- (*itr)->mPosition.y = value2;
- (*itr)->mPosition.z = value3;
- break;
- case AL_DIRECTION:
- (*itr)->mDirection.x = value1;
- (*itr)->mDirection.y = value2;
- (*itr)->mDirection.z = value3;
- break;
- }
- }
- }
- void alxStreamSourcei(AUDIOHANDLE handle, ALenum pname, ALint value)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- //case AL_SOURCE_AMBIENT:
- // (*itr)->mDescription.mIs3D = value;
- // break;
- case AL_CONE_INNER_ANGLE:
- (*itr)->mDescription.mConeInsideAngle = value;
- break;
- case AL_CONE_OUTER_ANGLE:
- (*itr)->mDescription.mConeOutsideAngle = value;
- break;
- }
- }
- }
- void alxStreamGetSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat *value)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_GAIN:
- *value = Audio::linearToDB((*itr)->mDescription.mVolume);
- break;
- case AL_GAIN_LINEAR:
- *value = (*itr)->mDescription.mVolume;
- break;
- case AL_PITCH:
- *value = (*itr)->mPitch;
- break;
- case AL_REFERENCE_DISTANCE:
- *value = (*itr)->mDescription.mReferenceDistance;
- break;
- case AL_CONE_OUTER_GAIN:
- *value = (*itr)->mDescription.mMaxDistance;
- break;
- }
- }
- }
- void alxStreamGetSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat *value1, ALfloat *value2, ALfloat *value3)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- case AL_POSITION:
- *value1 = (*itr)->mPosition.x;
- *value2 = (*itr)->mPosition.y;
- *value3 = (*itr)->mPosition.z;
- break;
- case AL_DIRECTION:
- *value1 = (*itr)->mDirection.x;
- *value2 = (*itr)->mDirection.y;
- *value3 = (*itr)->mDirection.z;
- break;
- }
- }
- }
- void alxStreamGetSourcei(AUDIOHANDLE handle, ALenum pname, ALint *value)
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if(itr)
- {
- switch(pname)
- {
- //case AL_SOURCE_AMBIENT:
- // *value = (*itr)->mDescription.mIs3D;
- // break;
- case AL_LOOPING:
- *value = true;
- break;
- case AL_CONE_INNER_ANGLE:
- *value = (*itr)->mDescription.mConeInsideAngle;
- break;
- case AL_CONE_OUTER_ANGLE:
- *value = (*itr)->mDescription.mConeOutsideAngle;
- break;
- }
- }
- }
- //--------------------------------------------------------------------------
- // AL get/set methods: Source
- //--------------------------------------------------------------------------
- // - only need to worry about playing sources.. proper volume gets set on
- // create source (so, could get out of sync if someone changes volume between
- // a createSource and playSource call...)
- void alxUpdateTypeGain(U32 type)
- {
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] == NULL_AUDIOHANDLE)
- continue;
- if(type != mType[i])
- continue;
- ALint state = AL_STOPPED;
- alGetSourcei(mSource[i], AL_SOURCE_STATE, &state);
- if(state == AL_PLAYING)
- {
- // volume = SourceVolume * ChannelVolume * MasterVolume
- F32 vol = mClampF(mSourceVolume[i] * mAudioChannelVolumes[mType[i]] * mMasterVolume, 0.f, 1.f);
- alSourcef(mSource[i], AL_GAIN, Audio::linearToDB(vol) );
- }
- }
- }
- void alxSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat value)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- {
- // ensure gain_linear
- if(pname == AL_GAIN)
- {
- value = Audio::DBToLinear(value);
- pname = AL_GAIN_LINEAR;
- }
- // need to process gain settings (so source can be affected by channel/master gains)
- if(pname == AL_GAIN_LINEAR)
- {
- U32 idx = alxFindIndex(handle);
- AssertFatal(idx != MAX_AUDIOSOURCES, "alxSourcef: handle not located for found source");
- if(idx == MAX_AUDIOSOURCES)
- return;
- // update the stored value
- mSourceVolume[idx] = value;
- // volume = SourceVolume * ChannelVolume * MasterVolume
- // #ifdef REL_WORKAROUND
- // ALint val = AL_TRUE;
- // alGetSourcei(source, AL_SOURCE_ABSOLUTE, &val);
- // if(val == AL_FALSE)
- // #else
- // ALint val = AL_FALSE;
- // alGetSourcei(source, AL_SOURCE_RELATIVE, &val);
- // if(val == AL_TRUE)
- // #endif
- {
- F32 vol = mClampF(mSourceVolume[idx] * mAudioChannelVolumes[mType[idx]] * mMasterVolume, 0.f, 1.f);
- alSourcef(source, AL_GAIN, Audio::linearToDB(vol) );
- }
- }
- else
- alSourcef(source, pname, value);
- }
- alxLoopSourcef(handle, pname, value);
- alxStreamSourcef(handle, pname, value);
- }
- void alxSourcefv(AUDIOHANDLE handle, ALenum pname, ALfloat *values)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- alSourcefv(source, pname, values);
- if((pname == AL_POSITION) || (pname == AL_DIRECTION) || (pname == AL_VELOCITY)) {
- alxLoopSource3f(handle, pname, values[0], values[1], values[2]);
- alxStreamSource3f(handle, pname, values[0], values[1], values[2]);
- }
- }
- void alxSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat value1, ALfloat value2, ALfloat value3)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- {
- ALfloat values[3];
- values[0] = value1;
- values[1] = value2;
- values[2] = value3;
- alSourcefv(source, pname, values);
- }
- alxLoopSource3f(handle, pname, value1, value2, value3);
- alxStreamSource3f(handle, pname, value1, value2, value3);
- }
- void alxSourcei(AUDIOHANDLE handle, ALenum pname, ALint value)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- alSourcei(source, pname, value);
- alxLoopSourcei(handle, pname, value);
- alxStreamSourcei(handle, pname, value);
- }
- // sets the position and direction of the source
- void alxSourceMatrixF(AUDIOHANDLE handle, const MatrixF *transform)
- {
- ALuint source = alxFindSource(handle);
- Point3F pos;
- transform->getColumn(3, &pos);
- Point3F dir;
- transform->getColumn(1, &dir);
- if(source != INVALID_SOURCE)
- {
- // OpenAL uses a Right-Handed corrdinate system so flip the orientation vector
- alSource3f(source, AL_POSITION, pos.x, pos.y, pos.z);
- alSource3f(source, AL_DIRECTION, -dir.x, -dir.y, -dir.z);
- }
- alxLoopSource3f(handle, AL_POSITION, pos.x, pos.y, pos.z);
- alxLoopSource3f(handle, AL_DIRECTION, dir.x, dir.y, dir.z);
- alxStreamSource3f(handle, AL_POSITION, pos.x, pos.y, pos.z);
- alxStreamSource3f(handle, AL_DIRECTION, dir.x, dir.y, dir.z);
- }
- //--------------------------------------------------------------------------
- void alxGetSourcef(AUDIOHANDLE handle, ALenum pname, ALfloat *value)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- {
- // gain queries return unattenuated values
- if((pname == AL_GAIN) || (pname == AL_GAIN_LINEAR))
- {
- U32 idx = alxFindIndex(handle);
- AssertFatal(idx != MAX_AUDIOSOURCES, "alxGetSourcef: found source but handle is invalid");
- if(idx == MAX_AUDIOSOURCES)
- {
- *value = 0.f;
- return;
- }
- if(pname == AL_GAIN)
- *value = Audio::linearToDB(mSourceVolume[idx]);
- else
- *value = mSourceVolume[idx];
- }
- else
- alGetSourcef(source, pname, value);
- }
- else if(handle & AUDIOHANDLE_LOOPING_BIT)
- alxLoopGetSourcef(handle, pname, value);
- else
- alxStreamGetSourcef(handle, pname, value);
- }
- void alxGetSourcefv(AUDIOHANDLE handle, ALenum pname, ALfloat *values)
- {
- if((pname == AL_POSITION) || (pname == AL_DIRECTION) || (pname == AL_VELOCITY))
- alxGetSource3f(handle, pname, &values[0], &values[1], &values[2]);
- }
- void alxGetSource3f(AUDIOHANDLE handle, ALenum pname, ALfloat *value1, ALfloat *value2, ALfloat *value3)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- {
- ALfloat values[3];
- alGetSourcefv(source, pname, values);
- *value1 = values[0];
- *value2 = values[1];
- *value3 = values[2];
- }
- else if(handle & AUDIOHANDLE_LOOPING_BIT)
- alxLoopGetSource3f(handle, pname, value1, value2, value3);
- else
- alxStreamGetSource3f(handle, pname, value1, value2, value3);
- }
- void alxGetSourcei(AUDIOHANDLE handle, ALenum pname, ALint *value)
- {
- ALuint source = alxFindSource(handle);
- if(source != INVALID_SOURCE)
- alGetSourcei(source, pname, value);
- else if(handle & AUDIOHANDLE_LOOPING_BIT)
- alxLoopGetSourcei(handle, pname, value);
- else
- alxStreamGetSourcei(handle, pname, value);
- }
- //--------------------------------------------------------------------------
- /** alListenerfv extension for use with MatrixF's
- Set the listener's position and orientation using a matrix
- */
- void alxListenerMatrixF(const MatrixF *transform)
- {
- Point3F p1, p2;
- transform->getColumn(3, &p1);
- alListener3f(AL_POSITION, p1.x, p1.y, p1.z);
- transform->getColumn(2, &p1); // Up Vector
- transform->getColumn(1, &p2); // Forward Vector
- F32 orientation[6];
- orientation[0] = -p1.x;
- orientation[1] = -p1.y;
- orientation[2] = -p1.z;
- orientation[3] = p2.x;
- orientation[4] = p2.y;
- orientation[5] = p2.z;
- alListenerfv(AL_ORIENTATION, orientation);
- }
- //--------------------------------------------------------------------------
- /** alListenerf extension supporting linear gain
- */
- void alxListenerf(ALenum param, ALfloat value)
- {
- if (param == AL_GAIN_LINEAR)
- {
- value = Audio::linearToDB(value);
- param = AL_GAIN;
- }
- alListenerf(param, value);
- }
- //--------------------------------------------------------------------------
- /** alGetListenerf extension supporting linear gain
- */
- void alxGetListenerf(ALenum param, ALfloat *value)
- {
- if (param == AL_GAIN_LINEAR)
- {
- alGetListenerf(AL_GAIN, value);
- *value = Audio::DBToLinear(*value);
- }
- else
- alGetListenerf(param, value);
- }
- //--------------------------------------------------------------------------
- // Simple metrics
- //--------------------------------------------------------------------------
- #ifdef TORQUE_GATHER_METRICS
- static void alxGatherMetrics()
- {
- S32 mNumOpenHandles = 0;
- S32 mNumOpenLoopingHandles = 0;
- S32 mNumOpenStreamingHandles = 0;
- S32 mNumActiveStreams = 0;
- S32 mNumNullActiveStreams = 0;
- S32 mNumActiveLoopingStreams = 0;
- S32 mNumActiveStreamingStreams = 0;
- S32 mNumLoopingStreams = 0;
- S32 mNumInactiveLoopingStreams = 0;
- S32 mNumCulledLoopingStreams = 0;
- S32 mNumStreamingStreams = 0;
- S32 mNumInactiveStreamingStreams = 0;
- S32 mNumCulledStreamingStreams = 0;
- // count installed streams and open handles
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] != NULL_AUDIOHANDLE)
- {
- mNumOpenHandles++;
- if(mHandle[i] & AUDIOHANDLE_LOOPING_BIT)
- mNumOpenLoopingHandles++;
- if(mHandle[i] & AUDIOHANDLE_STREAMING_BIT)
- mNumOpenStreamingHandles++;
- }
- ALint state = AL_STOPPED;
- alGetSourcei(mSource[i], AL_SOURCE_STATE, &state);
- if(state == AL_PLAYING)
- {
- mNumActiveStreams++;
- if(mHandle[i] == NULL_AUDIOHANDLE)
- mNumNullActiveStreams++;
- if(mHandle[i] & AUDIOHANDLE_LOOPING_BIT)
- mNumActiveLoopingStreams++;
- if(mHandle[i] & AUDIOHANDLE_STREAMING_BIT)
- mNumActiveStreamingStreams++;
- }
- }
- for(LoopingList::iterator itr = mLoopingList.begin(); itr != mLoopingList.end(); itr++)
- mNumLoopingStreams++;
- for(LoopingList::iterator itr = mLoopingInactiveList.begin(); itr != mLoopingInactiveList.end(); itr++)
- mNumInactiveLoopingStreams++;
- for(LoopingList::iterator itr = mLoopingCulledList.begin(); itr != mLoopingCulledList.end(); itr++)
- mNumCulledLoopingStreams++;
- for(StreamingList::iterator itr = mStreamingList.begin(); itr != mStreamingList.end(); itr++)
- mNumStreamingStreams++;
- for(StreamingList::iterator itr = mStreamingInactiveList.begin(); itr != mStreamingInactiveList.end(); itr++)
- mNumInactiveStreamingStreams++;
- for(StreamingList::iterator itr = mStreamingCulledList.begin(); itr != mStreamingCulledList.end(); itr++)
- mNumCulledStreamingStreams++;
- Con::setIntVariable("Audio::numOpenHandles", mNumOpenHandles);
- Con::setIntVariable("Audio::numOpenLoopingHandles", mNumOpenLoopingHandles);
- Con::setIntVariable("Audio::numOpenStreamingHandles", mNumOpenStreamingHandles);
- Con::setIntVariable("Audio::numActiveStreams", mNumActiveStreams);
- Con::setIntVariable("Audio::numNullActiveStreams", mNumNullActiveStreams);
- Con::setIntVariable("Audio::numActiveLoopingStreams", mNumActiveLoopingStreams);
- Con::setIntVariable("Audio::numActiveStreamingStreams", mNumActiveStreamingStreams);
- Con::setIntVariable("Audio::numLoopingStreams", mNumLoopingStreams);
- Con::setIntVariable("Audio::numInactiveLoopingStreams", mNumInactiveLoopingStreams);
- Con::setIntVariable("Audio::numCulledLoopingStreams", mNumCulledLoopingStreams);
- Con::setIntVariable("Audio::numStreamingStreams", mNumStreamingStreams);
- Con::setIntVariable("Audio::numInactiveStreamingStreams", mNumInactiveStreamingStreams);
- Con::setIntVariable("Audio::numCulledStreamingStreams", mNumCulledStreamingStreams);
- }
- #endif
- //--------------------------------------------------------------------------
- // Audio Update...
- //--------------------------------------------------------------------------
- void alxLoopingUpdate()
- {
- static LoopingList culledList;
- U32 updateTime = Platform::getRealMilliseconds();
- // check if can wakeup the inactive loopers
- if(mLoopingCulledList.size())
- {
- Point3F listener;
- alxGetListenerPoint3F(AL_POSITION, &listener);
- // get the 'sort' value for this sound (could be based on time played...),
- // and add to the culled list
- LoopingList::iterator itr;
- culledList.clear();
- for(itr = mLoopingCulledList.begin(); itr != mLoopingCulledList.end(); itr++)
- {
- if((*itr)->mScore <= MIN_UNCULL_GAIN)
- continue;
- if((updateTime - (*itr)->mCullTime) < MIN_UNCULL_PERIOD)
- continue;
- culledList.push_back(*itr);
- }
- if(!culledList.size())
- return;
- U32 index = MAX_AUDIOSOURCES;
- if(culledList.size() > 1)
- culledList.sort();
- for(itr = culledList.begin(); itr != culledList.end(); itr++)
- {
- if(!findFreeSource(&index))
- {
- // score does not include master volume
- if(!cullSource(&index, (*itr)->mScore))
- break;
- // check buffer
- if(!bool((*itr)->mBuffer))
- {
- // remove from culled list
- LoopingList::iterator tmp;
- tmp = mLoopingCulledList.findImage((*itr)->mHandle);
- AssertFatal(tmp, "alxLoopingUpdate: failed to find culled source");
- mLoopingCulledList.erase_fast(tmp);
- // remove from looping list (and free)
- tmp = mLoopingList.findImage((*itr)->mHandle);
- if(tmp)
- {
- (*tmp)->clear();
- mLoopingFreeList.push_back(*tmp);
- mLoopingList.erase_fast(tmp);
- }
- continue;
- }
- }
- // remove from culled list
- LoopingList::iterator tmp = mLoopingCulledList.findImage((*itr)->mHandle);
- AssertFatal(tmp, "alxLoopingUpdate: failed to find culled source");
- mLoopingCulledList.erase_fast(tmp);
- // restore all state data
- mHandle[index] = (*itr)->mHandle;
- mBuffer[index] = (*itr)->mBuffer;
- mScore[index] = (*itr)->mScore;
- mSourceVolume[index] = (*itr)->mDescription.mVolume;
- mType[index] = (*itr)->mDescription.mVolumeChannel;
- mSampleEnvironment[index] = (*itr)->mEnvironment;
- ALuint source = mSource[index];
- // setup play info
- alGetError();
- alxSourcePlay(source, *itr);
- if(mEnvironmentEnabled)
- alxSourceEnvironment(source, *itr);
- alxPlay(mHandle[index]);
- }
- }
- }
- void alxStreamingUpdate()
- {
- // update buffer queues on active streamers
- // update the loopers
- for(StreamingList::iterator itr = mStreamingList.begin(); itr != mStreamingList.end(); itr++)
- {
- if((*itr)->mHandle & AUDIOHANDLE_INACTIVE_BIT)
- continue;
- (*itr)->updateBuffers();
- }
- static StreamingList culledList;
- U32 updateTime = Platform::getRealMilliseconds();
- // check if can wakeup the inactive loopers
- if(mStreamingCulledList.size())
- {
- Point3F listener;
- alxGetListenerPoint3F(AL_POSITION, &listener);
- // get the 'sort' value for this sound (could be based on time played...),
- // and add to the culled list
- StreamingList::iterator itr;
- culledList.clear();
- for(itr = mStreamingCulledList.begin(); itr != mStreamingCulledList.end(); itr++)
- {
- if((*itr)->mScore <= MIN_UNCULL_GAIN)
- continue;
- if((updateTime - (*itr)->mCullTime) < MIN_UNCULL_PERIOD)
- continue;
- culledList.push_back(*itr);
- }
- if(!culledList.size())
- return;
- U32 index = MAX_AUDIOSOURCES;
- if(culledList.size() > 1)
- culledList.sort();
- for(itr = culledList.begin(); itr != culledList.end(); itr++)
- {
- if(!findFreeSource(&index))
- {
- // score does not include master volume
- if(!cullSource(&index, (*itr)->mScore))
- break;
- // check buffer
- //if(!bool((*itr)->mBuffer))
- //{
- // remove from culled list
- StreamingList::iterator tmp;
- tmp = mStreamingCulledList.findImage((*itr)->mHandle);
- AssertFatal(tmp, "alxStreamingUpdate: failed to find culled source");
- mStreamingCulledList.erase_fast(tmp);
- // remove from streaming list (and free)
- tmp = mStreamingList.findImage((*itr)->mHandle);
- if(tmp)
- {
- delete(*tmp);
- mStreamingList.erase_fast(tmp);
- }
- continue;
- //}
- }
- // remove from culled list
- StreamingList::iterator tmp = mStreamingCulledList.findImage((*itr)->mHandle);
- AssertFatal(tmp, "alxStreamingUpdate: failed to find culled source");
- mStreamingCulledList.erase_fast(tmp);
- alxSourcePlay(*itr);
- // restore all state data
- mHandle[index] = (*itr)->mHandle;
- mScore[index] = (*itr)->mScore;
- mSourceVolume[index] = (*itr)->mDescription.mVolume;
- mType[index] = (*itr)->mDescription.mVolumeChannel;
- mSampleEnvironment[index] = (*itr)->mEnvironment;
- ALuint source = mSource[index];
- (*itr)->mSource = mSource[index];
- // setup play info
- alGetError();
- if(mEnvironmentEnabled)
- alxSourceEnvironment(source, *itr);
- alxPlay(mHandle[index]);
- }
- }
- }
- //--------------------------------------------------------------------------
- void alxCloseHandles()
- {
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] & AUDIOHANDLE_LOADING_BIT)
- continue;
- if(mHandle[i] == NULL_AUDIOHANDLE)
- continue;
- ALint state = 0;
- alGetSourcei(mSource[i], AL_SOURCE_STATE, &state);
- if(state == AL_PLAYING || state == AL_PAUSED)
- continue;
- if(!(mHandle[i] & AUDIOHANDLE_INACTIVE_BIT))
- {
- // should be playing? must have encounted an error.. remove
- LoopingList::iterator itr = mLoopingList.findImage(mHandle[i]);
- if(itr && !((*itr)->mHandle & AUDIOHANDLE_INACTIVE_BIT))
- {
- AssertFatal(!mLoopingInactiveList.findImage((*itr)->mHandle), "alxCloseHandles: image incorrectly in inactive list");
- AssertFatal(!mLoopingCulledList.findImage((*itr)->mHandle), "alxCloseHandles: image already in culled list");
- mLoopingCulledList.push_back(*itr);
- (*itr)->mHandle |= AUDIOHANDLE_INACTIVE_BIT;
- mHandle[i] = NULL_AUDIOHANDLE;
- mBuffer[i] = 0;
- }
- // should be playing? must have encounted an error.. remove
- // StreamingList::iterator itr2 = mStreamingList.findImage(mHandle[i]);
- // if(itr2 && !((*itr2)->mHandle & AUDIOHANDLE_INACTIVE_BIT))
- // {
- // AssertFatal(!mStreamingInactiveList.findImage((*itr2)->mHandle), "alxCloseHandles: image incorrectly in inactive list");
- // AssertFatal(!mStreamingCulledList.findImage((*itr2)->mHandle), "alxCloseHandles: image already in culled list");
- // (*itr2)->freeStream();
- //
- // mStreamingCulledList.push_back(*itr2);
- // (*itr2)->mHandle |= AUDIOHANDLE_INACTIVE_BIT;
- //
- // mHandle[i] = NULL_AUDIOHANDLE;
- // mBuffer[i] = 0;
- // }
- }
- alSourcei(mSource[i], AL_BUFFER, AL_NONE);
- mHandle[i] = NULL_AUDIOHANDLE;
- mBuffer[i] = 0;
- }
- }
- //----------------------------------------------------------------------------------
- // - update the score for each audio source. this is used for culing sources.
- // normal ranges are between 0.f->1.f, voice/loading/music streams are scored
- // outside this range so that they will not be culled
- // - does not scale by attenuated volumes
- void alxUpdateScores(bool sourcesOnly)
- {
- Point3F listener;
- alxGetListenerPoint3F(AL_POSITION, &listener);
- // do the base sources
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] == NULL_AUDIOHANDLE)
- {
- mScore[i] = 0.f;
- continue;
- }
- ALint state = 0;
- alGetSourcei(mSource[i], AL_SOURCE_STATE, &state);
- if(state==AL_PAUSED)
- continue;
- // grab the volume.. (not attenuated by master for score)
- F32 volume = mSourceVolume[i] * mAudioChannelVolumes[mType[i]];
- // 3d?
- mScore[i] = volume;
- #ifdef REL_WORKAROUND
- ALint val = AL_FALSE;
- alGetSourcei(mSource[i], AL_SOURCE_ABSOLUTE, &val);
- if(val == AL_TRUE)
- #else
- ALint val = AL_FALSE;
- alGetSourcei(mSource[i], AL_SOURCE_RELATIVE, &val);
- if(val == AL_FALSE)
- #endif
- {
- // approximate 3d volume
- Point3F pos;
- alGetSourcefv(mSource[i], AL_POSITION, (ALfloat*)((F32*)pos) );
- ALfloat min=0, max=1;
- alGetSourcef(mSource[i], AL_REFERENCE_DISTANCE, &min);
- alGetSourcef(mSource[i], AL_MAX_DISTANCE, &max);
- pos -= listener;
- F32 dist = pos.magnitudeSafe();
- if(dist >= max)
- mScore[i] = 0.f;
- else if(dist > min)
- mScore[i] *= (max-dist) / (max-min);
- }
- }
- if(sourcesOnly)
- return;
- U32 updateTime = Platform::getRealMilliseconds();
- // update the loopers
- for(LoopingList::iterator itr = mLoopingList.begin(); itr != mLoopingList.end(); itr++)
- {
- if(!((*itr)->mHandle & AUDIOHANDLE_INACTIVE_BIT))
- continue;
- if((updateTime - (*itr)->mCullTime) < MIN_UNCULL_PERIOD)
- continue;
- (*itr)->mScore = (*itr)->mDescription.mVolume;
- if((*itr)->mDescription.mIs3D)
- {
- Point3F pos = (*itr)->mPosition - listener;
- F32 dist = pos.magnitudeSafe();
- F32 min = (*itr)->mDescription.mReferenceDistance;
- F32 max = (*itr)->mDescription.mMaxDistance;
- if(dist >= max)
- (*itr)->mScore = 0.f;
- else if(dist > min)
- (*itr)->mScore *= (max-dist) / (max-min);
- }
- // attenuate by the channel gain
- (*itr)->mScore *= mAudioChannelVolumes[(*itr)->mDescription.mVolumeChannel];
- }
- // update the streamers
- for(StreamingList::iterator itr = mStreamingList.begin(); itr != mStreamingList.end(); itr++)
- {
- if(!((*itr)->mHandle & AUDIOHANDLE_INACTIVE_BIT))
- continue;
- if((updateTime - (*itr)->mCullTime) < MIN_UNCULL_PERIOD)
- continue;
- (*itr)->mScore = (*itr)->mDescription.mVolume;
- if((*itr)->mDescription.mIs3D)
- {
- Point3F pos = (*itr)->mPosition - listener;
- F32 dist = pos.magnitudeSafe();
- F32 min = (*itr)->mDescription.mReferenceDistance;
- F32 max = (*itr)->mDescription.mMaxDistance;
- if(dist >= max)
- (*itr)->mScore = 0.f;
- else if(dist > min)
- (*itr)->mScore *= (max-dist) / (max-min);
- }
- // attenuate by the channel gain
- (*itr)->mScore *= mAudioChannelVolumes[(*itr)->mDescription.mVolumeChannel];
- }
- }
- // the directx buffers are set to mute at max distance, but many of the providers seem to
- // ignore this flag... that is why this is here
- void alxUpdateMaxDistance()
- {
- Point3F listener;
- alxGetListenerPoint3F(AL_POSITION, &listener);
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] == NULL_AUDIOHANDLE)
- continue;
- #ifdef REL_WORKAROUND
- ALint val = AL_FALSE;
- alGetSourcei(mSource[i], AL_SOURCE_ABSOLUTE, &val);
- if(val == AL_FALSE)
- #else
- ALint val = AL_FALSE;
- alGetSourcei(mSource[i], AL_SOURCE_RELATIVE, &val);
- if(val == AL_TRUE)
- #endif
- continue;
- Point3F pos;
- alGetSourcefv(mSource[i], AL_POSITION, (F32*)pos);
- F32 dist = 0.f;
- alGetSourcef(mSource[i], AL_MAX_DISTANCE, &dist);
- pos -= listener;
- dist -= pos.len();
- F32 gain = (dist < 0.f) ? 0.f : mSourceVolume[i] * mAudioChannelVolumes[mType[i]] * mMasterVolume;
- alSourcef(mSource[i], AL_GAIN, Audio::linearToDB(gain));
- }
- }
- //--------------------------------------------------------------------------
- // Called to update alx system
- //--------------------------------------------------------------------------
- void alxUpdate()
- {
- alxUpdateMaxDistance();
- alxCloseHandles();
- alxUpdateScores(false);
- alxLoopingUpdate();
- alxStreamingUpdate();
- #ifdef TORQUE_GATHER_METRICS
- alxGatherMetrics();
- #endif
- }
- //--------------------------------------------------------------------------
- // Misc
- //--------------------------------------------------------------------------
- // client-side function only
- ALuint alxGetWaveLen(ALuint buffer)
- {
- if(buffer == AL_INVALID)
- return(0);
- ALint frequency = 0;
- ALint bits = 0;
- ALint channels = 0;
- ALint size;
- alGetBufferi(buffer, AL_FREQUENCY, &frequency);
- alGetBufferi(buffer, AL_BITS, &bits);
- alGetBufferi(buffer, AL_CHANNELS, &channels);
- alGetBufferi(buffer, AL_SIZE, &size);
- if(!frequency || !bits || !channels)
- {
- Con::errorf(ConsoleLogEntry::General, "alxGetWaveLen: invalid buffer");
- return(0);
- }
- ALuint len = (ALuint)((F64(size) * 8000.f) / F64(frequency * bits * channels));
- return(len);
- }
- bool alxCheckError(const char* sourceFuncName, const char* alFuncName)
- {
- ALenum errorVal = alGetError();
- switch (errorVal)
- {
- case AL_NO_ERROR:
- break;
- case AL_INVALID_NAME:
- Con::errorf("%s - %s OpenAL AL_INVALID_NAME error code returned", sourceFuncName, alFuncName);
- break;
- case AL_INVALID_ENUM:
- Con::errorf("%s - %s OpenAL AL_INVALID_ENUM error code returned", sourceFuncName, alFuncName);
- break;
- case AL_INVALID_VALUE:
- Con::errorf("%s - %s OpenAL AL_INVALID_VALUE error code returned", sourceFuncName, alFuncName);
- break;
- case AL_INVALID_OPERATION:
- Con::errorf("%s - %s OpenAL AL_INVALID_OPERATION error code returned", sourceFuncName, alFuncName);
- break;
- case AL_OUT_OF_MEMORY:
- Con::errorf("%s - %s OpenAL AL_OUT_OF_MEMORY error code returned", sourceFuncName, alFuncName);
- break;
- default:
- Con::errorf("%s - %s OpenAL has encountered a problem and won't tell us what it is. %d", sourceFuncName, alFuncName, errorVal);
- };
- if (errorVal == AL_NO_ERROR)
- return true;
- else
- return false;
- }
- //--------------------------------------------------------------------------
- // Environment:
- //--------------------------------------------------------------------------
- void alxEnvironmenti(ALenum pname, ALint value)
- {
- /* todo
- alEnvironmentiIASIG(mEnvironment, pname, value);
- */
- }
- void alxEnvironmentf(ALenum pname, ALfloat value)
- {
- /* todo
- alEnvironmentfIASIG(mEnvironment, pname, value);
- */
- }
- void alxGetEnvironmenti(ALenum pname, ALint * value)
- {
- /* todo
- alGetEnvironmentiIASIG_EXT(mEnvironment, pname, value);
- */
- }
- void alxGetEnvironmentf(ALenum pname, ALfloat * value)
- {
- /* todo
- alGetEnvironmentfIASIG_EXT(mEnvironment, pname, value);
- */
- }
- void alxEnableEnvironmental(bool enable)
- {
- if(mEnvironmentEnabled == enable)
- return;
- // go through the playing sources and update their reverb mix
- // - only 3d samples get environmental fx
- // - only loopers can reenable fx
- for(U32 i = 0; i < mNumSources; i++)
- {
- if(mHandle[i] == NULL_AUDIOHANDLE)
- continue;
- ALint val = AL_FALSE;
- // 3d?
- #ifdef REL_WORKAROUND
- alGetSourcei(mSource[i], AL_SOURCE_ABSOLUTE, &val);
- if(val == AL_FALSE)
- #else
- alGetSourcei(mSource[i], AL_SOURCE_RELATIVE, &val);
- if(val == AL_TRUE)
- #endif
- continue;
- // stopped?
- val = AL_STOPPED;
- alGetSourcei(mSource[i], AL_SOURCE_STATE, &val);
- // only looping sources can reenable environmental effects (no description around
- // for the non-loopers)
- if(enable)
- {
- LoopingList::iterator itr = mLoopingList.findImage(mHandle[i]);
- if(!itr)
- continue;
- /* todo
- alSourcef(mSource[i], AL_ENV_SAMPLE_REVERB_MIX_EXT, (*itr)->mDescription.mEnvironmentLevel);
- */
- }
- /* todo
- else
- alSourcef(mSource[i], AL_ENV_SAMPLE_REVERB_MIX_EXT, 0.f);
- */
- }
- mEnvironmentEnabled = enable;
- }
- void alxSetEnvironment(const AudioEnvironment * env)
- {
- /* todo
- mCurrentEnvironment = const_cast<AudioEnvironment*>(env);
- // reset environmental audio?
- if(!env)
- {
- alxEnvironmenti(AL_ENV_ROOM_IASIG, AL_ENVIRONMENT_GENERIC);
- return;
- }
- // room trashes all the values
- if(env->mUseRoom)
- {
- alxEnvironmenti(AL_ENV_ROOM_IASIG, env->mRoom);
- return;
- }
- // set all the params
- alxEnvironmenti(AL_ENV_ROOM_HIGH_FREQUENCY_IASIG, env->mRoomHF);
- alxEnvironmenti(AL_ENV_REFLECTIONS_IASIG, env->mReflections);
- alxEnvironmenti(AL_ENV_REVERB_IASIG, env->mReverb);
- alxEnvironmentf(AL_ENV_ROOM_ROLLOFF_FACTOR_IASIG, env->mRoomRolloffFactor);
- alxEnvironmentf(AL_ENV_DECAY_TIME_IASIG, env->mDecayTime);
- alxEnvironmentf(AL_ENV_DECAY_HIGH_FREQUENCY_RATIO_IASIG, env->mDecayTime);
- alxEnvironmentf(AL_ENV_REFLECTIONS_DELAY_IASIG, env->mReflectionsDelay);
- alxEnvironmentf(AL_ENV_REVERB_DELAY_IASIG, env->mReverbDelay);
- alxEnvironmentf(AL_ENV_DENSITY_IASIG, env->mAirAbsorption);
- alxEnvironmentf(AL_ENV_DIFFUSION_IASIG, env->mEnvironmentDiffusion);
- // ext:
- alxEnvironmenti(AL_ENV_ROOM_VOLUME_EXT, env->mRoomVolume);
- alxEnvironmenti(AL_ENV_FLAGS_EXT, env->mFlags);
- alxEnvironmentf(AL_ENV_EFFECT_VOLUME_EXT, env->mEffectVolume);
- alxEnvironmentf(AL_ENV_DAMPING_EXT, env->mDamping);
- alxEnvironmentf(AL_ENV_ENVIRONMENT_SIZE_EXT, env->mEnvironmentSize);
- */
- }
- const AudioEnvironment * alxGetEnvironment()
- {
- return(mCurrentEnvironment);
- }
- F32 alxGetStreamPosition( AUDIOHANDLE handle )
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if( !itr )
- return -1.f;
- return (*itr)->getElapsedTime();
- }
- F32 alxGetStreamDuration( AUDIOHANDLE handle )
- {
- StreamingList::iterator itr = mStreamingList.findImage(handle);
- if( !itr )
- return -1.f;
- return (*itr)->getTotalTime();
- }
- // Namespace: Audio ---------------------------------------------------------
- namespace Audio
- {
- //---------------------------------------------------------------------------
- // the following db<->linear conversion functions come from Loki openAL linux driver
- // code, here more for completeness than anything else (all current audio code
- // uses AL_GAIN_LINEAR)... in Audio:: so that looping updates and audio channel updates
- // can convert gain types and to give the miles driver access
- static const F32 logtab[] = {
- 0.00f, 0.001f, 0.002f, 0.003f, 0.004f,
- 0.005f, 0.01f, 0.011f, 0.012f, 0.013f,
- 0.014f, 0.015f, 0.016f, 0.02f, 0.021f,
- 0.022f, 0.023f, 0.024f, 0.025f, 0.03f,
- 0.031f, 0.032f, 0.033f, 0.034f, 0.04f,
- 0.041f, 0.042f, 0.043f, 0.044f, 0.05f,
- 0.051f, 0.052f, 0.053f, 0.054f, 0.06f,
- 0.061f, 0.062f, 0.063f, 0.064f, 0.07f,
- 0.071f, 0.072f, 0.073f, 0.08f, 0.081f,
- 0.082f, 0.083f, 0.084f, 0.09f, 0.091f,
- 0.092f, 0.093f, 0.094f, 0.10f, 0.101f,
- 0.102f, 0.103f, 0.11f, 0.111f, 0.112f,
- 0.113f, 0.12f, 0.121f, 0.122f, 0.123f,
- 0.124f, 0.13f, 0.131f, 0.132f, 0.14f,
- 0.141f, 0.142f, 0.143f, 0.15f, 0.151f,
- 0.152f, 0.16f, 0.161f, 0.162f, 0.17f,
- 0.171f, 0.172f, 0.18f, 0.181f, 0.19f,
- 0.191f, 0.192f, 0.20f, 0.201f, 0.21f,
- 0.211f, 0.22f, 0.221f, 0.23f, 0.231f,
- 0.24f, 0.25f, 0.251f, 0.26f, 0.27f,
- 0.271f, 0.28f, 0.29f, 0.30f, 0.301f,
- 0.31f, 0.32f, 0.33f, 0.34f, 0.35f,
- 0.36f, 0.37f, 0.38f, 0.39f, 0.40f,
- 0.41f, 0.43f, 0.50f, 0.60f, 0.65f,
- 0.70f, 0.75f, 0.80f, 0.85f, 0.90f,
- 0.95f, 0.97f, 0.99f };
- const int logmax = sizeof logtab / sizeof *logtab;
- F32 DBToLinear(F32 value)
- {
- if(value <= 0.f)
- return(0.f);
- if(value >= 1.f)
- return(1.f);
- S32 max = logmax;
- S32 min = 0;
- S32 mid;
- S32 last = -1;
- mid = (max - min) / 2;
- do {
- last = mid;
- if(logtab[mid] == value)
- break;
- if(logtab[mid] < value)
- min = mid;
- else
- max = mid;
- mid = min + ((max - min) / 2);
- } while(last != mid);
- return((F32)mid / logmax);
- }
- F32 linearToDB(F32 value)
- {
- if(value <= 0.f)
- return(0.f);
- if(value >= 1.f)
- return(1.f);
- return(logtab[(U32)(logmax * value)]);
- }
- //---------------------------------------------------------------------------
- static ALvoid errorCallback(ALbyte *msg)
- {
- // used to allow our OpenAL implementation to display info on the console
- Con::errorf(ConsoleLogEntry::General, (const char *)msg);
- }
- void shutdownContext()
- {
- // invalidate active handles
- dMemset(mSource, 0, sizeof(mSource));
- }
- //--------------------------------------------------------------------------
- bool OpenALInit()
- {
- Con::printSeparator();
- Con::printf("Audio initialization:");
- OpenALShutdown();
- if(!OpenALDLLInit())
- return false;
- // Open a device
- #ifdef TORQUE_OS_IOS
- ALenum result = AL_NO_ERROR;
- mDevice = alcOpenDevice(NULL);
- result = alGetError();
- AssertNoOALError("Error opening output device");
- //-Mat for streaming mp3
- //-Sven Moved up to allow for music and audio to run with iPod Music
- SoundEngine::SoundEngine_Initialize( DEFAULT_SOUND_OUTPUT_RATE );
-
- // PUAP -Mat output rate must be set before calling alcCreateContext()
- alcMacOSXMixerOutputRateProc(DEFAULT_SOUND_OUTPUT_RATE);
-
- // Create an openAL context
- mContext = alcCreateContext(mDevice,NULL);
- // Make this context the active context
- alcMakeContextCurrent(mContext);
- AssertNoOALError("Error setting current OpenAL context");
- //now request the number of audio sources we want, if we can't get that many decrement until we have a number we can get
- #elif defined(TORQUE_OS_OSX)
- mDevice = alcOpenDevice((const ALCchar*)NULL);
- #elif defined(TORQUE_OS_ANDROID)
- mDevice = alcOpenDevice("openal-soft");
- #else
- mDevice = (ALCvoid *)alcOpenDevice((const ALCchar*)NULL);
- #endif
- if (mDevice == (ALCvoid *)NULL)
- return false;
- // Create an openAL context
- #if defined(TORQUE_OS_LINUX) || defined(TORQUE_OS_OPENBSD)
- int freq = Con::getIntVariable("Pref::Unix::OpenALFrequency");
- if (freq == 0)
- freq = 22050;
- Con::printf(" Setting OpenAL output frequency to %d", freq);
- // some versions of openal have bugs converting between 22050 and 44100
- // samples when the lib is in 44100 mode.
- int attrlist[] = {
- // this 0x100 is "ALC_FREQUENCY" in the linux openal implementation.
- // it doesn't match the value of the creative headers, so we can't use
- // that define. seems like linux torque really shouldn't be using the
- // creative headers.
- 0x100, freq,
- 0
- };
- mContext = alcCreateContext((ALCdevice*)mDevice,attrlist);
- #elif defined(TORQUE_OS_ANDROID)
- mContext = alcCreateContext((ALCdevice*)mDevice, NULL);
- #elif defined(TORQUE_OS_EMSCRIPTEN)
- mContext = alcCreateContext((ALCdevice*)mDevice, NULL);;
- #elif defined(TORQUE_OS_IOS)
- #else
- mContext = alcCreateContext(mDevice,NULL);
- #endif
- if (mContext == NULL)
- return false;
- // Make this context the active context
- #if defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_LINUX) || defined(TORQUE_OS_EMSCRIPTEN) || defined(TORQUE_OS_OPENBSD)
- alcMakeContextCurrent((ALCcontext*)mContext);
- #else
- alcMakeContextCurrent(mContext);
- #endif
- ALenum err = alGetError();
- mRequestSources = MAX_AUDIOSOURCES;
- while(true)
- {
- alGenSources(mRequestSources, mSource);
- err = alGetError();
- if (err == AL_NO_ERROR)
- break;
-
- mRequestSources--;
- if (mRequestSources == 0)
- {
- OpenALShutdown();
- return (false);
- }
- }
- mNumSources = mRequestSources;
- // invalidate all existing handles
- dMemset(mHandle, NULL_AUDIOHANDLE, sizeof(mHandle));
- // default all channels to full gain
- for(U32 i = 0; i < Audio::AudioVolumeChannels; i++)
- mAudioChannelVolumes[i] = 1.0f;
- // Clear Error Code
- alGetError();
- // Similiar to DSound Model w/o min distance clamping
- alEnable(AL_DISTANCE_MODEL);
- alDistanceModel(AL_INVERSE_DISTANCE);
- alDopplerFactor(1.f);
- alListenerf(AL_GAIN_LINEAR, 1.f);
- //The audio listener is initialized at position 0,0
- //Listener orientation
- //The first three values represent an "at" vector which points towards the screen.
- //The second set of three values represent the "up" vector (Y+)
- F32 listenerPos[] = { 0.f, 0.f, 0.f };
- F32 listenerVel[] = { 0.f, 0.f, 0.f };
- F32 listenerOrientation[] = { 0.f, 0.f, -1.0f, 0.f, 1.f, 0.f };
- alListenerfv(AL_POSITION, listenerPos);
- alListenerfv(AL_VELOCITY, listenerVel);
- alListenerfv(AL_ORIENTATION, listenerOrientation);
- return true;
- }
- //--------------------------------------------------------------------------
- void OpenALShutdown()
- {
- alxStopAll();
- //if(mInitialized)
- {
- alxEnvironmentDestroy();
- }
- while(mLoopingList.size())
- {
- mLoopingList.last()->mBuffer.purge();
- delete mLoopingList.last();
- mLoopingList.pop_back();
- }
- while(mLoopingFreeList.size())
- {
- mLoopingFreeList.last()->mBuffer.purge();
- delete mLoopingFreeList.last();
- mLoopingFreeList.pop_back();
- }
-
- //clear error buffer
- alGetError();
- for(U32 i = 0; i < MAX_AUDIOSOURCES; i++)
- {
- ALint tempbuff = 0;
- alGetSourcei( mSource[i], AL_BUFFER, &tempbuff);
- if (alIsBuffer(tempbuff) && tempbuff !=0)
- {
- ALuint buffer = tempbuff;
- alSourceUnqueueBuffers( mSource[i], 1, &buffer);
- alxCheckError("OpenALShutdown()","alSourceUnqueueBuffers");
- }
- }
- alDeleteSources(mNumSources, mSource);
- if (mContext)
- {
- #if defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_LINUX) || defined(TORQUE_OS_OPENBSD)
- alcDestroyContext((ALCcontext*)mContext);
- #elif defined(TORQUE_OS_EMSCRIPTEN)
- alcDestroyContext((ALCcontext*)mContext);
- #else
- alcDestroyContext(mContext);
- #endif
- mContext = NULL;
- }
- if (mDevice)
- {
- #if defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_LINUX) || defined(TORQUE_OS_OPENBSD)
- alcCloseDevice((ALCdevice*)mDevice);
- #elif defined(TORQUE_OS_EMSCRIPTEN)
- alcCloseDevice((ALCdevice*)mDevice);
- #else
- alcCloseDevice(mDevice);
- #endif
- mDevice = NULL;
- }
- OpenALDLLShutdown();
- }
- } // end OpenAL namespace
- AudioStreamSource* alxFindAudioStreamSource(AUDIOHANDLE handle)
- {
- StreamingList::iterator itr2 = mStreamingList.findImage(handle);
- if(itr2)
- return *itr2;
- return NULL;
- }
|