AudibleSound.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792
  1. /*
  2. ** Command & Conquer Generals(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/AudibleSound.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 8/27/01 7:25p $*
  29. * *
  30. * $Revision:: 27 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "audiblesound.h"
  36. #include "wwaudio.h"
  37. #include "ww3d.h"
  38. #include "wwdebug.h"
  39. #include "soundbuffer.h"
  40. #include "utils.h"
  41. #include "soundscene.h"
  42. #include "filteredsound.h"
  43. #include "threads.h"
  44. #include "soundchunkids.h"
  45. #include "simpledefinitionfactory.h"
  46. #include "persistfactory.h"
  47. #include "logicalsound.h"
  48. #include "definitionclassids.h"
  49. #include "soundstreamhandle.h"
  50. #include "sound2dhandle.h"
  51. //////////////////////////////////////////////////////////////////////////////////
  52. // Static factories
  53. //////////////////////////////////////////////////////////////////////////////////
  54. DECLARE_DEFINITION_FACTORY(AudibleSoundDefinitionClass, CLASSID_SOUND_DEF, "Sound") _SoundDefFactory;
  55. SimplePersistFactoryClass<AudibleSoundDefinitionClass, CHUNKID_SOUND_DEF> _AudibleSoundDefPersistFactory;
  56. SimplePersistFactoryClass<AudibleSoundClass, CHUNKID_AUDIBLE_SOUND> _AudibleSoundPersistFactory;
  57. //////////////////////////////////////////////////////////////////////////////////
  58. // Save/Load constants
  59. //////////////////////////////////////////////////////////////////////////////////
  60. namespace AUDIBLE_SOUND_SAVELOAD
  61. {
  62. enum
  63. {
  64. CHUNKID_VARIABLES = 0x00000100,
  65. CHUNKID_BASE_CLASS
  66. };
  67. enum
  68. {
  69. VARID_STATE = 0x01,
  70. VARID_TYPE,
  71. VARID_PRIORITY,
  72. VARID_VOLUME,
  73. VARID_PAN,
  74. VARID_LOOP_COUNT,
  75. VARID_LOOPS_LEFT,
  76. VARID_SOUND_LENGTH,
  77. VARID_CURR_POS,
  78. VARID_TRANSFORM,
  79. VARID_PREV_TRANSFORM,
  80. VARID_IS_CULLED,
  81. VARID_IS_DIRTY,
  82. VARID_DROP_OFF,
  83. VARID_FILENAME,
  84. VARID_THIS_PTR,
  85. VARID_START_OFFSET,
  86. VARID_LISTENER_TRANSFORM,
  87. VARID_PITCH_FACTOR
  88. };
  89. }
  90. namespace AUDIBLE_SOUND_DEF_SAVELOAD
  91. {
  92. enum
  93. {
  94. CHUNKID_VARIABLES = 0x00000100,
  95. CHUNKID_BASE_CLASS = 0x00000200,
  96. };
  97. enum
  98. {
  99. VARID_UNUSED1 = 0x01,
  100. VARID_UNUSED2,
  101. VARID_PRIORITY,
  102. VARID_VOLUME,
  103. VARID_PAN,
  104. VARID_LOOP_COUNT,
  105. VARID_DROP_OFF,
  106. VARID_MAX_VOL,
  107. VARID_TYPE,
  108. VARID_IS3D,
  109. VARID_FILENAME,
  110. VARID_DISPLAY_TEXT,
  111. VARID_LOGICAL_MASK,
  112. VARID_LOGICAL_DELAY,
  113. VARID_CREATE_LOGICAL,
  114. VARID_LOGICAL_DROP_OFF,
  115. VARID_SPHERE_COLOR,
  116. VARID_START_OFFSET,
  117. VARID_PITCH_FACTOR
  118. };
  119. }
  120. ////////////////////////////////////////////////////////////////////////////////////////////////
  121. //
  122. // AudibleSoundClass
  123. //
  124. ////////////////////////////////////////////////////////////////////////////////////////////////
  125. AudibleSoundClass::AudibleSoundClass (void)
  126. : m_Priority (0.5F),
  127. m_RuntimePriority (0),
  128. m_SoundHandle (NULL),
  129. m_Length (0),
  130. m_CurrentPosition (0),
  131. m_Timestamp (0),
  132. m_State (STATE_STOPPED),
  133. m_Buffer (NULL),
  134. m_Volume (1.0F),
  135. m_Pan (0.5F),
  136. m_LoopCount (1),
  137. m_LoopsLeft (0),
  138. m_Type (TYPE_SOUND_EFFECT),
  139. m_bDirty (true),
  140. m_DropOffRadius (1),
  141. m_IsCulled (true),
  142. m_pConvertedFormat (NULL),
  143. m_PrevTransform (1),
  144. m_Transform (1),
  145. m_ListenerTransform (1),
  146. m_Definition (NULL),
  147. m_LogicalSound (NULL),
  148. m_StartOffset (0),
  149. m_PitchFactor (1.0F)
  150. {
  151. return ;
  152. }
  153. ////////////////////////////////////////////////////////////////////////////////////////////////
  154. //
  155. // AudibleSoundClass
  156. //
  157. ////////////////////////////////////////////////////////////////////////////////////////////////
  158. AudibleSoundClass::AudibleSoundClass (const AudibleSoundClass &src)
  159. : m_Priority (0.5F),
  160. m_RuntimePriority (0),
  161. m_SoundHandle (NULL),
  162. m_Length (0),
  163. m_CurrentPosition (0),
  164. m_Timestamp (0),
  165. m_State (STATE_STOPPED),
  166. m_Buffer (NULL),
  167. m_Volume (1.0F),
  168. m_Pan (0.5F),
  169. m_LoopCount (1),
  170. m_LoopsLeft (0),
  171. m_Type (TYPE_SOUND_EFFECT),
  172. m_bDirty (true),
  173. m_DropOffRadius (1),
  174. m_IsCulled (true),
  175. m_pConvertedFormat (NULL),
  176. m_PrevTransform (1),
  177. m_Transform (1),
  178. m_Definition (NULL),
  179. m_LogicalSound (NULL),
  180. m_StartOffset (0),
  181. m_PitchFactor (1.0F)
  182. {
  183. (*this) = src;
  184. return ;
  185. }
  186. ////////////////////////////////////////////////////////////////////////////////////////////////
  187. //
  188. // ~AudibleSoundClass
  189. //
  190. ////////////////////////////////////////////////////////////////////////////////////////////////
  191. AudibleSoundClass::~AudibleSoundClass (void)
  192. {
  193. m_State = STATE_STOPPED;
  194. Free_Conversion ();
  195. REF_PTR_RELEASE (m_LogicalSound);
  196. //
  197. // Delay the release of the buffer (fixes a sync bug
  198. // with Miles internals).
  199. //
  200. if (m_Buffer != NULL) {
  201. WWAudioThreadsClass::Add_Delayed_Release_Object (m_Buffer);
  202. m_Buffer = NULL;
  203. }
  204. Free_Miles_Handle ();
  205. return ;
  206. }
  207. ////////////////////////////////////////////////////////////////////////////////////////////////
  208. //
  209. // operator=
  210. //
  211. ////////////////////////////////////////////////////////////////////////////////////////////////
  212. const AudibleSoundClass &
  213. AudibleSoundClass::operator= (const AudibleSoundClass &src)
  214. {
  215. m_Timestamp = src.m_Timestamp;
  216. m_Type = src.m_Type;
  217. m_LoopCount = src.m_LoopCount;
  218. m_LoopsLeft = src.m_LoopsLeft;
  219. m_Length = src.m_Length;
  220. m_CurrentPosition = src.m_CurrentPosition;
  221. m_bDirty = src.m_bDirty;
  222. m_DropOffRadius = src.m_DropOffRadius;
  223. m_PrevTransform = src.m_PrevTransform;
  224. m_State = STATE_STOPPED;
  225. Set_Buffer (src.m_Buffer);
  226. m_State = src.m_State;
  227. Cull_Sound (src.m_IsCulled);
  228. Set_Volume (src.m_Volume);
  229. Set_Pan (src.m_Pan);
  230. Set_Priority (src.m_Priority);
  231. Set_Transform (src.m_Transform);
  232. Set_Listener_Transform (src.m_ListenerTransform);
  233. return (*this);
  234. }
  235. ////////////////////////////////////////////////////////////////////////////////////////////////
  236. //
  237. // Set_Buffer
  238. //
  239. ////////////////////////////////////////////////////////////////////////////////////////////////
  240. void
  241. AudibleSoundClass::Set_Buffer (SoundBufferClass *buffer)
  242. {
  243. //
  244. // Delay the release of the buffer (fixes a sync bug
  245. // with Miles internals).
  246. //
  247. if (m_Buffer != NULL) {
  248. WWAudioThreadsClass::Add_Delayed_Release_Object (m_Buffer);
  249. m_Buffer = NULL;
  250. }
  251. REF_PTR_SET (m_Buffer, buffer);
  252. // Stop playing if necessary
  253. bool resume = false;
  254. if (m_State == STATE_PLAYING) {
  255. resume = Stop (false);
  256. }
  257. // Get the time (in ms) that this buffer will play for...
  258. if (m_Buffer != NULL) {
  259. m_Length = m_Buffer->Get_Duration ();
  260. }
  261. // Reinitialize the handle with this new data
  262. Initialize_Miles_Handle ();
  263. // Resume playing if necessary
  264. if (resume) {
  265. Play ();
  266. }
  267. return ;
  268. }
  269. ////////////////////////////////////////////////////////////////////////////////////////////////
  270. //
  271. // Get_Buffer
  272. //
  273. ////////////////////////////////////////////////////////////////////////////////////////////////
  274. SoundBufferClass *
  275. AudibleSoundClass::Get_Buffer (void) const
  276. {
  277. if (m_Buffer) {
  278. m_Buffer->Add_Ref ();
  279. }
  280. return m_Buffer;
  281. }
  282. ////////////////////////////////////////////////////////////////////////////////////////////////
  283. //
  284. // Peek_Buffer
  285. //
  286. ////////////////////////////////////////////////////////////////////////////////////////////////
  287. SoundBufferClass *
  288. AudibleSoundClass::Peek_Buffer (void) const
  289. {
  290. return m_Buffer;
  291. }
  292. ////////////////////////////////////////////////////////////////////////////////////////////////
  293. //
  294. // Play
  295. //
  296. ////////////////////////////////////////////////////////////////////////////////////////////////
  297. bool
  298. AudibleSoundClass::Play (bool alloc_handle)
  299. {
  300. MMSLockClass lock;
  301. // If we don't have a valid handle already, try to get one from miles
  302. if (alloc_handle && (m_pConvertedFormat == NULL)) {
  303. Allocate_Miles_Handle ();
  304. }
  305. // Let the audio system know this sound is playing
  306. if (m_State != STATE_PLAYING) {
  307. WWAudioClass::Get_Instance ()->Add_To_Playlist (this);
  308. m_State = STATE_PLAYING;
  309. m_Timestamp = ::GetTickCount ();
  310. m_LoopsLeft = m_LoopCount;
  311. // If we have a valid handle, then start playing the sample
  312. if (m_SoundHandle != NULL) {
  313. m_SoundHandle->Start_Sample ();
  314. }
  315. m_CurrentPosition = m_StartOffset * m_Length;
  316. if (m_CurrentPosition > 0) {
  317. Seek (m_CurrentPosition);
  318. }
  319. // Fire an event
  320. On_Event (AudioCallbackClass::EVENT_SOUND_STARTED);
  321. //
  322. // Create the associate logical sound (if necessary)
  323. //
  324. if (m_LogicalSound == NULL && m_Definition != NULL) {
  325. m_LogicalSound = m_Definition->Create_Logical ();
  326. }
  327. //
  328. // Add this logical sound to the scene
  329. //
  330. if (m_LogicalSound != NULL) {
  331. m_LogicalSound->Set_User_Data (m_UserObj, m_UserData);
  332. m_LogicalSound->Set_Transform (m_Transform);
  333. m_LogicalSound->Add_To_Scene ();
  334. }
  335. //
  336. // Should we send off the text notification?
  337. //
  338. if (m_IsCulled == false && m_Definition != NULL) {
  339. const StringClass &text = m_Definition->Get_Display_Text ();
  340. WWAudioClass::Get_Instance ()->Fire_Text_Callback (this, text);
  341. }
  342. }
  343. return true;
  344. }
  345. ////////////////////////////////////////////////////////////////////////////////////////////////
  346. //
  347. // Pause
  348. //
  349. ////////////////////////////////////////////////////////////////////////////////////////////////
  350. bool
  351. AudibleSoundClass::Pause (void)
  352. {
  353. MMSLockClass lock;
  354. // Assume failure
  355. bool retval = false;
  356. if (m_State == STATE_PLAYING) {
  357. // Pass the pause request onto miles
  358. if (m_SoundHandle != NULL) {
  359. m_SoundHandle->Stop_Sample ();
  360. }
  361. // Remember our new state
  362. m_State = STATE_PAUSED;
  363. retval = true;
  364. }
  365. // Return the true/false result code
  366. return retval;
  367. }
  368. ////////////////////////////////////////////////////////////////////////////////////////////////
  369. //
  370. // Resume
  371. //
  372. ////////////////////////////////////////////////////////////////////////////////////////////////
  373. bool
  374. AudibleSoundClass::Resume (void)
  375. {
  376. MMSLockClass lock;
  377. // Assume failure
  378. bool retval = false;
  379. if (m_State == STATE_PAUSED) {
  380. // Pass the resume request onto miles
  381. if (m_SoundHandle != NULL) {
  382. m_SoundHandle->Resume_Sample ();
  383. }
  384. // Remember our new state
  385. m_State = STATE_PLAYING;
  386. retval = true;
  387. }
  388. // Return the true/false result code
  389. return retval;
  390. }
  391. ////////////////////////////////////////////////////////////////////////////////////////////////
  392. //
  393. // Stop
  394. //
  395. ////////////////////////////////////////////////////////////////////////////////////////////////
  396. bool
  397. AudibleSoundClass::Stop (bool remove_from_playlist)
  398. {
  399. MMSLockClass lock;
  400. // Assume failure
  401. bool retval = false;
  402. if ((m_State == STATE_PAUSED) ||
  403. (m_State == STATE_PLAYING)) {
  404. // Actually stop the sample from playing
  405. if (m_SoundHandle != NULL) {
  406. m_SoundHandle->Stop_Sample ();
  407. }
  408. // Free up the handle we have been using
  409. Free_Miles_Handle ();
  410. m_State = STATE_STOPPED;
  411. retval = true;
  412. // Reset some of the playing attributes
  413. m_Timestamp = 0;
  414. m_CurrentPosition = 0;
  415. if (remove_from_playlist) {
  416. WWAudioClass::Get_Instance ()->Remove_From_Playlist (this);
  417. }
  418. //
  419. // Stop the logical portion of the sound
  420. //
  421. if (m_LogicalSound != NULL && m_LogicalSound->Is_Single_Shot () == false) {
  422. m_LogicalSound->Remove_From_Scene ();
  423. }
  424. }
  425. // Return the true/false result code
  426. return retval;
  427. }
  428. ////////////////////////////////////////////////////////////////////////////////////////////////
  429. //
  430. // Seek
  431. //
  432. ////////////////////////////////////////////////////////////////////////////////////////////////
  433. void
  434. AudibleSoundClass::Seek (unsigned long milliseconds)
  435. {
  436. MMSLockClass lock;
  437. if ((milliseconds >= 0) && (milliseconds < m_Length)) {
  438. // Record our new position and recalculate the 'starting' timestamp
  439. // from this information
  440. m_CurrentPosition = milliseconds;
  441. if (m_State == STATE_PLAYING) {
  442. m_Timestamp = ::GetTickCount () - m_CurrentPosition;
  443. }
  444. // Update the actual sound data if we are playing the sound
  445. if (m_SoundHandle != NULL) {
  446. m_SoundHandle->Set_Sample_MS_Position (m_CurrentPosition);
  447. }
  448. }
  449. return ;
  450. }
  451. ////////////////////////////////////////////////////////////////////////////////////////////////
  452. //
  453. // Set_Miles_Handle
  454. //
  455. ////////////////////////////////////////////////////////////////////////////////////////////////
  456. void
  457. AudibleSoundClass::Set_Miles_Handle (MILES_HANDLE handle)
  458. {
  459. //
  460. // Start fresh
  461. //
  462. Free_Miles_Handle ();
  463. //
  464. // Is our data valid?
  465. //
  466. if (handle != INVALID_MILES_HANDLE && m_Buffer != NULL) {
  467. //
  468. // Determine which type of sound handle to create, streaming or standard 2D
  469. //
  470. if (m_Buffer->Is_Streaming ()) {
  471. m_SoundHandle = W3DNEW SoundStreamHandleClass;
  472. } else {
  473. m_SoundHandle = W3DNEW Sound2DHandleClass;
  474. }
  475. //
  476. // Configure the sound handle
  477. //
  478. m_SoundHandle->Set_Miles_Handle (handle);
  479. //
  480. // Use this new handle
  481. //
  482. Initialize_Miles_Handle ();
  483. }
  484. return ;
  485. }
  486. ////////////////////////////////////////////////////////////////////////////////////////////////
  487. //
  488. // Initialize_Miles_Handle
  489. //
  490. ////////////////////////////////////////////////////////////////////////////////////////////////
  491. void
  492. AudibleSoundClass::Initialize_Miles_Handle (void)
  493. {
  494. MMSLockClass lock;
  495. // If this sound is already playing, then update its
  496. // playing position to make sure we really should
  497. // be playing it... (it will free the miles handle if not)
  498. if (m_State == STATE_PLAYING) {
  499. Update_Play_Position ();
  500. }
  501. // Do we have a valid sample handle from miles?
  502. if (m_SoundHandle != NULL) {
  503. //
  504. // Initialize the handle
  505. //
  506. m_SoundHandle->Initialize (m_Buffer);
  507. //
  508. // Record the total length of the sample in milliseconds...
  509. //
  510. m_SoundHandle->Get_Sample_MS_Position ((S32 *)&m_Length, NULL);
  511. //
  512. // Pass our cached settings onto miles
  513. //
  514. m_SoundHandle->Set_Sample_Volume (0);
  515. m_SoundHandle->Set_Sample_Pan (int(m_Pan * 127.0F));
  516. m_SoundHandle->Set_Sample_Loop_Count (m_LoopCount);
  517. //
  518. // Apply the pitch factor (if necessary)
  519. //
  520. if (m_PitchFactor != 1.0F) {
  521. Set_Pitch_Factor (m_PitchFactor);
  522. }
  523. // If this sound is already playing (and just now got a handle)
  524. // then make sure we start it.
  525. if (m_State == STATE_PLAYING) {
  526. m_SoundHandle->Start_Sample ();
  527. // Update the loop count based on the number of loops left
  528. m_SoundHandle->Set_Sample_Loop_Count (m_LoopsLeft);
  529. }
  530. // Seek to the position of the sound where we last left off.
  531. // For example, this sound could have gotten bumped due to a low priority,
  532. // but is now back and ready to resume at the position it would have been
  533. // at if it was never bumped.
  534. Seek (m_CurrentPosition);
  535. //
  536. // Pass the 'real' volume onto miles
  537. //
  538. float real_volume = Determine_Real_Volume ();
  539. m_SoundHandle->Set_Sample_Volume (int(real_volume * 127.0F));
  540. //
  541. // Associate this object instance with the handle
  542. //
  543. m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, (S32)this);
  544. }
  545. return ;
  546. }
  547. ////////////////////////////////////////////////////////////////////////////////////////////////
  548. //
  549. // Free_Miles_Handle
  550. //
  551. ////////////////////////////////////////////////////////////////////////////////////////////////
  552. void
  553. AudibleSoundClass::Free_Miles_Handle (void)
  554. {
  555. MMSLockClass lock;
  556. // Do we have a valid sample handle from miles?
  557. if (m_SoundHandle != NULL) {
  558. //
  559. // Release our hold on this handle
  560. //
  561. m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, NULL);
  562. m_SoundHandle->End_Sample ();
  563. //
  564. // Remove the association between file handle and AudibleSoundClass object
  565. //
  566. //m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, NULL);
  567. //
  568. // Free the sound handle object
  569. //
  570. delete m_SoundHandle;
  571. m_SoundHandle = NULL;
  572. }
  573. return ;
  574. }
  575. ////////////////////////////////////////////////////////////////////////////////////////////////
  576. //
  577. // Get_Pan
  578. //
  579. ////////////////////////////////////////////////////////////////////////////////////////////////
  580. float
  581. AudibleSoundClass::Get_Pan (void)
  582. {
  583. MMSLockClass lock;
  584. //
  585. // Do we have a valid sample handle from miles?
  586. //
  587. if (m_SoundHandle != NULL) {
  588. m_Pan = ((float)m_SoundHandle->Get_Sample_Pan ()) / 127.0F;
  589. }
  590. return m_Pan;
  591. }
  592. ////////////////////////////////////////////////////////////////////////////////////////////////
  593. //
  594. // Set_Pan
  595. //
  596. ////////////////////////////////////////////////////////////////////////////////////////////////
  597. void
  598. AudibleSoundClass::Set_Pan (float pan)
  599. {
  600. MMSLockClass lock;
  601. //
  602. // Cache the normalized pan value
  603. //
  604. m_Pan = min (pan, 1.0F);
  605. m_Pan = max (m_Pan, 0.0F);
  606. //
  607. // Do we have a valid sample handle from miles?
  608. //
  609. if (m_SoundHandle != NULL) {
  610. m_SoundHandle->Set_Sample_Pan (int(m_Pan * 127.0F));
  611. }
  612. return ;
  613. }
  614. ////////////////////////////////////////////////////////////////////////////////////////////////
  615. //
  616. // Set_Pitch_Factor
  617. //
  618. ////////////////////////////////////////////////////////////////////////////////////////////////
  619. void
  620. AudibleSoundClass::Set_Pitch_Factor (float factor)
  621. {
  622. MMSLockClass lock;
  623. m_PitchFactor = factor;
  624. //
  625. // Do we have a valid sample handle from miles?
  626. //
  627. if (m_SoundHandle != NULL) {
  628. if (m_Buffer != NULL) {
  629. //
  630. // Get the base rate of the sound and scale our playback rate
  631. // based on the factor
  632. //
  633. int base_rate = m_Buffer->Get_Rate ();
  634. int new_rate = base_rate * m_PitchFactor;
  635. m_SoundHandle->Set_Sample_Playback_Rate (new_rate);
  636. }
  637. }
  638. return ;
  639. }
  640. ////////////////////////////////////////////////////////////////////////////////////////////////
  641. //
  642. // Get_Playback_Rate
  643. //
  644. ////////////////////////////////////////////////////////////////////////////////////////////////
  645. int
  646. AudibleSoundClass::Get_Playback_Rate (void)
  647. {
  648. MMSLockClass lock;
  649. int retval = 0;
  650. // Do we have a valid sample handle from miles?
  651. if (m_SoundHandle != NULL) {
  652. retval = m_SoundHandle->Get_Sample_Playback_Rate ();
  653. }
  654. return retval;
  655. }
  656. ////////////////////////////////////////////////////////////////////////////////////////////////
  657. //
  658. // Set_Playback_Rate
  659. //
  660. ////////////////////////////////////////////////////////////////////////////////////////////////
  661. void
  662. AudibleSoundClass::Set_Playback_Rate (int rate_in_hz)
  663. {
  664. MMSLockClass lock;
  665. // Do we have a valid sample handle from miles?
  666. if (m_SoundHandle != NULL) {
  667. m_SoundHandle->Set_Sample_Playback_Rate (rate_in_hz);
  668. }
  669. return ;
  670. }
  671. ////////////////////////////////////////////////////////////////////////////////////////////////
  672. //
  673. // Get_Volume
  674. //
  675. ////////////////////////////////////////////////////////////////////////////////////////////////
  676. float
  677. AudibleSoundClass::Get_Volume (void)
  678. {
  679. MMSLockClass lock;
  680. // Do we have a valid sample handle from miles?
  681. if (m_SoundHandle != NULL) {
  682. m_Volume = ((float)m_SoundHandle->Get_Sample_Volume ()) / 127.0F;
  683. }
  684. // Return the current pan value
  685. return m_Volume;
  686. }
  687. ////////////////////////////////////////////////////////////////////////////////////////////////
  688. //
  689. // Set_Volume
  690. //
  691. ////////////////////////////////////////////////////////////////////////////////////////////////
  692. void
  693. AudibleSoundClass::Set_Volume (float volume)
  694. {
  695. MMSLockClass lock;
  696. // Cache the normalized volume value
  697. m_Volume = min (volume, 1.0F);
  698. m_Volume = max (m_Volume, 0.0F);
  699. // Do we have a valid sample handle from miles?
  700. if (m_SoundHandle != NULL) {
  701. // Calculate the 'real' volume to set based on the global volume and the sound
  702. // effect volume.
  703. float real_volume = Determine_Real_Volume ();
  704. m_SoundHandle->Set_Sample_Volume (int(real_volume * 127.0F));
  705. }
  706. return ;
  707. }
  708. ////////////////////////////////////////////////////////////////////////////////////////////////
  709. //
  710. // Get_Loops_Left
  711. //
  712. ////////////////////////////////////////////////////////////////////////////////////////////////
  713. int
  714. AudibleSoundClass::Get_Loops_Left (void) const
  715. {
  716. return m_LoopsLeft;
  717. }
  718. ////////////////////////////////////////////////////////////////////////////////////////////////
  719. //
  720. // Set_Loop_Count
  721. //
  722. ////////////////////////////////////////////////////////////////////////////////////////////////
  723. void
  724. AudibleSoundClass::Set_Loop_Count (int count)
  725. {
  726. MMSLockClass lock;
  727. // Cache the loop count
  728. m_LoopCount = count;
  729. // Do we have a valid sample handle from miles?
  730. if (m_SoundHandle != NULL) {
  731. m_SoundHandle->Set_Sample_Loop_Count (m_LoopCount);
  732. }
  733. return ;
  734. }
  735. ////////////////////////////////////////////////////////////////////////////////////////////////
  736. //
  737. // Set_Priority
  738. //
  739. ////////////////////////////////////////////////////////////////////////////////////////////////
  740. void
  741. AudibleSoundClass::Set_Priority (float priority)
  742. {
  743. MMSLockClass lock;
  744. // Cache the normalized priority
  745. m_Priority = min (priority, 1.0F);
  746. m_Priority = max (m_Priority, 0.0F);
  747. return ;
  748. }
  749. ////////////////////////////////////////////////////////////////////////////////////////////////
  750. //
  751. // On_Frame_Update
  752. //
  753. ////////////////////////////////////////////////////////////////////////////////////////////////
  754. bool
  755. AudibleSoundClass::On_Frame_Update (unsigned int milliseconds)
  756. {
  757. //
  758. // Do we need to track this sound's play-progress?
  759. //
  760. if ((m_LoopCount != INFINITE_LOOPS) &&
  761. (m_State == STATE_PLAYING) &&
  762. (m_Length > 0))
  763. {
  764. Update_Play_Position ();
  765. }
  766. if (m_pConvertedFormat != NULL) {
  767. m_pConvertedFormat->Re_Sync (*this);
  768. }
  769. //
  770. // Move the logical sound with the audible one...
  771. //
  772. if (m_LogicalSound != NULL) {
  773. m_LogicalSound->Set_Transform (m_Transform);
  774. }
  775. return true;
  776. }
  777. ////////////////////////////////////////////////////////////////////////////////////////////////
  778. //
  779. // Update_Play_Position
  780. //
  781. ////////////////////////////////////////////////////////////////////////////////////////////////
  782. void
  783. AudibleSoundClass::Update_Play_Position (void)
  784. {
  785. // Determine the current offset from the beginning of the sound buffer.
  786. unsigned long play_time = ::GetTickCount () - m_Timestamp;
  787. m_CurrentPosition = play_time;
  788. // Have we gone past the end of a sounds play-time?
  789. if ((m_CurrentPosition > m_Length) && (m_Length > 0)) {
  790. // Normalize our position and timestamp information
  791. m_CurrentPosition = m_CurrentPosition % m_Length;
  792. m_Timestamp = ::GetTickCount () - m_CurrentPosition;
  793. // Decrement our count of remaining loops (if necessary)
  794. if (m_LoopCount != INFINITE_LOOPS) {
  795. m_LoopsLeft -= (play_time / m_Length);
  796. }
  797. // Trigger the 'end loop' event
  798. On_Loop_End ();
  799. }
  800. return ;
  801. }
  802. ////////////////////////////////////////////////////////////////////////////////////////////////
  803. //
  804. // Allocate_Miles_Handle
  805. //
  806. ////////////////////////////////////////////////////////////////////////////////////////////////
  807. void
  808. AudibleSoundClass::Allocate_Miles_Handle (void)
  809. {
  810. //
  811. // If we need to, get a play-handle from the audio system
  812. //
  813. if (m_SoundHandle == NULL) {
  814. Set_Miles_Handle ((MILES_HANDLE)WWAudioClass::Get_Instance ()->Get_2D_Sample (*this));
  815. }
  816. return ;
  817. }
  818. ////////////////////////////////////////////////////////////////////////////////////////////////
  819. //
  820. // On_Loop_End
  821. //
  822. ////////////////////////////////////////////////////////////////////////////////////////////////
  823. void
  824. AudibleSoundClass::On_Loop_End (void)
  825. {
  826. // Determine if the sound is actually finished or still looping
  827. if ((m_LoopCount != INFINITE_LOOPS) && (m_LoopsLeft < 1)) {
  828. // Let the audio system know that we are done with this sound
  829. Stop ();
  830. if (m_Scene != NULL) {
  831. Remove_From_Scene ();
  832. }
  833. // Fire an event
  834. On_Event (AudioCallbackClass::EVENT_SOUND_ENDED);
  835. } else {
  836. Restart_Loop ();
  837. }
  838. return ;
  839. }
  840. ////////////////////////////////////////////////////////////////////////////////////////////////
  841. //
  842. // Determine_Real_Volume
  843. //
  844. ////////////////////////////////////////////////////////////////////////////////////////////////
  845. float
  846. AudibleSoundClass::Determine_Real_Volume (void) const
  847. {
  848. float volume = m_Volume;
  849. // Is this a piece of music or is it a sound effect?
  850. if (m_Type == TYPE_MUSIC) {
  851. volume = volume * WWAudioClass::Get_Instance ()->Get_Music_Volume ();
  852. } else if (m_Type == TYPE_SOUND_EFFECT) {
  853. volume = volume * WWAudioClass::Get_Instance ()->Get_Sound_Effects_Volume ();
  854. }
  855. // Return the 'real' volume
  856. return volume;
  857. }
  858. ////////////////////////////////////////////////////////////////////////////////////////////////
  859. //
  860. // Get_Filename
  861. //
  862. ////////////////////////////////////////////////////////////////////////////////////////////////
  863. LPCTSTR
  864. AudibleSoundClass::Get_Filename (void) const
  865. {
  866. LPCTSTR filename = NULL;
  867. if (m_Buffer != NULL) {
  868. filename = m_Buffer->Get_Filename ();
  869. }
  870. return filename;
  871. }
  872. ////////////////////////////////////////////////////////////////////////////////////////////////
  873. //
  874. // Cull_Sound
  875. //
  876. ////////////////////////////////////////////////////////////////////////////////////////////////
  877. void
  878. AudibleSoundClass::Cull_Sound (bool culled)
  879. {
  880. // Is our state changing?
  881. if (m_IsCulled != culled) {
  882. m_IsCulled = culled;
  883. //
  884. // If this sound is culled, then throw away its play-handle.
  885. // Otherwise, make sure we have a valid handle.
  886. //
  887. // Note: We also free the handle if a converted form
  888. // of the sound is currently playing.
  889. //
  890. if (m_IsCulled || (m_pConvertedFormat != NULL)) {
  891. Free_Miles_Handle ();
  892. } else {
  893. Allocate_Miles_Handle ();
  894. }
  895. }
  896. return ;
  897. }
  898. ////////////////////////////////////////////////////////////////////////////////////////////////
  899. //
  900. // Set_Transform
  901. //
  902. ////////////////////////////////////////////////////////////////////////////////////////////////
  903. void
  904. AudibleSoundClass::Set_Transform (const Matrix3D &transform)
  905. {
  906. // Update our internal transform
  907. m_PrevTransform = m_Transform;
  908. m_Transform = transform;
  909. Set_Dirty ();
  910. return ;
  911. }
  912. ////////////////////////////////////////////////////////////////////////////////////////////////
  913. //
  914. // Set_Position
  915. //
  916. ////////////////////////////////////////////////////////////////////////////////////////////////
  917. void
  918. AudibleSoundClass::Set_Position (const Vector3 &position)
  919. {
  920. // Update our internal transform
  921. m_Transform.Set_Translation (position);
  922. Set_Dirty ();
  923. return ;
  924. }
  925. ////////////////////////////////////////////////////////////////////////////////////////////////
  926. //
  927. // Add_To_Scene
  928. //
  929. ////////////////////////////////////////////////////////////////////////////////////////////////
  930. void
  931. AudibleSoundClass::Add_To_Scene (bool start_playing)
  932. {
  933. SoundSceneClass *scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
  934. if ((scene != NULL) && (m_Scene == NULL)) {
  935. //
  936. // Add this sound to the static culling system
  937. //
  938. m_Scene = scene;
  939. scene->Add_Static_Sound (this, start_playing);
  940. }
  941. return ;
  942. }
  943. ////////////////////////////////////////////////////////////////////////////////////////////////
  944. //
  945. // Remove_From_Scene
  946. //
  947. ////////////////////////////////////////////////////////////////////////////////////////////////
  948. void
  949. AudibleSoundClass::Remove_From_Scene (void)
  950. {
  951. if (m_Scene != NULL) {
  952. //
  953. // Remove this sound from the static culling system
  954. //
  955. m_Scene->Remove_Static_Sound (this);
  956. m_Scene = NULL;
  957. m_PhysWrapper = NULL;
  958. }
  959. return ;
  960. }
  961. ////////////////////////////////////////////////////////////////////////////////////////////////
  962. //
  963. // Set_DropOff_Radius
  964. //
  965. ////////////////////////////////////////////////////////////////////////////////////////////////
  966. void
  967. AudibleSoundClass::Set_DropOff_Radius (float radius)
  968. {
  969. m_DropOffRadius = radius;
  970. Set_Dirty ();
  971. return ;
  972. }
  973. ////////////////////////////////////////////////////////////////////////////////////////////////
  974. //
  975. // Re_Sync
  976. //
  977. ////////////////////////////////////////////////////////////////////////////////////////////////
  978. void
  979. AudibleSoundClass::Re_Sync (AudibleSoundClass &src)
  980. {
  981. m_Timestamp = src.m_Timestamp;
  982. m_State = src.m_State;
  983. m_Type = src.m_Type;
  984. m_LoopCount = src.m_LoopCount;
  985. m_LoopsLeft = src.m_LoopsLeft;
  986. m_Length = src.m_Length;
  987. m_CurrentPosition = src.m_CurrentPosition;
  988. m_bDirty = src.m_bDirty;
  989. m_DropOffRadius = src.m_DropOffRadius;
  990. m_PrevTransform = src.m_PrevTransform;
  991. Cull_Sound (src.m_IsCulled);
  992. Set_Volume (src.m_Volume);
  993. Set_Pan (src.m_Pan);
  994. Set_Priority (src.m_Priority);
  995. Set_Transform (src.m_Transform);
  996. Set_Listener_Transform (src.m_ListenerTransform);
  997. if (m_State != STATE_PLAYING) {
  998. Free_Miles_Handle ();
  999. }
  1000. return ;
  1001. }
  1002. ////////////////////////////////////////////////////////////////////////////////////////////////
  1003. //
  1004. // Free_Conversion
  1005. //
  1006. ////////////////////////////////////////////////////////////////////////////////////////////////
  1007. void
  1008. AudibleSoundClass::Free_Conversion (void)
  1009. {
  1010. if (m_pConvertedFormat != NULL) {
  1011. m_pConvertedFormat->Stop ();
  1012. REF_PTR_RELEASE (m_pConvertedFormat);
  1013. }
  1014. //
  1015. // Reacquire a play-handle if necessary
  1016. //
  1017. if ((m_IsCulled == false) && (m_State == STATE_PLAYING)) {
  1018. Allocate_Miles_Handle ();
  1019. }
  1020. return ;
  1021. }
  1022. ////////////////////////////////////////////////////////////////////////////////////////////////
  1023. //
  1024. // Convert_To_Filtered
  1025. //
  1026. ////////////////////////////////////////////////////////////////////////////////////////////////
  1027. void
  1028. AudibleSoundClass::Convert_To_Filtered (void)
  1029. {
  1030. if (m_pConvertedFormat == NULL) {
  1031. //
  1032. // Make a copy of the sound in its new format
  1033. //
  1034. m_pConvertedFormat = W3DNEW FilteredSoundClass;
  1035. switch (Get_Class_ID ())
  1036. {
  1037. case CLASSID_3D:
  1038. (*m_pConvertedFormat) = (const Sound3DClass &)(*this);
  1039. break;
  1040. case CLASSID_PSEUDO3D:
  1041. (*m_pConvertedFormat) = (const SoundPseudo3DClass &)(*this);
  1042. break;
  1043. case CLASSID_FILTERED:
  1044. (*m_pConvertedFormat) = (const FilteredSoundClass &)(*this);
  1045. break;
  1046. default:
  1047. (*m_pConvertedFormat) = (*this);
  1048. break;
  1049. }
  1050. Free_Miles_Handle ();
  1051. }
  1052. return ;
  1053. }
  1054. ////////////////////////////////////////////////////////////////////////////////////////////////
  1055. //
  1056. // As_Converted_Format
  1057. //
  1058. ////////////////////////////////////////////////////////////////////////////////////////////////
  1059. AudibleSoundClass *
  1060. AudibleSoundClass::As_Converted_Format (void)
  1061. {
  1062. if (m_pConvertedFormat == NULL) {
  1063. Convert_To_Filtered ();
  1064. }
  1065. return m_pConvertedFormat;
  1066. }
  1067. ////////////////////////////////////////////////////////////////////////////////////////////////
  1068. //
  1069. // Get_Factory
  1070. //
  1071. ////////////////////////////////////////////////////////////////////////////////////////////////
  1072. const PersistFactoryClass &
  1073. AudibleSoundClass::Get_Factory (void) const
  1074. {
  1075. return _AudibleSoundPersistFactory;
  1076. }
  1077. //************************************************************************************************
  1078. //*
  1079. //* Start of AudibleSoundDefinitionClass
  1080. //*
  1081. //************************************************************************************************
  1082. ////////////////////////////////////////////////////////////////////////////////////////////////
  1083. //
  1084. // AudibleSoundDefinitionClass
  1085. //
  1086. ////////////////////////////////////////////////////////////////////////////////////////////////
  1087. AudibleSoundDefinitionClass::AudibleSoundDefinitionClass (void)
  1088. : m_Priority (0.5F),
  1089. m_Volume (1.0F),
  1090. m_Pan (0.5F),
  1091. m_LoopCount (1),
  1092. m_DropOffRadius (40.0F),
  1093. m_LogicalDropOffRadius (-1.0F),
  1094. m_MaxVolRadius (20.0F),
  1095. m_Is3D (true),
  1096. m_Type (AudibleSoundClass::TYPE_SOUND_EFFECT),
  1097. m_LogicalTypeMask (0),
  1098. m_LogicalNotifyDelay (2),
  1099. m_CreateLogical (false),
  1100. m_AttenuationSphereColor (0, 0.75F, 0.75F),
  1101. m_StartOffset (0),
  1102. m_PitchFactor (1.0F)
  1103. {
  1104. //
  1105. // Audible sound params
  1106. //
  1107. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_SOUND_FILENAME, m_Filename, "Filename");
  1108. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_DropOffRadius, "Drop-off Radius");
  1109. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_MaxVolRadius, "Max-Vol Radius");
  1110. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_BOOL, m_Is3D, "Is 3D Sound");
  1111. INT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_LoopCount, 0, 1000000);
  1112. FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Volume, 0, 1.0F);
  1113. FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Pan, 0, 1.0F);
  1114. FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Priority, 0, 1.0F);
  1115. ENUM_PARAM (AudibleSoundDefinitionClass, m_Type, ("Sound Effect", AudibleSoundClass::TYPE_SOUND_EFFECT, "Music", AudibleSoundClass::TYPE_MUSIC, 0));
  1116. FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_StartOffset, 0, 1.0F);
  1117. FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_PitchFactor, 0, 1.0F);
  1118. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_STRING, m_DisplayText, "Display Text");
  1119. //
  1120. // Logical sound params
  1121. //
  1122. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_BOOL, m_CreateLogical, "Create Logical Sound");
  1123. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_LogicalDropOffRadius, "Logical Drop-off Radius");
  1124. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_LogicalNotifyDelay, "Logical Notif Delay");
  1125. #ifdef PARAM_EDITING_ON
  1126. //
  1127. // Configure the logical type mask enumeration
  1128. //
  1129. EnumParameterClass *param = W3DNEW EnumParameterClass (&m_LogicalTypeMask);
  1130. param->Set_Name ("Logical Type");
  1131. int count = WWAudioClass::Get_Instance ()->Get_Logical_Type_Count ();
  1132. for (int index = 0; index < count; index ++) {
  1133. StringClass display_name(0,true);
  1134. int id = WWAudioClass::Get_Instance ()->Get_Logical_Type (index, display_name);
  1135. param->Add_Value (display_name, id);
  1136. }
  1137. GENERIC_EDITABLE_PARAM(AudibleSoundDefinitionClass, param);
  1138. #endif
  1139. NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_COLOR, m_AttenuationSphereColor, "Sphere Color");
  1140. return ;
  1141. }
  1142. // SKB: Put here because of conficts with CLASSID_???? with other projects.
  1143. uint32 AudibleSoundDefinitionClass::Get_Class_ID (void) const
  1144. {
  1145. return CLASSID_SOUND;
  1146. }
  1147. ////////////////////////////////////////////////////////////////////////////////////////////////
  1148. //
  1149. // Initialize_From_Sound
  1150. //
  1151. ////////////////////////////////////////////////////////////////////////////////////////////////
  1152. void
  1153. AudibleSoundDefinitionClass::Initialize_From_Sound (AudibleSoundClass *sound)
  1154. {
  1155. //
  1156. // Read the settings from the sound object
  1157. //
  1158. if (sound != NULL) {
  1159. Sound3DClass *sound_3d = sound->As_Sound3DClass ();
  1160. //
  1161. // Choose defaults for the values that we can't get from
  1162. // the sound.
  1163. //
  1164. m_LogicalDropOffRadius = -1.0F;
  1165. m_LogicalNotifyDelay = 2;
  1166. m_LogicalTypeMask = 0;
  1167. m_CreateLogical = false;
  1168. m_Pan = 0.5F;
  1169. m_DisplayText = "";
  1170. //
  1171. // Copy the values that we can from the sound object
  1172. //
  1173. m_Filename = sound->Get_Filename ();
  1174. m_DropOffRadius = sound->Get_DropOff_Radius ();
  1175. m_Priority = sound->Peek_Priority ();
  1176. m_Is3D = (sound_3d != NULL);
  1177. m_Type = sound->Get_Type ();
  1178. m_LoopCount = sound->Get_Loop_Count ();
  1179. m_Volume = sound->Get_Volume ();
  1180. m_StartOffset = sound->Get_Start_Offset ();
  1181. m_PitchFactor = sound->Get_Pitch_Factor ();
  1182. if (sound_3d != NULL) {
  1183. m_MaxVolRadius = sound_3d->Get_Max_Vol_Radius ();
  1184. }
  1185. }
  1186. return ;
  1187. }
  1188. ////////////////////////////////////////////////////////////////////////////////////////////////
  1189. //
  1190. // Get_Factory
  1191. //
  1192. ////////////////////////////////////////////////////////////////////////////////////////////////
  1193. const PersistFactoryClass &
  1194. AudibleSoundDefinitionClass::Get_Factory (void) const
  1195. {
  1196. return _AudibleSoundDefPersistFactory;
  1197. }
  1198. //////////////////////////////////////////////////////////////////////////////////
  1199. //
  1200. // Save
  1201. //
  1202. //////////////////////////////////////////////////////////////////////////////////
  1203. bool
  1204. AudibleSoundDefinitionClass::Save (ChunkSaveClass &csave)
  1205. {
  1206. using namespace AUDIBLE_SOUND_DEF_SAVELOAD;
  1207. bool retval = true;
  1208. csave.Begin_Chunk (CHUNKID_VARIABLES);
  1209. retval &= Save_Variables (csave);
  1210. csave.End_Chunk ();
  1211. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  1212. retval &= DefinitionClass::Save (csave);
  1213. csave.End_Chunk ();
  1214. return retval;
  1215. }
  1216. //////////////////////////////////////////////////////////////////////////////////
  1217. //
  1218. // Load
  1219. //
  1220. //////////////////////////////////////////////////////////////////////////////////
  1221. bool
  1222. AudibleSoundDefinitionClass::Load (ChunkLoadClass &cload)
  1223. {
  1224. using namespace AUDIBLE_SOUND_DEF_SAVELOAD;
  1225. bool retval = true;
  1226. while (cload.Open_Chunk ()) {
  1227. switch (cload.Cur_Chunk_ID ()) {
  1228. case CHUNKID_VARIABLES:
  1229. retval &= Load_Variables (cload);
  1230. break;
  1231. case CHUNKID_BASE_CLASS:
  1232. retval &= DefinitionClass::Load (cload);
  1233. break;
  1234. }
  1235. cload.Close_Chunk ();
  1236. }
  1237. return retval;
  1238. }
  1239. //////////////////////////////////////////////////////////////////////////////////
  1240. //
  1241. // Save_Variables
  1242. //
  1243. //////////////////////////////////////////////////////////////////////////////////
  1244. bool
  1245. AudibleSoundDefinitionClass::Save_Variables (ChunkSaveClass &csave)
  1246. {
  1247. using namespace AUDIBLE_SOUND_DEF_SAVELOAD;
  1248. //
  1249. // Save the audible variables
  1250. //
  1251. WRITE_MICRO_CHUNK (csave, VARID_PRIORITY, m_Priority)
  1252. WRITE_MICRO_CHUNK (csave, VARID_VOLUME, m_Volume)
  1253. WRITE_MICRO_CHUNK (csave, VARID_PAN, m_Pan)
  1254. WRITE_MICRO_CHUNK (csave, VARID_LOOP_COUNT, m_LoopCount)
  1255. WRITE_MICRO_CHUNK (csave, VARID_DROP_OFF, m_DropOffRadius)
  1256. WRITE_MICRO_CHUNK (csave, VARID_MAX_VOL, m_MaxVolRadius)
  1257. WRITE_MICRO_CHUNK (csave, VARID_TYPE, m_Type)
  1258. WRITE_MICRO_CHUNK (csave, VARID_IS3D, m_Is3D)
  1259. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_FILENAME, m_Filename)
  1260. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_DISPLAY_TEXT, m_DisplayText)
  1261. WRITE_MICRO_CHUNK (csave, VARID_START_OFFSET, m_StartOffset);
  1262. WRITE_MICRO_CHUNK (csave, VARID_PITCH_FACTOR, m_PitchFactor);
  1263. //
  1264. // Save the logical variables
  1265. //
  1266. WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_MASK, m_LogicalTypeMask)
  1267. WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_DELAY, m_LogicalNotifyDelay)
  1268. WRITE_MICRO_CHUNK (csave, VARID_CREATE_LOGICAL, m_CreateLogical)
  1269. WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_DROP_OFF, m_LogicalDropOffRadius)
  1270. WRITE_MICRO_CHUNK (csave, VARID_SPHERE_COLOR, m_AttenuationSphereColor)
  1271. return true;
  1272. }
  1273. //////////////////////////////////////////////////////////////////////////////////
  1274. //
  1275. // Load_Variables
  1276. //
  1277. //////////////////////////////////////////////////////////////////////////////////
  1278. bool
  1279. AudibleSoundDefinitionClass::Load_Variables (ChunkLoadClass &cload)
  1280. {
  1281. using namespace AUDIBLE_SOUND_DEF_SAVELOAD;
  1282. //
  1283. // Loop through all the microchunks that define the variables
  1284. //
  1285. while (cload.Open_Micro_Chunk ()) {
  1286. switch (cload.Cur_Micro_Chunk_ID ()) {
  1287. READ_MICRO_CHUNK (cload, VARID_PRIORITY, m_Priority)
  1288. READ_MICRO_CHUNK (cload, VARID_VOLUME, m_Volume)
  1289. READ_MICRO_CHUNK (cload, VARID_PAN, m_Pan)
  1290. READ_MICRO_CHUNK (cload, VARID_LOOP_COUNT, m_LoopCount)
  1291. READ_MICRO_CHUNK (cload, VARID_DROP_OFF, m_DropOffRadius)
  1292. READ_MICRO_CHUNK (cload, VARID_MAX_VOL, m_MaxVolRadius)
  1293. READ_MICRO_CHUNK (cload, VARID_TYPE, m_Type)
  1294. READ_MICRO_CHUNK (cload, VARID_IS3D, m_Is3D)
  1295. READ_MICRO_CHUNK_WWSTRING (cload, VARID_FILENAME, m_Filename)
  1296. READ_MICRO_CHUNK_WWSTRING (cload, VARID_DISPLAY_TEXT, m_DisplayText)
  1297. READ_MICRO_CHUNK (cload, VARID_LOGICAL_MASK, m_LogicalTypeMask)
  1298. READ_MICRO_CHUNK (cload, VARID_LOGICAL_DELAY, m_LogicalNotifyDelay)
  1299. READ_MICRO_CHUNK (cload, VARID_CREATE_LOGICAL, m_CreateLogical)
  1300. READ_MICRO_CHUNK (cload, VARID_LOGICAL_DROP_OFF, m_LogicalDropOffRadius)
  1301. READ_MICRO_CHUNK (cload, VARID_SPHERE_COLOR, m_AttenuationSphereColor)
  1302. READ_MICRO_CHUNK (cload, VARID_START_OFFSET, m_StartOffset);
  1303. READ_MICRO_CHUNK (cload, VARID_PITCH_FACTOR, m_PitchFactor);
  1304. }
  1305. cload.Close_Micro_Chunk ();
  1306. }
  1307. return true;
  1308. }
  1309. //////////////////////////////////////////////////////////////////////////////////
  1310. //
  1311. // Create
  1312. //
  1313. //////////////////////////////////////////////////////////////////////////////////
  1314. PersistClass *
  1315. AudibleSoundDefinitionClass::Create (void) const
  1316. {
  1317. return Create_Sound (CLASSID_3D);
  1318. }
  1319. //////////////////////////////////////////////////////////////////////////////////
  1320. //
  1321. // Create_Sound
  1322. //
  1323. //////////////////////////////////////////////////////////////////////////////////
  1324. AudibleSoundClass *
  1325. AudibleSoundDefinitionClass::Create_Sound (int classid_hint) const
  1326. {
  1327. AudibleSoundClass *new_sound = NULL;
  1328. //
  1329. // If this is a relative path, strip it off and assume
  1330. // the current directory is set correctly.
  1331. //
  1332. StringClass real_filename(m_Filename,true);
  1333. const char *dir_delimiter = ::strrchr (m_Filename, '\\');
  1334. if (dir_delimiter != NULL && m_Filename.Get_Length () > 2 && m_Filename[1] != ':') {
  1335. real_filename = (dir_delimiter + 1);
  1336. }
  1337. //
  1338. // Should we create a 2D or 3D sound?
  1339. //
  1340. if (m_Is3D) {
  1341. new_sound = WWAudioClass::Get_Instance ()->Create_3D_Sound (real_filename, classid_hint);
  1342. } else {
  1343. new_sound = WWAudioClass::Get_Instance ()->Create_Sound_Effect (real_filename);
  1344. }
  1345. //
  1346. // Did we successfully create the sound?
  1347. //
  1348. if (new_sound != NULL) {
  1349. //
  1350. // Configure the sound
  1351. //
  1352. new_sound->Set_Type ((AudibleSoundClass::SOUND_TYPE)m_Type);
  1353. new_sound->Set_Priority (m_Priority);
  1354. new_sound->Set_Volume (m_Volume);
  1355. new_sound->Set_Loop_Count (m_LoopCount);
  1356. new_sound->Set_DropOff_Radius (m_DropOffRadius);
  1357. new_sound->Set_Definition ((AudibleSoundDefinitionClass *)this);
  1358. new_sound->Set_Start_Offset (m_StartOffset);
  1359. new_sound->Set_Pitch_Factor (m_PitchFactor);
  1360. if (m_Is3D) {
  1361. ((Sound3DClass *)new_sound)->Set_Max_Vol_Radius (m_MaxVolRadius);
  1362. }
  1363. }
  1364. return new_sound;
  1365. }
  1366. //////////////////////////////////////////////////////////////////////////////////
  1367. //
  1368. // Create_Logical
  1369. //
  1370. //////////////////////////////////////////////////////////////////////////////////
  1371. LogicalSoundClass *
  1372. AudibleSoundDefinitionClass::Create_Logical (void)
  1373. {
  1374. LogicalSoundClass *logical_sound = NULL;
  1375. if (m_CreateLogical) {
  1376. //
  1377. // Create and configure the logical sound
  1378. //
  1379. logical_sound = W3DNEW LogicalSoundClass;
  1380. logical_sound->Set_Type_Mask (m_LogicalTypeMask);
  1381. logical_sound->Set_Notify_Delay (m_LogicalNotifyDelay);
  1382. logical_sound->Set_Single_Shot (m_LoopCount != 0);
  1383. //
  1384. // Use the audible sound's drop-off radius if the logical
  1385. // isn't set...
  1386. //
  1387. if (m_LogicalDropOffRadius < 0) {
  1388. logical_sound->Set_DropOff_Radius (m_DropOffRadius);
  1389. } else {
  1390. logical_sound->Set_DropOff_Radius (m_LogicalDropOffRadius);
  1391. }
  1392. }
  1393. return logical_sound;
  1394. }
  1395. //////////////////////////////////////////////////////////////////////////////////
  1396. //
  1397. // Save
  1398. //
  1399. //////////////////////////////////////////////////////////////////////////////////
  1400. bool
  1401. AudibleSoundClass::Save (ChunkSaveClass &csave)
  1402. {
  1403. using namespace AUDIBLE_SOUND_SAVELOAD;
  1404. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  1405. SoundSceneObjClass::Save (csave);
  1406. csave.End_Chunk ();
  1407. uint32 temp_position = 0;
  1408. csave.Begin_Chunk (CHUNKID_VARIABLES);
  1409. WRITE_MICRO_CHUNK (csave, VARID_STATE, m_State);
  1410. WRITE_MICRO_CHUNK (csave, VARID_TYPE, m_Type);
  1411. WRITE_MICRO_CHUNK (csave, VARID_PRIORITY, m_Priority);
  1412. WRITE_MICRO_CHUNK (csave, VARID_VOLUME, m_Volume);
  1413. WRITE_MICRO_CHUNK (csave, VARID_PAN, m_Pan);
  1414. WRITE_MICRO_CHUNK (csave, VARID_LOOP_COUNT, m_LoopCount);
  1415. WRITE_MICRO_CHUNK (csave, VARID_LOOPS_LEFT, m_LoopsLeft);
  1416. WRITE_MICRO_CHUNK (csave, VARID_SOUND_LENGTH, m_Length);
  1417. WRITE_MICRO_CHUNK (csave, VARID_CURR_POS, temp_position);
  1418. WRITE_MICRO_CHUNK (csave, VARID_TRANSFORM, m_Transform);
  1419. WRITE_MICRO_CHUNK (csave, VARID_PREV_TRANSFORM, m_PrevTransform);
  1420. WRITE_MICRO_CHUNK (csave, VARID_IS_CULLED, m_IsCulled);
  1421. WRITE_MICRO_CHUNK (csave, VARID_IS_DIRTY, m_bDirty);
  1422. WRITE_MICRO_CHUNK (csave, VARID_DROP_OFF, m_DropOffRadius);
  1423. WRITE_MICRO_CHUNK (csave, VARID_START_OFFSET, m_StartOffset);
  1424. WRITE_MICRO_CHUNK (csave, VARID_PITCH_FACTOR, m_PitchFactor);
  1425. WRITE_MICRO_CHUNK (csave, VARID_LISTENER_TRANSFORM, m_ListenerTransform);
  1426. if (m_Buffer != NULL) {
  1427. WRITE_MICRO_CHUNK_STRING (csave, VARID_FILENAME, m_Buffer->Get_Filename ());
  1428. }
  1429. AudibleSoundClass *this_ptr = this;
  1430. WRITE_MICRO_CHUNK (csave, VARID_THIS_PTR, this_ptr);
  1431. csave.End_Chunk ();
  1432. return true;
  1433. }
  1434. //////////////////////////////////////////////////////////////////////////////////
  1435. //
  1436. // Load
  1437. //
  1438. //////////////////////////////////////////////////////////////////////////////////
  1439. bool
  1440. AudibleSoundClass::Load (ChunkLoadClass &cload)
  1441. {
  1442. using namespace AUDIBLE_SOUND_SAVELOAD;
  1443. StringClass filename(0,true);
  1444. while (cload.Open_Chunk ()) {
  1445. switch (cload.Cur_Chunk_ID ()) {
  1446. case CHUNKID_BASE_CLASS:
  1447. SoundSceneObjClass::Load (cload);
  1448. break;
  1449. case CHUNKID_VARIABLES:
  1450. {
  1451. //
  1452. // Read all the variables from their micro-chunks
  1453. //
  1454. while (cload.Open_Micro_Chunk ()) {
  1455. switch (cload.Cur_Micro_Chunk_ID ()) {
  1456. READ_MICRO_CHUNK (cload, VARID_STATE, m_State);
  1457. READ_MICRO_CHUNK (cload, VARID_TYPE, m_Type);
  1458. READ_MICRO_CHUNK (cload, VARID_PRIORITY, m_Priority);
  1459. READ_MICRO_CHUNK (cload, VARID_VOLUME, m_Volume);
  1460. READ_MICRO_CHUNK (cload, VARID_PAN, m_Pan);
  1461. READ_MICRO_CHUNK (cload, VARID_LOOP_COUNT, m_LoopCount);
  1462. READ_MICRO_CHUNK (cload, VARID_LOOPS_LEFT, m_LoopsLeft);
  1463. READ_MICRO_CHUNK (cload, VARID_SOUND_LENGTH, m_Length);
  1464. READ_MICRO_CHUNK (cload, VARID_CURR_POS, m_CurrentPosition);
  1465. READ_MICRO_CHUNK (cload, VARID_TRANSFORM, m_Transform);
  1466. READ_MICRO_CHUNK (cload, VARID_PREV_TRANSFORM, m_PrevTransform);
  1467. READ_MICRO_CHUNK (cload, VARID_IS_CULLED, m_IsCulled);
  1468. READ_MICRO_CHUNK (cload, VARID_IS_DIRTY, m_bDirty);
  1469. READ_MICRO_CHUNK (cload, VARID_DROP_OFF, m_DropOffRadius);
  1470. READ_MICRO_CHUNK (cload, VARID_START_OFFSET, m_StartOffset);
  1471. READ_MICRO_CHUNK (cload, VARID_PITCH_FACTOR, m_PitchFactor);
  1472. READ_MICRO_CHUNK (cload, VARID_LISTENER_TRANSFORM, m_ListenerTransform);
  1473. READ_MICRO_CHUNK_WWSTRING (cload, VARID_FILENAME, filename);
  1474. case VARID_THIS_PTR:
  1475. {
  1476. AudibleSoundClass *old_ptr = NULL;
  1477. cload.Read(&old_ptr, sizeof (old_ptr));
  1478. SaveLoadSystemClass::Register_Pointer (old_ptr, this);
  1479. }
  1480. break;
  1481. }
  1482. cload.Close_Micro_Chunk ();
  1483. }
  1484. }
  1485. break;
  1486. }
  1487. cload.Close_Chunk ();
  1488. }
  1489. //
  1490. // Reconstruct the sound buffer we had before we saved
  1491. //
  1492. if (filename.Get_Length () > 0) {
  1493. bool is_3d = (As_Sound3DClass () != NULL);
  1494. SoundBufferClass *buffer = WWAudioClass::Get_Instance ()->Get_Sound_Buffer (filename, is_3d);
  1495. Set_Buffer (buffer);
  1496. REF_PTR_RELEASE (buffer);
  1497. }
  1498. return true;
  1499. }