Sound3D.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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/Sound3D.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 8/13/01 3:50p $*
  29. * *
  30. * $Revision:: 18 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "sound3d.h"
  36. #include "soundbuffer.h"
  37. #include "wwaudio.h"
  38. #include "soundscene.h"
  39. #include "utils.h"
  40. #include "soundchunkids.h"
  41. #include "persistfactory.h"
  42. #include "chunkio.h"
  43. #include "sound3dhandle.h"
  44. //////////////////////////////////////////////////////////////////////////////////
  45. //
  46. // Static factories
  47. //
  48. //////////////////////////////////////////////////////////////////////////////////
  49. SimplePersistFactoryClass<Sound3DClass, CHUNKID_SOUND3D> _Sound3DPersistFactory;
  50. enum
  51. {
  52. CHUNKID_VARIABLES = 0x11090955,
  53. CHUNKID_BASE_CLASS
  54. };
  55. enum
  56. {
  57. VARID_AUTO_CALC_VEL = 0x01,
  58. VARID_CURR_VEL,
  59. VARID_XXX1,
  60. VARID_XXX2,
  61. VARID_MAX_VOL_RADIUS,
  62. VARID_IS_STATIC,
  63. };
  64. ////////////////////////////////////////////////////////////////////////////////////////////////
  65. //
  66. // Sound3DClass
  67. //
  68. ////////////////////////////////////////////////////////////////////////////////////////////////
  69. Sound3DClass::Sound3DClass (void)
  70. : m_bAutoCalcVel (true),
  71. m_CurrentVelocity (0, 0, 0),
  72. m_MaxVolRadius (0),
  73. m_LastUpdate (0),
  74. m_IsStatic (false),
  75. m_IsTransformInitted (false)
  76. {
  77. return ;
  78. }
  79. ////////////////////////////////////////////////////////////////////////////////////////////////
  80. //
  81. // Sound3DClass
  82. //
  83. ////////////////////////////////////////////////////////////////////////////////////////////////
  84. Sound3DClass::Sound3DClass (const Sound3DClass &src)
  85. : m_bAutoCalcVel (true),
  86. m_CurrentVelocity (0, 0, 0),
  87. m_MaxVolRadius (0),
  88. m_LastUpdate (0),
  89. m_IsStatic (false),
  90. m_IsTransformInitted (false),
  91. AudibleSoundClass (src)
  92. {
  93. (*this) = src;
  94. return ;
  95. }
  96. ////////////////////////////////////////////////////////////////////////////////////////////////
  97. //
  98. // ~Sound3DClass
  99. //
  100. ////////////////////////////////////////////////////////////////////////////////////////////////
  101. Sound3DClass::~Sound3DClass (void)
  102. {
  103. Free_Miles_Handle ();
  104. return ;
  105. }
  106. ////////////////////////////////////////////////////////////////////////////////////////////////
  107. //
  108. // operator=
  109. //
  110. ////////////////////////////////////////////////////////////////////////////////////////////////
  111. const Sound3DClass &
  112. Sound3DClass::operator= (const Sound3DClass &src)
  113. {
  114. m_bAutoCalcVel = src.m_bAutoCalcVel;
  115. m_CurrentVelocity = src.m_CurrentVelocity;
  116. m_MaxVolRadius = src.m_MaxVolRadius;
  117. m_IsStatic = src.m_IsStatic;
  118. m_LastUpdate = src.m_LastUpdate;
  119. // Call the base class
  120. AudibleSoundClass::operator= (src);
  121. return (*this);
  122. }
  123. ////////////////////////////////////////////////////////////////////////////////////////////////
  124. //
  125. // Play
  126. //
  127. ////////////////////////////////////////////////////////////////////////////////////////////////
  128. bool
  129. Sound3DClass::Play (bool alloc_handle)
  130. {
  131. // Record our first 'tick' if we just started playing
  132. if (m_State != STATE_PLAYING) {
  133. m_LastUpdate = ::GetTickCount ();
  134. }
  135. // Allow the base class to process this call
  136. return AudibleSoundClass::Play (m_IsCulled == false);
  137. }
  138. ////////////////////////////////////////////////////////////////////////////////////////////////
  139. //
  140. // On_Frame_Update
  141. //
  142. ////////////////////////////////////////////////////////////////////////////////////////////////
  143. bool
  144. Sound3DClass::On_Frame_Update (unsigned int milliseconds)
  145. {
  146. Matrix3D prev_tm = m_PrevTransform;
  147. if (m_bDirty && (m_PhysWrapper != NULL)) {
  148. m_Scene->Update_Sound (m_PhysWrapper);
  149. m_bDirty = false;
  150. }
  151. //
  152. // Update the sound's position if its linked to a render object
  153. //
  154. Apply_Auto_Position ();
  155. //
  156. // Make sure the transform is initialized
  157. //
  158. if (m_IsTransformInitted == false) {
  159. prev_tm = m_Transform;
  160. }
  161. //
  162. // Update the current velocity if we are 'auto-calcing'.
  163. //
  164. if (m_bAutoCalcVel && Get_Class_ID () != CLASSID_LISTENER) {
  165. Vector3 last_pos = prev_tm.Get_Translation ();
  166. Vector3 curr_pos = m_Transform.Get_Translation ();
  167. //
  168. // Don't update the velocity if we haven't moved (optimization -- Miles calls
  169. // can be really slow)
  170. //
  171. if (last_pos != curr_pos) {
  172. Vector3 curr_vel;
  173. //
  174. // Extrapolate our current velocity given the last time slice and the distance
  175. // we moved.
  176. //
  177. float secs_since_last_update = (::GetTickCount () - m_LastUpdate);
  178. if (secs_since_last_update > 0) {
  179. curr_vel = ((curr_pos - last_pos) / secs_since_last_update);
  180. } else {
  181. curr_vel.Set (0, 0, 0);
  182. }
  183. Set_Velocity (curr_vel);
  184. }
  185. }
  186. // Remember when the last time we updated our 'auto-calc'
  187. // variables.
  188. m_LastUpdate = ::GetTickCount ();
  189. m_PrevTransform = m_Transform;
  190. // Allow the base class to process this call
  191. return AudibleSoundClass::On_Frame_Update ();
  192. }
  193. ////////////////////////////////////////////////////////////////////////////////////////////////
  194. //
  195. // Set_Transform
  196. //
  197. ////////////////////////////////////////////////////////////////////////////////////////////////
  198. void
  199. Sound3DClass::Set_Transform (const Matrix3D &transform)
  200. {
  201. if (transform == m_Transform) {
  202. return ;
  203. }
  204. // Update our internal transform
  205. m_PrevTransform = m_Transform;
  206. m_Transform = transform;
  207. Set_Dirty ();
  208. if (m_IsTransformInitted == false) {
  209. m_PrevTransform = transform;
  210. m_IsTransformInitted = true;
  211. }
  212. Update_Miles_Transform ();
  213. return ;
  214. }
  215. ////////////////////////////////////////////////////////////////////////////////////////////////
  216. //
  217. // Set_Listener_Transform
  218. //
  219. ////////////////////////////////////////////////////////////////////////////////////////////////
  220. void
  221. Sound3DClass::Set_Listener_Transform (const Matrix3D &tm)
  222. {
  223. //
  224. // If the transform has changed, then cache the new transform
  225. // and update the sound's position in the "Mile's" world
  226. //
  227. if (m_ListenerTransform != tm) {
  228. m_ListenerTransform = tm;
  229. Update_Miles_Transform ();
  230. }
  231. return ;
  232. }
  233. ////////////////////////////////////////////////////////////////////////////////////////////////
  234. //
  235. // Update_Miles_Transform
  236. //
  237. ////////////////////////////////////////////////////////////////////////////////////////////////
  238. void
  239. Sound3DClass::Update_Miles_Transform (void)
  240. {
  241. //
  242. // Do we have a valid miles handle?
  243. //
  244. if (m_SoundHandle != NULL) {
  245. //
  246. // Build a matrix to transform coordinates from world-space to listener-space
  247. //
  248. Matrix3D world_to_listener_tm;
  249. m_ListenerTransform.Get_Orthogonal_Inverse (world_to_listener_tm);
  250. //
  251. // Transform the object's TM into "listener-space"
  252. //
  253. #ifdef ALLOW_TEMPORARIES
  254. Matrix3D listener_space_tm = world_to_listener_tm * m_Transform;
  255. #else
  256. Matrix3D listener_space_tm;
  257. listener_space_tm.mul(world_to_listener_tm, m_Transform);
  258. #endif
  259. //
  260. // Pass the sound's position onto miles
  261. //
  262. Vector3 position = listener_space_tm.Get_Translation ();
  263. ::AIL_set_3D_position (m_SoundHandle->Get_H3DSAMPLE (), -position.Y, position.Z, position.X);
  264. //
  265. // Pass the sound's orientation (facing) onto miles
  266. //
  267. Vector3 facing = listener_space_tm.Get_X_Vector ();
  268. Vector3 up = listener_space_tm.Get_Z_Vector ();
  269. ::AIL_set_3D_orientation (m_SoundHandle->Get_H3DSAMPLE (),
  270. -facing.Y,
  271. facing.Z,
  272. facing.X,
  273. -up.Y,
  274. up.Z,
  275. up.X);
  276. }
  277. return ;
  278. }
  279. ////////////////////////////////////////////////////////////////////////////////////////////////
  280. //
  281. // Set_Position
  282. //
  283. ////////////////////////////////////////////////////////////////////////////////////////////////
  284. void
  285. Sound3DClass::Set_Position (const Vector3 &position)
  286. {
  287. //
  288. // Pass the sound's position onto miles
  289. //
  290. if (m_Transform.Get_Translation () != position) {
  291. // Update our internal transform
  292. //
  293. // SKB: 4/13/01 - Confirmed to be OK by Pat Smith.
  294. // Took Set_Transform() outside of condition because even if sound is
  295. // not playing I need to be able to change it's position.
  296. // I had a problem that sounds would never be added to the scene because
  297. // their positions stayed at 0,0,0 even after this Set_Postion() call.
  298. m_PrevTransform = m_Transform;
  299. m_Transform.Set_Translation (position);
  300. Set_Dirty ();
  301. if (m_IsTransformInitted == false) {
  302. m_PrevTransform = m_Transform;
  303. m_IsTransformInitted = true;
  304. }
  305. if (m_SoundHandle != NULL) {
  306. //
  307. // Transform the sound's position into 'listener-space'
  308. //
  309. Vector3 sound_pos = position;
  310. Vector3 listener_space_pos;
  311. Matrix3D::Inverse_Transform_Vector (m_ListenerTransform, sound_pos, &listener_space_pos);
  312. //
  313. // Update the object's position inside of Miles
  314. //
  315. ::AIL_set_3D_position (m_SoundHandle->Get_H3DSAMPLE (), -listener_space_pos.Y,
  316. listener_space_pos.Z, listener_space_pos.X);
  317. }
  318. }
  319. return ;
  320. }
  321. ////////////////////////////////////////////////////////////////////////////////////////////////
  322. //
  323. // Set_Velocity
  324. //
  325. ////////////////////////////////////////////////////////////////////////////////////////////////
  326. void
  327. Sound3DClass::Set_Velocity (const Vector3 &velocity)
  328. {
  329. MMSLockClass lock;
  330. m_CurrentVelocity = velocity;
  331. Set_Dirty ();
  332. //
  333. // Pass the sound's velocity onto miles
  334. //
  335. if (m_SoundHandle != NULL) {
  336. //WWDEBUG_SAY (("Current Velocity: %.2f %.2f %.2f\n", m_CurrentVelocity.X, m_CurrentVelocity.Y, m_CurrentVelocity.Z));
  337. ::AIL_set_3D_velocity_vector (m_SoundHandle->Get_H3DSAMPLE (),
  338. -m_CurrentVelocity.Y,
  339. m_CurrentVelocity.Z,
  340. m_CurrentVelocity.X);
  341. }
  342. return ;
  343. }
  344. ////////////////////////////////////////////////////////////////////////////////////////////////
  345. //
  346. // Set_DropOff_Radius
  347. //
  348. ////////////////////////////////////////////////////////////////////////////////////////////////
  349. void
  350. Sound3DClass::Set_DropOff_Radius (float radius)
  351. {
  352. //MMSLockClass lock;
  353. m_DropOffRadius = radius;
  354. Set_Dirty ();
  355. // Pass attenuation settings onto miles
  356. if (m_SoundHandle != NULL) {
  357. ::AIL_set_3D_sample_distances ( m_SoundHandle->Get_H3DSAMPLE (),
  358. m_DropOffRadius,
  359. (m_MaxVolRadius > 1.0F) ? m_MaxVolRadius : 1.0F);
  360. }
  361. return ;
  362. }
  363. ////////////////////////////////////////////////////////////////////////////////////////////////
  364. //
  365. // Set_Max_Vol_Radius
  366. //
  367. ////////////////////////////////////////////////////////////////////////////////////////////////
  368. void
  369. Sound3DClass::Set_Max_Vol_Radius (float radius)
  370. {
  371. m_MaxVolRadius = radius;
  372. Set_Dirty ();
  373. // Pass attenuation settings onto miles
  374. if (m_SoundHandle != NULL) {
  375. ::AIL_set_3D_sample_distances ( m_SoundHandle->Get_H3DSAMPLE (),
  376. m_DropOffRadius,
  377. (m_MaxVolRadius > 1.0F) ? m_MaxVolRadius : 1.0F);
  378. }
  379. return ;
  380. }
  381. ////////////////////////////////////////////////////////////////////////////////////////////////
  382. //
  383. // Initialize_Miles_Handle
  384. //
  385. ////////////////////////////////////////////////////////////////////////////////////////////////
  386. void
  387. Sound3DClass::Initialize_Miles_Handle (void)
  388. {
  389. MMSLockClass lock;
  390. // If this sound is already playing, then update its
  391. // playing position to make sure we really should
  392. // be playing it... (it will free the miles handle if not)
  393. if (m_State == STATE_PLAYING) {
  394. Update_Play_Position ();
  395. }
  396. // Do we have a valid sample handle from miles?
  397. if (m_SoundHandle != NULL) {
  398. //
  399. // Pass the actual sound data onto the sample
  400. //
  401. m_SoundHandle->Initialize (m_Buffer);
  402. //
  403. // Record the total length of the sample in milliseconds...
  404. //
  405. m_SoundHandle->Get_Sample_MS_Position ((S32 *)&m_Length, NULL);
  406. //
  407. // Pass our cached settings onto miles
  408. //
  409. float real_volume = Determine_Real_Volume ();
  410. m_SoundHandle->Set_Sample_Volume (int(real_volume * 127.0F));
  411. m_SoundHandle->Set_Sample_Pan (int(m_Pan * 127.0F));
  412. m_SoundHandle->Set_Sample_Loop_Count (m_LoopCount);
  413. //
  414. // Pass attenuation settings onto miles
  415. //
  416. ::AIL_set_3D_sample_distances ( m_SoundHandle->Get_H3DSAMPLE (),
  417. m_DropOffRadius,
  418. (m_MaxVolRadius > 1.0F) ? m_MaxVolRadius : 1.0F);
  419. //
  420. // Assign the 3D effects level accordingly (for reverb, etc)
  421. //
  422. ::AIL_set_3D_sample_effects_level (m_SoundHandle->Get_H3DSAMPLE (),
  423. WWAudioClass::Get_Instance ()->Get_Effects_Level ());
  424. //
  425. // Pass the sound's position and orientation onto Miles
  426. //
  427. Update_Miles_Transform ();
  428. //
  429. // Apply the pitch factor (if necessary)
  430. //
  431. if (m_PitchFactor != 1.0F) {
  432. Set_Pitch_Factor (m_PitchFactor);
  433. }
  434. // If this sound is already playing (and just now got a handle)
  435. // then make sure we start it.
  436. if (m_State == STATE_PLAYING) {
  437. m_SoundHandle->Start_Sample ();
  438. // Update the loop count based on the number of loops left
  439. m_SoundHandle->Set_Sample_Loop_Count (m_LoopsLeft);
  440. }
  441. // Seek to the position of the sound where we last left off.
  442. // For example, this sound could have gotten bumped due to a low priority,
  443. // but is now back and ready to resume at the position it would have been
  444. // at if it was never bumped.
  445. Seek (m_CurrentPosition);
  446. // Associate this object instance with the handle
  447. m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, (S32)this);
  448. }
  449. return ;
  450. }
  451. ////////////////////////////////////////////////////////////////////////////////////////////////
  452. //
  453. // Allocate_Miles_Handle
  454. //
  455. ////////////////////////////////////////////////////////////////////////////////////////////////
  456. void
  457. Sound3DClass::Allocate_Miles_Handle (void)
  458. {
  459. //MMSLockClass lock;
  460. //
  461. // If we need to, get a play-handle from the audio system
  462. //
  463. if (m_SoundHandle == NULL) {
  464. Set_Miles_Handle ((MILES_HANDLE)WWAudioClass::Get_Instance ()->Get_3D_Sample (*this));
  465. }
  466. return ;
  467. }
  468. ////////////////////////////////////////////////////////////////////////////////////////////////
  469. //
  470. // Add_To_Scene
  471. //
  472. ////////////////////////////////////////////////////////////////////////////////////////////////
  473. void
  474. Sound3DClass::Add_To_Scene (bool start_playing)
  475. {
  476. SoundSceneClass *scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
  477. if ((scene != NULL) && (m_Scene == NULL)) {
  478. // Determine what culling system this sound belongs to
  479. if (m_IsStatic) {
  480. scene->Add_Static_Sound (this, start_playing);
  481. } else {
  482. scene->Add_Sound (this, start_playing);
  483. }
  484. m_Scene = scene;
  485. }
  486. return ;
  487. }
  488. ////////////////////////////////////////////////////////////////////////////////////////////////
  489. //
  490. // Remove_From_Scene
  491. //
  492. ////////////////////////////////////////////////////////////////////////////////////////////////
  493. void
  494. Sound3DClass::Remove_From_Scene (void)
  495. {
  496. if (m_Scene != NULL) {
  497. // Determine what culling system this sound belongs to
  498. if (m_IsStatic) {
  499. m_Scene->Remove_Static_Sound (this);
  500. } else {
  501. m_Scene->Remove_Sound (this);
  502. }
  503. m_Scene = NULL;
  504. m_PhysWrapper = NULL;
  505. }
  506. return ;
  507. }
  508. ////////////////////////////////////////////////////////////////////////////////////////////////
  509. //
  510. // On_Loop_End
  511. //
  512. ////////////////////////////////////////////////////////////////////////////////////////////////
  513. void
  514. Sound3DClass::On_Loop_End (void)
  515. {
  516. // Allow the base class to process this message
  517. AudibleSoundClass::On_Loop_End ();
  518. return ;
  519. }
  520. /////////////////////////////////////////////////////////////////////////////////
  521. //
  522. // Get_Factory
  523. //
  524. /////////////////////////////////////////////////////////////////////////////////
  525. const PersistFactoryClass &
  526. Sound3DClass::Get_Factory (void) const
  527. {
  528. return _Sound3DPersistFactory;
  529. }
  530. //////////////////////////////////////////////////////////////////////////////////
  531. //
  532. // Save
  533. //
  534. //////////////////////////////////////////////////////////////////////////////////
  535. bool
  536. Sound3DClass::Save (ChunkSaveClass &csave)
  537. {
  538. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  539. AudibleSoundClass::Save (csave);
  540. csave.End_Chunk ();
  541. csave.Begin_Chunk (CHUNKID_VARIABLES);
  542. WRITE_MICRO_CHUNK (csave, VARID_AUTO_CALC_VEL, m_bAutoCalcVel);
  543. WRITE_MICRO_CHUNK (csave, VARID_CURR_VEL, m_CurrentVelocity);
  544. WRITE_MICRO_CHUNK (csave, VARID_MAX_VOL_RADIUS, m_MaxVolRadius);
  545. WRITE_MICRO_CHUNK (csave, VARID_IS_STATIC, m_IsStatic);
  546. csave.End_Chunk ();
  547. return true;
  548. }
  549. //////////////////////////////////////////////////////////////////////////////////
  550. //
  551. // Load
  552. //
  553. //////////////////////////////////////////////////////////////////////////////////
  554. bool
  555. Sound3DClass::Load (ChunkLoadClass &cload)
  556. {
  557. while (cload.Open_Chunk ()) {
  558. switch (cload.Cur_Chunk_ID ()) {
  559. case CHUNKID_BASE_CLASS:
  560. AudibleSoundClass::Load (cload);
  561. break;
  562. case CHUNKID_VARIABLES:
  563. {
  564. //
  565. // Read all the variables from their micro-chunks
  566. //
  567. while (cload.Open_Micro_Chunk ()) {
  568. switch (cload.Cur_Micro_Chunk_ID ()) {
  569. READ_MICRO_CHUNK (cload, VARID_AUTO_CALC_VEL, m_bAutoCalcVel);
  570. READ_MICRO_CHUNK (cload, VARID_CURR_VEL, m_CurrentVelocity);
  571. READ_MICRO_CHUNK (cload, VARID_MAX_VOL_RADIUS, m_MaxVolRadius);
  572. READ_MICRO_CHUNK (cload, VARID_IS_STATIC, m_IsStatic);
  573. }
  574. cload.Close_Micro_Chunk ();
  575. }
  576. }
  577. break;
  578. }
  579. cload.Close_Chunk ();
  580. }
  581. return true;
  582. }
  583. ////////////////////////////////////////////////////////////////////////////////////////////////
  584. //
  585. // Set_Miles_Handle
  586. //
  587. ////////////////////////////////////////////////////////////////////////////////////////////////
  588. void
  589. Sound3DClass::Set_Miles_Handle (MILES_HANDLE handle)
  590. {
  591. //
  592. // Start fresh
  593. //
  594. Free_Miles_Handle ();
  595. //
  596. // Is our data valid?
  597. //
  598. if (handle != INVALID_MILES_HANDLE && m_Buffer != NULL) {
  599. //
  600. // Configure the sound handle
  601. //
  602. m_SoundHandle = W3DNEW Sound3DHandleClass;
  603. m_SoundHandle->Set_Miles_Handle (handle);
  604. //
  605. // Use this new handle
  606. //
  607. Initialize_Miles_Handle ();
  608. }
  609. return ;
  610. }