WWAudio.cpp 98 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWAudio *
  23. * *
  24. * $Archive:: /Commando/Code/WWAudio/WWAudio.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 1/30/02 2:47p $*
  29. * *
  30. * $Revision:: 76 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "always.h"
  36. #include <Windows.H>
  37. #include "WWAudio.H"
  38. #include "WWDebug.H"
  39. #include "Utils.H"
  40. #include "RealCRC.H"
  41. #include "SoundBuffer.H"
  42. #include "AudibleSound.H"
  43. #include "Sound3D.H"
  44. #include "RawFile.H"
  45. #include "WW3D.H"
  46. #include "SoundScene.H"
  47. #include "SoundPseudo3D.H"
  48. #include "FFactory.H"
  49. #include "Registry.H"
  50. #include "Threads.H"
  51. #include "LogicalSound.h"
  52. #include "LogicalListener.h"
  53. #include "definitionclassids.h"
  54. #include "wwmemlog.h"
  55. #include "wwprofile.h"
  56. #include "Ini.h"
  57. #ifdef G_CODE_BASE
  58. #include "..\wwlib\argv.h"
  59. #endif
  60. ////////////////////////////////////////////////////////////////////////////////////////////////
  61. // Static member initialization
  62. ////////////////////////////////////////////////////////////////////////////////////////////////
  63. WWAudioClass *WWAudioClass::_theInstance = NULL;
  64. HANDLE WWAudioClass::_TimerSyncEvent = NULL;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////
  66. // Registry value names
  67. ////////////////////////////////////////////////////////////////////////////////////////////////
  68. const char *VALUE_NAME_IS_STEREO = "stereo";
  69. const char *VALUE_NAME_BITS = "bits";
  70. const char *VALUE_NAME_HERTZ = "hertz";
  71. const char *VALUE_NAME_DEVICE_NAME = "device name";
  72. const char *VALUE_NAME_MUSIC_ENABLED = "music enabled";
  73. const char *VALUE_NAME_SOUND_ENABLED = "sound enabled";
  74. const char *VALUE_NAME_DIALOG_ENABLED = "dialog enabled";
  75. const char *VALUE_NAME_CINEMATIC_ENABLED = "cinematic enabled";
  76. const char *VALUE_NAME_MUSIC_VOL = "music volume";
  77. const char *VALUE_NAME_SOUND_VOL = "sound volume";
  78. const char *VALUE_NAME_DIALOG_VOL = "dialog volume";
  79. const char *VALUE_NAME_CINEMATIC_VOL = "cinematic volume";
  80. const char *VALUE_NAME_SPEAKER_TYPE = "speaker type";
  81. const int MAX_VIRTUAL_CHANNELS = 100;
  82. ////////////////////////////////////////////////////////////////////////////////////////////////
  83. // INI names
  84. ////////////////////////////////////////////////////////////////////////////////////////////////
  85. const char *WWAUDIO_INI_FILENAME = "WWAudio.ini";
  86. const char *WWAUDIO_INI_RELATIVE_PATHNAME = "Data\\WWAudio.ini";
  87. const char *INI_DEFAULT_VOLUME_SECTION = "Default Volume";
  88. const char *INI_MUSIC_VOLUME_ENTRY = "MUSIC_VOLUME";
  89. const char *INI_SOUND_VOLUME_ENTRY = "SOUND_VOLUME";
  90. const char *INI_DIALOG_VOLUME_ENTRY = "DIALOG_VOLUME";
  91. const char *INI_CINEMATIC_VOLUME_ENTRY = "CINEMATIC_VOLUME";
  92. ////////////////////////////////////////////////////////////////////////////////////////////////
  93. // Local inlines
  94. ////////////////////////////////////////////////////////////////////////////////////////////////
  95. __inline bool
  96. WWAudioClass::Is_OK_To_Give_Handle (const AudibleSoundClass &sound_obj)
  97. {
  98. bool is_ok = false;
  99. AudibleSoundClass::SOUND_TYPE type = sound_obj.Get_Type ();
  100. if (m_AreNewSoundsEnabled) {
  101. if (((type == AudibleSoundClass::TYPE_SOUND_EFFECT) && m_AreSoundEffectsEnabled) ||
  102. ((type == AudibleSoundClass::TYPE_MUSIC) && m_IsMusicEnabled) ||
  103. ((type == AudibleSoundClass::TYPE_DIALOG) && m_IsDialogEnabled) ||
  104. ((type == AudibleSoundClass::TYPE_CINEMATIC) && m_IsCinematicSoundEnabled))
  105. {
  106. is_ok = true;
  107. }
  108. }
  109. return is_ok;
  110. }
  111. ////////////////////////////////////////////////////////////////////////////////////////////////
  112. //
  113. // WWAudioClass
  114. //
  115. // 1/25/2002 12:13PM ST. Added the 'lite' flag which causes us to go through the motions of
  116. // creating the object (including theInstance) so it exists but disables
  117. // the call that initialises Miles and doesn't create a sound scene.
  118. //
  119. ////////////////////////////////////////////////////////////////////////////////////////////////
  120. WWAudioClass::WWAudioClass (bool lite)
  121. : m_Driver2D (NULL),
  122. m_Driver3D (NULL),
  123. m_PlaybackRate (44100),
  124. m_PlaybackBits (16),
  125. m_PlaybackStereo (true),
  126. m_SpeakerType (0),
  127. m_ReverbFilter (INVALID_MILES_HANDLE),
  128. m_UpdateTimer (-1),
  129. m_Driver3DPseudo (NULL),
  130. m_MusicVolume (DEF_MUSIC_VOL),
  131. m_SoundVolume (DEF_SFX_VOL),
  132. m_RealMusicVolume (DEF_MUSIC_VOL),
  133. m_RealSoundVolume (DEF_SFX_VOL),
  134. m_MaxCacheSize (DEF_CACHE_SIZE * 1024),
  135. m_CurrentCacheSize (0),
  136. m_Max2DSamples (DEF_2D_SAMPLE_COUNT),
  137. m_Max3DSamples (DEF_3D_SAMPLE_COUNT),
  138. m_Max2DBufferSize (DEF_MAX_2D_BUFFER_SIZE),
  139. m_Max3DBufferSize (DEF_MAX_3D_BUFFER_SIZE),
  140. m_SoundScene (NULL),
  141. m_IsMusicEnabled (true),
  142. m_IsDialogEnabled (true),
  143. m_IsCinematicSoundEnabled (true),
  144. m_AreSoundEffectsEnabled (true),
  145. m_FileFactory (NULL),
  146. m_EffectsLevel (0),
  147. m_CurrPage (PAGE_PRIMARY),
  148. m_AreNewSoundsEnabled (true),
  149. m_BackgroundMusic (NULL),
  150. m_ReverbRoomType (ENVIRONMENT_GENERIC),
  151. m_NonDialogFadeTime (DEF_FADE_TIME),
  152. m_FadeType (FADE_NONE),
  153. m_FadeTimer (0),
  154. m_CachedIsMusicEnabled (true),
  155. m_CachedIsDialogEnabled (true),
  156. m_CachedIsCinematicSoundEnabled (true),
  157. m_CachedAreSoundEffectsEnabled (true),
  158. AudioIni (NULL)
  159. {
  160. ::InitializeCriticalSection (&MMSLockClass::_MSSLockCriticalSection);
  161. m_ForceDisable = lite;
  162. //
  163. // Start Miles Sound System
  164. //
  165. if (!lite) {
  166. AIL_startup ();
  167. }
  168. _theInstance = this;
  169. _TimerSyncEvent = ::CreateEvent (NULL, TRUE, FALSE, "WWAUDIO_TIMER_SYNC");
  170. //
  171. // Set some default values
  172. //
  173. Set_Sound_Effects_Volume ();
  174. Set_Music_Volume ();
  175. //
  176. // Allocate the virtual channels
  177. //
  178. for (int index = 0; index < MAX_VIRTUAL_CHANNELS; index ++) {
  179. m_VirtualChannels.Add (NULL);
  180. }
  181. // Create a new sound scene to manage our 3D sounds...
  182. if (!lite) {
  183. m_SoundScene = new SoundSceneClass;
  184. }
  185. m_Max3DBufferSize = m_Max3DBufferSize * 2.0F;
  186. return;
  187. }
  188. ////////////////////////////////////////////////////////////////////////////////////////////////
  189. //
  190. // ~WWAudioClass
  191. //
  192. ////////////////////////////////////////////////////////////////////////////////////////////////
  193. WWAudioClass::~WWAudioClass (void)
  194. {
  195. //
  196. // Stop the background music
  197. //
  198. Set_Background_Music (NULL);
  199. //
  200. // Make sure the delayed-release thread is terminated
  201. // before we exit (otherwise the process will crash).
  202. //
  203. WWAudioThreadsClass::End_Delayed_Release_Thread ();
  204. Shutdown ();
  205. _theInstance = NULL;
  206. ::CloseHandle(_TimerSyncEvent);
  207. _TimerSyncEvent = NULL;
  208. ::DeleteCriticalSection (&MMSLockClass::_MSSLockCriticalSection);
  209. //
  210. // Free the list of logical "types".
  211. //
  212. Reset_Logical_Types ();
  213. if (AudioIni != NULL) delete AudioIni;
  214. return;
  215. }
  216. ////////////////////////////////////////////////////////////////////////////////////////////////
  217. //
  218. // Flush_Cache
  219. //
  220. ////////////////////////////////////////////////////////////////////////////////////////////////
  221. void
  222. WWAudioClass::Flush_Cache (void)
  223. {
  224. // Loop through all the hash indicies
  225. for (int hash_index = 0; hash_index < MAX_CACHE_HASH; hash_index ++) {
  226. // Loop through all the buffers at this hash index and free them all
  227. for (int index = 0; index < m_CachedBuffers[hash_index].Count (); index ++) {
  228. CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
  229. // Free the buffer data
  230. SAFE_FREE (info.string_id);
  231. REF_PTR_RELEASE (info.buffer);
  232. }
  233. // Remove all the entries for this hash index
  234. m_CachedBuffers[hash_index].Delete_All ();
  235. }
  236. m_CurrentCacheSize = 0;
  237. return;
  238. }
  239. ////////////////////////////////////////////////////////////////////////////////////////////////
  240. //
  241. // Open_2D_Device
  242. //
  243. ////////////////////////////////////////////////////////////////////////////////////////////////
  244. WWAudioClass::DRIVER_TYPE_2D
  245. WWAudioClass::Open_2D_Device (LPWAVEFORMAT format)
  246. {
  247. MMSLockClass lock;
  248. //
  249. // Store the playback settings for future reference
  250. //
  251. m_PlaybackRate = format->nSamplesPerSec;
  252. m_PlaybackBits = (format->nAvgBytesPerSec << 3) / (format->nChannels * format->nSamplesPerSec);
  253. m_PlaybackStereo = bool(format->nChannels > 1);
  254. //
  255. // Assume we will open the DirectSound driver
  256. //
  257. DRIVER_TYPE_2D type = DRIVER2D_DSOUND;
  258. // First close the current 2D device and take
  259. // all the sound handles away from the sound objects.
  260. Close_2D_Device ();
  261. AIL_set_preference (AIL_LOCK_PROTECTION, NO);
  262. // Try to use DirectSound if possible
  263. S32 success = ::AIL_set_preference (DIG_USE_WAVEOUT, FALSE);
  264. //WWASSERT (success == AIL_NO_ERROR); // This assert fires if there is no sound card.
  265. // Open the driver
  266. success = ::AIL_waveOutOpen (&m_Driver2D, NULL, 0, format);
  267. // Do we need to switch from direct sound to waveout?
  268. if ((success == AIL_NO_ERROR) &&
  269. (m_Driver2D != NULL) &&
  270. (m_Driver2D->emulated_ds == TRUE)) {
  271. ::AIL_waveOutClose (m_Driver2D);
  272. success = 2;
  273. WWDEBUG_SAY (("WWAudio: Detected 2D DirectSound emulation, switching to WaveOut.\r\n"));
  274. }
  275. // If we couldn't open the direct sound device, then use the
  276. // default wave out device
  277. if (success != AIL_NO_ERROR) {
  278. // Try to use the default wave out driver
  279. success = ::AIL_set_preference (DIG_USE_WAVEOUT, TRUE);
  280. //WWASSERT (success == AIL_NO_ERROR); // This assert fires if there is no sound card.
  281. // Open the driver
  282. success = ::AIL_waveOutOpen (&m_Driver2D, NULL, 0, format);
  283. type = (success == AIL_NO_ERROR) ? DRIVER2D_WAVEOUT : DRIVER2D_ERROR;
  284. }
  285. // Allocate all the available handles if we were successful
  286. if (success == AIL_NO_ERROR) {
  287. Allocate_2D_Handles ();
  288. ReAssign_2D_Handles ();
  289. } else {
  290. Close_2D_Device ();
  291. WWDEBUG_SAY (("WWAudio: Error initializing 2D device.\r\n"));
  292. }
  293. // Return the opened device type
  294. return type;
  295. }
  296. ////////////////////////////////////////////////////////////////////////////////////////////////
  297. //
  298. // Open_2D_Device
  299. //
  300. ////////////////////////////////////////////////////////////////////////////////////////////////
  301. WWAudioClass::DRIVER_TYPE_2D
  302. WWAudioClass::Open_2D_Device
  303. (
  304. bool stereo,
  305. int bits,
  306. int hertz
  307. )
  308. {
  309. // Build a wave format structure from the params
  310. PCMWAVEFORMAT wave_format = { 0 };
  311. wave_format.wf.wFormatTag = WAVE_FORMAT_PCM;
  312. wave_format.wf.nChannels = stereo ? 2 : 1;
  313. wave_format.wf.nSamplesPerSec = hertz;
  314. wave_format.wf.nAvgBytesPerSec = (wave_format.wf.nChannels * wave_format.wf.nSamplesPerSec * bits) >> 3;
  315. wave_format.wf.nBlockAlign = (wave_format.wf.nChannels * bits) >> 3;
  316. wave_format.wBitsPerSample = bits;
  317. DRIVER_TYPE_2D type = DRIVER2D_ERROR;
  318. while (((type = Open_2D_Device ((LPWAVEFORMAT)&wave_format)) == DRIVER2D_ERROR) &&
  319. (wave_format.wf.nSamplesPerSec >= 11025)) {
  320. //
  321. // Cut the playback rate in half and try again
  322. //
  323. wave_format.wf.nSamplesPerSec = wave_format.wf.nSamplesPerSec >> 1;
  324. wave_format.wf.nAvgBytesPerSec = (wave_format.wf.nChannels * wave_format.wf.nSamplesPerSec * bits) >> 3;
  325. wave_format.wf.nBlockAlign = (wave_format.wf.nChannels * bits) >> 3;
  326. }
  327. // Pass this structure onto the function that actually opens the device
  328. return type;
  329. }
  330. ////////////////////////////////////////////////////////////////////////////////////////////////
  331. //
  332. // Close_2D_Device
  333. //
  334. ////////////////////////////////////////////////////////////////////////////////////////////////
  335. bool
  336. WWAudioClass::Close_2D_Device (void)
  337. {
  338. MMSLockClass lock;
  339. //
  340. // Note: We MUST close the 3D device when we close the 2D device...
  341. //
  342. Close_3D_Device ();
  343. //
  344. // Free any 2D sound handles
  345. //
  346. Remove_2D_Sound_Handles ();
  347. Release_2D_Handles ();
  348. //
  349. // Do we have an open driver handle to close?
  350. //
  351. bool retval = false;
  352. if (m_Driver2D != NULL) {
  353. //
  354. // Close the driver
  355. //
  356. ::AIL_waveOutClose (m_Driver2D);
  357. m_Driver2D = NULL;
  358. retval = true;
  359. }
  360. return retval;
  361. }
  362. ////////////////////////////////////////////////////////////////////////////////////////////////
  363. //
  364. // Close_3D_Device
  365. //
  366. ////////////////////////////////////////////////////////////////////////////////////////////////
  367. bool
  368. WWAudioClass::Close_3D_Device (void)
  369. {
  370. MMSLockClass lock;
  371. bool retval = false;
  372. //
  373. // Remove all the handles
  374. //
  375. Remove_3D_Sound_Handles ();
  376. Release_3D_Handles ();
  377. //
  378. // Do we have an open driver handle to close?
  379. //
  380. if (m_Driver3D != NULL) {
  381. ::AIL_close_3D_provider (m_Driver3D);
  382. m_Driver3D = NULL;
  383. retval = true;
  384. }
  385. return retval;
  386. }
  387. ////////////////////////////////////////////////////////////////////////////////////////////////
  388. //
  389. // Get_Sound_Buffer
  390. //
  391. ////////////////////////////////////////////////////////////////////////////////////////////////
  392. SoundBufferClass *
  393. WWAudioClass::Get_Sound_Buffer (const char *filename, bool is_3d)
  394. {
  395. WWPROFILE ("Get_Sound_Buffer");
  396. //
  397. // Try to find the buffer in our cache, otherwise create a new buffer.
  398. //
  399. SoundBufferClass *buffer = Find_Cached_Buffer (filename);
  400. if (buffer == NULL) {
  401. FileClass *file = Get_File (filename);
  402. if (file != NULL && file->Is_Available ()) {
  403. buffer = Create_Sound_Buffer (*file, filename, is_3d);
  404. } else {
  405. static int count = 0;
  406. if ( ++count < 10 ) {
  407. WWDEBUG_SAY(( "Sound \"%s\" not found\r\n", filename ));
  408. }
  409. }
  410. Return_File (file);
  411. }
  412. return buffer;
  413. }
  414. ////////////////////////////////////////////////////////////////////////////////////////////////
  415. //
  416. // Get_Sound_Buffer
  417. //
  418. ////////////////////////////////////////////////////////////////////////////////////////////////
  419. SoundBufferClass *
  420. WWAudioClass::Get_Sound_Buffer (FileClass &file, const char *string_id, bool is_3d)
  421. {
  422. WWMEMLOG(MEM_SOUND);
  423. //
  424. // Try to find the buffer in our cache, otherwise create a new buffer.
  425. //
  426. SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
  427. if (buffer == NULL) {
  428. buffer = Create_Sound_Buffer (file, string_id, is_3d);
  429. }
  430. return buffer;
  431. }
  432. ////////////////////////////////////////////////////////////////////////////////////////////////
  433. //
  434. // Find_Cached_Buffer
  435. //
  436. ////////////////////////////////////////////////////////////////////////////////////////////////
  437. SoundBufferClass *
  438. WWAudioClass::Find_Cached_Buffer (const char *string_id)
  439. {
  440. WWPROFILE ("Find_Cached_Buffer");
  441. SoundBufferClass *sound_buffer = NULL;
  442. // Param OK?
  443. WWASSERT (string_id != NULL);
  444. if (string_id != NULL) {
  445. //
  446. // Determine which index in our hash table to use
  447. //
  448. int hash_index = ::CRC_Stringi (string_id) & CACHE_HASH_MASK;
  449. //
  450. // Loop through all the buffers at this hash index and try to find
  451. // one that matches the requested name
  452. //
  453. for (int index = 0; index < m_CachedBuffers[hash_index].Count (); index ++) {
  454. //
  455. // Is this the sound buffer we were looking for?
  456. //
  457. CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
  458. if (::lstrcmpi (info.string_id, string_id) == 0) {
  459. sound_buffer = info.buffer;
  460. sound_buffer->Add_Ref ();
  461. break;
  462. }
  463. }
  464. }
  465. //
  466. // Return a pointer to the cached sound buffer
  467. //
  468. return sound_buffer;
  469. }
  470. ////////////////////////////////////////////////////////////////////////////////////////////////
  471. //
  472. // Free_Cache_Space
  473. //
  474. ////////////////////////////////////////////////////////////////////////////////////////////////
  475. bool
  476. WWAudioClass::Free_Cache_Space (int bytes)
  477. {
  478. int bytes_freed = 0;
  479. // Loop through all the hash indicies
  480. for (int hash_index = 0;
  481. (hash_index < MAX_CACHE_HASH) && (bytes_freed < bytes);
  482. hash_index ++) {
  483. // Loop through all the buffers at this hash index
  484. for (int index = 0;
  485. (index < m_CachedBuffers[hash_index].Count ()) && (bytes_freed < bytes);
  486. index ++) {
  487. // Can we free this cached buffer?
  488. CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
  489. if ((info.buffer != NULL) && (info.buffer->Num_Refs () == 1)) {
  490. // Add the size of this buffer to our count of bytes freed
  491. bytes_freed += info.buffer->Get_Raw_Length ();
  492. // Free the buffer data
  493. SAFE_FREE (info.string_id);
  494. REF_PTR_RELEASE (info.buffer);
  495. // Remove this entry from the hash table
  496. m_CachedBuffers[hash_index].Delete (index);
  497. index --;
  498. }
  499. }
  500. }
  501. // Make sure to recompute out current cache size
  502. m_CurrentCacheSize -= bytes_freed;
  503. WWASSERT (m_CurrentCacheSize >= 0);
  504. // Return true if we freed enough bytes in the cache
  505. return (bytes_freed >= bytes);
  506. }
  507. ////////////////////////////////////////////////////////////////////////////////////////////////
  508. //
  509. // Cache_Buffer
  510. //
  511. ////////////////////////////////////////////////////////////////////////////////////////////////
  512. bool
  513. WWAudioClass::Cache_Buffer
  514. (
  515. SoundBufferClass *buffer,
  516. const char *string_id
  517. )
  518. {
  519. WWPROFILE ("Cache_Buffer");
  520. // Assume failure
  521. bool retval = false;
  522. // Params OK?
  523. WWASSERT (buffer != NULL);
  524. WWASSERT (string_id != NULL);
  525. if ((buffer != NULL) && (string_id != NULL)) {
  526. //
  527. // Attempt to free space in the cache (if needed)
  528. //
  529. /*int space_needed = (m_CurrentCacheSize + buffer->Get_Raw_Length ()) - (int)m_MaxCacheSize;
  530. if (space_needed > 0) {
  531. Free_Cache_Space (space_needed);
  532. }*/
  533. // Do we have enough space in the cache for this buffer?
  534. //space_needed = (m_CurrentCacheSize + buffer->Get_Raw_Length ()) - (int)m_MaxCacheSize;
  535. //if (space_needed <= 0) {
  536. //
  537. // Determine which index in our hash table to use
  538. //
  539. int hash_index = ::CRC_Stringi (string_id) & CACHE_HASH_MASK;
  540. //
  541. // Add this buffer to the hash table at the given index.
  542. // Note: The assignment operator caused by the Add call
  543. // will add a reference to the sound buffer.
  544. //
  545. CACHE_ENTRY_STRUCT info;
  546. info.string_id = (char *)string_id;
  547. info.buffer = buffer;
  548. m_CachedBuffers[hash_index].Add (info);
  549. // Update our current cache size
  550. m_CurrentCacheSize += buffer->Get_Raw_Length ();
  551. retval = true;
  552. //}
  553. }
  554. if (retval == false) {
  555. WWDEBUG_SAY (("Unable to cache sound: %s.\r\n", string_id));
  556. }
  557. // Return the true/false result code
  558. return retval;
  559. }
  560. ////////////////////////////////////////////////////////////////////////////////////////////////
  561. //
  562. // Create_Sound_Buffer
  563. //
  564. ////////////////////////////////////////////////////////////////////////////////////////////////
  565. SoundBufferClass *
  566. WWAudioClass::Create_Sound_Buffer
  567. (
  568. FileClass & file,
  569. const char *string_id,
  570. bool is_3d
  571. )
  572. {
  573. WWPROFILE ("Create_Sound_Buffer");
  574. SoundBufferClass *sound_buffer = NULL;
  575. //
  576. // Determine how large this buffer can be
  577. //
  578. int max_size = is_3d ? m_Max3DBufferSize : m_Max2DBufferSize;
  579. //
  580. // Create a streaming sound buffer object if the
  581. // file is too large to preload.
  582. //
  583. if (file.Size () > max_size) {
  584. sound_buffer = new StreamSoundBufferClass;
  585. } else {
  586. sound_buffer = new SoundBufferClass;
  587. }
  588. SET_REF_OWNER(sound_buffer);
  589. //
  590. // Create a new sound buffer from the provided file
  591. //
  592. bool success = sound_buffer->Load_From_File (file);
  593. sound_buffer->Set_Filename (string_id);
  594. WWASSERT (success);
  595. // If we were successful in creating the sound buffer, then
  596. // try to cache it as well, otherwise free the buffer and return NULL.
  597. if (success && (string_id != NULL)) {
  598. Cache_Buffer (sound_buffer, string_id);
  599. } else if (success == false) {
  600. REF_PTR_RELEASE (sound_buffer);
  601. }
  602. // Return a pointer to the new sound buffer
  603. return sound_buffer;
  604. }
  605. ////////////////////////////////////////////////////////////////////////////////////////////////
  606. //
  607. // Create_Sound_Buffer
  608. //
  609. ////////////////////////////////////////////////////////////////////////////////////////////////
  610. SoundBufferClass *
  611. WWAudioClass::Create_Sound_Buffer
  612. (
  613. unsigned char * file_image,
  614. unsigned long bytes,
  615. const char * string_id,
  616. bool is_3d
  617. )
  618. {
  619. WWPROFILE ("Create_Sound_Buffer");
  620. // Create a new sound buffer from the provided file
  621. SoundBufferClass *sound_buffer = new SoundBufferClass;
  622. SET_REF_OWNER(sound_buffer);
  623. //
  624. // Initialize the sound from this piece of memory
  625. //
  626. bool success = sound_buffer->Load_From_Memory (file_image, bytes);
  627. sound_buffer->Set_Filename (string_id);
  628. WWASSERT (success);
  629. // If we were successful in creating the sound buffer, then
  630. // try to cache it as well, otherwise free the buffer and return NULL.
  631. if (success && (string_id != NULL)) {
  632. Cache_Buffer (sound_buffer, string_id);
  633. } else if (success == false) {
  634. REF_PTR_RELEASE (sound_buffer);
  635. }
  636. // Return a pointer to the new sound buffer
  637. return sound_buffer;
  638. }
  639. ////////////////////////////////////////////////////////////////////////////////////////////////
  640. //
  641. // Create_Sound_Effect
  642. //
  643. ////////////////////////////////////////////////////////////////////////////////////////////////
  644. AudibleSoundClass *
  645. WWAudioClass::Create_Sound_Effect (FileClass &file, const char *string_id)
  646. {
  647. WWPROFILE ("Create_Sound_Effect");
  648. // Create a new sound object
  649. AudibleSoundClass *sound_obj = NEW_REF( AudibleSoundClass, () );
  650. if (Is_Disabled () == false) {
  651. // Try to find the buffer in our cache, otherwise create a new buffer.
  652. SoundBufferClass *buffer = Get_Sound_Buffer (file, string_id, false);
  653. // Pass the actual sound data onto the sound object
  654. sound_obj->Set_Buffer (buffer);
  655. REF_PTR_RELEASE (buffer);
  656. }
  657. // Return a pointer to the sound effect
  658. return sound_obj;
  659. }
  660. ////////////////////////////////////////////////////////////////////////////////////////////////
  661. //
  662. // Create_Sound_Effect
  663. //
  664. ////////////////////////////////////////////////////////////////////////////////////////////////
  665. AudibleSoundClass *
  666. WWAudioClass::Create_Sound_Effect (const char *filename)
  667. {
  668. WWPROFILE ("Create_Sound_Effect");
  669. // Assume failure
  670. AudibleSoundClass *sound_obj = NULL;
  671. if (Is_Disabled () == false) {
  672. // Param OK?
  673. WWASSERT (filename != NULL);
  674. if (filename != NULL) {
  675. // Create a file object and pass it onto the appropriate function
  676. FileClass *file = Get_File (filename);
  677. if (file && file->Is_Available()) {
  678. sound_obj = Create_Sound_Effect (*file, filename);
  679. } else {
  680. WWDEBUG_SAY(( "Sound %s not found\r\n", filename ));
  681. }
  682. Return_File (file);
  683. }
  684. }
  685. // Return a pointer to the sound effect
  686. return sound_obj;
  687. }
  688. ////////////////////////////////////////////////////////////////////////////////////////////////
  689. //
  690. // Create_Sound_Effect
  691. //
  692. ////////////////////////////////////////////////////////////////////////////////////////////////
  693. AudibleSoundClass *
  694. WWAudioClass::Create_Sound_Effect
  695. (
  696. const char * string_id,
  697. unsigned char *raw_wave_data,
  698. unsigned long bytes
  699. )
  700. {
  701. WWPROFILE ("Create_Sound_Effect");
  702. // Create a new sound object
  703. AudibleSoundClass *sound_obj = NEW_REF( AudibleSoundClass, () );
  704. if (Is_Disabled () == false) {
  705. // Try to find the buffer in our cache, otherwise create a new buffer.
  706. SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
  707. if (buffer == NULL) {
  708. buffer = Create_Sound_Buffer (raw_wave_data, bytes, string_id, false);
  709. }
  710. // Pass the actual sound data onto the sound object
  711. sound_obj->Set_Buffer (buffer);
  712. REF_PTR_RELEASE (buffer);
  713. }
  714. // Return a pointer to the sound effect
  715. return sound_obj;
  716. }
  717. /////////////////////////////////////////////////////////////////////////////////
  718. //
  719. // Create_3D_Sound
  720. //
  721. ////////////////////////////////////////////////////////////////////////////////////////////////
  722. Sound3DClass *
  723. WWAudioClass::Create_3D_Sound (FileClass &file, const char *string_id, int classid_hint)
  724. {
  725. WWPROFILE ("Create_3D_Sound (FileClass)");
  726. Sound3DClass *sound_obj = NULL;
  727. if (Is_Disabled () == false) {
  728. // Try to find the buffer in our cache, otherwise create a new buffer.
  729. SoundBufferClass *buffer = Get_Sound_Buffer (file, string_id, true);
  730. //
  731. // What type of sound object should we create? A true 3D sound or one of
  732. // our pseudo-3d sounds? (volume and panning only)
  733. //
  734. if ( classid_hint == CLASSID_PSEUDO3D ||
  735. Validate_3D_Sound_Buffer (buffer) == false)
  736. {
  737. sound_obj = new SoundPseudo3DClass;
  738. sound_obj->Set_Buffer (buffer);
  739. } else if (buffer != NULL) {
  740. sound_obj = new Sound3DClass;
  741. sound_obj->Set_Buffer (buffer);
  742. }
  743. REF_PTR_RELEASE (buffer);
  744. }
  745. // Return a pointer to the sound effect
  746. return sound_obj;
  747. }
  748. ////////////////////////////////////////////////////////////////////////////////////////////////
  749. //
  750. // Create_3D_Sound
  751. //
  752. ////////////////////////////////////////////////////////////////////////////////////////////////
  753. Sound3DClass *
  754. WWAudioClass::Create_3D_Sound
  755. (
  756. const char * filename,
  757. int classid_hint
  758. )
  759. {
  760. WWPROFILE ("Create_3D_Sound (filename)");
  761. WWMEMLOG(MEM_SOUND);
  762. // Assume failure
  763. Sound3DClass *sound_obj = NULL;
  764. if (Is_Disabled () == false) {
  765. // Param OK?
  766. WWASSERT (filename != NULL);
  767. if (filename != NULL) {
  768. // Try to find the buffer in our cache, otherwise create a new buffer.
  769. SoundBufferClass *buffer = Get_Sound_Buffer (filename, true);
  770. //
  771. // What type of sound object should we create? A true 3D sound or one of
  772. // our pseudo-3d sounds? (volume and panning only)
  773. //
  774. if ( classid_hint == CLASSID_PSEUDO3D ||
  775. Validate_3D_Sound_Buffer (buffer) == false)
  776. {
  777. sound_obj = new SoundPseudo3DClass;
  778. sound_obj->Set_Buffer (buffer);
  779. } else if (buffer != NULL) {
  780. sound_obj = new Sound3DClass;
  781. sound_obj->Set_Buffer (buffer);
  782. } else {
  783. static int count = 0;
  784. if ( ++count < 10 ) {
  785. WWDEBUG_SAY(( "Sound File not Found \"%s\"\r\n", filename ));
  786. }
  787. }
  788. REF_PTR_RELEASE (buffer);
  789. }
  790. }
  791. // Return a pointer to the sound effect
  792. return sound_obj;
  793. }
  794. ////////////////////////////////////////////////////////////////////////////////////////////////
  795. //
  796. // Create_3D_Sound
  797. //
  798. ////////////////////////////////////////////////////////////////////////////////////////////////
  799. Sound3DClass *
  800. WWAudioClass::Create_3D_Sound
  801. (
  802. const char * string_id,
  803. unsigned char * raw_wave_data,
  804. unsigned long bytes,
  805. int classid_hint
  806. )
  807. {
  808. WWPROFILE ("Create_3D_Sound (Raw)");
  809. Sound3DClass *sound_obj = NULL;
  810. if (Is_Disabled () == false) {
  811. //
  812. // Try to find the buffer in our cache, otherwise create a new buffer.
  813. //
  814. SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
  815. if (buffer == NULL) {
  816. buffer = Create_Sound_Buffer (raw_wave_data, bytes, string_id, true);
  817. }
  818. //
  819. // What type of sound object should we create? A true 3D sound or one of
  820. // our pseudo-3d sounds? (volume and panning only)
  821. //
  822. if ( classid_hint == CLASSID_PSEUDO3D ||
  823. Validate_3D_Sound_Buffer (buffer) == false)
  824. {
  825. sound_obj = new SoundPseudo3DClass;
  826. sound_obj->Set_Buffer (buffer);
  827. } else if (buffer != NULL) {
  828. sound_obj = new Sound3DClass;
  829. sound_obj->Set_Buffer (buffer);
  830. }
  831. REF_PTR_RELEASE (buffer);
  832. }
  833. // Return a pointer to the sound effect
  834. return sound_obj;
  835. }
  836. ////////////////////////////////////////////////////////////////////////////////////////////////
  837. //
  838. // Create_Sound
  839. //
  840. ////////////////////////////////////////////////////////////////////////////////////////////////
  841. AudibleSoundClass *
  842. WWAudioClass::Create_Sound
  843. (
  844. int definition_id,
  845. RefCountClass *user_obj,
  846. uint32 user_data,
  847. int classid_hint
  848. )
  849. {
  850. WWPROFILE ("Create_Sound");
  851. AudibleSoundClass *sound = NULL;
  852. //
  853. // Find the definition
  854. //
  855. DefinitionClass *definition = DefinitionMgrClass::Find_Definition (definition_id);
  856. if (definition != NULL ) {
  857. //
  858. // Make sure this is really a sound definition
  859. //
  860. WWASSERT (definition->Get_Class_ID () == CLASSID_SOUND);
  861. if (definition->Get_Class_ID () == CLASSID_SOUND) {
  862. AudibleSoundDefinitionClass *sound_def = reinterpret_cast<AudibleSoundDefinitionClass *> (definition);
  863. //
  864. // Create an instance of the sound
  865. //
  866. sound = sound_def->Create_Sound (classid_hint);
  867. if (sound != NULL) {
  868. sound->Set_User_Data (user_obj, user_data);
  869. }
  870. }
  871. }
  872. return sound;
  873. }
  874. ////////////////////////////////////////////////////////////////////////////////////////////////
  875. //
  876. // Create_Sound
  877. //
  878. ////////////////////////////////////////////////////////////////////////////////////////////////
  879. AudibleSoundClass *
  880. WWAudioClass::Create_Sound
  881. (
  882. const char * def_name,
  883. RefCountClass *user_obj,
  884. uint32 user_data,
  885. int classid_hint
  886. )
  887. {
  888. WWPROFILE ("Create_Sound");
  889. AudibleSoundClass *sound = NULL;
  890. //
  891. // Find the definition
  892. //
  893. DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (def_name, CLASSID_SOUND, true);
  894. if (definition != NULL ) {
  895. //
  896. // Make sure this is really a sound definition
  897. //
  898. WWASSERT (definition->Get_Class_ID () == CLASSID_SOUND);
  899. if (definition->Get_Class_ID () == CLASSID_SOUND) {
  900. AudibleSoundDefinitionClass *sound_def = reinterpret_cast<AudibleSoundDefinitionClass *> (definition);
  901. //
  902. // Create an instance of the sound
  903. //
  904. sound = sound_def->Create_Sound (classid_hint);
  905. if (sound != NULL) {
  906. sound->Set_User_Data (user_obj, user_data);
  907. }
  908. }
  909. }
  910. return sound;
  911. }
  912. ////////////////////////////////////////////////////////////////////////////////////////////////
  913. //
  914. // Create_Continuous_Sound
  915. //
  916. ////////////////////////////////////////////////////////////////////////////////////////////////
  917. AudibleSoundClass *
  918. WWAudioClass::Create_Continuous_Sound
  919. (
  920. int definition_id,
  921. RefCountClass *user_obj,
  922. uint32 user_data,
  923. int classid_hint
  924. )
  925. {
  926. WWPROFILE ("Create_Continuous_Sound");
  927. //
  928. // Create an instance of the sound and play it
  929. //
  930. AudibleSoundClass *sound = Create_Sound (definition_id, user_obj, user_data, classid_hint);
  931. if (sound != NULL) {
  932. if (sound->Get_Loop_Count () != INFINITE_LOOPS) {
  933. WWDEBUG_SAY (("Audio Error: Creating a continuous sound with a finite loop count!\r\n"));
  934. }
  935. }
  936. return sound;
  937. }
  938. ////////////////////////////////////////////////////////////////////////////////////////////////
  939. //
  940. // Create_Instant_Sound
  941. //
  942. ////////////////////////////////////////////////////////////////////////////////////////////////
  943. int
  944. WWAudioClass::Create_Instant_Sound
  945. (
  946. int definition_id,
  947. const Matrix3D & tm,
  948. RefCountClass * user_obj,
  949. uint32 user_data,
  950. int classid_hint
  951. )
  952. {
  953. WWPROFILE ("Create_Instant_Sound");
  954. int sound_id = 0;
  955. //
  956. // Create an instance of the sound and play it
  957. //
  958. AudibleSoundClass *sound = Create_Sound (definition_id, user_obj, user_data, classid_hint);
  959. if (sound != NULL) {
  960. if (sound->Get_Loop_Count () == INFINITE_LOOPS) {
  961. WWDEBUG_SAY (("Audio Error: Creating an instant sound %s with an infinite loop count!\r\n",sound->Get_Definition()->Get_Name()));
  962. }
  963. sound_id = sound->Get_ID ();
  964. sound->Set_Transform (tm);
  965. sound->Add_To_Scene ();
  966. sound->Release_Ref ();
  967. }
  968. return sound_id;
  969. }
  970. ////////////////////////////////////////////////////////////////////////////////////////////////
  971. //
  972. // Create_Continuous_Sound
  973. //
  974. ////////////////////////////////////////////////////////////////////////////////////////////////
  975. AudibleSoundClass *
  976. WWAudioClass::Create_Continuous_Sound
  977. (
  978. const char * def_name,
  979. RefCountClass *user_obj,
  980. uint32 user_data,
  981. int classid_hint
  982. )
  983. {
  984. WWPROFILE ("Create_Continuous_Sound");
  985. //
  986. // Create an instance of the sound and play it
  987. //
  988. AudibleSoundClass *sound = Create_Sound (def_name, user_obj, user_data, classid_hint);
  989. if (sound != NULL) {
  990. if (sound->Get_Loop_Count () != INFINITE_LOOPS) {
  991. WWDEBUG_SAY (("Audio Error: Creating a continuous sound with a finite loop count!\r\n"));
  992. }
  993. }
  994. return sound;
  995. }
  996. ////////////////////////////////////////////////////////////////////////////////////////////////
  997. //
  998. // Create_Instant_Sound
  999. //
  1000. ////////////////////////////////////////////////////////////////////////////////////////////////
  1001. int
  1002. WWAudioClass::Create_Instant_Sound
  1003. (
  1004. const char * def_name,
  1005. const Matrix3D & tm,
  1006. RefCountClass * user_obj,
  1007. uint32 user_data,
  1008. int classid_hint
  1009. )
  1010. {
  1011. WWPROFILE ("Create_Instant_Sound");
  1012. int sound_id = 0;
  1013. //
  1014. // Create an instance of the sound and play it
  1015. //
  1016. AudibleSoundClass *sound = Create_Sound (def_name, user_obj, user_data, classid_hint);
  1017. if (sound != NULL) {
  1018. if (sound->Get_Loop_Count () == INFINITE_LOOPS) {
  1019. WWDEBUG_SAY (("Audio Error: Creating an instant sound %s with an infinite loop count!\r\n",sound->Get_Definition()->Get_Name()));
  1020. }
  1021. sound_id = sound->Get_ID ();
  1022. sound->Set_Transform (tm);
  1023. sound->Add_To_Scene ();
  1024. sound->Release_Ref ();
  1025. }
  1026. return sound_id;
  1027. }
  1028. ////////////////////////////////////////////////////////////////////////////////////////////////
  1029. //
  1030. // Flush_Playlist
  1031. //
  1032. ////////////////////////////////////////////////////////////////////////////////////////////////
  1033. void
  1034. WWAudioClass::Flush_Playlist (SOUND_PAGE page)
  1035. {
  1036. //
  1037. // Loop through all the entries in this playlist
  1038. //
  1039. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  1040. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  1041. if (sound_obj != NULL) {
  1042. sound_obj->Stop ();
  1043. sound_obj->Remove_From_Scene ();
  1044. }
  1045. //REF_PTR_RELEASE (sound_obj);
  1046. }
  1047. //
  1048. // Now, make sure to free any completed sounds
  1049. //
  1050. Free_Completed_Sounds ();
  1051. //
  1052. // Free the list structure
  1053. //
  1054. m_Playlist[page].Delete_All ();
  1055. return ;
  1056. }
  1057. ////////////////////////////////////////////////////////////////////////////////////////////////
  1058. //
  1059. // Flush_Playlist
  1060. //
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////
  1062. void
  1063. WWAudioClass::Flush_Playlist (void)
  1064. {
  1065. Flush_Playlist (PAGE_PRIMARY);
  1066. Flush_Playlist (PAGE_SECONDARY);
  1067. return ;
  1068. }
  1069. ////////////////////////////////////////////////////////////////////////////////////////////////
  1070. //
  1071. // Free_Completed_Sounds
  1072. //
  1073. ////////////////////////////////////////////////////////////////////////////////////////////////
  1074. void
  1075. WWAudioClass::Free_Completed_Sounds (void)
  1076. {
  1077. if (m_CompletedSounds.Count () > 0) {
  1078. //
  1079. // Loop through all the entries in the completed sounds list
  1080. //
  1081. for (int index = 0; index < m_CompletedSounds.Count (); index ++) {
  1082. AudibleSoundClass *sound_obj = m_CompletedSounds[index];
  1083. WWASSERT(sound_obj != NULL); //TSS 05/24/99
  1084. //
  1085. // Be careful not to remove the sound from the playlist unless
  1086. // its really done playing
  1087. //
  1088. if (sound_obj->Get_State () == AudibleSoundClass::STATE_STOPPED) {
  1089. //
  1090. // Remove this sound from the playlist
  1091. //
  1092. bool found = false;
  1093. for (int page = 0; page < PAGE_COUNT && !found; page ++) {
  1094. for (int play_index = 0; (play_index < m_Playlist[page].Count ()) && !found; play_index ++) {
  1095. if (m_Playlist[page][play_index] == sound_obj) {
  1096. //
  1097. // Free our hold on this sound object
  1098. //
  1099. m_Playlist[page].Delete (play_index);
  1100. REF_PTR_RELEASE (sound_obj);
  1101. found = true;
  1102. }
  1103. }
  1104. }
  1105. }
  1106. }
  1107. //
  1108. // Free the list structure
  1109. //
  1110. m_CompletedSounds.Delete_All ();
  1111. //
  1112. // Try to give a play-handle back to a sound that was priority-bumped.
  1113. //
  1114. Reprioritize_Playlist ();
  1115. }
  1116. return;
  1117. }
  1118. ////////////////////////////////////////////////////////////////////////////////////////////////
  1119. //
  1120. // Get_Playlist_Entry
  1121. //
  1122. ////////////////////////////////////////////////////////////////////////////////////////////////
  1123. AudibleSoundClass *
  1124. WWAudioClass::Get_Playlist_Entry (int index) const
  1125. {
  1126. AudibleSoundClass *sound_obj = NULL;
  1127. // Params OK?
  1128. WWASSERT (index >= 0 && index < m_Playlist[m_CurrPage].Count ());
  1129. if ((index >= 0) && (index < m_Playlist[m_CurrPage].Count ())) {
  1130. m_Playlist[m_CurrPage][index]->Add_Ref ();
  1131. m_Playlist[m_CurrPage][index];
  1132. }
  1133. // Return a pointer to the sound object
  1134. return sound_obj;
  1135. }
  1136. ////////////////////////////////////////////////////////////////////////////////////////////
  1137. //
  1138. // Add_To_Playlist
  1139. //
  1140. ////////////////////////////////////////////////////////////////////////////////////////////////
  1141. bool
  1142. WWAudioClass::Add_To_Playlist (AudibleSoundClass *sound)
  1143. {
  1144. bool retval = false;
  1145. WWASSERT (sound != NULL);
  1146. if (sound != NULL) {
  1147. //
  1148. // Loop through all the entries in the playlist
  1149. //
  1150. bool already_added = false;
  1151. for (int index = 0; (index < m_Playlist[m_CurrPage].Count ()) && (already_added == false); index ++) {
  1152. already_added = (sound == m_Playlist[m_CurrPage][index]);
  1153. }
  1154. //
  1155. // Add this sound to our playlist
  1156. //
  1157. if (already_added == false) {
  1158. sound->Add_Ref ();
  1159. m_Playlist[m_CurrPage].Add (sound);
  1160. }
  1161. }
  1162. return retval;
  1163. }
  1164. ////////////////////////////////////////////////////////////////////////////////////////////
  1165. //
  1166. // Remove_From_Playlist
  1167. //
  1168. ////////////////////////////////////////////////////////////////////////////////////////////////
  1169. bool
  1170. WWAudioClass::Remove_From_Playlist (AudibleSoundClass *sound_obj)
  1171. {
  1172. bool retval = false;
  1173. WWASSERT (sound_obj != NULL);
  1174. if (sound_obj != NULL) {
  1175. //
  1176. // Loop through all the entries in the playlist
  1177. //
  1178. for (int page = 0; page < PAGE_COUNT && !retval; page ++) {
  1179. for (int index = 0; (index < m_Playlist[page].Count ()) && !retval; index ++) {
  1180. //
  1181. // Is this the entry we are looking for?
  1182. //
  1183. if (sound_obj == m_Playlist[page][index]) {
  1184. //
  1185. // Add this sound to the 'completed' list
  1186. //
  1187. m_CompletedSounds.Add (sound_obj);
  1188. retval = true;
  1189. }
  1190. }
  1191. }
  1192. //
  1193. // Notify any callbacks that this sound is ending...
  1194. //
  1195. if (sound_obj->Get_Loop_Count () != INFINITE_LOOPS) {
  1196. for (int index = 0; index < m_EOSCallbackList.Count (); index ++) {
  1197. uint32 user_data = NULL;
  1198. LPFNEOSCALLBACK callback = m_EOSCallbackList.Get_Callback (index, &user_data);
  1199. if (callback != NULL) {
  1200. (*callback) (sound_obj, user_data);
  1201. }
  1202. }
  1203. }
  1204. }
  1205. return retval;
  1206. }
  1207. ////////////////////////////////////////////////////////////////////////////////////////////
  1208. //
  1209. // Is_Sound_In_Playlist
  1210. //
  1211. ////////////////////////////////////////////////////////////////////////////////////////////////
  1212. bool
  1213. WWAudioClass::Is_Sound_In_Playlist (AudibleSoundClass *sound_obj)
  1214. {
  1215. // Assume failure
  1216. bool retval = false;
  1217. // Loop through all the entries in the playlist
  1218. for (int index = 0; (index < m_Playlist[m_CurrPage].Count ()) && (retval == false); index ++) {
  1219. if (sound_obj == m_Playlist[m_CurrPage][index]) {
  1220. retval = true;
  1221. }
  1222. }
  1223. // Return the true/false result code
  1224. return retval;
  1225. }
  1226. ////////////////////////////////////////////////////////////////////////////////////////////
  1227. //
  1228. // Reprioritize_Playlist
  1229. //
  1230. ////////////////////////////////////////////////////////////////////////////////////////////////
  1231. void
  1232. WWAudioClass::Reprioritize_Playlist (void)
  1233. {
  1234. AudibleSoundClass *sound_to_get_handle = NULL;
  1235. float hightest_priority = 0;
  1236. //
  1237. // Loop through all the entries in the playlist
  1238. //
  1239. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1240. //
  1241. // Is this the highest priority without a miles handle?
  1242. //
  1243. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1244. if ((sound_obj->Get_Miles_Handle () == NULL) &&
  1245. (sound_obj->Is_Sound_Culled () == false) &&
  1246. (sound_obj->Get_Priority () > hightest_priority))
  1247. {
  1248. //
  1249. // This is now the highest priority sound effect without
  1250. // a play-handle.
  1251. //
  1252. sound_to_get_handle = sound_obj;
  1253. hightest_priority = sound_obj->Get_Priority ();
  1254. }
  1255. }
  1256. //
  1257. // Get a new handle for this sound if necessary
  1258. //
  1259. if (sound_to_get_handle != NULL) {
  1260. sound_to_get_handle->Allocate_Miles_Handle ();
  1261. }
  1262. return;
  1263. }
  1264. ////////////////////////////////////////////////////////////////////////////////////////////
  1265. //
  1266. // On_Frame_Update
  1267. //
  1268. ////////////////////////////////////////////////////////////////////////////////////////////////
  1269. void
  1270. WWAudioClass::On_Frame_Update (unsigned int milliseconds)
  1271. {
  1272. //
  1273. // Free any sounds we completed last frame
  1274. //
  1275. Free_Completed_Sounds ();
  1276. //
  1277. // Calculate the time in ms since the last frame
  1278. //
  1279. unsigned int time_delta = milliseconds;
  1280. if (time_delta == 0) {
  1281. time_delta = WW3D::Get_Frame_Time ();
  1282. }
  1283. //
  1284. // Update the sound scene as necessary
  1285. //
  1286. if (m_CurrPage == PAGE_PRIMARY && m_SoundScene != NULL) {
  1287. m_SoundScene->On_Frame_Update (milliseconds);
  1288. m_SoundScene->Collect_Logical_Sounds ();
  1289. }
  1290. //int dialog_count = 0;
  1291. //
  1292. // Loop through all the entries in the playlist
  1293. //
  1294. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1295. //
  1296. // Update this sound object
  1297. //
  1298. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1299. sound_obj->On_Frame_Update (time_delta);
  1300. //
  1301. // Is this an important piece of dialog?
  1302. //
  1303. /*if ( sound_obj->Is_Sound_Culled () == false &&
  1304. sound_obj->Get_Type () == AudibleSoundClass::TYPE_DIALOG &&
  1305. sound_obj->Get_Priority () > 0.5F)
  1306. {
  1307. dialog_count ++;
  1308. }*/
  1309. }
  1310. //
  1311. // Fade sound fx and music when there's important dialog playing.
  1312. //
  1313. /*if (dialog_count == 0) {
  1314. Fade_Non_Dialog_In ();
  1315. } else {
  1316. Fade_Non_Dialog_Out ();
  1317. }*/
  1318. //
  1319. // Update any fading we have going on
  1320. //
  1321. //Update_Fade ();
  1322. return;
  1323. }
  1324. ////////////////////////////////////////////////////////////////////////////////////////////
  1325. //
  1326. // Release_2D_Handles
  1327. //
  1328. ////////////////////////////////////////////////////////////////////////////////////////////////
  1329. void
  1330. WWAudioClass::Release_2D_Handles (void)
  1331. {
  1332. MMSLockClass lock;
  1333. // Release our hold on all the samples we've allocated
  1334. for (int index = 0; index < m_2DSampleHandles.Count (); index ++) {
  1335. HSAMPLE sample = m_2DSampleHandles[index];
  1336. if (sample != NULL) {
  1337. ::AIL_release_sample_handle (sample);
  1338. }
  1339. }
  1340. m_2DSampleHandles.Delete_All ();
  1341. return;
  1342. }
  1343. ////////////////////////////////////////////////////////////////////////////////////////////
  1344. //
  1345. // Allocate_2D_Handles
  1346. //
  1347. ////////////////////////////////////////////////////////////////////////////////////////////////
  1348. void
  1349. WWAudioClass::Allocate_2D_Handles (void)
  1350. {
  1351. MMSLockClass lock;
  1352. // Start fresh
  1353. Release_2D_Handles ();
  1354. if (m_Driver2D != NULL) {
  1355. // Attempt to allocate our share of 2D sample handles
  1356. for (int index = 0; index < m_Max2DSamples; index ++) {
  1357. HSAMPLE sample = ::AIL_allocate_sample_handle (m_Driver2D);
  1358. if (sample != NULL) {
  1359. ::AIL_set_sample_user_data (sample, INFO_OBJECT_PTR, NULL);
  1360. m_2DSampleHandles.Add (sample);
  1361. }
  1362. }
  1363. // Record our actual number of available 2D sample handles
  1364. m_Max2DSamples = m_2DSampleHandles.Count ();
  1365. }
  1366. return;
  1367. }
  1368. ////////////////////////////////////////////////////////////////////////////////////////////
  1369. //
  1370. // Get_2D_Sample
  1371. //
  1372. ////////////////////////////////////////////////////////////////////////////////////////////
  1373. HSAMPLE
  1374. WWAudioClass::Get_2D_Sample (const AudibleSoundClass &sound_obj)
  1375. {
  1376. if (Is_OK_To_Give_Handle (sound_obj) == false) {
  1377. return (HSAMPLE)INVALID_MILES_HANDLE;
  1378. }
  1379. MMSLockClass lock;
  1380. float lowest_priority = sound_obj.Get_Priority ();
  1381. float lowest_runtime_priority = sound_obj.Get_Runtime_Priority ();
  1382. AudibleSoundClass *lowest_pri_sound = NULL;
  1383. HSAMPLE lowest_pri_sample = NULL;
  1384. HSAMPLE free_sample = (HSAMPLE)INVALID_MILES_HANDLE;
  1385. // Loop through all the available sample handles and try to find
  1386. // one that isn't being used to play a sound.
  1387. bool found = false;
  1388. for (int index = 0; (index < m_2DSampleHandles.Count ()) && !found; index ++) {
  1389. HSAMPLE sample = m_2DSampleHandles[index];
  1390. if (sample != NULL) {
  1391. // Get a pointer to the object that is currently using this sample
  1392. AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_sample_user_data (sample, INFO_OBJECT_PTR);
  1393. if (sound_obj == NULL) {
  1394. // Return this sample handle to the caller
  1395. free_sample = sample;
  1396. found = true;
  1397. } else {
  1398. //
  1399. // Determine if this sound's priority is lesser then the sound we want to play.
  1400. // This is done by comparing both the designer-specified priority and the current
  1401. // runtime priority (which is calculated by distance to the listener).
  1402. //
  1403. float priority = sound_obj->Get_Priority ();
  1404. float runtime_priority = sound_obj->Get_Runtime_Priority ();
  1405. if ( (priority < lowest_priority) ||
  1406. (priority == lowest_priority && runtime_priority <= lowest_runtime_priority))
  1407. {
  1408. lowest_priority = priority;
  1409. lowest_pri_sound = sound_obj;
  1410. lowest_pri_sample = sample;
  1411. lowest_runtime_priority = runtime_priority;
  1412. }
  1413. }
  1414. }
  1415. }
  1416. // Steal the sample handle from the lower priority
  1417. // sound and return the handle to the caller.
  1418. if ((found == false) && (lowest_pri_sound != NULL)) {
  1419. lowest_pri_sound->Free_Miles_Handle ();
  1420. free_sample = lowest_pri_sample;
  1421. }
  1422. // Return the free sample handle if we found one
  1423. return free_sample;
  1424. }
  1425. ////////////////////////////////////////////////////////////////////////////////////////////
  1426. //
  1427. // Get_3D_Sample
  1428. //
  1429. ////////////////////////////////////////////////////////////////////////////////////////////////
  1430. H3DSAMPLE
  1431. WWAudioClass::Get_3D_Sample (const Sound3DClass &sound_obj)
  1432. {
  1433. if (Is_OK_To_Give_Handle (sound_obj) == false) {
  1434. return (H3DSAMPLE)INVALID_MILES_HANDLE;
  1435. }
  1436. MMSLockClass lock;
  1437. float lowest_priority = sound_obj.Get_Priority ();
  1438. float lowest_runtime_priority = sound_obj.Get_Runtime_Priority ();
  1439. AudibleSoundClass *lowest_pri_sound = NULL;
  1440. H3DSAMPLE lowest_pri_sample = NULL;
  1441. H3DSAMPLE free_sample = (H3DSAMPLE)INVALID_MILES_HANDLE;
  1442. // Loop through all the available sample handles and try to find
  1443. // one that isn't being used to play a sound.
  1444. bool found = false;
  1445. for (int index = 0; (index < m_3DSampleHandles.Count ()) && !found; index ++) {
  1446. H3DSAMPLE sample = m_3DSampleHandles[index];
  1447. if (sample != NULL) {
  1448. // Get a pointer to the object that is currently using this sample
  1449. AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_3D_object_user_data (sample, INFO_OBJECT_PTR);
  1450. if (sound_obj == NULL) {
  1451. // Return this sample handle to the caller
  1452. free_sample = sample;
  1453. found = true;
  1454. } else {
  1455. //
  1456. // Determine if this sound's priority is lesser then the sound we want to play.
  1457. // This is done by comparing both the designer-specified priority and the current
  1458. // runtime priority (which is calculated by distance to the listener).
  1459. //
  1460. float priority = sound_obj->Get_Priority ();
  1461. float runtime_priority = sound_obj->Get_Runtime_Priority ();
  1462. if ( (priority < lowest_priority) ||
  1463. (priority == lowest_priority && runtime_priority <= lowest_runtime_priority))
  1464. {
  1465. lowest_priority = priority;
  1466. lowest_pri_sound = sound_obj;
  1467. lowest_pri_sample = sample;
  1468. lowest_runtime_priority = runtime_priority;
  1469. }
  1470. }
  1471. }
  1472. }
  1473. // Steal the sample handle from the lower priority
  1474. // sound and return the handle to the caller.
  1475. if ((found == false) && (lowest_pri_sound != NULL)) {
  1476. lowest_pri_sound->Free_Miles_Handle ();
  1477. free_sample = lowest_pri_sample;
  1478. }
  1479. // Return the free sample handle if we found one
  1480. return free_sample;
  1481. }
  1482. ////////////////////////////////////////////////////////////////////////////////////////////
  1483. //
  1484. // Get_Listener_Handle
  1485. //
  1486. ////////////////////////////////////////////////////////////////////////////////////////////////
  1487. H3DPOBJECT
  1488. WWAudioClass::Get_Listener_Handle (void)
  1489. {
  1490. MMSLockClass lock;
  1491. return ::AIL_3D_open_listener (m_Driver3D);
  1492. }
  1493. ////////////////////////////////////////////////////////////////////////////////////////////
  1494. //
  1495. // Build_3D_Driver_List
  1496. //
  1497. ////////////////////////////////////////////////////////////////////////////////////////////////
  1498. void
  1499. WWAudioClass::Build_3D_Driver_List (void)
  1500. {
  1501. MMSLockClass lock;
  1502. HPROENUM next = HPROENUM_FIRST;
  1503. HPROVIDER provider = NULL;
  1504. char *name = NULL;
  1505. while (::AIL_enumerate_3D_providers (&next, &provider, &name) > 0) {
  1506. // Can we successfully open this provider?
  1507. if (::AIL_open_3D_provider (provider) == M3D_NOERR) {
  1508. DRIVER_INFO_STRUCT *info = new DRIVER_INFO_STRUCT;
  1509. info->driver = provider;
  1510. info->name = ::strdup (name);
  1511. m_Driver3DList.Add (info);
  1512. ::AIL_close_3D_provider (provider);
  1513. } else {
  1514. char *error_info = ::AIL_last_error ();
  1515. WWDEBUG_SAY (("WWAudio: Unable to open %s.\r\n", name));
  1516. WWDEBUG_SAY (("WWAudio: Reason %s.\r\n", error_info));
  1517. }
  1518. }
  1519. //
  1520. // Attempt to select one of the known drivers (in the following order).
  1521. //
  1522. if ( (Select_3D_Device (DRIVER3D_PSEUDO) == false) &&
  1523. (Select_3D_Device (DRIVER3D_EAX) == false) &&
  1524. (Select_3D_Device (DRIVER3D_A3D) == false) &&
  1525. (Select_3D_Device (DRIVER3D_D3DSOUND) == false) &&
  1526. (Select_3D_Device (DRIVER3D_DOLBY) == false))
  1527. {
  1528. //
  1529. // Couldn't select a known driver, so just use the first possible.
  1530. //
  1531. if (m_Driver3DList.Count () > 0) {
  1532. Select_3D_Device ((int)0);
  1533. }
  1534. }
  1535. return;
  1536. }
  1537. ////////////////////////////////////////////////////////////////////////////////////////////
  1538. //
  1539. // Free_3D_Driver_List
  1540. //
  1541. ////////////////////////////////////////////////////////////////////////////////////////////////
  1542. void
  1543. WWAudioClass::Free_3D_Driver_List (void)
  1544. {
  1545. MMSLockClass lock;
  1546. //
  1547. // Remove all the handles
  1548. //
  1549. Remove_3D_Sound_Handles ();
  1550. Release_3D_Handles ();
  1551. //
  1552. // Loop through all the driver entries and free them all
  1553. //
  1554. for (int index = 0; index < m_Driver3DList.Count (); index ++) {
  1555. DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
  1556. if (info != NULL) {
  1557. //
  1558. // Free the information we have stored with this driver
  1559. //
  1560. if (info->name != NULL) {
  1561. ::free (info->name);
  1562. }
  1563. delete info;
  1564. }
  1565. }
  1566. if (m_Driver3D != NULL) {
  1567. ::AIL_close_3D_provider (m_Driver3D);
  1568. m_Driver3D = NULL;
  1569. }
  1570. //
  1571. // Clear the list
  1572. //
  1573. m_Driver3DList.Delete_All ();
  1574. return;
  1575. }
  1576. ////////////////////////////////////////////////////////////////////////////////////////////
  1577. //
  1578. // Select_3D_Device
  1579. //
  1580. ////////////////////////////////////////////////////////////////////////////////////////////////
  1581. bool
  1582. WWAudioClass::Select_3D_Device (const char *device_name)
  1583. {
  1584. bool retval = false;
  1585. //
  1586. // Loop through all the drivers until we've found the one we want
  1587. //
  1588. for (int index = 0; index < m_Driver3DList.Count (); index ++) {
  1589. DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
  1590. if (info != NULL) {
  1591. //
  1592. // Is this the device we were looking for?
  1593. //
  1594. if (::lstrcmpi (info->name, device_name) == 0) {
  1595. retval = Select_3D_Device (device_name, info->driver);
  1596. break;
  1597. }
  1598. }
  1599. }
  1600. return retval;
  1601. }
  1602. ////////////////////////////////////////////////////////////////////////////////////////////
  1603. //
  1604. // Select_3D_Device
  1605. //
  1606. ////////////////////////////////////////////////////////////////////////////////////////////////
  1607. bool
  1608. WWAudioClass::Select_3D_Device (const char *device_name, HPROVIDER provider)
  1609. {
  1610. bool retval = false;
  1611. if ((provider != NULL) && (provider != m_Driver3D)) {
  1612. Close_3D_Device ();
  1613. //
  1614. // Select this device and re-allocate all handles
  1615. //
  1616. if (::AIL_open_3D_provider (provider) == M3D_NOERR) {
  1617. m_Driver3D = provider;
  1618. m_SoundScene->Initialize ();
  1619. Allocate_3D_Handles ();
  1620. AIL_set_3D_speaker_type (provider, AIL_3D_2_SPEAKER);
  1621. //
  1622. // Adjust the effects level to 1.0 if this is an EAX based driver
  1623. //
  1624. StringClass lower_name = device_name;
  1625. ::strlwr (lower_name.Peek_Buffer ());
  1626. if (::strstr (device_name, "eax") != 0) {
  1627. m_EffectsLevel = 1.0F;
  1628. } else {
  1629. m_EffectsLevel = 0.0F;
  1630. }
  1631. m_Driver3DName = device_name;
  1632. }
  1633. retval = true;
  1634. }
  1635. // Return true if we successfully selected the device
  1636. return retval;
  1637. }
  1638. ////////////////////////////////////////////////////////////////////////////////////////////
  1639. //
  1640. // Select_3D_Device
  1641. //
  1642. ////////////////////////////////////////////////////////////////////////////////////////////////
  1643. bool
  1644. WWAudioClass::Select_3D_Device (int index)
  1645. {
  1646. bool retval = false;
  1647. //
  1648. // Index valid?
  1649. //
  1650. if ((index >= 0) && (index < m_Driver3DList.Count ())) {
  1651. Select_3D_Device (m_Driver3DList[index]->name, m_Driver3DList[index]->driver);
  1652. WWDEBUG_SAY (("WWAudio: Selecting 3D sound device: %s.\r\n", m_Driver3DList[index]->name));
  1653. retval = true;
  1654. }
  1655. //
  1656. // Return true if we successfully selected the device
  1657. //
  1658. return retval;
  1659. }
  1660. ////////////////////////////////////////////////////////////////////////////////////////////
  1661. //
  1662. // Select_3D_Device
  1663. //
  1664. ////////////////////////////////////////////////////////////////////////////////////////////////
  1665. bool
  1666. WWAudioClass::Select_3D_Device (DRIVER_TYPE_3D type)
  1667. {
  1668. // Return true if we successfully selected the device
  1669. return Select_3D_Device (Find_3D_Device (type));
  1670. }
  1671. ////////////////////////////////////////////////////////////////////////////////////////////
  1672. //
  1673. // Find_3D_Device
  1674. //
  1675. ////////////////////////////////////////////////////////////////////////////////////////////////
  1676. int
  1677. WWAudioClass::Find_3D_Device (DRIVER_TYPE_3D type)
  1678. {
  1679. // Determine which substring to search for in the
  1680. // name of the driver.
  1681. const char *sub_string = "RSX";
  1682. switch (type) {
  1683. case DRIVER3D_D3DSOUND:
  1684. sub_string = "DirectSound";
  1685. break;
  1686. case DRIVER3D_EAX:
  1687. sub_string = "EAX";
  1688. break;
  1689. case DRIVER3D_A3D:
  1690. sub_string = "A3D";
  1691. break;
  1692. case DRIVER3D_PSEUDO:
  1693. sub_string = "Fast";
  1694. break;
  1695. case DRIVER3D_DOLBY:
  1696. sub_string = "Dolby";
  1697. break;
  1698. }
  1699. // Loop through all the driver entries and free them all
  1700. int driver_index = -1;
  1701. for (int index = 0; (index < m_Driver3DList.Count ()) && (driver_index == -1); index ++) {
  1702. DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
  1703. if ((info != NULL) && (info->name != NULL)) {
  1704. // Is this the driver we were looking for?
  1705. if (::strstr (info->name, sub_string) != NULL) {
  1706. driver_index = index;
  1707. }
  1708. }
  1709. }
  1710. // Return -1 if not found, otherwise the 0 based index
  1711. return driver_index;
  1712. }
  1713. ////////////////////////////////////////////////////////////////////////////////////////////
  1714. //
  1715. // Allocate_3D_Handles
  1716. //
  1717. ////////////////////////////////////////////////////////////////////////////////////////////////
  1718. void
  1719. WWAudioClass::Allocate_3D_Handles (void)
  1720. {
  1721. MMSLockClass lock;
  1722. // Start fresh
  1723. Release_3D_Handles ();
  1724. if (m_Driver3D != NULL) {
  1725. // Attempt to allocate our share of 3D sample handles
  1726. for (int index = 0; index < m_Max3DSamples; index ++) {
  1727. H3DSAMPLE sample = ::AIL_allocate_3D_sample_handle (m_Driver3D);
  1728. if (sample != NULL) {
  1729. ::AIL_set_3D_object_user_data (sample, INFO_OBJECT_PTR, NULL);
  1730. m_3DSampleHandles.Add (sample);
  1731. }
  1732. }
  1733. }
  1734. return;
  1735. }
  1736. ////////////////////////////////////////////////////////////////////////////////////////////
  1737. //
  1738. // Release_3D_Handles
  1739. //
  1740. ////////////////////////////////////////////////////////////////////////////////////////////////
  1741. void
  1742. WWAudioClass::Release_3D_Handles (void)
  1743. {
  1744. MMSLockClass lock;
  1745. //
  1746. // Release our hold on all the samples we've allocated
  1747. //
  1748. for (int index = 0; index < m_3DSampleHandles.Count (); index ++) {
  1749. H3DSAMPLE sample = m_3DSampleHandles[index];
  1750. if (sample != NULL) {
  1751. ::AIL_release_3D_sample_handle (sample);
  1752. }
  1753. }
  1754. m_3DSampleHandles.Delete_All ();
  1755. return;
  1756. }
  1757. ////////////////////////////////////////////////////////////////////////////////////////////
  1758. //
  1759. // Validate_3D_Sound_Buffer
  1760. //
  1761. ////////////////////////////////////////////////////////////////////////////////////////////////
  1762. bool
  1763. WWAudioClass::Validate_3D_Sound_Buffer (SoundBufferClass *buffer)
  1764. {
  1765. bool retval = false;
  1766. //
  1767. // 3D sound buffer MUST be uncompressed mono WAV data
  1768. //
  1769. if ((buffer != NULL) &&
  1770. (buffer->Get_Channels () == 1) &&
  1771. (buffer->Get_Type () == WAVE_FORMAT_PCM) &&
  1772. (buffer->Is_Streaming () == false))
  1773. {
  1774. retval = true;
  1775. }
  1776. // Return a true/false result code
  1777. return retval;
  1778. }
  1779. ////////////////////////////////////////////////////////////////////////////////////////////
  1780. //
  1781. // ReAssign_2D_Handles
  1782. //
  1783. ////////////////////////////////////////////////////////////////////////////////////////////////
  1784. void
  1785. WWAudioClass::ReAssign_2D_Handles (void)
  1786. {
  1787. // Loop through all the entries in the playlist
  1788. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1789. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1790. // If this is a 2D sound effect, then force it to 'get' a new
  1791. // sound handle.
  1792. if ((sound_obj->Get_Class_ID () == CLASSID_2D) ||
  1793. (sound_obj->Get_Class_ID () == CLASSID_PSEUDO3D) ||
  1794. (sound_obj->Get_Class_ID () == CLASSID_2DTRIGGER))
  1795. {
  1796. sound_obj->Free_Miles_Handle ();
  1797. sound_obj->Allocate_Miles_Handle ();
  1798. }
  1799. }
  1800. return;
  1801. }
  1802. ////////////////////////////////////////////////////////////////////////////////////////////
  1803. //
  1804. // ReAssign_3D_Handles
  1805. //
  1806. ////////////////////////////////////////////////////////////////////////////////////////////////
  1807. void
  1808. WWAudioClass::ReAssign_3D_Handles (void)
  1809. {
  1810. // Loop through all the entries in the playlist
  1811. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1812. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1813. // If this is a 3D sound effect, then force it to 'get' a new
  1814. // sound handle.
  1815. if (sound_obj->Get_Class_ID () == CLASSID_3D) {
  1816. sound_obj->Free_Miles_Handle ();
  1817. sound_obj->Allocate_Miles_Handle ();
  1818. }
  1819. }
  1820. return;
  1821. }
  1822. ////////////////////////////////////////////////////////////////////////////////////////////
  1823. //
  1824. // Remove_2D_Sound_Handles
  1825. //
  1826. ////////////////////////////////////////////////////////////////////////////////////////////////
  1827. void
  1828. WWAudioClass::Remove_2D_Sound_Handles (void)
  1829. {
  1830. //
  1831. // Loop over all the 2D handles
  1832. //
  1833. for (int index = 0; index < m_2DSampleHandles.Count (); index ++) {
  1834. HSAMPLE sample = m_2DSampleHandles[index];
  1835. if (sample != NULL) {
  1836. //
  1837. // Get a pointer to the object that is currently using this sample
  1838. //
  1839. AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_sample_user_data (sample, INFO_OBJECT_PTR);
  1840. if (sound_obj != NULL) {
  1841. sound_obj->Free_Miles_Handle ();
  1842. }
  1843. }
  1844. }
  1845. return;
  1846. }
  1847. ////////////////////////////////////////////////////////////////////////////////////////////
  1848. //
  1849. // Remove_3D_Sound_Handles
  1850. //
  1851. ////////////////////////////////////////////////////////////////////////////////////////////////
  1852. void
  1853. WWAudioClass::Remove_3D_Sound_Handles (void)
  1854. {
  1855. //
  1856. // Loop over all the 3D handles
  1857. //
  1858. for (int index = 0; index < m_3DSampleHandles.Count (); index ++) {
  1859. H3DSAMPLE sample = m_3DSampleHandles[index];
  1860. if (sample != NULL) {
  1861. //
  1862. // Get a pointer to the object that is currently using this sample
  1863. //
  1864. AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_3D_object_user_data (sample, INFO_OBJECT_PTR);
  1865. if (sound_obj != NULL) {
  1866. sound_obj->Free_Miles_Handle ();
  1867. }
  1868. }
  1869. }
  1870. return ;
  1871. }
  1872. ////////////////////////////////////////////////////////////////////////////////////////////
  1873. //
  1874. // Set_Dialog_Volume
  1875. //
  1876. ////////////////////////////////////////////////////////////////////////////////////////////////
  1877. void
  1878. WWAudioClass::Set_Dialog_Volume (float volume)
  1879. {
  1880. m_DialogVolume = volume;
  1881. m_DialogVolume = min (1.0F, m_DialogVolume);
  1882. m_DialogVolume = max (0.0F, m_DialogVolume);
  1883. // Update all the currently playing 'Dialog' to
  1884. // reflect this new volume
  1885. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1886. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1887. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_DIALOG) {
  1888. sound_obj->Update_Volume ();
  1889. }
  1890. }
  1891. return ;
  1892. }
  1893. ////////////////////////////////////////////////////////////////////////////////////////////
  1894. //
  1895. // Set_Cinematic_Volume
  1896. //
  1897. ////////////////////////////////////////////////////////////////////////////////////////////////
  1898. void
  1899. WWAudioClass::Set_Cinematic_Volume (float volume)
  1900. {
  1901. m_CinematicVolume = volume;
  1902. m_CinematicVolume = min (1.0F, m_CinematicVolume);
  1903. m_CinematicVolume = max (0.0F, m_CinematicVolume);
  1904. //
  1905. // Update all the currently playing cinematic-counds to
  1906. // reflect this new volume
  1907. //
  1908. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1909. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1910. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_CINEMATIC) {
  1911. sound_obj->Update_Volume ();
  1912. }
  1913. }
  1914. return ;
  1915. }
  1916. ////////////////////////////////////////////////////////////////////////////////////////////
  1917. //
  1918. // Set_Sound_Effects_Volume
  1919. //
  1920. ////////////////////////////////////////////////////////////////////////////////////////////////
  1921. void
  1922. WWAudioClass::Set_Sound_Effects_Volume (float volume)
  1923. {
  1924. m_RealSoundVolume = volume;
  1925. m_RealSoundVolume = min (1.0F, m_RealSoundVolume);
  1926. m_RealSoundVolume = max (0.0F, m_RealSoundVolume);
  1927. Internal_Set_Sound_Effects_Volume (m_RealSoundVolume);
  1928. return ;
  1929. }
  1930. ////////////////////////////////////////////////////////////////////////////////////////////
  1931. //
  1932. // Set_Music_Volume
  1933. //
  1934. ////////////////////////////////////////////////////////////////////////////////////////////////
  1935. void
  1936. WWAudioClass::Set_Music_Volume (float volume)
  1937. {
  1938. m_RealMusicVolume = volume;
  1939. m_RealMusicVolume = min (1.0F, m_RealMusicVolume);
  1940. m_RealMusicVolume = max (0.0F, m_RealMusicVolume);
  1941. Internal_Set_Music_Volume (m_RealMusicVolume);
  1942. return;
  1943. }
  1944. ////////////////////////////////////////////////////////////////////////////////////////////
  1945. //
  1946. // Internal_Set_Sound_Effects_Volume
  1947. //
  1948. ////////////////////////////////////////////////////////////////////////////////////////////////
  1949. void
  1950. WWAudioClass::Internal_Set_Sound_Effects_Volume (float volume)
  1951. {
  1952. m_SoundVolume = volume;
  1953. m_SoundVolume = min (1.0F, m_SoundVolume);
  1954. m_SoundVolume = max (0.0F, m_SoundVolume);
  1955. // Update all the currently playing 'Sound Effects' to
  1956. // reflect this new volume
  1957. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1958. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1959. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
  1960. sound_obj->Update_Volume ();
  1961. }
  1962. }
  1963. return ;
  1964. }
  1965. ////////////////////////////////////////////////////////////////////////////////////////////
  1966. //
  1967. // Internal_Set_Music_Volume
  1968. //
  1969. ////////////////////////////////////////////////////////////////////////////////////////////////
  1970. void
  1971. WWAudioClass::Internal_Set_Music_Volume (float volume)
  1972. {
  1973. m_MusicVolume = volume;
  1974. m_MusicVolume = min (1.0F, m_MusicVolume);
  1975. m_MusicVolume = max (0.0F, m_MusicVolume);
  1976. // Update all currently playing music to
  1977. // reflect this new volume
  1978. for (int index = 0; index < m_Playlist[m_CurrPage].Count (); index ++) {
  1979. AudibleSoundClass *sound_obj = m_Playlist[m_CurrPage][index];
  1980. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
  1981. sound_obj->Update_Volume ();
  1982. }
  1983. }
  1984. return;
  1985. }
  1986. ////////////////////////////////////////////////////////////////////////////////////////////
  1987. //
  1988. // Is_Disabled
  1989. //
  1990. ////////////////////////////////////////////////////////////////////////////////////////////////
  1991. bool
  1992. WWAudioClass::Is_Disabled (void) const
  1993. {
  1994. static bool _firsttime = true;
  1995. static bool _disabled = false;
  1996. if (_firsttime) {
  1997. _firsttime = false;
  1998. #ifdef G_CODE_BASE
  1999. //
  2000. // Use command line arguement.
  2001. //
  2002. ArgvClass argv;
  2003. if (argv.Find("-NOAUDIO")) {
  2004. _disabled = true;
  2005. }
  2006. #endif
  2007. //
  2008. // Read the disabled key from the registry
  2009. //
  2010. RegistryClass registry ("SOFTWARE\\Westwood\\WWAudio");
  2011. if (registry.Is_Valid ()) {
  2012. if (registry.Get_Int ("Disabled", 0) == 1) {
  2013. _disabled = true;
  2014. WWDEBUG_SAY (("WWAudio: Audio system disabled in registry.\r\n"));
  2015. }
  2016. }
  2017. }
  2018. return (_disabled | m_ForceDisable);
  2019. }
  2020. ////////////////////////////////////////////////////////////////////////////////////////////
  2021. //
  2022. // Initialize
  2023. //
  2024. ////////////////////////////////////////////////////////////////////////////////////////////////
  2025. void
  2026. WWAudioClass::Initialize (const char *registry_subkey_name)
  2027. {
  2028. WWMEMLOG(MEM_SOUND);
  2029. if (Is_Disabled () == false) {
  2030. //
  2031. // Initialize the audio system from the registry settings
  2032. //
  2033. Load_From_Registry (registry_subkey_name);
  2034. //
  2035. // Grab the first (and only) filter for use with our 'tinny' effect.
  2036. //
  2037. HPROENUM next = HPROENUM_FIRST;
  2038. char *name = NULL;
  2039. if (::AIL_enumerate_filters (&next, &m_ReverbFilter, &name) == 0) {
  2040. m_ReverbFilter = INVALID_MILES_HANDLE;
  2041. }
  2042. m_RealMusicVolume = m_MusicVolume;
  2043. m_RealSoundVolume = m_SoundVolume;
  2044. }
  2045. //
  2046. // Register the file callbacks so we can support streaming from MIX files...
  2047. //
  2048. ::AIL_set_file_callbacks (File_Open_Callback, File_Close_Callback,
  2049. File_Seek_Callback, File_Read_Callback);
  2050. return ;
  2051. }
  2052. ////////////////////////////////////////////////////////////////////////////////////////////
  2053. //
  2054. // Initialize
  2055. //
  2056. ////////////////////////////////////////////////////////////////////////////////////////////////
  2057. void
  2058. WWAudioClass::Initialize
  2059. (
  2060. bool stereo,
  2061. int bits,
  2062. int hertz
  2063. )
  2064. {
  2065. // Open the default 2D device, then build a list of 3D
  2066. // devices and open the default.
  2067. if (Is_Disabled () == false) {
  2068. Open_2D_Device (stereo, bits, hertz);
  2069. Build_3D_Driver_List ();
  2070. //
  2071. // Grab the first (and only) filter for use with our 'tinny' effect.
  2072. //
  2073. HPROENUM next = HPROENUM_FIRST;
  2074. char *name = NULL;
  2075. if (::AIL_enumerate_filters (&next, &m_ReverbFilter, &name) == 0) {
  2076. m_ReverbFilter = INVALID_MILES_HANDLE;
  2077. }
  2078. }
  2079. //
  2080. // Register the file callbacks so we can support streaming from MIX files...
  2081. //
  2082. ::AIL_set_file_callbacks (File_Open_Callback, File_Close_Callback,
  2083. File_Seek_Callback, File_Read_Callback);
  2084. return;
  2085. }
  2086. ////////////////////////////////////////////////////////////////////////////////////////////
  2087. //
  2088. // Shutdown
  2089. //
  2090. ////////////////////////////////////////////////////////////////////////////////////////////////
  2091. void
  2092. WWAudioClass::Shutdown (void)
  2093. {
  2094. //
  2095. // If there is a timer running, then stop the timer...
  2096. //
  2097. if (m_UpdateTimer != -1) {
  2098. // Kill the timer
  2099. ::AIL_stop_timer (m_UpdateTimer);
  2100. ::AIL_release_timer_handle (m_UpdateTimer);
  2101. m_UpdateTimer = -1;
  2102. // Wait for the timer callback function to end
  2103. ::WaitForSingleObject (_TimerSyncEvent, 20000);
  2104. ::CloseHandle (_TimerSyncEvent);
  2105. _TimerSyncEvent = NULL;
  2106. }
  2107. //
  2108. // Stop the background music
  2109. //
  2110. Set_Background_Music (NULL);
  2111. //
  2112. // Stop all sounds from playing
  2113. //
  2114. Flush_Playlist ();
  2115. if (m_SoundScene != NULL) {
  2116. m_SoundScene->Flush_Scene ();
  2117. }
  2118. //
  2119. // Free all our cached sound buffers
  2120. //
  2121. Flush_Cache ();
  2122. //
  2123. // Close-out our hold on any driver resources
  2124. //
  2125. Remove_2D_Sound_Handles ();
  2126. Remove_3D_Sound_Handles ();
  2127. Release_2D_Handles ();
  2128. Release_3D_Handles ();
  2129. Free_3D_Driver_List ();
  2130. SAFE_DELETE (m_SoundScene);
  2131. Close_2D_Device ();
  2132. //
  2133. // Shutdown Miles Sound System
  2134. //
  2135. ::AIL_shutdown ();
  2136. return;
  2137. }
  2138. ////////////////////////////////////////////////////////////////////////////////////////////
  2139. //
  2140. // Register_EOS_Callback
  2141. //
  2142. ////////////////////////////////////////////////////////////////////////////////////////////////
  2143. void
  2144. WWAudioClass::Register_EOS_Callback (LPFNEOSCALLBACK callback, DWORD user_param)
  2145. {
  2146. m_EOSCallbackList.Add_Callback (callback, user_param);
  2147. return;
  2148. }
  2149. ////////////////////////////////////////////////////////////////////////////////////////////
  2150. //
  2151. // UnRegister_EOS_Callback
  2152. //
  2153. ////////////////////////////////////////////////////////////////////////////////////////////////
  2154. void
  2155. WWAudioClass::UnRegister_EOS_Callback (LPFNEOSCALLBACK callback)
  2156. {
  2157. m_EOSCallbackList.Remove_Callback (callback);
  2158. return;
  2159. }
  2160. ////////////////////////////////////////////////////////////////////////////////////////////
  2161. //
  2162. // Register_Text_Callback
  2163. //
  2164. ////////////////////////////////////////////////////////////////////////////////////////////////
  2165. void
  2166. WWAudioClass::Register_Text_Callback (LPFNTEXTCALLBACK callback, DWORD user_param)
  2167. {
  2168. m_TextCallbackList.Add_Callback (callback, user_param);
  2169. return;
  2170. }
  2171. ////////////////////////////////////////////////////////////////////////////////////////////
  2172. //
  2173. // UnRegister_Text_Callback
  2174. //
  2175. ////////////////////////////////////////////////////////////////////////////////////////////////
  2176. void
  2177. WWAudioClass::UnRegister_Text_Callback (LPFNTEXTCALLBACK callback)
  2178. {
  2179. m_TextCallbackList.Remove_Callback (callback);
  2180. return;
  2181. }
  2182. ////////////////////////////////////////////////////////////////////////////////////////////
  2183. //
  2184. // Fire_Text_Callback
  2185. //
  2186. ////////////////////////////////////////////////////////////////////////////////////////////////
  2187. void
  2188. WWAudioClass::Fire_Text_Callback (AudibleSoundClass *sound_obj, const StringClass &text)
  2189. {
  2190. if (text.Get_Length () > 0) {
  2191. //
  2192. // Loop over all the text-callbacks that have been registered
  2193. //
  2194. for (int index = 0; index < m_TextCallbackList.Count (); index ++) {
  2195. uint32 user_data = 0L;
  2196. LPFNTEXTCALLBACK callback = m_TextCallbackList.Get_Callback (index, &user_data);
  2197. if (callback != NULL) {
  2198. //
  2199. // Fire the notification
  2200. //
  2201. (*callback) (sound_obj, text, user_data);
  2202. }
  2203. }
  2204. }
  2205. return ;
  2206. }
  2207. ////////////////////////////////////////////////////////////////////////////////////////////
  2208. //
  2209. // Allow_Sound_Effects
  2210. //
  2211. ////////////////////////////////////////////////////////////////////////////////////////////////
  2212. void
  2213. WWAudioClass::Allow_Sound_Effects (bool onoff)
  2214. {
  2215. //
  2216. // Is the state changing?
  2217. //
  2218. if (m_AreSoundEffectsEnabled != onoff) {
  2219. m_AreSoundEffectsEnabled = onoff;
  2220. //
  2221. // Update all the currently playing 'Sound Effects' to
  2222. // reflect this new state.
  2223. //
  2224. if (m_AreSoundEffectsEnabled) {
  2225. for (int page = 0; page < PAGE_COUNT; page ++) {
  2226. Push_Active_Sound_Page ((WWAudioClass::SOUND_PAGE)page);
  2227. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2228. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2229. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
  2230. sound_obj->Allocate_Miles_Handle ();
  2231. }
  2232. }
  2233. Pop_Active_Sound_Page ();
  2234. }
  2235. } else {
  2236. for (int page = 0; page < PAGE_COUNT; page ++) {
  2237. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2238. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2239. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
  2240. sound_obj->Free_Miles_Handle ();
  2241. }
  2242. }
  2243. }
  2244. }
  2245. }
  2246. return;
  2247. }
  2248. ////////////////////////////////////////////////////////////////////////////////////////////
  2249. //
  2250. // Allow_Music
  2251. //
  2252. ////////////////////////////////////////////////////////////////////////////////////////////////
  2253. void
  2254. WWAudioClass::Allow_Music (bool onoff)
  2255. {
  2256. // Is the state changing?
  2257. if (m_IsMusicEnabled != onoff) {
  2258. m_IsMusicEnabled = onoff;
  2259. //
  2260. // Update all the currently playing 'music tracks' to
  2261. // reflect this new state.
  2262. //
  2263. if (m_IsMusicEnabled) {
  2264. for (int page = 0; page < PAGE_COUNT; page ++) {
  2265. Push_Active_Sound_Page ((WWAudioClass::SOUND_PAGE)page);
  2266. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2267. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2268. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
  2269. sound_obj->Stop (false);
  2270. sound_obj->Play ();
  2271. }
  2272. }
  2273. Pop_Active_Sound_Page ();
  2274. }
  2275. } else {
  2276. for (int page = 0; page < PAGE_COUNT; page ++) {
  2277. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2278. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2279. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
  2280. sound_obj->Free_Miles_Handle ();
  2281. }
  2282. }
  2283. }
  2284. }
  2285. }
  2286. return;
  2287. }
  2288. ////////////////////////////////////////////////////////////////////////////////////////////
  2289. //
  2290. // Allow_Dialog
  2291. //
  2292. ////////////////////////////////////////////////////////////////////////////////////////////////
  2293. void
  2294. WWAudioClass::Allow_Dialog (bool onoff)
  2295. {
  2296. // Is the state changing?
  2297. if (m_IsDialogEnabled != onoff) {
  2298. m_IsDialogEnabled = onoff;
  2299. //
  2300. // Update all the currently playing 'dialog' to
  2301. // reflect this new state.
  2302. //
  2303. if (m_IsDialogEnabled) {
  2304. for (int page = 0; page < PAGE_COUNT; page ++) {
  2305. Push_Active_Sound_Page ((WWAudioClass::SOUND_PAGE)page);
  2306. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2307. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2308. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_DIALOG) {
  2309. sound_obj->Stop (false);
  2310. sound_obj->Play ();
  2311. }
  2312. }
  2313. Pop_Active_Sound_Page ();
  2314. }
  2315. } else {
  2316. for (int page = 0; page < PAGE_COUNT; page ++) {
  2317. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2318. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2319. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_DIALOG) {
  2320. sound_obj->Free_Miles_Handle ();
  2321. }
  2322. }
  2323. }
  2324. }
  2325. }
  2326. return;
  2327. }
  2328. ////////////////////////////////////////////////////////////////////////////////////////////
  2329. //
  2330. // Allow_Cinematic_Sound
  2331. //
  2332. ////////////////////////////////////////////////////////////////////////////////////////////////
  2333. void
  2334. WWAudioClass::Allow_Cinematic_Sound (bool onoff)
  2335. {
  2336. // Is the state changing?
  2337. if (m_IsCinematicSoundEnabled != onoff) {
  2338. m_IsCinematicSoundEnabled = onoff;
  2339. //
  2340. // Update all the currently playing 'dialog' to
  2341. // reflect this new state.
  2342. //
  2343. if (m_IsCinematicSoundEnabled) {
  2344. for (int page = 0; page < PAGE_COUNT; page ++) {
  2345. Push_Active_Sound_Page ((WWAudioClass::SOUND_PAGE)page);
  2346. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2347. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2348. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_CINEMATIC) {
  2349. sound_obj->Stop (false);
  2350. sound_obj->Play ();
  2351. }
  2352. }
  2353. Pop_Active_Sound_Page ();
  2354. }
  2355. } else {
  2356. for (int page = 0; page < PAGE_COUNT; page ++) {
  2357. for (int index = 0; index < m_Playlist[page].Count (); index ++) {
  2358. AudibleSoundClass *sound_obj = m_Playlist[page][index];
  2359. if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_CINEMATIC) {
  2360. sound_obj->Free_Miles_Handle ();
  2361. }
  2362. }
  2363. }
  2364. }
  2365. }
  2366. return;
  2367. }
  2368. ////////////////////////////////////////////////////////////////////////////////////////////
  2369. //
  2370. // Simple_Play_2D_Sound_Effect
  2371. //
  2372. ////////////////////////////////////////////////////////////////////////////////////////////////
  2373. bool
  2374. WWAudioClass::Simple_Play_2D_Sound_Effect
  2375. (
  2376. const char *filename,
  2377. float priority,
  2378. float volume
  2379. )
  2380. {
  2381. bool retval = false;
  2382. AudibleSoundClass *sound = Create_Sound_Effect (filename);
  2383. if (sound != NULL) {
  2384. sound->Set_Priority (priority);
  2385. sound->Set_Loop_Count (1);
  2386. sound->Set_Volume(volume);
  2387. sound->Play ();
  2388. sound->Release_Ref ();
  2389. sound = NULL;
  2390. retval = true;
  2391. }
  2392. return retval;
  2393. }
  2394. ////////////////////////////////////////////////////////////////////////////////////////////
  2395. //
  2396. // Simple_Play_2D_Sound_Effect
  2397. //
  2398. ////////////////////////////////////////////////////////////////////////////////////////////////
  2399. bool
  2400. WWAudioClass::Simple_Play_2D_Sound_Effect
  2401. (
  2402. FileClass &file,
  2403. float priority,
  2404. float volume
  2405. )
  2406. {
  2407. bool retval = false;
  2408. AudibleSoundClass *sound = Create_Sound_Effect (file);
  2409. if (sound != NULL) {
  2410. sound->Set_Priority (priority);
  2411. sound->Set_Loop_Count (1);
  2412. sound->Set_Volume(volume);
  2413. sound->Play ();
  2414. sound->Release_Ref ();
  2415. sound = NULL;
  2416. retval = true;
  2417. }
  2418. return retval;
  2419. }
  2420. ////////////////////////////////////////////////////////////////////////////////////////////
  2421. //
  2422. // Get_File
  2423. //
  2424. ////////////////////////////////////////////////////////////////////////////////////////////////
  2425. FileClass *
  2426. WWAudioClass::Get_File (LPCTSTR filename)
  2427. {
  2428. FileClass *file = NULL;
  2429. if (m_FileFactory != NULL) {
  2430. file = m_FileFactory->Get_File (filename);
  2431. } else {
  2432. file = _TheFileFactory->Get_File(filename);
  2433. }
  2434. // Return a pointer to the file
  2435. return file;
  2436. }
  2437. ////////////////////////////////////////////////////////////////////////////////////////////
  2438. //
  2439. // Return_File
  2440. //
  2441. ////////////////////////////////////////////////////////////////////////////////////////////////
  2442. void
  2443. WWAudioClass::Return_File (FileClass *file)
  2444. {
  2445. if (m_FileFactory != NULL) {
  2446. m_FileFactory->Return_File (file);
  2447. } else {
  2448. SAFE_DELETE (file);
  2449. }
  2450. return;
  2451. }
  2452. ////////////////////////////////////////////////////////////////////////////////////////////
  2453. //
  2454. // Create_Logical_Sound
  2455. //
  2456. ////////////////////////////////////////////////////////////////////////////////////////////
  2457. LogicalSoundClass *
  2458. WWAudioClass::Create_Logical_Sound (void)
  2459. {
  2460. return new LogicalSoundClass;
  2461. }
  2462. ////////////////////////////////////////////////////////////////////////////////////////////
  2463. //
  2464. // Create_Logical_Listener
  2465. //
  2466. ////////////////////////////////////////////////////////////////////////////////////////////
  2467. LogicalListenerClass *
  2468. WWAudioClass::Create_Logical_Listener (void)
  2469. {
  2470. return new LogicalListenerClass;
  2471. }
  2472. ////////////////////////////////////////////////////////////////////////////////////////////
  2473. //
  2474. // Add_Logical_Type
  2475. //
  2476. ////////////////////////////////////////////////////////////////////////////////////////////
  2477. void
  2478. WWAudioClass::Add_Logical_Type (int id, LPCTSTR display_name)
  2479. {
  2480. m_LogicalTypes.Add (LOGICAL_TYPE_STRUCT (id, display_name));
  2481. return ;
  2482. }
  2483. ////////////////////////////////////////////////////////////////////////////////////////////
  2484. //
  2485. // Reset_Logical_Types
  2486. //
  2487. ////////////////////////////////////////////////////////////////////////////////////////////
  2488. void
  2489. WWAudioClass::Reset_Logical_Types (void)
  2490. {
  2491. m_LogicalTypes.Delete_All ();
  2492. return ;
  2493. }
  2494. ////////////////////////////////////////////////////////////////////////////////////////////
  2495. //
  2496. // Get_Logical_Type
  2497. //
  2498. ////////////////////////////////////////////////////////////////////////////////////////////
  2499. int
  2500. WWAudioClass::Get_Logical_Type (int index, StringClass &name)
  2501. {
  2502. int type_id = 0;
  2503. WWASSERT (index >= 0 && index < m_LogicalTypes.Count ());
  2504. if (index >= 0 && index < m_LogicalTypes.Count ()) {
  2505. type_id = m_LogicalTypes[index].id;
  2506. name = m_LogicalTypes[index].display_name;
  2507. }
  2508. return type_id;
  2509. }
  2510. ////////////////////////////////////////////////////////////////////////////////////////////
  2511. //
  2512. // Find_Sound_Object
  2513. //
  2514. ////////////////////////////////////////////////////////////////////////////////////////////
  2515. SoundSceneObjClass *
  2516. WWAudioClass::Find_Sound_Object (uint32 sound_obj_id)
  2517. {
  2518. SoundSceneObjClass *sound_obj = NULL;
  2519. //
  2520. // Lookup the sound object and return it to the caller
  2521. //
  2522. int index = 0;
  2523. if (SoundSceneObjClass::Find_Sound_Object (sound_obj_id, &index)) {
  2524. sound_obj = SoundSceneObjClass::m_GlobalSoundList[index];
  2525. }
  2526. return sound_obj;
  2527. }
  2528. ////////////////////////////////////////////////////////////////////////////////////////////
  2529. //
  2530. // Load_From_Registry
  2531. //
  2532. ////////////////////////////////////////////////////////////////////////////////////////////
  2533. bool
  2534. WWAudioClass::Load_From_Registry (const char *subkey_name)
  2535. {
  2536. bool retval = true;
  2537. StringClass device_name;
  2538. bool is_stereo = true;
  2539. int bits = 16;
  2540. int hertz = 44100;
  2541. //
  2542. // Load the settings from the registry
  2543. //
  2544. if (Load_From_Registry (subkey_name, device_name, is_stereo, bits, hertz,
  2545. m_AreSoundEffectsEnabled, m_IsMusicEnabled, m_IsDialogEnabled, m_IsCinematicSoundEnabled,
  2546. m_SoundVolume, m_MusicVolume, m_DialogVolume, m_CinematicVolume, m_SpeakerType))
  2547. {
  2548. //
  2549. // Close any open devices
  2550. //
  2551. Free_3D_Driver_List ();
  2552. Close_2D_Device ();
  2553. //
  2554. // Open the 2D device as specified
  2555. //
  2556. Open_2D_Device (is_stereo, bits, hertz);
  2557. //
  2558. // Find and open the 3D device specified
  2559. //
  2560. Build_3D_Driver_List ();
  2561. Select_3D_Device (device_name);
  2562. retval = true;
  2563. //
  2564. // Select the speaker type
  2565. //
  2566. Set_Speaker_Type (m_SpeakerType);
  2567. }
  2568. m_RealMusicVolume = m_MusicVolume;
  2569. m_RealSoundVolume = m_SoundVolume;
  2570. return retval;
  2571. }
  2572. ////////////////////////////////////////////////////////////////////////////////////////////
  2573. //
  2574. // Load_From_Registry
  2575. //
  2576. ////////////////////////////////////////////////////////////////////////////////////////////
  2577. bool
  2578. WWAudioClass::Load_From_Registry
  2579. (
  2580. const char * subkey_name,
  2581. StringClass & device_name,
  2582. bool & is_stereo,
  2583. int & bits,
  2584. int & hertz,
  2585. bool & sound_enabled,
  2586. bool & music_enabled,
  2587. bool & dialog_enabled,
  2588. bool & cinematic_enabled,
  2589. float & sound_volume,
  2590. float & music_volume,
  2591. float & dialog_volume,
  2592. float & cinematic_volume,
  2593. int & speaker_type
  2594. )
  2595. {
  2596. bool retval = false;
  2597. //
  2598. // Attempt to open the registry key
  2599. //
  2600. RegistryClass registry (subkey_name);
  2601. if (registry.Is_Valid ()) {
  2602. int defaultmusicvolume, defaultsoundvolume, defaultdialogvolume, defaultcinematicvolume;
  2603. //
  2604. // Read the device name into a string object
  2605. //
  2606. char temp_buffer[256] = { 0 };
  2607. registry.Get_String (VALUE_NAME_DEVICE_NAME, temp_buffer, sizeof (temp_buffer));
  2608. device_name = temp_buffer;
  2609. //
  2610. // Read the 2D settings
  2611. //
  2612. is_stereo = (registry.Get_Int (VALUE_NAME_IS_STEREO, true) == 1);
  2613. bits = registry.Get_Int (VALUE_NAME_BITS, 16);
  2614. hertz = registry.Get_Int (VALUE_NAME_HERTZ, 44100);
  2615. //
  2616. // Read the sound/music enabled settings
  2617. //
  2618. music_enabled = (registry.Get_Int (VALUE_NAME_MUSIC_ENABLED, 1) == 1);
  2619. sound_enabled = (registry.Get_Int (VALUE_NAME_SOUND_ENABLED, 1) == 1);
  2620. dialog_enabled = (registry.Get_Int (VALUE_NAME_DIALOG_ENABLED, 1) == 1);
  2621. cinematic_enabled = (registry.Get_Int (VALUE_NAME_CINEMATIC_ENABLED, 1) == 1);
  2622. Load_Default_Volume (defaultmusicvolume, defaultsoundvolume, defaultdialogvolume, defaultcinematicvolume);
  2623. //
  2624. // Read the volume information
  2625. //
  2626. music_volume = registry.Get_Int (VALUE_NAME_MUSIC_VOL, defaultmusicvolume) / 100.0F;
  2627. sound_volume = registry.Get_Int (VALUE_NAME_SOUND_VOL, defaultsoundvolume) / 100.0F;
  2628. dialog_volume = registry.Get_Int (VALUE_NAME_DIALOG_VOL, defaultdialogvolume) / 100.0F;
  2629. cinematic_volume = registry.Get_Int (VALUE_NAME_CINEMATIC_VOL, defaultcinematicvolume) / 100.0F;
  2630. music_volume = WWMath::Clamp (music_volume, 0, 1.0F);
  2631. sound_volume = WWMath::Clamp (sound_volume, 0, 1.0F);
  2632. dialog_volume = WWMath::Clamp (dialog_volume, 0, 1.0F);
  2633. cinematic_volume = WWMath::Clamp (cinematic_volume, 0, 1.0F);
  2634. //
  2635. // Misc
  2636. //
  2637. speaker_type = registry.Get_Int (VALUE_NAME_SPEAKER_TYPE, 0);
  2638. retval = true;
  2639. }
  2640. return retval;
  2641. }
  2642. ////////////////////////////////////////////////////////////////////////////////////////////
  2643. //
  2644. // Save_To_Registry
  2645. //
  2646. ////////////////////////////////////////////////////////////////////////////////////////////
  2647. bool
  2648. WWAudioClass::Save_To_Registry (const char *subkey_name)
  2649. {
  2650. StringClass device_name;
  2651. //
  2652. // Get the name of the current 3D driver
  2653. //
  2654. for (int index = 0; index < m_Driver3DList.Count (); index ++) {
  2655. DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
  2656. //
  2657. // Is this the device we were looking for?
  2658. //
  2659. if (info != NULL && info->driver == m_Driver3D) {
  2660. device_name = info->name;
  2661. break;
  2662. }
  2663. }
  2664. //
  2665. // Save these settings to the registry
  2666. //
  2667. return Save_To_Registry (subkey_name, device_name, m_PlaybackStereo, m_PlaybackBits, m_PlaybackRate,
  2668. m_AreSoundEffectsEnabled, m_IsMusicEnabled, m_IsDialogEnabled, m_IsCinematicSoundEnabled,
  2669. m_SoundVolume, m_MusicVolume, m_DialogVolume, m_CinematicVolume, m_SpeakerType);
  2670. }
  2671. ////////////////////////////////////////////////////////////////////////////////////////////
  2672. //
  2673. // Save_To_Registry
  2674. //
  2675. ////////////////////////////////////////////////////////////////////////////////////////////
  2676. bool
  2677. WWAudioClass::Save_To_Registry
  2678. (
  2679. const char * subkey_name,
  2680. const StringClass & device_name,
  2681. bool is_stereo,
  2682. int bits,
  2683. int hertz,
  2684. bool sound_enabled,
  2685. bool music_enabled,
  2686. bool dialog_enabled,
  2687. bool cinematic_enabled,
  2688. float sound_volume,
  2689. float music_volume,
  2690. float dialog_volume,
  2691. float cinematic_volume,
  2692. int speaker_type
  2693. )
  2694. {
  2695. bool retval = false;
  2696. //
  2697. // Attempt to open the registry key
  2698. //
  2699. RegistryClass registry (subkey_name);
  2700. if (registry.Is_Valid ()) {
  2701. //
  2702. // Save the settings to the registry
  2703. //
  2704. registry.Set_String (VALUE_NAME_DEVICE_NAME, device_name);
  2705. registry.Set_Int (VALUE_NAME_IS_STEREO, is_stereo);
  2706. registry.Set_Int (VALUE_NAME_BITS, bits);
  2707. registry.Set_Int (VALUE_NAME_HERTZ, hertz);
  2708. registry.Set_Int (VALUE_NAME_MUSIC_ENABLED, music_enabled);
  2709. registry.Set_Int (VALUE_NAME_SOUND_ENABLED, sound_enabled);
  2710. registry.Set_Int (VALUE_NAME_DIALOG_ENABLED, dialog_enabled);
  2711. registry.Set_Int (VALUE_NAME_CINEMATIC_ENABLED, cinematic_enabled);
  2712. registry.Set_Int (VALUE_NAME_MUSIC_VOL, music_volume * 100);
  2713. registry.Set_Int (VALUE_NAME_SOUND_VOL, sound_volume * 100);
  2714. registry.Set_Int (VALUE_NAME_DIALOG_VOL, dialog_volume * 100);
  2715. registry.Set_Int (VALUE_NAME_CINEMATIC_VOL, cinematic_volume * 100);
  2716. registry.Set_Int (VALUE_NAME_SPEAKER_TYPE, speaker_type);
  2717. retval = true;
  2718. }
  2719. return retval;
  2720. }
  2721. ////////////////////////////////////////////////////////////////////////////////////////////
  2722. //
  2723. // File_Open_Callback
  2724. //
  2725. ////////////////////////////////////////////////////////////////////////////////////////////
  2726. U32 AILCALLBACK
  2727. WWAudioClass::File_Open_Callback (char const *filename, U32 *file_handle)
  2728. {
  2729. U32 retval = false;
  2730. if (Get_Instance () != NULL) {
  2731. //
  2732. // Open the file
  2733. //
  2734. FileClass *file = Get_Instance ()->Get_File (filename);
  2735. if (file != NULL && file->Open ()) {
  2736. (*file_handle) = (U32)file;
  2737. retval = true;
  2738. }
  2739. }
  2740. return retval;
  2741. }
  2742. ////////////////////////////////////////////////////////////////////////////////////////////
  2743. //
  2744. // File_Close_Callback
  2745. //
  2746. ////////////////////////////////////////////////////////////////////////////////////////////
  2747. void AILCALLBACK
  2748. WWAudioClass::File_Close_Callback (U32 file_handle)
  2749. {
  2750. if (Get_Instance () != NULL) {
  2751. //
  2752. // Close the file (if necessary)
  2753. //
  2754. FileClass *file = reinterpret_cast<FileClass *> (file_handle);
  2755. if (file != NULL) {
  2756. Get_Instance ()->Return_File (file);
  2757. }
  2758. }
  2759. return ;
  2760. }
  2761. ////////////////////////////////////////////////////////////////////////////////////////////
  2762. //
  2763. // File_Seek_Callback
  2764. //
  2765. ////////////////////////////////////////////////////////////////////////////////////////////
  2766. S32 AILCALLBACK
  2767. WWAudioClass::File_Seek_Callback (U32 file_handle, S32 offset, U32 type)
  2768. {
  2769. S32 retval = 0;
  2770. //
  2771. // Convert the handle to a file handle type
  2772. //
  2773. FileClass *file = reinterpret_cast<FileClass *> (file_handle);
  2774. if (file != NULL) {
  2775. //
  2776. // Convert the Miles seek type to one of our own
  2777. //
  2778. int seek_type = SEEK_CUR;
  2779. switch (type)
  2780. {
  2781. case AIL_FILE_SEEK_BEGIN:
  2782. seek_type = SEEK_SET;
  2783. break;
  2784. case AIL_FILE_SEEK_CURRENT:
  2785. seek_type = SEEK_CUR;
  2786. break;
  2787. case AIL_FILE_SEEK_END:
  2788. seek_type = SEEK_END;
  2789. break;
  2790. }
  2791. //
  2792. // Perform the seek
  2793. //
  2794. retval = file->Seek (offset, seek_type);
  2795. }
  2796. return retval;
  2797. }
  2798. ////////////////////////////////////////////////////////////////////////////////////////////
  2799. //
  2800. // File_Read_Callback
  2801. //
  2802. ////////////////////////////////////////////////////////////////////////////////////////////
  2803. U32 AILCALLBACK
  2804. WWAudioClass::File_Read_Callback (U32 file_handle, void *buffer, U32 bytes)
  2805. {
  2806. U32 retval = 0;
  2807. //
  2808. // Convert the handle to a file handle type
  2809. //
  2810. FileClass *file = reinterpret_cast<FileClass *> (file_handle);
  2811. if (file != NULL) {
  2812. //
  2813. // Read the bytes from the file
  2814. //
  2815. retval = file->Read (buffer, bytes);
  2816. }
  2817. return retval;
  2818. }
  2819. ////////////////////////////////////////////////////////////////////////////////////////////
  2820. //
  2821. // Fade_Background_Music
  2822. //
  2823. ////////////////////////////////////////////////////////////////////////////////////////////
  2824. void
  2825. WWAudioClass::Fade_Background_Music (const char *filename, int fade_out_time, int fade_in_time)
  2826. {
  2827. //
  2828. // Fade-out the background music (as necessary)
  2829. //
  2830. if (m_BackgroundMusic != NULL) {
  2831. m_BackgroundMusic->Fade_Out (fade_out_time);
  2832. REF_PTR_RELEASE (m_BackgroundMusic);
  2833. }
  2834. m_BackgroundMusicName = filename;
  2835. if (filename != NULL) {
  2836. //
  2837. // Create the sound
  2838. //
  2839. m_BackgroundMusic = Create_Sound_Effect (filename);
  2840. if (m_BackgroundMusic != NULL) {
  2841. //
  2842. // Configure the sound and start playing it
  2843. //
  2844. m_BackgroundMusic->Set_Priority (1.0F);
  2845. m_BackgroundMusic->Set_Runtime_Priority (1.0F);
  2846. m_BackgroundMusic->Set_Loop_Count (INFINITE_LOOPS);
  2847. m_BackgroundMusic->Set_Type (AudibleSoundClass::TYPE_MUSIC);
  2848. m_BackgroundMusic->Cull_Sound (false);
  2849. m_BackgroundMusic->Fade_In (fade_in_time);
  2850. }
  2851. }
  2852. return ;
  2853. }
  2854. ////////////////////////////////////////////////////////////////////////////////////////////
  2855. //
  2856. // Set_Background_Music
  2857. //
  2858. ////////////////////////////////////////////////////////////////////////////////////////////
  2859. void
  2860. WWAudioClass::Set_Background_Music (const char *filename)
  2861. {
  2862. //
  2863. // Stop the background music
  2864. //
  2865. if (m_BackgroundMusic != NULL) {
  2866. m_BackgroundMusic->Stop ();
  2867. REF_PTR_RELEASE (m_BackgroundMusic);
  2868. }
  2869. m_BackgroundMusicName = filename;
  2870. if (filename != NULL) {
  2871. //
  2872. // Create the sound
  2873. //
  2874. m_BackgroundMusic = Create_Sound_Effect (filename);
  2875. if (m_BackgroundMusic != NULL) {
  2876. //
  2877. // Configure the sound and start playing it
  2878. //
  2879. m_BackgroundMusic->Set_Priority (1.0F);
  2880. m_BackgroundMusic->Set_Runtime_Priority (1.0F);
  2881. m_BackgroundMusic->Set_Loop_Count (INFINITE_LOOPS);
  2882. m_BackgroundMusic->Set_Type (AudibleSoundClass::TYPE_MUSIC);
  2883. m_BackgroundMusic->Cull_Sound (false);
  2884. m_BackgroundMusic->Play ();
  2885. }
  2886. }
  2887. return ;
  2888. }
  2889. ////////////////////////////////////////////////////////////////////////////////////////////
  2890. //
  2891. // Set_Active_Sound_Page
  2892. //
  2893. ////////////////////////////////////////////////////////////////////////////////////////////
  2894. void
  2895. WWAudioClass::Set_Active_Sound_Page (SOUND_PAGE page)
  2896. {
  2897. if (page == m_CurrPage) {
  2898. return ;
  2899. }
  2900. //
  2901. // Pause any sounds that are playing in the old page
  2902. //
  2903. for (int index = 0; index < m_Playlist[m_CurrPage].Count ();index ++) {
  2904. m_Playlist[m_CurrPage][index]->Pause ();
  2905. }
  2906. //
  2907. // Resume any sounds that are playing in the new page
  2908. //
  2909. for (index = 0; index < m_Playlist[page].Count ();index ++) {
  2910. m_Playlist[page][index]->Resume ();
  2911. }
  2912. m_CurrPage = page;
  2913. return ;
  2914. }
  2915. ////////////////////////////////////////////////////////////////////////////////////////////
  2916. //
  2917. // Fade_Non_Dialog_In
  2918. //
  2919. ////////////////////////////////////////////////////////////////////////////////////////////
  2920. void
  2921. WWAudioClass::Fade_Non_Dialog_In (void)
  2922. {
  2923. if (m_FadeType == FADE_IN || m_FadeType == FADE_NONE) {
  2924. return ;
  2925. }
  2926. m_FadeType = FADE_IN;
  2927. m_FadeTimer = m_NonDialogFadeTime;
  2928. return ;
  2929. }
  2930. ////////////////////////////////////////////////////////////////////////////////////////////
  2931. //
  2932. // Fade_Non_Dialog_Out
  2933. //
  2934. ////////////////////////////////////////////////////////////////////////////////////////////
  2935. void
  2936. WWAudioClass::Fade_Non_Dialog_Out (void)
  2937. {
  2938. if (m_FadeType == FADE_OUT || m_FadeType == FADED_OUT) {
  2939. return ;
  2940. }
  2941. m_FadeType = FADE_OUT;
  2942. m_FadeTimer = m_NonDialogFadeTime;
  2943. return ;
  2944. }
  2945. ////////////////////////////////////////////////////////////////////////////////////////////
  2946. //
  2947. // Update_Fade
  2948. //
  2949. ////////////////////////////////////////////////////////////////////////////////////////////
  2950. void
  2951. WWAudioClass::Update_Fade (void)
  2952. {
  2953. if (m_FadeType == FADE_NONE || m_FadeType == FADED_OUT) {
  2954. return ;
  2955. }
  2956. m_FadeTimer -= (WW3D::Get_Frame_Time () / 1000.0F);
  2957. m_FadeTimer = max (m_FadeTimer, 0.0F);
  2958. //
  2959. // Determine what percent we should ramp up or down to...
  2960. //
  2961. float percent = (m_FadeTimer / m_NonDialogFadeTime);
  2962. percent = WWMath::Clamp (percent, 0.0F, 1.0F);
  2963. //
  2964. // Invert the percent if we're fading out
  2965. //
  2966. if (m_FadeType == FADE_IN) {
  2967. percent = 1.0F - percent;
  2968. }
  2969. //
  2970. // Determine what the current percent is
  2971. //
  2972. const float FADE_MAX = 0.6F;
  2973. percent = (1.0F - FADE_MAX) + (percent * FADE_MAX);
  2974. //
  2975. // Re-adjust the music and sound effect volumes
  2976. //
  2977. Internal_Set_Music_Volume (m_RealMusicVolume * percent);
  2978. Internal_Set_Sound_Effects_Volume (m_RealSoundVolume * percent);
  2979. //
  2980. // If we've done the fade, then return to the "no fade" stage
  2981. //
  2982. if (m_FadeTimer == 0) {
  2983. if (m_FadeType == FADE_OUT) {
  2984. m_FadeType = FADED_OUT;
  2985. } else {
  2986. m_FadeType = FADE_NONE;
  2987. }
  2988. }
  2989. return ;
  2990. }
  2991. ////////////////////////////////////////////////////////////////////////////////////////////
  2992. //
  2993. // Peek_2D_Sample
  2994. //
  2995. ////////////////////////////////////////////////////////////////////////////////////////////
  2996. AudibleSoundClass *
  2997. WWAudioClass::Peek_2D_Sample (int index)
  2998. {
  2999. if (index < 0 || index > m_2DSampleHandles.Count ()) {
  3000. return NULL;
  3001. }
  3002. MMSLockClass lock;
  3003. AudibleSoundClass *retval = NULL;
  3004. //
  3005. // Try to get the sound object associated with this handle
  3006. //
  3007. HSAMPLE sample = m_2DSampleHandles[index];
  3008. if (sample != NULL) {
  3009. retval = (AudibleSoundClass *)::AIL_sample_user_data (sample, INFO_OBJECT_PTR);
  3010. }
  3011. return retval;
  3012. }
  3013. ////////////////////////////////////////////////////////////////////////////////////////////
  3014. //
  3015. // Peek_3D_Sample
  3016. //
  3017. ////////////////////////////////////////////////////////////////////////////////////////////
  3018. AudibleSoundClass *
  3019. WWAudioClass::Peek_3D_Sample (int index)
  3020. {
  3021. if (index < 0 || index > m_3DSampleHandles.Count ()) {
  3022. return NULL;
  3023. }
  3024. MMSLockClass lock;
  3025. AudibleSoundClass *retval = NULL;
  3026. //
  3027. // Try to get the sound object associated with this handle
  3028. //
  3029. H3DSAMPLE sample = m_3DSampleHandles[index];
  3030. if (sample != NULL) {
  3031. retval = (AudibleSoundClass *)::AIL_3D_object_user_data (sample, INFO_OBJECT_PTR);
  3032. }
  3033. return retval;
  3034. }
  3035. ////////////////////////////////////////////////////////////////////////////////////////////
  3036. //
  3037. // Acquire_Virtual_Channel
  3038. //
  3039. ////////////////////////////////////////////////////////////////////////////////////////////
  3040. bool
  3041. WWAudioClass::Acquire_Virtual_Channel (AudibleSoundClass *sound_obj, int channel_index)
  3042. {
  3043. //
  3044. // Verify parameters
  3045. //
  3046. channel_index --;
  3047. if (sound_obj == NULL || channel_index < 0 || channel_index >= MAX_VIRTUAL_CHANNELS) {
  3048. return false;
  3049. }
  3050. //
  3051. // Is there already a sound playing on this channel?
  3052. //
  3053. bool retval = true;
  3054. if (m_VirtualChannels[channel_index] != NULL) {
  3055. AudibleSoundClass *curr_sound = m_VirtualChannels[channel_index];
  3056. //
  3057. // If the new sound has overriding priority, then stop the sound
  3058. // that's currently playing on this channel
  3059. //
  3060. if (sound_obj->Get_Priority () >= curr_sound->Get_Priority ()) {
  3061. m_VirtualChannels[channel_index] = NULL;
  3062. curr_sound->Stop ();
  3063. REF_PTR_RELEASE (curr_sound);
  3064. } else {
  3065. retval = false;
  3066. }
  3067. }
  3068. //
  3069. // Store this sound in the virtual channel
  3070. //
  3071. if (retval) {
  3072. m_VirtualChannels[channel_index] = sound_obj;
  3073. sound_obj->Add_Ref ();
  3074. }
  3075. return retval;
  3076. }
  3077. ////////////////////////////////////////////////////////////////////////////////////////////
  3078. //
  3079. // Release_Virtual_Channel
  3080. //
  3081. ////////////////////////////////////////////////////////////////////////////////////////////
  3082. void
  3083. WWAudioClass::Release_Virtual_Channel (AudibleSoundClass *sound_obj, int channel_index)
  3084. {
  3085. //
  3086. // Verify parameters
  3087. //
  3088. channel_index --;
  3089. if (sound_obj == NULL || channel_index < 0 || channel_index >= MAX_VIRTUAL_CHANNELS) {
  3090. return ;
  3091. }
  3092. //
  3093. // Check to ensure this sound has control of the virtual channel
  3094. //
  3095. if (m_VirtualChannels[channel_index] == sound_obj) {
  3096. //
  3097. // Free the channel
  3098. //
  3099. m_VirtualChannels[channel_index] = NULL;
  3100. REF_PTR_RELEASE (sound_obj);
  3101. }
  3102. return ;
  3103. }
  3104. ////////////////////////////////////////////////////////////////////////////////////////////
  3105. //
  3106. // Set_Speaker_Type
  3107. //
  3108. ////////////////////////////////////////////////////////////////////////////////////////////
  3109. void
  3110. WWAudioClass::Set_Speaker_Type (int speaker_type)
  3111. {
  3112. m_SpeakerType = speaker_type;
  3113. //
  3114. // Pass the new speaker type onto miles
  3115. //
  3116. if (m_Driver3D != NULL) {
  3117. ::AIL_set_3D_speaker_type (m_Driver3D, speaker_type);
  3118. }
  3119. return ;
  3120. }
  3121. ////////////////////////////////////////////////////////////////////////////////////////////
  3122. //
  3123. // Get_Speaker_Type
  3124. //
  3125. ////////////////////////////////////////////////////////////////////////////////////////////
  3126. int
  3127. WWAudioClass::Get_Speaker_Type (void) const
  3128. {
  3129. return m_SpeakerType;
  3130. }
  3131. ////////////////////////////////////////////////////////////////////////////////////////////
  3132. //
  3133. // Push_Active_Sound_Page
  3134. //
  3135. ////////////////////////////////////////////////////////////////////////////////////////////
  3136. void
  3137. WWAudioClass::Push_Active_Sound_Page (SOUND_PAGE page)
  3138. {
  3139. m_PageStack.Add (m_CurrPage);
  3140. Set_Active_Sound_Page (page);
  3141. return ;
  3142. }
  3143. ////////////////////////////////////////////////////////////////////////////////////////////
  3144. //
  3145. // Pop_Active_Sound_Page
  3146. //
  3147. ////////////////////////////////////////////////////////////////////////////////////////////
  3148. void
  3149. WWAudioClass::Pop_Active_Sound_Page (void)
  3150. {
  3151. if (m_PageStack.Count () > 0) {
  3152. SOUND_PAGE new_page = m_PageStack[m_PageStack.Count () - 1];
  3153. m_PageStack.Delete (m_PageStack.Count () - 1);
  3154. Set_Active_Sound_Page (new_page);
  3155. }
  3156. return ;
  3157. }
  3158. ////////////////////////////////////////////////////////////////////////////////////////////
  3159. //
  3160. // Temp_Disable_Audio
  3161. //
  3162. ////////////////////////////////////////////////////////////////////////////////////////////
  3163. void
  3164. WWAudioClass::Temp_Disable_Audio (bool onoff)
  3165. {
  3166. if (onoff) {
  3167. m_CachedIsMusicEnabled = m_IsMusicEnabled;
  3168. m_CachedIsDialogEnabled = m_IsDialogEnabled;
  3169. m_CachedIsCinematicSoundEnabled = m_IsCinematicSoundEnabled;
  3170. m_CachedAreSoundEffectsEnabled = m_AreSoundEffectsEnabled;
  3171. Allow_Sound_Effects (false);
  3172. Allow_Music (false);
  3173. Allow_Dialog (false);
  3174. Allow_Cinematic_Sound (false);
  3175. } else {
  3176. Allow_Sound_Effects (m_CachedAreSoundEffectsEnabled);
  3177. Allow_Music (m_CachedIsMusicEnabled);
  3178. Allow_Dialog (m_CachedIsDialogEnabled);
  3179. Allow_Cinematic_Sound (m_CachedIsCinematicSoundEnabled);
  3180. }
  3181. return ;
  3182. }
  3183. ////////////////////////////////////////////////////////////////////////////////////////////
  3184. //
  3185. // Load_Default_Volume
  3186. //
  3187. ////////////////////////////////////////////////////////////////////////////////////////////
  3188. void WWAudioClass::Load_Default_Volume (int &defaultmusicvolume, int &defaultsoundvolume, int &defaultdialogvolume, int &defaultcinematicvolume)
  3189. {
  3190. const int minsetting = 0;
  3191. const int maxsetting = 100;
  3192. // IML: If the audio INI has not yet been loaded then do it now.
  3193. if (AudioIni == NULL) {
  3194. AudioIni = new INIClass;
  3195. if (!AudioIni->Load (WWAUDIO_INI_FILENAME)) {
  3196. AudioIni->Load (WWAUDIO_INI_RELATIVE_PATHNAME);
  3197. }
  3198. }
  3199. defaultmusicvolume = MIN (maxsetting, MAX (minsetting, AudioIni->Get_Int (INI_DEFAULT_VOLUME_SECTION, INI_MUSIC_VOLUME_ENTRY, 31)));
  3200. defaultsoundvolume = MIN (maxsetting, MAX (minsetting, AudioIni->Get_Int (INI_DEFAULT_VOLUME_SECTION, INI_SOUND_VOLUME_ENTRY, 43)));
  3201. defaultdialogvolume = MIN (maxsetting, MAX (minsetting, AudioIni->Get_Int (INI_DEFAULT_VOLUME_SECTION, INI_DIALOG_VOLUME_ENTRY, 50)));
  3202. defaultcinematicvolume = MIN (maxsetting, MAX (minsetting, AudioIni->Get_Int (INI_DEFAULT_VOLUME_SECTION, INI_CINEMATIC_VOLUME_ENTRY, 100)));
  3203. }