| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*****************************************************************************
- ** **
- ** Westwood Studios Pacific. **
- ** **
- ** Confidential Information **
- ** Copyright (C) 2000 - All Rights Reserved **
- ** **
- ******************************************************************************
- ** **
- ** Project: Dune Emperor **
- ** **
- ** Module: <module> (<prefix>_) **
- ** **
- ** Version: $ID$ **
- ** **
- ** File name: audevent.cpp **
- ** **
- ** Created by: 04/28/99 TR **
- ** **
- ** Description: <description> **
- ** **
- *****************************************************************************/
- /*****************************************************************************
- ** Includes **
- *****************************************************************************/
- #define _DEFINE_EVENT_TOKENS
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <wpaudio/altypes.h>
- #include <wpaudio/cache.h>
- #include <wpaudio/events.h>
- #include <wpaudio/level.h>
- #include <wpaudio/profiler.h>
- #include <wpaudio/channel.h>
- #include <wpaudio/device.h>
- #include <wpaudio/attributes.h>
- #include <wpaudio/handle.h>
- // 'assignment within condition expression'.
- #pragma warning(disable : 4706)
- DBG_DECLARE_TYPE ( AudioEventClass)
- DBG_DECLARE_TYPE ( AudioEvent )
- DBG_DECLARE_TYPE ( AudioEventHandle )
- /*****************************************************************************
- ** Externals **
- *****************************************************************************/
- /*****************************************************************************
- ** Defines **
- *****************************************************************************/
- #define DEBUG_EVENT_CONTENTION 0
- #define AUDIO_INVALID_STAMP 0
- #define MAX_EVENTS 100
- #define AVERAGE_LOUDNESS 10
- #define FULL_LOUDNESS 100
- #define VOLUME_QUANTIZE_LEVELS 10
- #define EVENT_MIN_DELAY 33 // milliseconds
- #define NUM_BUCKETS_PRI ( AUDIO_NUM_EVENT_PRIORITIES + 2 ) // Player sounds are +2!
- #define NUM_BUCKETS_VOL 10
- #define VOLUME_QUANTIZE ( AUDIO_LEVEL_MAX / NUM_BUCKETS_VOL )
- #define AUDIO_EVENT_DEFAULT_LIMIT 3
- #define ID_HANDLE ((int) &audioEventClasses)
- /*****************************************************************************
- ** Private Types **
- *****************************************************************************/
- typedef enum
- {
- AUDIO_EVENT_NEW, // event has not been serviced
- AUDIO_EVENT_START_PLAYING, // event is ready for playing
- AUDIO_EVENT_WAITING, // event is waiting
- AUDIO_EVENT_PLAYING, // event is playing
- AUDIO_EVENT_DONE // event is over
- } AudioEventState;
- struct AudioEventClassTag
- {
- ListNode nd;
- int valid; // TRUE if event class has been defined
- AudioEventControl control; // audio event control flags
- AudioLevel baseLevel; // base volume
- AudioPriority priority; // sound priority
- int count; // number of currently active events for this class
- int limit; // maximum number of active events allowed
- int limitLoop; // maximum iterations before looping ends (0 means never)
- int range; // energy level of sound
- int min_volume; // min volume for global event type
- uint minDelay; // minimum delay time (ms)
- uint maxDelay; // maximum delay time (ms)
- int minFShift; // max negative frequency shift percentage
- int maxFShift; // max positive frequency shift percentage
- int vShift; // volume shift percentage
- int volumeCompression;// should this event class be volume compressed
- AudioAttribs *fadeAttribs; // Fader to use for this event
- AudioAttribs *masterAttribs; // Master control to use for this event
- ListHead local; // local events list
- int lastFrame; // id of the last frame the local list was sorted
- uint lastBucketStamp; // id of the last frame this class was bucketed
- AudioPriority maxPri; // highest priority of any event of this class
- ListNode nodeVol; // for volume list
- uint maxVol; // current level of loudest event of this class
- // sample list
- char *sampleName[MAX_AUDIO_EVENT_SAMPLES];
- int numSamples;
- int attackCount;
- int decayCount;
- int morningCount;
- int eveningCount;
- int nightCount;
- char *name;
- void *data;
- #ifdef _DEBUG
- AudioFormat format; // format of last sample added;
- int format_same;
- #endif
- DBG_TYPE ()
- };
- //
- // AudioEvent
- //
- #define mAUDIO_EVENT_DEAD 0x00000001 // this event can be returned to the pool
- #define mAUDIO_EVENT_PLAYING 0x00000002 // playing a sample
- #define mAUDIO_EVENT_CHANNEL 0x00000004 // have a channel
- #define mAUDIO_EVENT_NO_ATTACK 0x00000008 // dont play attack sample if there is one
- #define mAUDIO_EVENT_NO_DECAY 0x00000010 // dont play decay sample if there is one
- #define mAUDIO_EVENT_END 0x00000020 // event to finish up
- #define mAUDIO_EVENT_DO_END 0x00000040 // end latch
- #define mAUDIO_EVENT_ALLOCATED 0x00000080 // struct was malloced
- struct AudioEventTag
- {
- ListNode nd; // global event list
- ListNode local; // local event list
- volatile int flags; // event control flags
- volatile AudioEventState state; // event current state
- volatile AudioEventState nextState; // next event state if waiting
- AudioEventClass *eclass; // event class info
- AudioCacheItem *item[MAX_AUDIO_EVENT_SAMPLES]; // audio cache item
- int numItems;
- int currentItem; // which sample of the event item list we are currently processing
- AudioChannel *channel; // audio channel we are playing on
- AudioAttribs attribs; // event playback attribs
- int stamp; // unique instance id
- volatile uint delay;
- volatile TimeStamp timeOut;
- AudioSample volatile*startSample;
- int fshift;
- int vshift;
- int adjustPriority; // priority modifier
- Lock paused;
- int sequence[MAX_AUDIO_EVENT_SAMPLES]; // play sequence
- int numSequence;
- int loopCount;
- int loadSequence[MAX_AUDIO_EVENT_SAMPLES];
- int numLoadSequence;
- int loadLoopCount;
- int loadNdx;
- int loadSaveNdx;
- int timeOfDay;
- AudioEventHandle *handle; // keep tack of handle
- DBG_TYPE ()
- };
- typedef struct EClassBucketTag
- {
- ListHead bucketVol[ NUM_BUCKETS_VOL ];
- } EClassBucket;
- /*****************************************************************************
- ** Private Data **
- *****************************************************************************/
- static ListHead audioEventClasses;
- static AudioCache *audioCache = NULL;
- static AudioDevice *audioDevice = NULL;
- static int initialized = FALSE;
- static int eventsOn = TRUE;
- static int eventsOK = FALSE;
- static ListHead audioEvents;
- static AudioMemoryPool *audioEventPool = NULL;
- static int audioStamp = AUDIO_INVALID_STAMP+1;
- static int frameStamp = 0;
- static uint bucketStamp = 0; // Never clear this!
- static EClassBucket eClassBucket[ NUM_BUCKETS_PRI ];
- static AudioAttribs audioCompressionAttribs;
- /*****************************************************************************
- ** Public Data **
- *****************************************************************************/
- int AudioEventsCount = 0;
- int AudioEventsPeak = 0;
- int AudioGameFrame = 0; // increment this every game frame
- /*****************************************************************************
- ** Private Prototypes **
- *****************************************************************************/
- static AudioChannel* audioPrepareChannel ( int pri, int flags );
- static int audioEventPrep ( AudioEvent *event );
- static int audioEventStart ( AudioEvent *event );
- static AudioSample* eventFirstSample ( AudioEvent *event );
- static AudioSample* eventNextSample ( AudioEvent *event );
- static void audioEventDestroy ( AudioEvent *event );
- static void eventUnlockSamples ( AudioEvent *event );
- /*****************************************************************************
- ** Private Functions **
- *****************************************************************************/
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void audioInitEventClass ( AudioEventClass *eclass )
- {
- memset ( eclass, 0, sizeof(AudioEventClass ));
- ListNodeInit ( &eclass->nd );
- DBG_SET_TYPE ( eclass, AudioEventClass );
- AudioEventClassReset ( eclass );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventAddLocalSort ( AudioEvent *new_event )
- {
- AudioEventClass *eclass;
- ListNode *node, *head;
- AudioEvent *event;
- uint volume, new_volume;
- DBG_ASSERT_TYPE ( new_event, AudioEvent );
- eclass = new_event->eclass;
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- new_volume = AudioAttribsGetVolume ( &new_event->attribs );
- head = (ListNode*) &eclass->local;
- node = head->next;
- while ( node != head )
- {
- int dif, slack;
- uint baseLev;
- event = (AudioEvent *) ( (uint) node - ((uint) &new_event->local - (uint) new_event ));
- volume = AudioAttribsGetVolume ( &event->attribs );
- baseLev = (uint) AudioLevelGet( &eclass->baseLevel );
- DBG_ASSERT( volume <= baseLev );
- slack = baseLev / VOLUME_QUANTIZE_LEVELS;
- dif = (volume - new_volume);
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( ((dif)>=0 ? dif : -dif ) < slack )
- {
- // we consider the events to be of the same volume
- if ( (eclass->control & AUDIO_EVENT_CTRL_INTERRUPT) )
- {
- // give new events priority over old ones
- if ( (event->state != AUDIO_EVENT_NEW) )
- {
- break;
- }
- }
- else
- {
- // give old events priority over new ones
- if ( (event->state == AUDIO_EVENT_NEW) )
- {
- break;
- }
- }
- }
- else if ( volume < new_volume )
- {
- break;
- }
- node = node->next;
- }
- ListNodeInit ( &new_event->local );
- ListNodeInsert ( node, &new_event->local );
- eclass->count++;
- if ( eclass->limit && (eclass->count > eclass->limit) )
- {
- event = (AudioEvent *) ( (uint) head->prev - ((uint) &new_event->local - (uint) new_event ));
- ListNodeRemove ( &event->local );
- AudioEventKill ( event );
- eclass->count--;
- DBG_ASSERT ( eclass->count == eclass->limit );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventWait ( AudioEvent *event, TimeStamp delay, AudioEventState nextState )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- event->nextState = nextState;
- if ( AudioEventIsPaused ( event ))
- {
- event->timeOut = delay;
- }
- else
- {
- event->timeOut = AudioGetTime() + delay;
- }
- event->state = AUDIO_EVENT_WAITING;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static AudioSample* eventFirstSample ( AudioEvent *event )
- {
- int j=0;
- int i;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( (event->numSequence = event->numItems) == 0 || event->flags & mAUDIO_EVENT_END )
- {
- return NULL;
- }
- if ( event->eclass->minDelay < EVENT_MIN_DELAY )
- {
-
- if ( event->eclass->control & AUDIO_EVENT_CTRL_ATTACK )
- {
- j++;
- event->numSequence--;
- event->currentItem = 0;
- }
- else
- {
- event->currentItem = -1;
- }
-
- if ( event->eclass->control & AUDIO_EVENT_CTRL_DECAY )
- {
- event->numSequence--;
- }
-
- if ( event->numSequence <= 0 )
- {
- event->eclass->valid = FALSE;
- return NULL;
- }
-
- for ( i=0 ; i < event->numSequence; i++, j++ )
- {
- event->sequence[ i ] = j;
- }
-
- if ( event->flags & mAUDIO_EVENT_NO_ATTACK || !(event->eclass->control & AUDIO_EVENT_CTRL_ATTACK) )
- {
- return eventNextSample ( event );
- }
- }
- return AudioCacheItemSample ( event->item[0] );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static AudioSample* eventNextSample ( AudioEvent *event )
- {
- int i;
- AudioEventControl control;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- control = event->eclass->control;
- if ( event->eclass->minDelay >= EVENT_MIN_DELAY && !(event->flags & mAUDIO_EVENT_END) )
- {
- return NULL;
- }
- if ( event->numSequence == 0 || event->flags & mAUDIO_EVENT_END )
- {
- // end of sequence
- if ( control & AUDIO_EVENT_CTRL_LOOP && !(event->flags & mAUDIO_EVENT_END))
- {
- if ( !event->eclass->limitLoop || (event->loopCount < event->eclass->limitLoop - 1) )
- {
- event->loopCount++;
- return eventFirstSample ( event ); // begin again
- }
- }
- // the end
- if ( (!(event->eclass->control & AUDIO_EVENT_CTRL_DECAY) || event->flags & mAUDIO_EVENT_NO_DECAY)
- || event->numItems < 1 )
- {
- return NULL;
- }
- FLAGS_SET ( event->flags , mAUDIO_EVENT_NO_DECAY ); // only want the decay to play once
- return AudioCacheItemSample ( event->item[event->numItems-1] );
- }
- // choose the nex sample to play
- if ( control & AUDIO_EVENT_CTRL_RANDOM )
- {
- int ndx;
- ndx = AudioRandomPick( 0, event->numSequence -1 );
- event->currentItem =event->sequence[ndx];
- // remove from sequence
- for ( i=ndx; i < event->numSequence -1 ; i++)
- {
- event->sequence[i] = event->sequence[i+1];
- }
- }
- else
- {
- event->currentItem++;
- }
- event->numSequence--;
- return AudioCacheItemSample ( event->item[event->currentItem] );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int todAdjustStart( AudioEvent *event )
- {
- int afternoonCount = AudioEventClassNumSound(event->eclass) - (event->eclass->morningCount + event->eclass->eveningCount + event->eclass->nightCount + event->eclass->attackCount + event->eclass->decayCount);
- if (event->timeOfDay == 1) {
- // morning
- return 0;
- }
- if (event->timeOfDay == 2) {
- // afternoon
- return event->eclass->morningCount;
- }
- if (event->timeOfDay == 3) {
- // evening
- if (event->eclass->eveningCount != 0) {
- return event->eclass->morningCount + afternoonCount;
- }
- }
- if (event->timeOfDay == 4) {
- // night
- if (event->eclass->nightCount != 0) {
- return event->eclass->morningCount + afternoonCount + event->eclass->eveningCount;
- }
- }
- // default to returning the afternoon sounds
- return event->eclass->morningCount;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int todAdjustEnd( AudioEvent *event )
- {
- int afternoonCount = AudioEventClassNumSound(event->eclass) - (event->eclass->morningCount + event->eclass->eveningCount + event->eclass->nightCount + event->eclass->attackCount + event->eclass->decayCount);
- if (event->timeOfDay == 1) {
- // morning
- if (event->eclass->morningCount != 0) {
- return afternoonCount + event->eclass->eveningCount + event->eclass->nightCount;
- }
- }
- if (event->timeOfDay == 2) {
- // afternoon
- return event->eclass->eveningCount + event->eclass->nightCount;
- }
- if (event->timeOfDay == 3) {
- // evening
- if (event->eclass->eveningCount != 0) {
- return event->eclass->nightCount;
- }
- }
- if (event->timeOfDay == 4) {
- // night
- if (event->eclass->nightCount != 0) {
- return 0;
- }
- }
- // default to returning the afternoon sounds
- return event->eclass->eveningCount + event->eclass->nightCount;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int eventLoadSchedule( AudioEvent *event )
- {
- AudioEventClass *eclass;
- AudioEventControl control;
- int i;
- int item_ndx;
- eclass = event->eclass;
- control = eclass->control;
- if ( event->numLoadSequence == event->loadNdx )
- {
- int ndx = 0;
- if ( (!(eclass->control & AUDIO_EVENT_CTRL_LOOP) && event->loadLoopCount == 1 )
- || ((eclass->control & AUDIO_EVENT_CTRL_LOOP) && eclass->limitLoop && (event->loadLoopCount) >= eclass->limitLoop ))
- {
- return -1; // sequence is finished
- }
- // Time to create a new schedule.
- if ( eclass->attackCount && !(event->flags & mAUDIO_EVENT_NO_ATTACK))
- {
- event->loadSequence[ndx++] = AudioRandomPick ( 0, eclass->attackCount-1);
- }
- if ( eclass->control & AUDIO_EVENT_CTRL_ALL )
- {
- for ( i = eclass->attackCount + todAdjustStart(event); i < eclass->numSamples - (eclass->decayCount + todAdjustEnd(event)); i++ )
- {
- event->loadSequence[ ndx++ ] = i;
- }
- }
- else if ( eclass->control & AUDIO_EVENT_CTRL_RANDOM )
- {
- if ( event->loadLoopCount == 0 )
- {
- i = AudioRandomPick ( eclass->attackCount + todAdjustStart(event), eclass->numSamples - (eclass->decayCount + todAdjustEnd(event) + 1));
- event->loadSaveNdx = i;
- }
- else
- {
- i = event->loadSaveNdx;
- }
- event->loadSequence[ ndx++ ] = i;
- }
- else
- {
- event->loadSequence[ ndx++ ] = eclass->attackCount;
- }
- event->numLoadSequence = ndx;
- event->loadNdx = 0;
- event->loadLoopCount++;
- }
- // carry out the existing schedule
- if ( control & AUDIO_EVENT_CTRL_RANDOM &&
- ( (!eclass->attackCount || (event->flags & mAUDIO_EVENT_NO_ATTACK)) || event->loadNdx > 0 ))
- {
- int ndx, currentSampleIndex;
- ndx = AudioRandomPick( (!eclass->attackCount || (event->flags & mAUDIO_EVENT_NO_ATTACK)) ? 0 : 1, event->numLoadSequence - 1 );
- item_ndx = currentSampleIndex = event->loadSequence[ ndx ];
- // remove from sequence
- for ( i = ndx; i < event->numLoadSequence - 1; i++ )
- {
- event->loadSequence[ i ] = event->loadSequence[ i + 1 ];
- }
- event->numLoadSequence--;
- }
- else
- {
- item_ndx = event->loadSequence[ event->loadNdx ];
- event->loadNdx++;
- }
- return item_ndx;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventLoadItem( AudioEvent *event, int sampleIndex )
- {
- if ( event->item[ event->numItems ]
- = AudioCacheLoadItem( audioCache, event->eclass->sampleName[ sampleIndex ] ) )
- {
- AudioCacheItemLock( event->item[ event->numItems ] );
- event->numItems++;
- }
- #if DEBUG_EVENT_CONTENTION
- else
- {
- if ( event->channel->Control.Priority >= AUDIO_EVENT_CRITICAL_PRIORITY )
- {
- DBGPRINTF(( "eventLoadItem: '%s' could not load critical sample.\n", AudioEventName ( event ) ));
- }
- }
- #endif
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventLoadAndLockSamples ( AudioEvent *event )
- {
- int i, ndx;
- AudioEventControl control;
- AudioEventClass *eclass;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- control = event->eclass->control;
- eclass = event->eclass;
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- // This function will get called repeatedly for events with delay,
- // because these events re-enter state EVENT_START_PLAYING.
- // We need to load only the sample that's about to be used.
- if ( event->numItems )
- {
- if ( eclass->minDelay >= EVENT_MIN_DELAY )
- {
- eventUnlockSamples( event );
- }
- else
- {
- /// @todo, workout what this comment means
- // Shouldn't happen, but if it does, we're protected from
- // gobbling cache permanently by forgetting our old load...
- DBGPRINTF(( "eventLoadAndLockSamples: You are not reading this.\n" ));
- return;
- }
- }
- if ( eclass->minDelay < EVENT_MIN_DELAY )
- {
- // we are going to be using all samples
- if ( eclass->attackCount )
- {
- eventLoadItem ( event, AudioRandomPick ( 0, eclass->attackCount -1 ));
- }
- if ( eclass->control & AUDIO_EVENT_CTRL_ALL )
- {
- for ( i=eclass->attackCount + todAdjustStart(event); i < eclass->numSamples - (eclass->decayCount + todAdjustEnd(event)); i++ )
- {
- eventLoadItem( event, i );
- }
- }
- else if ( eclass->control & AUDIO_EVENT_CTRL_RANDOM )
- {
- i = AudioRandomPick ( eclass->attackCount + todAdjustStart(event), eclass->numSamples - (eclass->decayCount + todAdjustEnd(event) + 1) );
- eventLoadItem( event, i );
- }
- else
- {
- eventLoadItem( event, eclass->attackCount );
- }
- if ( eclass->decayCount )
- {
- eventLoadItem ( event, AudioRandomPick ( eclass->numSamples - eclass->decayCount, eclass->numSamples -1 ));
- }
- }
- else
- {
- int decay_ndx = -1;
- if ( eclass->decayCount && eclass->control & AUDIO_EVENT_CTRL_DECAY )
- {
- decay_ndx = AudioRandomPick ( eclass->numSamples - eclass->decayCount, eclass->numSamples-1);
- }
- // This event has delay. Load only the sample about to be used.
- // Note: we will leave the existing scheduling mechanism in place.
- // With only one sample loaded, however, it will have no decisions
- // to make. We will decide the true schedule in the function below.
- if ( (ndx = eventLoadSchedule( event )) >= 0 )
- {
- eventLoadItem( event, ndx );
- if ( decay_ndx != -1 )
- {
- eventLoadItem( event, decay_ndx ); // add it incase it is needed
- }
- }
- else
- {
- // end of sequence, must play decay if needed
- if ( decay_ndx != -1 && !(event->flags & mAUDIO_EVENT_NO_DECAY))
- {
- eventLoadItem( event, decay_ndx );
- FLAGS_SET ( event->flags, mAUDIO_EVENT_NO_DECAY );
- }
- }
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventUnlockSamples ( AudioEvent *event )
- {
- int i;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- for ( i=0; i < event->numItems; i++ )
- {
- AudioCacheItemUnlock ( event->item[i] );
- event->item[i] = NULL;
- }
- event->numItems = 0;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void eventReleaseChannel ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( event->channel && (event == (AudioEvent *) event->channel->Data) )
- {
- if ( event->flags & mAUDIO_EVENT_PLAYING )
- {
- AudioChannelStop ( event->channel );
- DBG_ASSERT ( !(event->flags & mAUDIO_EVENT_PLAYING) );
- }
- AudioChannelNoUse ( event->channel );
- event->channel->Data = NULL;
- event->channel->CB_Stop = NULL;
- event->channel->CB_NextSample = NULL;
- event->channel->CB_SampleDone = NULL;
- event->channel->SfxAttribs = NULL;
- event->channel->CompAttribs = NULL;
- event->channel->FadeAttribs = NULL;
- event->channel = NULL;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioEventStop ( AudioChannel *chan )
- {
- AudioEvent *event = (AudioEvent *) chan->Data;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- event->state = AUDIO_EVENT_DONE;
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void audioEventDestroy ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_MSGASSERT ( event->flags & mAUDIO_EVENT_DEAD, ("trying to destroy an event that is not dead"));
- ListNodeRemove ( &event->nd );
- event->stamp = AUDIO_INVALID_STAMP;
- DBG_INVALIDATE_TYPE ( event );
- if ( event->flags & mAUDIO_EVENT_ALLOCATED )
- {
- MEM_Free (event);
- }
- else
- {
- MemoryPoolReturnItem ( audioEventPool, event );
- }
- AudioEventsCount--;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioEventSampleDone ( AudioChannel *chan )
- {
- AudioEvent *event = (AudioEvent *) chan->Data;
- AudioEventState new_state;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- FLAGS_CLEAR ( event->flags, mAUDIO_EVENT_PLAYING );
- if ( event->state == AUDIO_EVENT_DONE )
- {
- return vNO_ERROR;
- }
- if ( event->startSample // If EVENT_CTRL_LOOP, preceding will be true even if load-sequenced
- || event->numLoadSequence || event->delay )
- {
- new_state = AUDIO_EVENT_START_PLAYING;
- }
- else
- {
- new_state = AUDIO_EVENT_DONE ;
- event->delay = 0;
- }
- if ( event->delay )
- {
- eventWait ( event, MSECONDS (event->delay), new_state );
- event->delay = 0;
- }
- else
- {
- event->state = new_state;
- }
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioEventNextSample ( AudioChannel *chan )
- {
- AudioEvent *event = (AudioEvent *) chan->Data;
- AudioSample *sample;
- uint delay;
- sample = eventNextSample ( event );
- if ( event->eclass->maxDelay < EVENT_MIN_DELAY )
- {
- // There is no delay
- AudioChannelSetSample ( chan, sample );
- return vNO_ERROR;
- }
- // There is a delay value. However see if it applies to this sample
- if ( sample )
- {
- // because there is a next sample we are in the middle of a event sequence.
- // We only delay samples within the sequence if it is ambient
- if ( !(event->eclass->control & (AUDIO_EVENT_CTRL_AMBIENT)) )
- {
- // this is not an ambient seqeuence so no delay
- AudioChannelSetSample ( chan, sample );
- return vNO_ERROR;
- }
- }
- else
- {
- // There is no next sample so we are at the end of the sequence
- // If this is NOT a postdelay event the don't delay
- if ( !(event->eclass->control & (AUDIO_EVENT_CTRL_POSTDELAY)) )
- {
- AudioChannelSetSample ( chan, NULL );
- return vNO_ERROR;
- }
- }
- // we are required to wait before going on to the next sample
- AudioChannelSetSample ( chan, NULL );
- delay = (uint) AudioRandomPick ( event->eclass->minDelay, event->eclass->maxDelay );
- if ( delay < EVENT_MIN_DELAY )
- {
- AudioChannelSetSample ( chan, sample );
- return vNO_ERROR;
- }
- event->delay = delay;
- event->startSample = sample;
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- //
- // We use buckets to sort event classes by priority and volume.
- // This is a new frame. Forget all previous sorting information.
- //
- static void bucketReset( void )
- {
- int i, k;
- EClassBucket *ecb;
- for ( i = 0, ecb = eClassBucket; i < NUM_BUCKETS_PRI; i++, ecb++ )
- {
- for ( k = 0; k < NUM_BUCKETS_VOL; k++ )
- {
- ListInit( &ecb->bucketVol[ k ] );
- }
- }
- bucketStamp++;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- //
- // Place this event into buckets according to priority and volume.
- // This will be used to choose event classes for sacrifice.
- //
- static void bucketAdd( AudioEvent *event )
- {
- EClassBucket *ecb;
- AudioEventClass *eclass;
- AudioPriority pri;
- uint vol;
- eclass = event->eclass;
- pri = (AudioPriority) ((uint) eclass->priority + (uint) event->adjustPriority);
- DBG_ASSERT( pri < NUM_BUCKETS_PRI );
- vol = AudioAttribsGetVolume( &event->attribs ) / VOLUME_QUANTIZE;
- ecb = &eClassBucket[ pri ];
- if ( eclass->lastBucketStamp == bucketStamp )
- {
- // Already in buckets. Check if re-sorting necessary.
- if ( pri > eclass->maxPri )
- {
- eclass->maxPri = pri;
- eclass->maxVol = vol;
- // Remove and re-insert.
- ListNodeRemove( &eclass->nodeVol );
- ListNodeInsert( &ecb->bucketVol[ vol ], &eclass->nodeVol );
- }
- else if ( pri == eclass->maxPri )
- {
- if ( vol > eclass->maxVol )
- {
- eclass->maxVol = vol;
- // Remove and re-insert.
- ListNodeRemove( &eclass->nodeVol );
- ListNodeInsert( &ecb->bucketVol[ vol ], &eclass->nodeVol );
- }
- }
- }
- else
- {
- // First use this frame. Initialize and put in buckets.
- eclass->lastBucketStamp = bucketStamp;
- eclass->maxPri = pri;
- eclass->maxVol = vol;
- ListNodeInit( &eclass->nodeVol );
- ListNodeInsert( &ecb->bucketVol[ vol ], &eclass->nodeVol );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void bucketRemove( AudioEventClass *eclass )
- {
- ListNodeRemove( &eclass->nodeVol );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- //
- // Get a "weaker" event class from the buckets. It must have
- // lower priority than 'pri'. Find the quietest such class.
- //
- static AudioEventClass *bucketGetWeaker( AudioPriority pri )
- {
- EClassBucket *ecb;
- ListNode *node;
- int i, v;
- for ( i = 0, ecb = eClassBucket; i < pri; i++, ecb++ )
- {
- for ( v = 0; v < NUM_BUCKETS_VOL; v++ )
- {
- node = ListFirstItem( &ecb->bucketVol[ v ] );
- if ( node )
- {
- AudioEventClass *event = (AudioEventClass*) node;
- event = (AudioEventClass*) ( (uint) event - ( (uint) &event->nodeVol - (uint) event ));
- return event;
- }
- }
- }
- return NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- //
- // Destroy an entire class of events to make room for newEvent.
- // Returns TRUE if any events were killed, FALSE otherwise.
- //
- static int eventClassSacrifice( AudioEvent *newEvent )
- {
- AudioEvent *event, *next, *head;
- AudioEventClass *eclassSacrifice = NULL;
- int killed = FALSE;
- eclassSacrifice = bucketGetWeaker( (AudioPriority) ( (uint) newEvent->eclass->priority
- + (uint) newEvent->adjustPriority) );
- if ( eclassSacrifice == NULL )
- {
- return FALSE;
- }
- #if DEBUG_EVENT_CONTENTION
- DBGPRINTF(( "eventClassSacrifice: class '%s' killed by class '%s'.\n",
- AudioEventClassName (eclassSacrifice), AudioEventName ( newEvent)));
- #endif
- bucketRemove( eclassSacrifice );
- head = (AudioEvent *) &audioEvents;
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- next = (AudioEvent *) event->nd.next;
- if ( event->eclass == eclassSacrifice )
- {
- AudioEventKill( event );
- audioEventDestroy( event );
- killed = TRUE;
- }
- event = next;
- }
- return killed; // Technically, if we get here, should always be TRUE.
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static AudioChannel* audioPrepareChannel ( int pri, int flags )
- {
- AudioChannel *chan = NULL;
- if ( audioDevice && ( chan = AudioDeviceGetChannel( audioDevice, AUDIO_CHANNEL_TYPE_STD )))
- {
- if ( !(chan->Control.Status & (mAUDIO_CTRL_PLAYING|mAUDIO_CTRL_PAUSED|mAUDIO_CTRL_INUSE) ) || chan->Control.Priority <= pri )
- {
- #ifdef _DEBUGx
- if (chan->Control.Status & (mAUDIO_CTRL_PLAYING|mAUDIO_CTRL_PAUSED|mAUDIO_CTRL_INUSE) )
- {
- DBGPRINTF (("Stealing channel 0x%08x\n", chan));
- }
- #endif
- AudioChannelStop ( chan );
- chan->Control.Priority = pri;
- if (flags & mAUDIO_LOOP )
- {
- chan->Control.LoopCount = AUDIO_CTRL_LOOP_FOREVER;
- }
- else
- {
- chan->Control.LoopCount = 0;
- }
- }
- else
- {
- goto error;
- }
- }
- #if 0
- else
- {
- DBGPRINTF(( "Could not get a channel\n" ));
- }
- #endif
- return chan;
- error:
- return NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioEventPrep ( AudioEvent *event )
- {
- AudioEventClass *eclass;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- eclass = event->eclass;
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( eclass->numSamples == 0 || !eclass->valid)
- {
- return FALSE;
- }
- event->loopCount = 0;
- if ( !(event->channel = audioPrepareChannel ( eclass->priority + event->adjustPriority, 0 ) ))
- {
- return FALSE;
- }
- event->fshift = 100 + AudioRandomPick( eclass->minFShift, eclass->maxFShift );
- event->vshift = AudioRandomPick( 0, eclass->vShift );
- AudioChannelUse ( event->channel );
- event->channel->Data = event;
- event->channel->CB_NextSample = audioEventNextSample;
- event->channel->CB_SampleDone = audioEventSampleDone;
- event->channel->CB_Stop = audioEventStop;
- event->state = AUDIO_EVENT_START_PLAYING;
- event->channel->SfxAttribs = &event->attribs;
- event->channel->CompAttribs = eclass->volumeCompression ? &audioCompressionAttribs : NULL ;
- event->channel->FadeAttribs = eclass->fadeAttribs;
- event->channel->GroupAttribs = eclass->masterAttribs;
- if ( eclass->maxDelay > EVENT_MIN_DELAY )
- {
- if ( !(eclass->control & (AUDIO_EVENT_CTRL_POSTDELAY)))
- {
- int delay;
-
- delay = AudioRandomPick( (eclass->control&AUDIO_EVENT_CTRL_AMBIENT) ? EVENT_MIN_DELAY : eclass->minDelay, eclass->maxDelay );
-
- if ( delay >= EVENT_MIN_DELAY )
- {
- eventWait ( event, MSECONDS(delay), AUDIO_EVENT_START_PLAYING );
- }
- }
- }
- // NOTE: we do not actually start the event playing
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioEventStart ( AudioEvent *event )
- {
- AudioSample *sample;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_MSGASSERT ( event->state == AUDIO_EVENT_START_PLAYING, ("event in a bad state"));
- DBG_MSGASSERT ( !AudioEventIsPaused(event), ("trying to start a paused event"));
- if ( event != (AudioEvent *)event->channel->Data )
- {
- // channel was stolen;
- return FALSE;
- }
- // IMPORTANT: set state to playing before starting the channel
- // It is possible that the channel could finish before we get to set the
- // new state.
- AudioChannelLock ( event->channel );
- msg_assert ( !(event->channel->Control.Status & mAUDIO_CTRL_ACTIVE ), ("bad assert. Show this to Tommy immediately!!"));
- sample = (AudioSample *) event->startSample;
- FLAGS_SET ( event->flags, mAUDIO_EVENT_NO_ATTACK );
- AudioChannelSetSample ( event->channel, sample );
- AudioChannelSetPitch ( event->channel, event->fshift );
- int volume = AUDIO_LEVEL_MAX;
- if ( event->vshift > 0 )
- {
- volume -= (AUDIO_LEVEL_MAX * event->vshift)/100;
- }
- AudioChannelSetVolume ( event->channel, volume );
- event->state = AUDIO_EVENT_PLAYING;
- FLAGS_SET ( event->flags, mAUDIO_EVENT_PLAYING );
- event->startSample = NULL;
- if ( AudioChannelStart ( event->channel ) != vNO_ERROR )
- {
- event->state = AUDIO_EVENT_START_PLAYING;
- event->startSample = sample;
- FLAGS_CLEAR ( event->flags, mAUDIO_EVENT_PLAYING );
- AudioChannelUnlock ( event->channel );
- return FALSE;
- }
- AudioChannelUnlock ( event->channel );
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static uint eventCalcVolume ( AudioEvent *event, int new_volume )
- {
- uint volume;
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT_TYPE ( event->eclass, AudioEventClass );
- if ( new_volume > AUDIO_VOLUME_MAX )
- {
- new_volume = AUDIO_VOLUME_MAX;
- }
- else if ( new_volume < AUDIO_VOLUME_MIN )
- {
- new_volume = AUDIO_VOLUME_MIN;
- }
- volume = AudioLevelApply( &event->eclass->baseLevel, new_volume );
- return volume;
- }
- /*****************************************************************************
- ** Public Functions **
- *****************************************************************************/
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventSetUp( AudioDevice *device, AudioCache *cache )
- {
- ListInit ( &audioEvents );
- ListInit ( &audioEventClasses );
- audioDevice = device;
- AudioAttribsInit ( &audioCompressionAttribs );
- AudioEventsCount = AudioEventsPeak = 0;
- initialized = TRUE;
- eventsOn = TRUE;
- eventsOK = FALSE;
- audioCache = cache;
- if ( !audioCache || !audioDevice )
- {
- return FALSE;
- }
- audioEventPool = MemoryPoolCreate ( MAX_EVENTS, sizeof ( AudioEvent ) );
- DBGPRINTF (( "event mempool size = %d\n", MAX_EVENTS * sizeof (AudioEvent )));
- eventsOK = audioEventPool != NULL;
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventCloseDown( void )
- {
- AudioEventClass *eclass;
- AudioKillAllEvents ( );
- AudioFlushAllDeadEvents ();
- while ( eclass = (AudioEventClass *) ListFirstItem ( &audioEventClasses ))
- {
- ListNodeRemove ( &eclass->nd );
- for( Int i = 0 ; i < MAX_AUDIO_EVENT_SAMPLES; i++ )
- {
- if ( eclass->sampleName[i] )
- {
- // allocated with strdup
- free( eclass->sampleName[i] );
- }
- }
- MEM_Free ( eclass );
- }
- if ( audioCache )
- {
- audioCache = NULL;
- }
- if ( audioEventPool )
- {
- MemoryPoolDestroy ( audioEventPool );
- audioEventPool = NULL;
- }
- eventsOK = FALSE;
- initialized = FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioServiceAllEvents ( void )
- {
- static int in = FALSE;
- AudioEvent *event, *next, *head;
- int loudness;
- int activeEvents = 0;
- int prepedEvents = 0;
- int processedEvents = 0;
- if ( !initialized || in )
- {
- return;
- }
- in = TRUE;
- #ifndef IG_FINAL_RELEASE
- {
- static int lastFrame = 0;
-
- if ( lastFrame != AudioGameFrame )
- {
- if ( audioCache )
- {
- ProfCacheNewFrame ( &audioCache->profile );
- }
- lastFrame = AudioGameFrame;
- }
-
- }
- #endif
- frameStamp++; // new frame
- // because of volume compression we require two passes
- // because of channel stealing we require three passes
- // because of event culling we require four passes
- head = (AudioEvent *) &audioEvents;
- // FIRST PASS: sort events locally by volume
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT_TYPE ( event->eclass, AudioEventClass );
- if ( event->eclass->lastFrame != frameStamp )
- {
- // reset local list
- ListInit ( &event->eclass->local);
- event->eclass->count = 0;
- event->eclass->lastFrame = frameStamp;
- }
- AudioAttribsUpdate ( &event->attribs );
- if ( event->state != AUDIO_EVENT_DONE )
- {
- eventAddLocalSort ( event );
- }
- event = (AudioEvent *) event->nd.next;
- }
- // SECOND PASS: service all events so that we know what
- // we are required to do
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- if ( event->state != AUDIO_EVENT_DONE )
- {
- processedEvents ++;
- }
- AudioEventService ( event );
- event = (AudioEvent *) event->nd.next;
- }
- // THIRD PASS: workout the volume compression level
- // and remove dead events
- event = (AudioEvent *) head->nd.next;
- loudness = 0;
- bucketReset(); // clear our memory of what classes are in use
- while ( event != head )
- {
- next = (AudioEvent *) event->nd.next;
- if ( !event->channel
- || event != (AudioEvent *) event->channel->Data )
- {
- #if DEBUG_EVENT_CONTENTION
- {
- AudioEvent thief;
- if ( event->channel )
- {
- // Channel must have been stolen, then.
- thief = (AudioEvent *) event->channel->Data;
- DBGPRINTF(( "AudioServiceAllEvents: class '%s' stole channel from '%s'.\n",
- AudioEventName ( thief ), AudioEventName ( event ) ));
- }
- }
- #endif
- // We have no channel. No point in going on.
- AudioEventKill( event );
- }
- if ( event->flags & mAUDIO_EVENT_DEAD )
- {
- audioEventDestroy( event );
- }
- else
- {
- if ( !AudioEventIsPaused ( event ))
- {
- loudness += AudioLevelApply ( &event->eclass->baseLevel, AVERAGE_LOUDNESS );
- }
- bucketAdd( event );
- }
- event = next;
- }
- if ( loudness > FULL_LOUDNESS )
- {
- AudioAttribsAdjustVolume ( &audioCompressionAttribs, (AUDIO_LEVEL_MAX * FULL_LOUDNESS)/loudness );
- }
- else
- {
- AudioAttribsAdjustVolume ( &audioCompressionAttribs, AUDIO_LEVEL_MAX);
- }
- AudioAttribsUpdate ( &audioCompressionAttribs );
- // FOURTH PASS: now that the compression level has been set
- // start any events that have been preped
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- next = (AudioEvent *) event->nd.next;
- if ( event->state == AUDIO_EVENT_START_PLAYING && !AudioEventIsPaused( event ) )
- {
- eventLoadAndLockSamples ( event );
- while ( !( event->startSample = eventFirstSample( event ) ) )
- {
- // The time for subtlety has passed. Attempt to clear
- // enough cache space for this event by destroying an
- // entire event class of lower priority (if any). Do
- // this until our event gets into the cache.
- if ( eventClassSacrifice( event ) )
- {
- next = (AudioEvent *) event->nd.next; // May have been killed.
- eventLoadAndLockSamples ( event );
- }
- else
- {
- #if DEBUG_EVENT_CONTENTION
- // We could not find an event class of lower priority.
- DBGPRINTF(( "AudioServiceAllEvents: class '%s' could not get cache.\n",
- AudioEventName ( event->eclass) ));
- if ( event->channel->Control.Priority >= AUDIO_EVENT_CRITICAL_PRIORITY )
- {
- AudioEvent event2, next2, head2;
- DBGPRINTF(( "Event dump -- these events are alive and own cache:\n" ));
- head2 = (AudioEvent *) &audioEvents;
- event2 = (AudioEvent *) head2->nd.next;
- while ( event2 != head2 )
- {
- next2 = (AudioEvent *) event2->nd.next;
- if ( event2 != event )
- {
- DBGPRINTF(( "- '%s'\n", AudioEventName ( event2 ) ));
- }
- event2 = next2;
- }
- }
- #endif
- break;
- }
- }
- if ( !( event->startSample = eventFirstSample( event ) )
- || !audioEventStart( event ) )
- {
- AudioEventKill ( event );
- audioEventDestroy ( event );
- }
- else
- {
- activeEvents++;
- }
- prepedEvents++;
- }
- event = next;
- }
- // DBGPRINTF (("compression = %3d (%5d) - active events = %3d of %3d; preped = %3d\n",
- // (AudioAttribsGetVolume ( &audioCompressionAttribs ) *100) /AUDIO_LEVEL_MAX,
- // loudness, activeEvents, processedEvents, prepedEvents));
- in = FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioKillAllEvents ( void )
- {
- AudioEvent *event, *next, *head;
- if ( !initialized )
- {
- return;
- }
- head = (AudioEvent *) &audioEvents;
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- next = (AudioEvent *) event->nd.next;
- AudioEventKill ( event );
- audioEventDestroy ( event );
- event = next;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioPauseAllEvents ( void )
- {
- AudioEvent *event, *head;
- if ( !initialized )
- {
- return;
- }
- head = (AudioEvent *) &audioEvents;
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- AudioEventPause ( event );
- event = (AudioEvent *) event->nd.next;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioResumeAllEvents ( void )
- {
- AudioEvent *event, *head;
- if ( !initialized )
- {
- return;
- }
- head = (AudioEvent *) &audioEvents;
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- AudioEventResume ( event );
- event = (AudioEvent *) event->nd.next;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioFlushAllDeadEvents ( void )
- {
- AudioEvent *event, *next, *head;
- if ( !initialized )
- {
- return;
- }
- head = (AudioEvent *) &audioEvents;
- event = (AudioEvent *) head->nd.next;
- while ( event != head )
- {
- next = (AudioEvent *) event->nd.next;
- if ( event->flags & mAUDIO_EVENT_DEAD )
- {
- audioEventDestroy ( event );
- }
- event = next;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioValidateAllEventClasses ( void )
- {
- AudioEventClass *eclass;
- eclass = (AudioEventClass *) ListFirstItem ( &audioEventClasses );
- while ( eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->valid = TRUE;
- eclass = (AudioEventClass *) ListNextItem ( &eclass->nd);
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- Int AudioEventCount( void )
- {
- return ListCountItems( &audioEventClasses );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEventClass*AudioGetFirstEventClass( void )
- {
- return (AudioEventClass *) ListFirstItem ( &audioEventClasses );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEventClass*AudioEventClassNext ( AudioEventClass *eclass )
- {
- if ( eclass )
- {
- return (AudioEventClass *) ListNextItem ( &eclass->nd);
- }
- return NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassRange ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( !initialized )
- {
- return 0;
- }
- return eclass->range;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassMinVolume ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( !initialized )
- {
- return 0;
- }
- return eclass->min_volume;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassValid ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( !initialized )
- {
- return FALSE;
- }
- return eclass->valid;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEvent *AudioEventCreate ( AudioEventClass *eclass )
- {
- AudioEvent *event;
- int allocated = FALSE;
- if ( !eventsOn || !eventsOK )
- {
- return NULL;
- }
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( !eclass->valid )
- {
- return NULL;
- }
- if ( !(event = (AudioEvent *) MemoryPoolGetItem ( audioEventPool )))
- {
- AudioFlushAllDeadEvents ( );
- if ( !(event = (AudioEvent *) MemoryPoolGetItem ( audioEventPool )))
- {
- ALLOC_STRUCT ( event, AudioEvent);
- allocated = TRUE;
- if ( !event )
- {
- DBGPRINTF (("event pool overflow\n"));
- return NULL;
- }
- }
- }
- AudioEventsCount++;
- if ( AudioEventsCount > AudioEventsPeak )
- {
- AudioEventsPeak = AudioEventsCount;
- }
- // initialise the event
- memset ( event, 0, sizeof ( AudioEvent ));
- event->eclass = eclass;
- ListNodeInit ( &event->nd );
- event->state = AUDIO_EVENT_NEW;
- event->adjustPriority = 0;
- event->numItems = event->numSequence = event->numLoadSequence = 0;
- AudioAttribsInit ( &event->attribs );
- LockInit ( &event->paused );
- DBG_SET_TYPE ( event, AudioEvent );
- ListAddToTail ( &audioEvents, &event->nd );
- event->stamp = audioStamp++;
- if ( allocated )
- {
- FLAGS_SET ( event->flags, mAUDIO_EVENT_ALLOCATED );
- }
- return event;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventNoAttack ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- FLAGS_SET ( event->flags, mAUDIO_EVENT_NO_ATTACK );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventKill ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- if ( event->flags & mAUDIO_EVENT_DEAD )
- {
- return;
- }
- eventReleaseChannel ( event );
- eventUnlockSamples ( event );
- event->state = AUDIO_EVENT_DONE;
- event->stamp = AUDIO_INVALID_STAMP;
- event->handle = NULL;
- FLAGS_SET ( event->flags, mAUDIO_EVENT_DEAD );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventPause ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- if ( !AudioEventIsPaused ( event ))
- {
- if ( event->state == AUDIO_EVENT_WAITING )
- {
- event->timeOut -= AudioGetTime ();
- }
- }
- LockAcquire ( &event->paused );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventResume ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- if ( AudioEventIsPaused ( event ))
- {
- LockRelease ( &event->paused );
- if ( !AudioEventIsPaused ( event ) )
- {
- if ( event->state == AUDIO_EVENT_WAITING )
- {
- event->timeOut += AudioGetTime();
- }
- }
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventIsPaused ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- return Locked ( &event->paused );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventEnd ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- if ( event->flags & mAUDIO_EVENT_END )
- {
- return;
- }
- if ( event->channel && event == (AudioEvent *) event->channel->Data )
- {
- AudioChannelLock ( event->channel );
- FLAGS_SET ( event->flags, mAUDIO_EVENT_END | mAUDIO_EVENT_DO_END );
- AudioChannelUnlock ( event->channel );
- }
- else
- {
- FLAGS_SET ( event->flags, mAUDIO_EVENT_END | mAUDIO_EVENT_DO_END );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventService ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- DBG_ASSERT ( initialized );
- if ( !eventsOn )
- {
- event->state = AUDIO_EVENT_DONE;
- }
- retry:
- switch ( event->state )
- {
- case AUDIO_EVENT_NEW:
- {
- if ( !audioEventPrep ( event ) )
- {
- AudioEventKill ( event );
- }
- }
- break;
- case AUDIO_EVENT_START_PLAYING:
- break;
- case AUDIO_EVENT_PLAYING:
- // check for rogue looping event
- if ( AudioEventNeverEnds ( event ) )
- {
- if ( !(event->flags & mAUDIO_EVENT_END ) && (!event->handle || AudioEventHandleGet ( event->handle ) != event))
- {
- // we have a looping smaple that has no handle attacked to it.
- // this means that the event can never be stopped (unless it gets bumped
- // by a higher priority event), which probable means that something has got wrong
- msg_assert ( FALSE, ("A looping audio event '%s' is playing but has no handle. \n\nPlease tell Tommy about this assert. It is ok to ignore this assert", AudioEventName ( event )));
- AudioEventKill ( event );
- }
- }
- if ( event->flags & mAUDIO_EVENT_DO_END )
- {
- do_ending:
- AudioChannel *chan = event->channel;
- if ( chan )
- {
- AudioChannelLock ( chan );
- FLAGS_CLEAR ( event->flags , mAUDIO_EVENT_DO_END );
- AudioChannelStop ( event->channel );
- if ( event->eclass->control & AUDIO_EVENT_CTRL_DECAY && !(event->flags & mAUDIO_EVENT_NO_DECAY))
- {
- event->state = AUDIO_EVENT_START_PLAYING;
- event->startSample = eventNextSample ( event );
- //msg_warning ( event->startSample, ("You can safely ignore this assert, but let me know about it.\n\nThanks, Tommy - ext 205"));
- if ( !AudioEventIsPaused ( event ))
- {
- if ( !audioEventStart ( event ) )
- {
- AudioEventKill ( event );
- }
- }
- }
- AudioChannelUnlock ( chan );
- }
- else
- {
- FLAGS_CLEAR ( event->flags , mAUDIO_EVENT_DO_END );
- }
- }
- break;
- case AUDIO_EVENT_WAITING:
- {
- if ( event->flags & mAUDIO_EVENT_DO_END )
- {
- goto do_ending;
- }
- if ( !AudioEventIsPaused( event ) && AudioGetTime () > event->timeOut )
- {
- event->state = event->nextState;
- goto retry;
- }
- }
- break;
- case AUDIO_EVENT_DONE:
- {
- AudioEventKill ( event );
- }
- break;
- default:
- DBG_MSGASSERT ( FALSE, ("bad event type"));
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleInit ( AudioEventHandle *handle )
- {
- DBG_ASSERT_PTR ( handle );
- handle->event = NULL;
- handle->stamp = AUDIO_INVALID_STAMP;
- handle->eclass = NULL;
- handle->id = ID_HANDLE;
- DBG_SET_TYPE ( handle, AudioEventHandle );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleDeinit ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- AudioEventHandleStop ( handle );
- handle->id = 0;
- DBG_INVALIDATE_TYPE ( handle );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleStop ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- AudioEvent *event = AudioEventHandleGet ( handle );
- if ( event )
- {
- AudioEventKill ( event );
- handle->event = NULL;
- }
- handle->eclass = NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleStopLooping ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- AudioEvent *event = AudioEventHandleGet ( handle );
- if ( event && AudioEventNeverEnds ( event ))
- {
- AudioEventKill ( event );
- handle->event = NULL;
- }
- handle->eclass = NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleEnd ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- AudioEvent *event = AudioEventHandleGet ( handle );
- if ( event )
- {
- AudioEventEnd ( event );
- handle->event = NULL;
- }
- handle->eclass = NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleEndLooping ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- AudioEvent *event = AudioEventHandleGet ( handle );
- if ( event && AudioEventNeverEnds ( event ))
- {
- AudioEventEnd ( event );
- handle->event = NULL;
- }
- handle->eclass = NULL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventHandleSet ( AudioEventHandle *handle, AudioEvent *event, AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE( handle, AudioEventHandle );
- if ( handle->id != ID_HANDLE )
- {
- return;
- }
- handle->eclass = eclass;
- if ( ( handle->event = event ))
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- handle->stamp = event->stamp;
- if ( !eclass )
- {
- handle->eclass = event->eclass;
- }
- event->handle = handle;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEvent* AudioEventHandleGet ( AudioEventHandle *handle )
- {
- AudioEvent *event;
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- if (!initialized || handle->id != ID_HANDLE )
- {
- return NULL;
- }
- if ( ( event = handle->event) )
- {
- if ( ( handle->eclass != event->eclass ) || handle->stamp != event->stamp )
- {
- handle->event = event = NULL;
- }
- }
- return event;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEventClass* AudioEventHandleGetClass ( AudioEventHandle *handle )
- {
- DBG_ASSERT_TYPE ( handle, AudioEventHandle );
- if (!initialized || handle->id != ID_HANDLE )
- {
- return NULL;
- }
- return handle->eclass;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventSetVolume ( AudioEvent *event, int new_volume )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- AudioLevelSet ( &event->attribs.VolumeLevel, eventCalcVolume ( event, new_volume) );
- AudioLevelUpdate ( &event->attribs.VolumeLevel );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventAdjustVolume ( AudioEvent *event, int new_volume )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( event->state == AUDIO_EVENT_PLAYING )
- {
- AudioLevelAdjust ( &event->attribs.VolumeLevel, eventCalcVolume ( event, new_volume) );
- }
- else
- {
- AudioEventSetVolume ( event, new_volume );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static uint eventCalcPan ( int new_pan )
- {
- // convert to audiolevel pan
- if ( new_pan > AUDIO_PAN_RIGHT )
- {
- new_pan = AUDIO_PAN_RIGHT;
- }
- else if ( new_pan < AUDIO_PAN_LEFT )
- {
- new_pan = AUDIO_PAN_LEFT;
- }
- return new_pan;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventSetPan ( AudioEvent *event, int new_pan )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- AudioLevelSet ( &event->attribs.PanPosition, eventCalcPan ( new_pan ) );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventAdjustPan ( AudioEvent *event, int new_pan )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( event->state == AUDIO_EVENT_PLAYING )
- {
- AudioLevelAdjust ( &event->attribs.PanPosition, eventCalcPan ( new_pan ) );
- }
- else
- {
- AudioEventSetPan ( event, new_pan );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventSetAdjustDuration ( AudioEvent *event, TimeStamp time )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- AudioLevelSetDuration ( &event->attribs.VolumeLevel, time, AUDIO_LEVEL_MAX );
- AudioLevelSetDuration ( &event->attribs.PitchLevel, time, AUDIO_LEVEL_MAX );
- AudioLevelSetDuration ( &event->attribs.PanPosition, time, AUDIO_LEVEL_MAX );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEventClass* AudioEventGetClass ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- return event->eclass;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventNeverEnds ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- return AudioEventClassNeverEnds ( event->eclass );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventSetTimeOfDay ( AudioEvent *event, int new_tod )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- event->timeOfDay = new_tod;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- char* AudioEventName ( AudioEvent *event )
- {
- DBG_ASSERT_TYPE ( event, AudioEvent );
- if ( !initialized )
- {
- return "no events";
- }
- if ( !event->eclass )
- {
- return "unknown";
- }
- return AudioEventClassName ( event->eclass);
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- char* AudioEventClassName ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( !initialized )
- {
- return "no events";
- }
- if ( !eclass->name )
- {
- return "(null)";
- }
- return eclass->name;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetName ( AudioEventClass *eclass, char *new_name )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->name = new_name;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetFadeAttribs ( AudioEventClass *eclass, AudioAttribs *attribs )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->fadeAttribs = attribs;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetMasterAttribs ( AudioEventClass *eclass, AudioAttribs *attribs )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->masterAttribs = attribs;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetData ( AudioEventClass *eclass, void *data)
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->data = data;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void* AudioEventClassGetData ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- return eclass->data;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- const char* AudioEventClassGetSoundName ( AudioEventClass *eclass, int index )
- {
- static const char *bogus = "";
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if (index < 0 || index >= eclass->numSamples) {
- return bogus;
- }
- return eclass->sampleName[index];
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- AudioEventClass *AudioEventClassCreate ( void )
- {
- AudioEventClass *eclass;
- if ( !initialized )
- {
- return NULL;
- }
- ALLOC_STRUCT ( eclass, AudioEventClass );
- audioInitEventClass ( eclass );
- ListAddToTail ( &audioEventClasses, &eclass->nd );
- return eclass;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassAddSound ( AudioEventClass *eclass, const char *name )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( eclass->numSamples == MAX_AUDIO_EVENT_SAMPLES )
- {
- msg_warning ( FALSE, ("Too many samples in audio event '%s' (Max %d)", AudioEventClassName ( eclass), MAX_AUDIO_EVENT_SAMPLES ));
- return FALSE;
- }
- if ( initialized )
- {
- if ( name != NULL )
- {
- eclass->sampleName[eclass->numSamples++] = strdup( name );
- }
- else
- {
- //DBGPRINTF (("Missing sample %s\n", name ));
- eclass->valid = FALSE;
- return FALSE;
- }
- }
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassNumSound ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- return eclass->numSamples;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetAttackCount ( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( count >= 0,("Attack count must be positive") );
- eclass->attackCount = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetDecayCount ( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( count >= 0,("Decay count must be positive") );
- eclass->decayCount = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetMorningSoundCount( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( count >= 0,("Morning Sound count must be positive") );
- eclass->morningCount = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetEveningSoundCount( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( count >= 0,("Evening Sound count must be positive") );
- eclass->eveningCount = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetNightSoundCount( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( count >= 0,("Night Sound count must be positive") );
- eclass->nightCount = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetPriority ( AudioEventClass *eclass, AudioPriority pri )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->priority = pri;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetVolume ( AudioEventClass *eclass, int vol )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- AudioLevelSet ( &eclass->baseLevel, vol );
- AudioLevelUpdate ( &eclass->baseLevel );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetControl ( AudioEventClass *eclass, AudioEventControl control )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->control = control;
- #ifdef _DEBUG
- msg_warning ( !( !eclass->format_same
- && (control & (AUDIO_EVENT_CTRL_LOOP|AUDIO_EVENT_CTRL_ALL )
- == (AUDIO_EVENT_CTRL_LOOP|AUDIO_EVENT_CTRL_ALL ) )),
- ("Audio event \"%s\" set to \"loop all\", however not all sounds are of the same format\n"
- "\nSame format means they must have the same Playback rate, same original sample width, and same number of channels", AudioEventClassName (eclass) ));
- #endif //_DEBUG
- if ( eclass->control & AUDIO_EVENT_CTRL_ATTACK )
- {
- if ( eclass->attackCount == 0)
- {
- eclass->attackCount = 1 ;
- }
- }
- else
- {
- eclass->attackCount = 0;
- }
- if ( eclass->control & AUDIO_EVENT_CTRL_DECAY )
- {
- if ( eclass->decayCount == 0)
- {
- eclass->decayCount = 1;
- }
- }
- else
- {
- eclass->decayCount = 0;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetLimit ( AudioEventClass *eclass, int limit )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->limit = limit;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetRange ( AudioEventClass *eclass, int range )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->range = range;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetMinVolume ( AudioEventClass *eclass, int min_vol )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->min_volume = min_vol;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetDelay ( AudioEventClass *eclass, int minDelay, int maxDelay )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( maxDelay >= minDelay, ("bad parameters on SetDelay"));
- eclass->minDelay = minDelay;
- eclass->maxDelay = maxDelay;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetPitchShift ( AudioEventClass *eclass, int minShift, int maxShift )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- msg_assert ( maxShift >= minShift, ("bad parameters on SetPitchShift"));
- eclass->minFShift = minShift;
- eclass->maxFShift = maxShift;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetVolumeShift ( AudioEventClass *eclass, int VShift)
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- if ( VShift > 100 )
- {
- VShift = 100;
- }
- else if ( VShift < 0 )
- {
- VShift = 0;
- }
- eclass->vShift = VShift;
- }
- //============================================================================
- // AudioEventClassSetVolumeCompression
- //============================================================================
- void AudioEventClassSetVolumeCompression ( AudioEventClass *eclass, int on)
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->volumeCompression = on;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassReset ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- ListNode nd;
- char *name;
- AudioAttribs *fadeAttribs;
- AudioAttribs *masterAttribs;
- // save fields that do not change
- nd = eclass->nd;
- name = eclass->name;
- masterAttribs = eclass->masterAttribs;
- fadeAttribs = eclass->fadeAttribs;
- memset ( eclass, 0, sizeof(AudioEventClass ));
- eclass->nd = nd;
- eclass->masterAttribs = masterAttribs;
- eclass->fadeAttribs = fadeAttribs;
- DBG_SET_TYPE ( eclass, AudioEventClass );
- eclass->valid = TRUE;
- eclass->control = AUDIO_EVENT_CTRL_NONE;
- eclass->limit = AUDIO_EVENT_DEFAULT_LIMIT;
- eclass->priority = AUDIO_EVENT_NORMAL_PRIORITY;
- eclass->range = 10; // in cells
- eclass->min_volume = 40;
- AudioLevelInit ( &eclass->baseLevel, AUDIO_LEVEL_MAX );
- #ifdef _DEBUG
- eclass->format_same = TRUE;
- AudioFormatInit ( &eclass->format );
- #endif
-
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventClassSetLoopCount ( AudioEventClass *eclass, int count )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- eclass->limitLoop = count;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventClassNeverEnds ( AudioEventClass *eclass )
- {
- DBG_ASSERT_TYPE ( eclass, AudioEventClass );
- return ((eclass->control & AUDIO_EVENT_CTRL_LOOP) && !eclass->limitLoop);
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventTurnOff ( void )
- {
- eventsOn = FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventTurnOn ( void )
- {
- eventsOn = TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- int AudioEventOn ( void )
- {
- return eventsOn;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioEventsDump ( void (*print) ( char *text ))
- {
- if ( audioCache )
- {
- char buffer[200];
- ProfCacheText ( &audioCache->profile, print );
- sprintf ( buffer, "AudioEvents : %05d - Max: %05d\n", AudioEventsCount, AudioEventsPeak);
- print ( buffer );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AudioFlushCache ( void )
- {
- if ( audioCache )
- {
- AudioCacheInvalidate ( audioCache );
- while ( AudioCacheFreeOldestItem( audioCache ) );
- }
- }
|