SoundObject.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Base/Stream.h>
  14. #include <Engine/Base/Console.h>
  15. #include <Engine/Base/CRC.h>
  16. #include <Engine/Math/Vector.h>
  17. #include <Engine/Math/Functions.h>
  18. #include <Engine/Sound/SoundObject.h>
  19. #include <Engine/Sound/SoundDecoder.h>
  20. #include <Engine/Sound/SoundData.h>
  21. #include <Engine/Sound/SoundLibrary.h>
  22. #include <Engine/Sound/SoundListener.h>
  23. #include <Engine/Entities/Entity.h>
  24. #include <Engine/Entities/InternalClasses.h>
  25. #include <Engine/Base/ListIterator.inl>
  26. #include <Engine/Templates/Stock_CSoundData.h>
  27. // sound event codes for prediction
  28. #define EVENT_SOUNDPLAY 0x0101
  29. #define EVENT_SOUNDSTOP 0x0102
  30. #define EVENT_SOUNDSETOFFSET 0x0103
  31. extern FLOAT snd_fEarsDistance;
  32. extern FLOAT snd_fDelaySoundSpeed;
  33. extern FLOAT snd_fDopplerSoundSpeed;
  34. extern FLOAT snd_fPanStrength;
  35. extern FLOAT snd_fLRFilter;
  36. extern FLOAT snd_fBFilter;
  37. extern FLOAT snd_fUFilter;
  38. extern FLOAT snd_fDFilter;
  39. extern BOOL _bPredictionActive;
  40. // console variables for volume
  41. extern FLOAT snd_fSoundVolume;
  42. extern FLOAT snd_fMusicVolume;
  43. static CTString GetPred(CEntity*pen)
  44. {
  45. CTString str1;
  46. if (pen->IsPredictor()) {
  47. str1 = "predictor";
  48. } else if (pen->IsPredicted()) {
  49. str1 = "predicted";
  50. } else if (pen->en_ulFlags & ENF_WILLBEPREDICTED) {
  51. str1 = "will be predicted";
  52. } else {
  53. str1 = "???";
  54. }
  55. CTString str;
  56. str.PrintF("%08x-%s", pen, str1);
  57. return str;
  58. }
  59. /* ====================================================
  60. *
  61. * Class global methods
  62. */
  63. /*
  64. * Constructor
  65. */
  66. CSoundObject::CSoundObject()
  67. {
  68. so_pCsdLink = NULL;
  69. so_psdcDecoder = NULL;
  70. so_penEntity = NULL;
  71. so_slFlags = 0;
  72. // clear sound settings
  73. so_spNew.sp_fLeftVolume = 1.0f;
  74. so_spNew.sp_fRightVolume = 1.0f;
  75. so_spNew.sp_slLeftFilter = 0x7FFF;
  76. so_spNew.sp_slRightFilter = 0x7FFF;
  77. so_spNew.sp_fPitchShift = 1.0f;
  78. so_spNew.sp_fPhaseShift = 0.0f;
  79. so_spNew.sp_fDelay = 0.0f;
  80. so_sp = so_spNew;
  81. so_fLeftOffset = 0.0f;
  82. so_fRightOffset = 0.0f;
  83. so_fOffsetDelta = 0.0f;
  84. so_fDelayed = 0.0f;
  85. so_fLastLeftVolume = 1.0f;
  86. so_fLastRightVolume = 1.0f;
  87. so_swLastLeftSample = 0;
  88. so_swLastRightSample = 0;
  89. // 3d effects
  90. so_sp3.sp3_fFalloff = 0.0f;
  91. so_sp3.sp3_fHotSpot = 0.0f;
  92. so_sp3.sp3_fMaxVolume = 0.0f;
  93. so_sp3.sp3_fPitch = 1.0f;
  94. };
  95. /*
  96. * Destructor
  97. */
  98. CSoundObject::~CSoundObject()
  99. {
  100. Stop_internal();
  101. };
  102. // copy from another object of same class
  103. void CSoundObject::Copy(CSoundObject &soOther)
  104. {
  105. Stop_internal();
  106. so_sp = so_spNew = soOther.so_sp;
  107. so_sp3 = soOther.so_sp3;
  108. so_penEntity = NULL;
  109. so_slFlags = soOther.so_slFlags;
  110. if (soOther.so_slFlags&SOF_PLAY) {
  111. Play(soOther.so_pCsdLink, soOther.so_slFlags);
  112. }
  113. }
  114. // Set 3D parameters
  115. void CSoundObject::Set3DParameters( FLOAT fFalloff, FLOAT fHotSpot,
  116. FLOAT fMaxVolume, FLOAT fPitch)
  117. {
  118. ASSERT( (fFalloff > 0) && (fHotSpot >= 0));
  119. ASSERT( fMaxVolume >= 0);
  120. ASSERT( fFalloff >= fHotSpot);
  121. ASSERT( fPitch > 0);
  122. CSoundObject *pso = this;
  123. // if the sound's entity is a predictor
  124. if (_bPredictionActive && so_penEntity!=NULL) {
  125. if (so_penEntity->IsPredictionHead()) {
  126. // get your prediction tail
  127. //CPrintF("SET3D: ");
  128. CEntity *pen = so_penEntity->GetPredictionTail();
  129. if (pen!=so_penEntity) {
  130. pso = (CSoundObject *)( ((UBYTE*)pen) + (int(this)-int(so_penEntity)) );
  131. }
  132. }
  133. }
  134. pso->so_sp3.sp3_fFalloff = fFalloff;
  135. pso->so_sp3.sp3_fHotSpot = fHotSpot;
  136. pso->so_sp3.sp3_fMaxVolume = fMaxVolume;
  137. pso->so_sp3.sp3_fPitch = fPitch;
  138. };
  139. /* ====================================================
  140. * Sound control methods
  141. */
  142. // get proper sound object for predicted events - return NULL the event is already predicted
  143. CSoundObject *CSoundObject::GetPredictionTail(ULONG ulTypeID, ULONG ulEventID)
  144. {
  145. // if the sound has an entity
  146. if (so_penEntity!=NULL) {
  147. //CPrintF(" {%s}", GetPred(so_penEntity));
  148. // if the entity is temporary predictor
  149. if (so_penEntity->GetFlags()&ENF_TEMPPREDICTOR) {
  150. //CPrintF(" temppred\n");
  151. // it must not play the sound
  152. return NULL;
  153. }
  154. SLONG slOffset = int(this)-int(so_penEntity);
  155. ULONG ulCRC;
  156. CRC_Start(ulCRC);
  157. CRC_AddLONG(ulCRC, slOffset);
  158. CRC_AddLONG(ulCRC, ulTypeID);
  159. CRC_Finish(ulCRC);
  160. // if the event is predicted
  161. if (so_penEntity->CheckEventPrediction(ulCRC, ulEventID)) {
  162. //CPrintF(" predicted\n");
  163. // return nothing
  164. return NULL;
  165. }
  166. CEntity *pen = so_penEntity;
  167. // find eventual prediction tail sound object
  168. if (pen->IsPredictor()) {
  169. pen = pen->GetPredictionTail();
  170. if (pen!=so_penEntity) {
  171. //CPrintF(" ROUTED\n");
  172. return (CSoundObject *)( ((UBYTE*)pen) + slOffset );
  173. }
  174. }
  175. }
  176. // if no specific prediction states - use this object
  177. //CPrintF(" ORIGINAL\n");
  178. return this;
  179. }
  180. /*
  181. * Play
  182. */
  183. void CSoundObject::Play(CSoundData *pCsdLink, SLONG slFlags)
  184. {
  185. // synchronize access to sounds
  186. CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
  187. //CPrintF("PLAY: '%s'", (const char*)pCsdLink->GetName().FileName());
  188. // get prediction tail
  189. CSoundObject *psoTail = GetPredictionTail(EVENT_SOUNDPLAY, (ULONG)pCsdLink);
  190. // if the event is predicted
  191. if (psoTail==NULL) {
  192. // do nothing;
  193. return;
  194. }
  195. // play the sound in the given object
  196. psoTail->Play_internal(pCsdLink, slFlags);
  197. }
  198. // play sound - internal function - doesn't account for prediction
  199. void CSoundObject::Play_internal( CSoundData *pCsdLink, SLONG slFlags)
  200. {
  201. ASSERT(so_penEntity==NULL || !so_penEntity->IsPredictor());
  202. // check if should continue with new sound
  203. BOOL bContinue =
  204. ((slFlags&SOF_SMOOTHCHANGE) &&
  205. (so_slFlags&SOF_PREPARE) &&
  206. (so_slFlags&SOF_PLAY));
  207. Stop_internal();
  208. // mark new data as referenced once more
  209. pCsdLink->AddReference();
  210. // mark old data as referenced once less
  211. so_pCsdLink->RemReference();
  212. // store init SoundData
  213. so_pCsdLink = pCsdLink;
  214. // add to link list
  215. so_pCsdLink->AddObjectLink(*this);
  216. // store flags
  217. so_slFlags = slFlags;
  218. // if should continue with new sound
  219. if (bContinue) {
  220. // play buffer immediately
  221. so_slFlags = so_slFlags | SOF_PREPARE | SOF_PLAY;
  222. } else {
  223. // play buffer
  224. so_slFlags = (so_slFlags & ~(SOF_PREPARE|SOF_PAUSED)) | SOF_PLAY;
  225. }
  226. // if the sound data is encoded
  227. if (so_pCsdLink->sd_ulFlags&SDF_ENCODED) {
  228. // create decoder
  229. if (so_pCsdLink->sd_ulFlags&SDF_STREAMING) {
  230. so_psdcDecoder = new CSoundDecoder(so_pCsdLink->GetName());
  231. } else {
  232. ASSERT(FALSE); // nonstreaming not supported anymore
  233. }
  234. }
  235. // remember starting parameters
  236. so_sp = so_spNew;
  237. // initialize mixer temporary variables
  238. if (!(slFlags&SOF_LOADED)) {
  239. so_fLastLeftVolume = so_sp.sp_fLeftVolume;
  240. so_fLastRightVolume = so_sp.sp_fRightVolume;
  241. so_fLeftOffset = 0.0f;
  242. so_fRightOffset = 0.0f;
  243. so_fOffsetDelta = 0.0f;
  244. so_fDelayed = 0.0f;
  245. if (!bContinue) {
  246. so_swLastLeftSample = 0;
  247. so_swLastRightSample = 0;
  248. } else {
  249. // adjust for master volume
  250. if(so_slFlags&SOF_MUSIC) {
  251. so_fLastLeftVolume *= snd_fMusicVolume;
  252. so_fLastRightVolume *= snd_fMusicVolume;
  253. } else {
  254. so_fLastLeftVolume *= snd_fSoundVolume;
  255. so_fLastRightVolume *= snd_fSoundVolume;
  256. }
  257. }
  258. }
  259. }
  260. // hard set sound offset in seconds
  261. void CSoundObject::SetOffset( FLOAT fOffset)
  262. {
  263. // synchronize access to sounds
  264. CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
  265. // get prediction tail
  266. //CPrintF("SETOFF: ");
  267. CSoundObject *psoTail = GetPredictionTail(EVENT_SOUNDSETOFFSET, 0);
  268. // if the event is predicted
  269. if (psoTail==NULL) {
  270. // do nothing;
  271. return;
  272. }
  273. // if sound not playing
  274. if (psoTail->so_pCsdLink==NULL) {
  275. // do nothing
  276. return;
  277. }
  278. // safety check
  279. ASSERT( fOffset>=0);
  280. if( fOffset<0) {
  281. CPrintF( "BUG: Trying to set negative offset (%.2g) in sound '%s' !\n", fOffset, (CTString&)psoTail->so_pCsdLink->GetName());
  282. fOffset = 0.0f;
  283. }
  284. // on the other hand, don't set offset for real - might be source for some bugs!
  285. return;
  286. // update sound offsets
  287. CPrintF("Setting offset: %g\n", fOffset);
  288. psoTail->so_fLeftOffset = psoTail->so_fRightOffset = psoTail->so_pCsdLink->sd_wfeFormat.nSamplesPerSec*fOffset;
  289. }
  290. /*
  291. * Stop
  292. */
  293. void CSoundObject::Stop(void)
  294. {
  295. // synchronize access to sounds
  296. CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
  297. //CPrintF("STOP");
  298. if (so_pCsdLink!=NULL) {
  299. //CPrintF(" '%s'", (const char*)so_pCsdLink->GetName().FileName());
  300. }
  301. CSoundObject *psoTail = this;
  302. // get prediction tail
  303. psoTail = GetPredictionTail(EVENT_SOUNDSTOP, (ULONG)so_pCsdLink);
  304. // if the event is predicted
  305. if (psoTail==NULL) {
  306. // do nothing;
  307. return;
  308. }
  309. psoTail->Stop_internal();
  310. }
  311. void CSoundObject::Stop_internal(void)
  312. {
  313. // sound is stoped
  314. so_slFlags &= ~(SOF_PLAY|SOF_PREPARE|SOF_PAUSED);
  315. // destroy decoder if exists
  316. if( so_psdcDecoder!=NULL) {
  317. delete so_psdcDecoder;
  318. so_psdcDecoder = NULL;
  319. }
  320. // if added in link list, remove it from list
  321. if( IsHooked()) {
  322. ASSERT(so_pCsdLink != NULL);
  323. so_pCsdLink->RemoveObjectLink(*this);
  324. // remove reference from SoundData
  325. so_pCsdLink->RemReference();
  326. // clear SoundData link
  327. so_pCsdLink = NULL;
  328. }
  329. };
  330. // Update all 3d effects
  331. void CSoundObject::Update3DEffects(void)
  332. {
  333. // if not 3d sound
  334. if( !(so_slFlags & SOF_3D)) {
  335. // do nothing;
  336. return;
  337. }
  338. // if (!(so_slFlags&SOF_PREPARE)) {
  339. // if the sound's entity is a predictor
  340. /* if (so_penEntity!=NULL && so_penEntity->IsPredictor()) {
  341. // kill the sound
  342. so_slFlags&=~SOF_PLAY;
  343. //CPrintF("Update canceled %s (%s)\n", (const char*)so_pCsdLink->GetName(), GetPred(so_penEntity));
  344. // do nothing;
  345. return;
  346. }
  347. */
  348. //CPrintF("Update PASSED %s (%s)\n", (const char*)so_pCsdLink->GetName(), GetPred(so_penEntity));
  349. // }
  350. // total parameters (accounting for all listeners)
  351. FLOAT fTLVolume = 0, fTRVolume = 0;
  352. FLOAT fTLFilter = UpperLimit(0.0f), fTRFilter = UpperLimit(0.0f);
  353. FLOAT fTLDelay = UpperLimit(0.0f), fTRDelay = UpperLimit(0.0f);
  354. FLOAT fTPitchShift = 0;
  355. // get your position parameters
  356. FLOAT3D vPosition(0,0,0);
  357. FLOAT3D vSpeed(0,0,0);
  358. if (so_penEntity!=NULL) {
  359. vPosition = so_penEntity->en_plPlacement.pl_PositionVector;
  360. if (so_penEntity->en_ulPhysicsFlags&EPF_MOVABLE) {
  361. CMovableEntity *penMovable = (CMovableEntity *)so_penEntity;
  362. vSpeed = penMovable->en_vCurrentTranslationAbsolute;
  363. }
  364. }
  365. // for each listener
  366. INDEX ctEffectiveListeners = 0;
  367. {FOREACHINLIST( CSoundListener, sli_lnInActiveListeners, _pSound->sl_lhActiveListeners, itsli)
  368. {
  369. CSoundListener &sli = *itsli;
  370. // if local, but not of this listener
  371. if ((so_slFlags&SOF_LOCAL) && so_penEntity!=sli.sli_penEntity) {
  372. // don't add this listener
  373. continue;
  374. }
  375. // calculated parameters for this listener
  376. FLOAT fLVolume, fRVolume;
  377. FLOAT fLFilter, fRFilter;
  378. FLOAT fLDelay , fRDelay ;
  379. FLOAT fPitchShift;
  380. // calculate distance from listener
  381. FLOAT3D vAbsDelta = vPosition - sli.sli_vPosition;
  382. FLOAT fAbsDelta = vAbsDelta.Length();
  383. // if too far away
  384. if (fAbsDelta>so_sp3.sp3_fFalloff) {
  385. // don't add this listener
  386. continue;
  387. }
  388. // calculate distance falloff factor
  389. FLOAT fDistanceFactor;
  390. if( fAbsDelta <= so_sp3.sp3_fHotSpot) {
  391. fDistanceFactor = 1;
  392. } else {
  393. fDistanceFactor = (so_sp3.sp3_fFalloff - fAbsDelta) /
  394. (so_sp3.sp3_fFalloff - so_sp3.sp3_fHotSpot);
  395. }
  396. ASSERT(fDistanceFactor>=0 && fDistanceFactor<=+1);
  397. // calculate volumetric influence
  398. // NOTE: decoded sounds must be threated as volumetric
  399. FLOAT fNonVolumetric = 1.0f;
  400. FLOAT fNonVolumetricAdvanced = 1.0f;
  401. if( (so_slFlags & SOF_VOLUMETRIC) || so_psdcDecoder!=NULL) {
  402. fNonVolumetric = 1.0f-fDistanceFactor;
  403. fNonVolumetricAdvanced = 0.0f;
  404. }
  405. ASSERT(fNonVolumetric>=0 && fNonVolumetric<=+1);
  406. // find doppler effect pitch shift
  407. fPitchShift = 1.0f;
  408. if (fAbsDelta>0.001f) {
  409. FLOAT3D vObjectDirection = vAbsDelta/fAbsDelta;
  410. FLOAT fObjectSpeed = vSpeed%vObjectDirection; // negative towards listener
  411. FLOAT fListenerSpeed = sli.sli_vSpeed%vObjectDirection; // positive towards object
  412. fPitchShift =
  413. (snd_fDopplerSoundSpeed+fListenerSpeed*fNonVolumetricAdvanced)/
  414. (snd_fDopplerSoundSpeed+fObjectSpeed*fNonVolumetricAdvanced);
  415. }
  416. // find position of sound relative to viewer orientation
  417. FLOAT3D vRelative = vAbsDelta*!sli.sli_mRotation;
  418. // find distances from left and right ear
  419. FLOAT fLDistance = (FLOAT3D(-snd_fEarsDistance*fNonVolumetricAdvanced/2,0,0)-vRelative).Length();
  420. FLOAT fRDistance = (FLOAT3D(+snd_fEarsDistance*fNonVolumetricAdvanced/2,0,0)-vRelative).Length();
  421. // calculate sound delay to each ear
  422. fLDelay = fLDistance/snd_fDelaySoundSpeed;
  423. fRDelay = fRDistance/snd_fDelaySoundSpeed;
  424. // calculate relative sound directions
  425. FLOAT fLRFactor=0; // positive right
  426. FLOAT fFBFactor=0; // positive front
  427. FLOAT fUDFactor=0; // positive up
  428. if (fAbsDelta>0.001f) {
  429. FLOAT3D vDir = vRelative/fAbsDelta;
  430. fLRFactor = +vDir(1);
  431. fFBFactor = -vDir(3);
  432. fUDFactor = +vDir(2);
  433. }
  434. ASSERT(fLRFactor>=-1.1 && fLRFactor<=+1.1);
  435. ASSERT(fFBFactor>=-1.1 && fFBFactor<=+1.1);
  436. ASSERT(fUDFactor>=-1.1 && fUDFactor<=+1.1);
  437. // calculate panning influence factor
  438. FLOAT fPanningFactor= fNonVolumetric*snd_fPanStrength;
  439. ASSERT(fPanningFactor>=0 && fPanningFactor<=+1);
  440. // calc volume for left and right channel
  441. FLOAT fVolume = so_sp3.sp3_fMaxVolume * fDistanceFactor;
  442. if( fLRFactor > 0) {
  443. fLVolume = (1-fLRFactor*fPanningFactor) * fVolume;
  444. fRVolume = fVolume;
  445. } else {
  446. fLVolume = fVolume;
  447. fRVolume = (1+fLRFactor*fPanningFactor) * fVolume;
  448. }
  449. // calculate filters
  450. FLOAT fListenerFilter = sli.sli_fFilter;
  451. if (so_slFlags&SOF_NOFILTER) {
  452. fListenerFilter = 0.0f;
  453. }
  454. fLFilter = fRFilter = 1+fListenerFilter;
  455. if( fLRFactor > 0) {
  456. fLFilter += fLRFactor*snd_fLRFilter*fNonVolumetricAdvanced;
  457. } else {
  458. fRFilter -= fLRFactor*snd_fLRFilter*fNonVolumetricAdvanced;
  459. }
  460. if( fFBFactor<0) {
  461. fLFilter -= snd_fBFilter*fFBFactor*fNonVolumetricAdvanced;
  462. fRFilter -= snd_fBFilter*fFBFactor*fNonVolumetricAdvanced;
  463. }
  464. if( fUDFactor>0) {
  465. fLFilter += snd_fUFilter*fUDFactor*fNonVolumetricAdvanced;
  466. fRFilter += snd_fUFilter*fUDFactor*fNonVolumetricAdvanced;
  467. } else {
  468. fLFilter -= snd_fDFilter*fUDFactor*fNonVolumetricAdvanced;
  469. fRFilter -= snd_fDFilter*fUDFactor*fNonVolumetricAdvanced;
  470. }
  471. // adjust calculated volume to the one of listener
  472. fLVolume *= sli.sli_fVolume;
  473. fRVolume *= sli.sli_fVolume;
  474. // update parameters for all listener
  475. fTLVolume = Max( fTLVolume, fLVolume);
  476. fTRVolume = Max( fTRVolume, fRVolume);
  477. fTLDelay = Min( fTLDelay , fLDelay );
  478. fTRDelay = Min( fTRDelay , fRDelay );
  479. fTLFilter = Min( fTLFilter, fLFilter);
  480. fTRFilter = Min( fTRFilter, fRFilter);
  481. fTPitchShift += fPitchShift;
  482. ctEffectiveListeners++;
  483. }}
  484. fTPitchShift /= ctEffectiveListeners;
  485. // calculate 2d parameters
  486. FLOAT fPitchShift = fTPitchShift * so_sp3.sp3_fPitch;
  487. FLOAT fPhaseShift = fTLDelay-fTRDelay;
  488. FLOAT fDelay = Min( fTRDelay,fTLDelay);
  489. // CPrintF("V:%f %f F:%f %f P:%f S:%f\n",
  490. // fTLVolume, fTRVolume,
  491. // fTLFilter, fTRFilter,
  492. // fPhaseShift,
  493. // fPitchShift);
  494. // set sound parameters
  495. fTLVolume = Clamp( fTLVolume, SL_VOLUME_MIN, SL_VOLUME_MAX);
  496. fTRVolume = Clamp( fTRVolume, SL_VOLUME_MIN, SL_VOLUME_MAX);
  497. SetVolume( fTLVolume, fTRVolume);
  498. if( fTLVolume>0 || fTRVolume>0) {
  499. // do safety clamping
  500. fTLFilter = ClampDn( fTLFilter, 1.0f);
  501. fTRFilter = ClampDn( fTRFilter, 1.0f);
  502. fDelay = ClampDn( fDelay, 0.0f);
  503. fPitchShift = ClampDn( fPitchShift, 0.001f);
  504. fPhaseShift = Clamp( fPhaseShift, -1.0f, +1.0f);
  505. // set sound params
  506. SetFilter( fTLFilter, fTRFilter);
  507. SetDelay( fDelay);
  508. SetPitch( fPitchShift);
  509. SetPhase( fPhaseShift);
  510. }
  511. }
  512. // Prepare sound
  513. void CSoundObject::PrepareSound(void)
  514. {
  515. ASSERT(so_penEntity==NULL || !so_penEntity->IsPredictor());
  516. so_fLastLeftVolume = so_spNew.sp_fLeftVolume;
  517. so_fLastRightVolume = so_spNew.sp_fRightVolume;
  518. // adjust for master volume
  519. if(so_slFlags&SOF_MUSIC) {
  520. so_fLastLeftVolume *= snd_fMusicVolume;
  521. so_fLastRightVolume *= snd_fMusicVolume;
  522. } else {
  523. so_fLastLeftVolume *= snd_fSoundVolume;
  524. so_fLastRightVolume *= snd_fSoundVolume;
  525. }
  526. };
  527. // Obtain sound and play it for this object
  528. void CSoundObject::Play_t(const CTFileName &fnmSound, SLONG slFlags) // throw char *
  529. {
  530. // obtain it (adds one reference)
  531. CSoundData *ptd = _pSoundStock->Obtain_t(fnmSound);
  532. // set it as data (adds one more reference, and remove old reference)
  533. Play(ptd, slFlags);
  534. // release it (removes one reference)
  535. _pSoundStock->Release(ptd);
  536. // total reference count +1+1-1 = +1 for new data -1 for old data
  537. };
  538. // read/write functions
  539. void CSoundObject::Read_t(CTStream *pistr) // throw char *
  540. {
  541. int iDroppedOut;
  542. // load file name
  543. CTFileName fnmSound;
  544. *pistr >> fnmSound;
  545. // load object preferences
  546. *pistr >> iDroppedOut;
  547. *pistr >> so_slFlags;
  548. *pistr >> so_spNew.sp_fLeftVolume;
  549. *pistr >> so_spNew.sp_fRightVolume;
  550. *pistr >> so_spNew.sp_slLeftFilter;
  551. *pistr >> so_spNew.sp_slRightFilter;
  552. *pistr >> so_spNew.sp_fPitchShift;
  553. *pistr >> so_spNew.sp_fPhaseShift;
  554. *pistr >> so_spNew.sp_fDelay;
  555. *pistr >> so_fDelayed;
  556. *pistr >> so_fLastLeftVolume;
  557. *pistr >> so_fLastRightVolume;
  558. *pistr >> so_swLastLeftSample;
  559. *pistr >> so_swLastRightSample;
  560. *pistr >> so_fLeftOffset;
  561. *pistr >> so_fRightOffset;
  562. *pistr >> so_fOffsetDelta;
  563. // load 3D parameters
  564. so_penEntity = NULL;
  565. *pistr >> so_sp3.sp3_fFalloff;
  566. *pistr >> so_sp3.sp3_fHotSpot;
  567. *pistr >> so_sp3.sp3_fMaxVolume;
  568. *pistr >> so_sp3.sp3_fPitch;
  569. // update current state
  570. so_sp = so_spNew;
  571. // Obtain and play object (sound)
  572. if ( fnmSound != "" && (so_slFlags&SOF_PLAY)) {
  573. Play_t( fnmSound, so_slFlags|SOF_LOADED);
  574. }
  575. };
  576. void CSoundObject::Write_t(CTStream *pistr) // throw char *
  577. {
  578. int iDroppedOut=0;
  579. // save file name
  580. if (so_pCsdLink!=NULL) {
  581. *pistr << (so_pCsdLink->GetName());
  582. } else {
  583. *pistr << CTFILENAME("");
  584. }
  585. // save object preferences
  586. *pistr << iDroppedOut;
  587. *pistr << so_slFlags;
  588. *pistr << so_spNew.sp_fLeftVolume;
  589. *pistr << so_spNew.sp_fRightVolume;
  590. *pistr << so_spNew.sp_slLeftFilter;
  591. *pistr << so_spNew.sp_slRightFilter;
  592. *pistr << so_spNew.sp_fPitchShift;
  593. *pistr << so_spNew.sp_fPhaseShift;
  594. *pistr << so_spNew.sp_fDelay;
  595. *pistr << so_fDelayed;
  596. *pistr << so_fLastLeftVolume;
  597. *pistr << so_fLastRightVolume;
  598. *pistr << so_swLastLeftSample;
  599. *pistr << so_swLastRightSample;
  600. *pistr << so_fLeftOffset;
  601. *pistr << so_fRightOffset;
  602. *pistr << so_fOffsetDelta;
  603. // save 3D parameters
  604. *pistr << so_sp3.sp3_fFalloff;
  605. *pistr << so_sp3.sp3_fHotSpot;
  606. *pistr << so_sp3.sp3_fMaxVolume;
  607. *pistr << so_sp3.sp3_fPitch;
  608. };