snd_emitter.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "snd_local.h"
  23. idCVar s_singleEmitter( "s_singleEmitter", "0", CVAR_INTEGER, "mute all sounds but this emitter" );
  24. idCVar s_showStartSound( "s_showStartSound", "0", CVAR_BOOL, "print a message every time a sound starts/stops" );
  25. idCVar s_useOcclusion( "s_useOcclusion", "1", CVAR_BOOL, "Attenuate sounds based on walls" );
  26. idCVar s_centerFractionVO( "s_centerFractionVO", "0.75", CVAR_FLOAT, "Portion of VO sounds routed to the center channel" );
  27. extern idCVar s_playDefaultSound;
  28. extern idCVar s_noSound;
  29. /*
  30. ================================================================================================
  31. idSoundFade
  32. ================================================================================================
  33. */
  34. /*
  35. ========================
  36. idSoundFade::Clear
  37. ========================
  38. */
  39. void idSoundFade::Clear() {
  40. fadeStartTime = 0;
  41. fadeEndTime = 0;
  42. fadeStartVolume = 0.0f;
  43. fadeEndVolume = 0.0f;
  44. }
  45. /*
  46. ========================
  47. idSoundFade::SetVolume
  48. ========================
  49. */
  50. void idSoundFade::SetVolume( float to ) {
  51. fadeStartVolume = to;
  52. fadeEndVolume = to;
  53. fadeStartTime = 0;
  54. fadeEndTime = 0;
  55. }
  56. /*
  57. ========================
  58. idSoundFade::Fade
  59. ========================
  60. */
  61. void idSoundFade::Fade( float to, int length, int soundTime ) {
  62. int startTime = soundTime;
  63. // if it is already fading to this volume at this rate, don't change it
  64. if ( fadeEndTime == startTime + length && fadeEndVolume == to ) {
  65. return;
  66. }
  67. fadeStartVolume = GetVolume( soundTime );
  68. fadeEndVolume = to;
  69. fadeStartTime = startTime;
  70. fadeEndTime = startTime + length;
  71. }
  72. /*
  73. ========================
  74. idSoundFade::GetVolume
  75. ========================
  76. */
  77. float idSoundFade::GetVolume( const int soundTime ) const {
  78. const float fadeDuration = ( fadeEndTime - fadeStartTime );
  79. const int currentTime = soundTime;
  80. const float playTime = ( currentTime - fadeStartTime );
  81. if ( fadeDuration <= 0.0f ) {
  82. return fadeEndVolume;
  83. } else if ( currentTime >= fadeEndTime ) {
  84. return fadeEndVolume;
  85. } else if ( currentTime > fadeStartTime ) {
  86. return fadeStartVolume + ( fadeEndVolume - fadeStartVolume ) * playTime / fadeDuration;
  87. } else {
  88. return fadeStartVolume;
  89. }
  90. }
  91. /*
  92. ========================
  93. idSoundChannel::idSoundChannel
  94. ========================
  95. */
  96. idSoundChannel::idSoundChannel() {
  97. emitter = NULL;
  98. hardwareVoice = NULL;
  99. startTime = 0;
  100. endTime = 0;
  101. leadinSample = NULL;
  102. loopingSample = NULL;
  103. logicalChannel = SCHANNEL_ANY;
  104. allowSlow = false;
  105. soundShader = NULL;
  106. volumeFade.Clear();
  107. volumeDB = DB_SILENCE;
  108. currentAmplitude = 0.0f;
  109. }
  110. /*
  111. ========================
  112. idSoundChannel::~idSoundChannel
  113. ========================
  114. */
  115. idSoundChannel::~idSoundChannel() {
  116. }
  117. /*
  118. ========================
  119. idSoundChannel::CanMute
  120. Never actually mute VO because we can't restart them precisely enough for lip syncing to not fuck up
  121. ========================
  122. */
  123. bool idSoundChannel::CanMute() const {
  124. return true;
  125. }
  126. /*
  127. ========================
  128. idSoundChannel::Mute
  129. A muted sound is considered still running, and can restart when a listener
  130. gets close enough.
  131. ========================
  132. */
  133. void idSoundChannel::Mute() {
  134. if ( hardwareVoice != NULL ) {
  135. soundSystemLocal.FreeVoice( hardwareVoice );
  136. hardwareVoice = NULL;
  137. }
  138. }
  139. /*
  140. ========================
  141. idSoundChannel::IsLooping
  142. ========================
  143. */
  144. bool idSoundChannel::IsLooping() const {
  145. return ( parms.soundShaderFlags & SSF_LOOPING ) != 0;
  146. }
  147. /*
  148. ========================
  149. idSoundChannel::CheckForCompletion
  150. ========================
  151. */
  152. bool idSoundChannel::CheckForCompletion( int currentTime ) {
  153. if ( leadinSample == NULL ) {
  154. return true;
  155. }
  156. // endTime of 0 indicates a sound should loop forever
  157. if ( endTime > 0 && endTime < currentTime ) {
  158. return true;
  159. }
  160. return false;
  161. }
  162. /*
  163. ========================
  164. idSoundChannel::UpdateVolume
  165. ========================
  166. */
  167. void idSoundChannel::UpdateVolume( int currentTime ) {
  168. idSoundWorldLocal * soundWorld = emitter->soundWorld;
  169. volumeDB = DB_SILENCE;
  170. currentAmplitude = 0.0f;
  171. if ( leadinSample == NULL ) {
  172. return;
  173. }
  174. if ( startTime > currentTime ) {
  175. return;
  176. }
  177. if ( endTime > 0 && endTime < currentTime ) {
  178. return;
  179. }
  180. // if you don't want to hear all the beeps from missing sounds
  181. if ( leadinSample->IsDefault() && !s_playDefaultSound.GetBool() ) {
  182. return;
  183. }
  184. bool emitterIsListener = ( emitter->emitterId == soundWorld->listener.id );
  185. // if it is a private sound, set the volume to zero unless we match the listener.id
  186. if ( parms.soundShaderFlags & SSF_PRIVATE_SOUND ) {
  187. if ( !emitterIsListener ) {
  188. return;
  189. }
  190. }
  191. if ( parms.soundShaderFlags & SSF_ANTI_PRIVATE_SOUND ) {
  192. if ( emitterIsListener ) {
  193. return;
  194. }
  195. }
  196. // volume fading
  197. float newVolumeDB = parms.volume;
  198. newVolumeDB += volumeFade.GetVolume( currentTime );
  199. newVolumeDB += soundWorld->volumeFade.GetVolume( currentTime );
  200. newVolumeDB += soundWorld->pauseFade.GetVolume( currentTime );
  201. if ( parms.soundClass >= 0 && parms.soundClass < SOUND_MAX_CLASSES ) {
  202. newVolumeDB += soundWorld->soundClassFade[parms.soundClass].GetVolume( currentTime );
  203. }
  204. bool global = ( parms.soundShaderFlags & SSF_GLOBAL ) != 0;
  205. // attenuation
  206. if ( !global && !emitterIsListener ) {
  207. float distance = ( parms.soundShaderFlags & SSF_NO_OCCLUSION ) == 0 ? emitter->spatializedDistance : emitter->directDistance;
  208. float mindist = parms.minDistance;
  209. float maxdist = parms.maxDistance;
  210. if ( distance >= maxdist ) {
  211. newVolumeDB = DB_SILENCE;
  212. } else if ( ( distance > mindist ) && ( maxdist > mindist ) ) {
  213. float f = ( distance - mindist ) / ( maxdist - mindist );
  214. newVolumeDB += LinearToDB( Square( 1.0f - f ) );
  215. }
  216. }
  217. if ( soundSystemLocal.musicMuted && ( parms.soundShaderFlags & SSF_MUSIC ) != 0 ) {
  218. newVolumeDB = DB_SILENCE;
  219. }
  220. // store the new volume on the channel
  221. volumeDB = newVolumeDB;
  222. // keep track of the maximum volume
  223. float currentVolumeDB = newVolumeDB;
  224. if ( hardwareVoice != NULL ) {
  225. float amplitude = hardwareVoice->GetAmplitude();
  226. if ( amplitude <= 0.0f ) {
  227. currentVolumeDB = DB_SILENCE;
  228. } else {
  229. currentVolumeDB += LinearToDB( amplitude );
  230. }
  231. currentAmplitude = amplitude;
  232. }
  233. }
  234. /*
  235. ========================
  236. idSoundChannel::UpdateHardware
  237. ========================
  238. */
  239. void idSoundChannel::UpdateHardware( float volumeAdd, int currentTime ) {
  240. idSoundWorldLocal * soundWorld = emitter->soundWorld;
  241. if ( soundWorld == NULL ) {
  242. return;
  243. }
  244. if ( leadinSample == NULL ) {
  245. return;
  246. }
  247. if ( startTime > currentTime ) {
  248. return;
  249. }
  250. if ( endTime > 0 && endTime < currentTime ) {
  251. return;
  252. }
  253. // convert volumes from decibels to linear
  254. float volume = Max( 0.0f, DBtoLinear( volumeDB + volumeAdd ) );
  255. if ( ( parms.soundShaderFlags & SSF_UNCLAMPED ) == 0 ) {
  256. volume = Min( 1.0f, volume );
  257. }
  258. bool global = ( parms.soundShaderFlags & SSF_GLOBAL ) != 0;
  259. bool omni = ( parms.soundShaderFlags & SSF_OMNIDIRECTIONAL ) != 0;
  260. bool emitterIsListener = ( emitter->emitterId == soundWorld->listener.id );
  261. int startOffset = 0;
  262. bool issueStart = false;
  263. if ( hardwareVoice == NULL ) {
  264. if ( volume <= 0.00001f ) {
  265. return;
  266. }
  267. hardwareVoice = soundSystemLocal.AllocateVoice( leadinSample, loopingSample );
  268. if ( hardwareVoice == NULL ) {
  269. return;
  270. }
  271. issueStart = true;
  272. startOffset = currentTime - startTime;
  273. }
  274. if ( omni || global || emitterIsListener ) {
  275. hardwareVoice->SetPosition( vec3_zero );
  276. } else {
  277. hardwareVoice->SetPosition( ( emitter->spatializedOrigin - soundWorld->listener.pos ) * soundWorld->listener.axis.Transpose() );
  278. }
  279. if ( parms.soundShaderFlags & SSF_VO ) {
  280. hardwareVoice->SetCenterChannel( s_centerFractionVO.GetFloat() );
  281. } else {
  282. hardwareVoice->SetCenterChannel( 0.0f );
  283. }
  284. extern idCVar timescale;
  285. hardwareVoice->SetGain( volume );
  286. hardwareVoice->SetInnerRadius( parms.minDistance * METERS_TO_DOOM );
  287. hardwareVoice->SetPitch( soundWorld->slowmoSpeed * idMath::ClampFloat( 0.2f, 5.0f, timescale.GetFloat() ) );
  288. if ( soundWorld->enviroSuitActive ) {
  289. hardwareVoice->SetOcclusion( 0.5f );
  290. } else {
  291. hardwareVoice->SetOcclusion( 0.0f );
  292. }
  293. if ( issueStart ) {
  294. hardwareVoice->Start( startOffset, parms.soundShaderFlags | ( parms.shakes == 0.0f ? SSF_NO_FLICKER : 0 ) );
  295. } else {
  296. hardwareVoice->Update();
  297. }
  298. }
  299. /*
  300. ================================================================================================
  301. idSoundEmitterLocal
  302. ================================================================================================
  303. */
  304. /*
  305. ========================
  306. idSoundEmitterLocal::idSoundEmitterLocal
  307. ========================
  308. */
  309. idSoundEmitterLocal::idSoundEmitterLocal() {
  310. Init( 0, NULL );
  311. }
  312. /*
  313. ========================
  314. idSoundEmitterLocal::~idSoundEmitterLocal
  315. ========================
  316. */
  317. idSoundEmitterLocal::~idSoundEmitterLocal() {
  318. assert( channels.Num() == 0 );
  319. }
  320. /*
  321. ========================
  322. idSoundEmitterLocal::Clear
  323. ========================
  324. */
  325. void idSoundEmitterLocal::Init( int i, idSoundWorldLocal * sw ) {
  326. index = i;
  327. soundWorld = sw;
  328. // Init should only be called on a freshly constructed sound emitter or in a Reset()
  329. assert( channels.Num() == 0 );
  330. canFree = false;
  331. origin.Zero();
  332. emitterId = 0;
  333. directDistance = 0.0f;
  334. lastValidPortalArea = -1;
  335. spatializedDistance = 0.0f;
  336. spatializedOrigin.Zero();
  337. memset( &parms, 0, sizeof( parms ) );
  338. }
  339. /*
  340. ========================
  341. idSoundEmitterLocal::Reset
  342. ========================
  343. */
  344. void idSoundEmitterLocal::Reset() {
  345. for ( int i = 0; i < channels.Num(); i++ ) {
  346. soundWorld->FreeSoundChannel( channels[i] );
  347. }
  348. channels.Clear();
  349. Init( index, soundWorld );
  350. }
  351. /*
  352. ==================
  353. idSoundEmitterLocal::OverrideParms
  354. ==================
  355. */
  356. void idSoundEmitterLocal::OverrideParms( const soundShaderParms_t * base, const soundShaderParms_t * over, soundShaderParms_t * out ) {
  357. if ( !over ) {
  358. *out = *base;
  359. return;
  360. }
  361. if ( over->minDistance ) {
  362. out->minDistance = over->minDistance;
  363. } else {
  364. out->minDistance = base->minDistance;
  365. }
  366. if ( over->maxDistance ) {
  367. out->maxDistance = over->maxDistance;
  368. } else {
  369. out->maxDistance = base->maxDistance;
  370. }
  371. if ( over->shakes ) {
  372. out->shakes = over->shakes;
  373. } else {
  374. out->shakes = base->shakes;
  375. }
  376. if ( over->volume ) {
  377. out->volume = over->volume;
  378. } else {
  379. out->volume = base->volume;
  380. }
  381. if ( over->soundClass ) {
  382. out->soundClass = over->soundClass;
  383. } else {
  384. out->soundClass = base->soundClass;
  385. }
  386. out->soundShaderFlags = base->soundShaderFlags | over->soundShaderFlags;
  387. }
  388. /*
  389. ========================
  390. idSoundEmitterLocal::CheckForCompletion
  391. Checks to see if any of the channels have completed, removing them as they do
  392. This will also play any postSounds on the same channel as their owner.
  393. Returns true if the emitter should be freed.
  394. ========================
  395. */
  396. bool idSoundEmitterLocal::CheckForCompletion( int currentTime ) {
  397. for ( int i = channels.Num() - 1; i >= 0 ; i-- ) {
  398. idSoundChannel * chan = channels[i];
  399. if ( chan->CheckForCompletion( currentTime ) ) {
  400. channels.RemoveIndex( i );
  401. soundWorld->FreeSoundChannel( chan );
  402. }
  403. }
  404. return ( canFree && channels.Num() == 0 );
  405. }
  406. /*
  407. ========================
  408. idSoundEmitterLocal::Update
  409. ========================
  410. */
  411. void idSoundEmitterLocal::Update( int currentTime ) {
  412. if ( channels.Num() == 0 ) {
  413. return;
  414. }
  415. directDistance = ( soundWorld->listener.pos - origin ).LengthFast() * DOOM_TO_METERS;
  416. spatializedDistance = directDistance;
  417. spatializedOrigin = origin;
  418. // Initialize all channels to silence
  419. for ( int i = 0; i < channels.Num(); i++ ) {
  420. channels[i]->volumeDB = DB_SILENCE;
  421. }
  422. if ( s_singleEmitter.GetInteger() > 0 && s_singleEmitter.GetInteger() != index ) {
  423. return;
  424. }
  425. if ( soundWorld->listener.area == -1 ) {
  426. // listener is outside the world
  427. return;
  428. }
  429. if ( soundSystemLocal.muted || soundWorld != soundSystemLocal.currentSoundWorld ) {
  430. return;
  431. }
  432. float maxDistance = 0.0f;
  433. bool maxDistanceValid = false;
  434. bool useOcclusion = false;
  435. if ( emitterId != soundWorld->listener.id ) {
  436. for ( int i = 0; i < channels.Num(); i++ ) {
  437. idSoundChannel * chan = channels[i];
  438. if ( ( chan->parms.soundShaderFlags & SSF_GLOBAL ) != 0 ) {
  439. continue;
  440. }
  441. useOcclusion = useOcclusion || ( ( chan->parms.soundShaderFlags & SSF_NO_OCCLUSION ) == 0 );
  442. maxDistanceValid = true;
  443. if ( maxDistance < channels[i]->parms.maxDistance ) {
  444. maxDistance = channels[i]->parms.maxDistance;
  445. }
  446. }
  447. }
  448. if ( maxDistanceValid && directDistance >= maxDistance ) {
  449. // too far away to possibly hear it
  450. return;
  451. }
  452. if ( useOcclusion && s_useOcclusion.GetBool() ) {
  453. // work out virtual origin and distance, which may be from a portal instead of the actual origin
  454. if ( soundWorld->renderWorld != NULL ) {
  455. // we have a valid renderWorld
  456. int soundInArea = soundWorld->renderWorld->PointInArea( origin );
  457. if ( soundInArea == -1 ) {
  458. soundInArea = lastValidPortalArea;
  459. } else {
  460. lastValidPortalArea = soundInArea;
  461. }
  462. if ( soundInArea != -1 && soundInArea != soundWorld->listener.area ) {
  463. spatializedDistance = maxDistance * METERS_TO_DOOM;
  464. soundWorld->ResolveOrigin( 0, NULL, soundInArea, 0.0f, origin, this );
  465. spatializedDistance *= DOOM_TO_METERS;
  466. }
  467. }
  468. }
  469. for ( int j = 0; j < channels.Num(); j++ ) {
  470. channels[j]->UpdateVolume( currentTime );
  471. }
  472. return;
  473. }
  474. /*
  475. ========================
  476. idSoundEmitterLocal::Index
  477. ========================
  478. */
  479. int idSoundEmitterLocal::Index() const {
  480. assert( soundWorld );
  481. assert( soundWorld->emitters[this->index] == this );
  482. return index;
  483. }
  484. /*
  485. ========================
  486. idSoundEmitterLocal::Free
  487. Doesn't free it until the next update.
  488. ========================
  489. */
  490. void idSoundEmitterLocal::Free( bool immediate ) {
  491. assert( soundWorld );
  492. assert( soundWorld->emitters[this->index] == this );
  493. if ( canFree ) {
  494. // Double free
  495. return;
  496. }
  497. if ( soundWorld && soundWorld->writeDemo ) {
  498. soundWorld->writeDemo->WriteInt( DS_SOUND );
  499. soundWorld->writeDemo->WriteInt( SCMD_FREE );
  500. soundWorld->writeDemo->WriteInt( index );
  501. soundWorld->writeDemo->WriteInt( immediate );
  502. }
  503. if ( immediate ) {
  504. Reset();
  505. }
  506. canFree = true;
  507. }
  508. /*
  509. ========================
  510. idSoundEmitterLocal::UpdateEmitter
  511. ========================
  512. */
  513. void idSoundEmitterLocal::UpdateEmitter( const idVec3 &origin, int listenerId, const soundShaderParms_t *parms ) {
  514. assert( soundWorld != NULL );
  515. assert( soundWorld->emitters[this->index] == this );
  516. if ( soundWorld && soundWorld->writeDemo ) {
  517. soundWorld->writeDemo->WriteInt( DS_SOUND );
  518. soundWorld->writeDemo->WriteInt( SCMD_UPDATE );
  519. soundWorld->writeDemo->WriteInt( index );
  520. soundWorld->writeDemo->WriteVec3( origin );
  521. soundWorld->writeDemo->WriteInt( listenerId );
  522. soundWorld->writeDemo->WriteFloat( parms->minDistance );
  523. soundWorld->writeDemo->WriteFloat( parms->maxDistance );
  524. soundWorld->writeDemo->WriteFloat( parms->volume );
  525. soundWorld->writeDemo->WriteFloat( parms->shakes );
  526. soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
  527. soundWorld->writeDemo->WriteInt( parms->soundClass );
  528. }
  529. this->origin = origin;
  530. this->emitterId = listenerId;
  531. this->parms = *parms;
  532. }
  533. /*
  534. ========================
  535. idSoundEmitterLocal::StartSound
  536. in most cases play sounds immediately, however
  537. intercept sounds using SSF_FINITE_SPEED_OF_SOUND
  538. and schedule them for playback later
  539. return: int - the length of the started sound in msec.
  540. ========================
  541. */
  542. int idSoundEmitterLocal::StartSound( const idSoundShader * shader, const s_channelType channel, float diversity, int shaderFlags, bool allowSlow ) {
  543. assert( soundWorld != NULL );
  544. assert( soundWorld->emitters[this->index] == this );
  545. if ( shader == NULL ) {
  546. return 0;
  547. }
  548. if ( soundWorld && soundWorld->writeDemo ) {
  549. soundWorld->writeDemo->WriteInt( DS_SOUND );
  550. soundWorld->writeDemo->WriteInt( SCMD_START );
  551. soundWorld->writeDemo->WriteInt( index );
  552. soundWorld->writeDemo->WriteHashString( shader->GetName() );
  553. soundWorld->writeDemo->WriteInt( channel );
  554. soundWorld->writeDemo->WriteFloat( diversity );
  555. soundWorld->writeDemo->WriteInt( shaderFlags );
  556. }
  557. if ( s_noSound.GetBool() ) {
  558. return 0;
  559. }
  560. int currentTime = soundWorld->GetSoundTime();
  561. bool showStartSound = s_showStartSound.GetBool();
  562. if ( showStartSound ) {
  563. idLib::Printf( "%dms: StartSound(%d:%d): %s: ", currentTime, index, channel, shader->GetName() );
  564. }
  565. // build the channel parameters by taking the shader parms and optionally overriding
  566. soundShaderParms_t chanParms;
  567. chanParms = shader->parms;
  568. OverrideParms( &chanParms, &parms, &chanParms );
  569. chanParms.soundShaderFlags |= shaderFlags;
  570. if ( shader->entries.Num() == 0 ) {
  571. if ( showStartSound ) {
  572. idLib::Printf( S_COLOR_RED "No Entries\n" );
  573. }
  574. return 0;
  575. }
  576. // PLAY_ONCE sounds will never be restarted while they are running
  577. if ( chanParms.soundShaderFlags & SSF_PLAY_ONCE ) {
  578. for ( int i = 0; i < channels.Num(); i++ ) {
  579. idSoundChannel * chan = channels[i];
  580. if ( chan->soundShader == shader && !chan->CheckForCompletion( currentTime ) ) {
  581. if ( showStartSound ) {
  582. idLib::Printf( S_COLOR_YELLOW "Not started because of playOnce\n" );
  583. }
  584. return 0;
  585. }
  586. }
  587. }
  588. // never play the same sound twice with the same starting time, even
  589. // if they are on different channels
  590. for ( int i = 0; i < channels.Num(); i++ ) {
  591. idSoundChannel * chan = channels[i];
  592. if ( chan->soundShader == shader && chan->startTime == currentTime && chan->endTime != 1 ) {
  593. if ( showStartSound ) {
  594. idLib::Printf( S_COLOR_RED "Already started this frame\n" );
  595. }
  596. return 0;
  597. }
  598. }
  599. // kill any sound that is currently playing on this channel
  600. if ( channel != SCHANNEL_ANY ) {
  601. for ( int i = 0; i < channels.Num(); i++ ) {
  602. idSoundChannel * chan = channels[i];
  603. if ( chan->soundShader && chan->logicalChannel == channel ) {
  604. if ( showStartSound ) {
  605. idLib::Printf( S_COLOR_YELLOW "OVERRIDE %s: ", chan->soundShader->GetName() );
  606. }
  607. channels.RemoveIndex( i );
  608. soundWorld->FreeSoundChannel( chan );
  609. break;
  610. }
  611. }
  612. }
  613. idSoundSample * leadinSample = NULL;
  614. idSoundSample * loopingSample = NULL;
  615. if ( shader->leadin && ( chanParms.soundShaderFlags & SSF_LOOPING ) ) {
  616. leadinSample = shader->entries[0];
  617. loopingSample = shader->entries.Num() > 1 ? shader->entries[1] : NULL;
  618. } else {
  619. if ( shader->entries.Num() == 1 ) {
  620. leadinSample = shader->entries[0];
  621. } else {
  622. int choice;
  623. if ( chanParms.soundShaderFlags & SSF_NO_DUPS ) {
  624. // Don't select the most recently played entry
  625. int mostRecentTime = 0;
  626. int mostRecent = 0;
  627. for ( int i = 0; i < shader->entries.Num(); i++ ) {
  628. int entryTime = shader->entries[i]->GetLastPlayedTime();
  629. if ( entryTime > mostRecentTime ) {
  630. mostRecentTime = entryTime;
  631. mostRecent = i;
  632. }
  633. }
  634. choice = (int)( diversity * ( shader->entries.Num() - 1 ) );
  635. if ( choice >= mostRecent ) {
  636. choice++;
  637. }
  638. } else {
  639. // pick a sound from the list based on the passed diversity
  640. choice = (int)( diversity * shader->entries.Num() );
  641. }
  642. choice = idMath::ClampInt( 0, shader->entries.Num() - 1, choice );
  643. leadinSample = shader->entries[choice];
  644. leadinSample->SetLastPlayedTime( soundWorld->GetSoundTime() );
  645. }
  646. if ( chanParms.soundShaderFlags & SSF_LOOPING ) {
  647. loopingSample = leadinSample;
  648. }
  649. }
  650. // set all the channel parameters here,
  651. // a hardware voice will be allocated next update if the volume is high enough to be audible
  652. if ( channels.Num() == channels.Max() ) {
  653. CheckForCompletion( currentTime ); // as a last chance try to release finished sounds here
  654. if ( channels.Num() == channels.Max() ) {
  655. if ( showStartSound ) {
  656. idLib::Printf( S_COLOR_RED "No free emitter channels!\n" );
  657. }
  658. return 0;
  659. }
  660. }
  661. idSoundChannel * chan = soundWorld->AllocSoundChannel();
  662. if ( chan == NULL ) {
  663. if ( showStartSound ) {
  664. idLib::Printf( S_COLOR_RED "No free global channels!\n" );
  665. }
  666. return 0;
  667. }
  668. channels.Append( chan );
  669. chan->emitter = this;
  670. chan->parms = chanParms;
  671. chan->soundShader = shader;
  672. chan->logicalChannel = channel;
  673. chan->leadinSample = leadinSample;
  674. chan->loopingSample = loopingSample;
  675. chan->allowSlow = allowSlow;
  676. // return length of sound in milliseconds
  677. int length = chan->leadinSample->LengthInMsec();
  678. // adjust the start time based on diversity for looping sounds, so they don't all start at the same point
  679. int startOffset = 0;
  680. if ( chan->IsLooping() && !shader->leadin ) {
  681. // looping sounds start at a random point...
  682. startOffset = soundSystemLocal.random.RandomInt( length );
  683. }
  684. chan->startTime = currentTime - startOffset;
  685. if ( ( chanParms.soundShaderFlags & SSF_LOOPING ) != 0 ) {
  686. // This channel will never end!
  687. chan->endTime = 0;
  688. } else {
  689. // This channel will automatically end at this time
  690. chan->endTime = chan->startTime + length + 100;
  691. }
  692. if ( showStartSound ) {
  693. if ( loopingSample == NULL || leadinSample == loopingSample ) {
  694. idLib::Printf( "Playing %s @ %d\n", leadinSample->GetName(), startOffset );
  695. } else {
  696. idLib::Printf( "Playing %s then looping %s\n", leadinSample->GetName(), loopingSample->GetName() );
  697. }
  698. }
  699. return length;
  700. }
  701. /*
  702. ========================
  703. idSoundEmitterLocal::OnReloadSound
  704. This is a shortened version of StartSound, called whenever a sound shader is reloaded.
  705. If the emitter is currently playing the given sound shader, restart it so
  706. a change in the sound sample used for a given sound shader will be picked up.
  707. ========================
  708. */
  709. void idSoundEmitterLocal::OnReloadSound( const idDecl *decl ) {
  710. }
  711. /*
  712. ========================
  713. idSoundEmitterLocal::StopSound
  714. Can pass SCHANNEL_ANY.
  715. ========================
  716. */
  717. void idSoundEmitterLocal::StopSound( const s_channelType channel ) {
  718. assert( soundWorld != NULL );
  719. assert( soundWorld->emitters[this->index] == this );
  720. if ( soundWorld && soundWorld->writeDemo ) {
  721. soundWorld->writeDemo->WriteInt( DS_SOUND );
  722. soundWorld->writeDemo->WriteInt( SCMD_STOP );
  723. soundWorld->writeDemo->WriteInt( index );
  724. soundWorld->writeDemo->WriteInt( channel );
  725. }
  726. for( int i = 0; i < channels.Num(); i++ ) {
  727. idSoundChannel * chan = channels[i];
  728. if ( channel != SCHANNEL_ANY && chan->logicalChannel != channel ) {
  729. continue;
  730. }
  731. if ( s_showStartSound.GetBool() ) {
  732. idLib::Printf( "%dms: StopSound(%d:%d): %s\n", soundWorld->GetSoundTime(), index, channel, chan->soundShader->GetName() );
  733. }
  734. // This forces CheckForCompletion to return true
  735. chan->endTime = 1;
  736. }
  737. }
  738. /*
  739. ========================
  740. idSoundEmitterLocal::ModifySound
  741. ========================
  742. */
  743. void idSoundEmitterLocal::ModifySound( const s_channelType channel, const soundShaderParms_t *parms ) {
  744. assert( soundWorld != NULL );
  745. assert( soundWorld->emitters[this->index] == this );
  746. if ( soundWorld && soundWorld->writeDemo ) {
  747. soundWorld->writeDemo->WriteInt( DS_SOUND );
  748. soundWorld->writeDemo->WriteInt( SCMD_MODIFY );
  749. soundWorld->writeDemo->WriteInt( index );
  750. soundWorld->writeDemo->WriteInt( channel );
  751. soundWorld->writeDemo->WriteFloat( parms->minDistance );
  752. soundWorld->writeDemo->WriteFloat( parms->maxDistance );
  753. soundWorld->writeDemo->WriteFloat( parms->volume );
  754. soundWorld->writeDemo->WriteFloat( parms->shakes );
  755. soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
  756. soundWorld->writeDemo->WriteInt( parms->soundClass );
  757. }
  758. for ( int i = channels.Num() - 1; i >= 0; i-- ) {
  759. idSoundChannel * chan = channels[i];
  760. if ( channel != SCHANNEL_ANY && chan->logicalChannel != channel ) {
  761. continue;
  762. }
  763. if ( s_showStartSound.GetBool() ) {
  764. idLib::Printf( "%dms: ModifySound(%d:%d): %s\n", soundWorld->GetSoundTime(), index, channel, chan->soundShader->GetName() );
  765. }
  766. OverrideParms( &chan->parms, parms, &chan->parms );
  767. }
  768. }
  769. /*
  770. ========================
  771. idSoundEmitterLocal::FadeSound
  772. ========================
  773. */
  774. void idSoundEmitterLocal::FadeSound( const s_channelType channel, float to, float over ) {
  775. assert( soundWorld != NULL );
  776. assert( soundWorld->emitters[this->index] == this );
  777. if ( soundWorld->writeDemo ) {
  778. soundWorld->writeDemo->WriteInt( DS_SOUND );
  779. soundWorld->writeDemo->WriteInt( SCMD_FADE );
  780. soundWorld->writeDemo->WriteInt( index );
  781. soundWorld->writeDemo->WriteInt( channel );
  782. soundWorld->writeDemo->WriteFloat( to );
  783. soundWorld->writeDemo->WriteFloat( over );
  784. }
  785. int overMSec = SEC2MS( over );
  786. for ( int i = 0; i < channels.Num(); i++ ) {
  787. idSoundChannel * chan = channels[i];
  788. if ( channel != SCHANNEL_ANY && chan->logicalChannel != channel ) {
  789. continue;
  790. }
  791. if ( s_showStartSound.GetBool() ) {
  792. idLib::Printf( "%dms: FadeSound(%d:%d): %s to %.2fdb over %.2f seconds\n", soundWorld->GetSoundTime(), index, channel, chan->soundShader->GetName(), to, over );
  793. }
  794. // fade it
  795. chan->volumeFade.Fade( to - chan->parms.volume, overMSec, soundWorld->GetSoundTime() );
  796. }
  797. }
  798. /*
  799. ========================
  800. idSoundEmitterLocal::CurrentlyPlaying
  801. ========================
  802. */
  803. bool idSoundEmitterLocal::CurrentlyPlaying( const s_channelType channel ) const {
  804. if ( channel == SCHANNEL_ANY ) {
  805. return ( channels.Num() > 0 );
  806. }
  807. for ( int i = 0; i < channels.Num(); ++i ) {
  808. if ( channels[i] != NULL && channels[i]->logicalChannel == channel ) {
  809. if ( channels[i]->endTime == 1 ) {
  810. return false;
  811. } else {
  812. return true;
  813. }
  814. }
  815. }
  816. return false;
  817. }
  818. /*
  819. ========================
  820. idSoundEmitterLocal::CurrentAmplitude
  821. ========================
  822. */
  823. float idSoundEmitterLocal::CurrentAmplitude() {
  824. float amplitude = 0.0f;
  825. int currentTime = soundWorld->GetSoundTime();
  826. for ( int i = 0; i < channels.Num(); i++ ) {
  827. idSoundChannel * chan = channels[i];
  828. if ( chan == NULL || currentTime < chan->startTime || ( chan->endTime > 0 && currentTime >= chan->endTime ) ) {
  829. continue;
  830. }
  831. int relativeTime = currentTime - chan->startTime;
  832. int leadinLength = chan->leadinSample->LengthInMsec();
  833. if ( relativeTime < leadinLength ) {
  834. amplitude = Max( amplitude, chan->leadinSample->GetAmplitude( relativeTime ) );
  835. } else if ( chan->loopingSample != NULL ) {
  836. amplitude = Max( amplitude, chan->loopingSample->GetAmplitude( ( relativeTime - leadinLength ) % chan->loopingSample->LengthInMsec() ) );
  837. }
  838. }
  839. return amplitude;
  840. }