snd_world.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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_lockListener( "s_lockListener", "0", CVAR_BOOL, "lock listener updates" );
  24. idCVar s_constantAmplitude( "s_constantAmplitude", "-1", CVAR_FLOAT, "" );
  25. idCVar s_maxEmitterChannels( "s_maxEmitterChannels", "48", CVAR_INTEGER, "Can be set lower than the absolute max of MAX_HARDWARE_VOICES" );
  26. idCVar s_cushionFadeChannels( "s_cushionFadeChannels", "2", CVAR_INTEGER, "Ramp currentCushionDB so this many emitter channels should be silent" );
  27. idCVar s_cushionFadeRate( "s_cushionFadeRate", "60", CVAR_FLOAT, "DB / second change to currentCushionDB" );
  28. idCVar s_cushionFadeLimit( "s_cushionFadeLimit", "-30", CVAR_FLOAT, "Never cushion fade beyond this level" );
  29. idCVar s_cushionFadeOver( "s_cushionFadeOver", "10", CVAR_FLOAT, "DB above s_cushionFadeLimit to start ramp to silence" );
  30. idCVar s_unpauseFadeInTime( "s_unpauseFadeInTime", "250", CVAR_INTEGER, "When unpausing a sound world, milliseconds to fade sounds in over" );
  31. idCVar s_doorDistanceAdd( "s_doorDistanceAdd", "150", CVAR_FLOAT, "reduce sound volume with this distance when going through a door" );
  32. idCVar s_drawSounds( "s_drawSounds", "0", CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
  33. idCVar s_showVoices( "s_showVoices", "0", CVAR_BOOL, "show active voices" );
  34. idCVar s_volume_dB( "s_volume_dB", "0", CVAR_ARCHIVE | CVAR_FLOAT, "volume in dB" );
  35. extern idCVar s_noSound;
  36. /*
  37. ========================
  38. idSoundWorldLocal::idSoundWorldLocal
  39. ========================
  40. */
  41. idSoundWorldLocal::idSoundWorldLocal() {
  42. volumeFade.Clear();
  43. for ( int i = 0; i < SOUND_MAX_CLASSES; i++ ) {
  44. soundClassFade[i].Clear();
  45. }
  46. renderWorld = NULL;
  47. writeDemo = NULL;
  48. listener.axis.Identity();
  49. listener.pos.Zero();
  50. listener.id = -1;
  51. listener.area = 0;
  52. shakeAmp = 0.0f;
  53. currentCushionDB = DB_SILENCE;
  54. localSound = AllocSoundEmitter();
  55. pauseFade.Clear();
  56. pausedTime = 0;
  57. accumulatedPauseTime = 0;
  58. isPaused = false;
  59. slowmoSpeed = 1.0f;
  60. enviroSuitActive = false;
  61. }
  62. /*
  63. ========================
  64. idSoundWorldLocal::~idSoundWorldLocal
  65. ========================
  66. */
  67. idSoundWorldLocal::~idSoundWorldLocal() {
  68. if ( soundSystemLocal.currentSoundWorld == this ) {
  69. soundSystemLocal.currentSoundWorld = NULL;
  70. }
  71. for ( int i = 0; i < emitters.Num(); i++ ) {
  72. emitters[i]->Reset();
  73. emitterAllocator.Free( emitters[i] );
  74. }
  75. // Make sure we aren't leaking emitters or channels
  76. assert( emitterAllocator.GetAllocCount() == 0 );
  77. assert( channelAllocator.GetAllocCount() == 0 );
  78. emitterAllocator.Shutdown();
  79. channelAllocator.Shutdown();
  80. renderWorld = NULL;
  81. localSound = NULL;
  82. }
  83. /*
  84. ========================
  85. idSoundWorldLocal::AllocSoundEmitter
  86. This is called from the main thread.
  87. ========================
  88. */
  89. idSoundEmitter * idSoundWorldLocal::AllocSoundEmitter() {
  90. idSoundEmitterLocal * emitter = emitterAllocator.Alloc();
  91. emitter->Init( emitters.Append( emitter ), this );
  92. return emitter;
  93. }
  94. /*
  95. ========================
  96. idSoundWorldLocal::AllocSoundChannel
  97. ========================
  98. */
  99. idSoundChannel * idSoundWorldLocal::AllocSoundChannel() {
  100. return channelAllocator.Alloc();
  101. }
  102. /*
  103. ========================
  104. idSoundWorldLocal::FreeSoundChannel
  105. ========================
  106. */
  107. void idSoundWorldLocal::FreeSoundChannel( idSoundChannel * channel ) {
  108. channel->Mute();
  109. channelAllocator.Free( channel );
  110. }
  111. /*
  112. ========================
  113. idSoundWorldLocal::CurrentShakeAmplitude
  114. ========================
  115. */
  116. float idSoundWorldLocal::CurrentShakeAmplitude() {
  117. if ( s_constantAmplitude.GetFloat() >= 0.0f ) {
  118. return s_constantAmplitude.GetFloat();
  119. }
  120. return shakeAmp;
  121. }
  122. /*
  123. ========================
  124. idSoundWorldLocal::PlaceListener
  125. ========================
  126. */
  127. void idSoundWorldLocal::PlaceListener( const idVec3 & origin, const idMat3 & axis, const int id ) {
  128. if ( writeDemo ) {
  129. writeDemo->WriteInt( DS_SOUND );
  130. writeDemo->WriteInt( SCMD_PLACE_LISTENER );
  131. writeDemo->WriteVec3( origin );
  132. writeDemo->WriteMat3( axis );
  133. writeDemo->WriteInt( id );
  134. }
  135. if ( s_lockListener.GetBool() ) {
  136. return;
  137. }
  138. listener.axis = axis;
  139. listener.pos = origin;
  140. listener.id = id;
  141. if ( renderWorld ) {
  142. listener.area = renderWorld->PointInArea( origin ); // where are we?
  143. } else {
  144. listener.area = 0;
  145. }
  146. }
  147. /*
  148. ========================
  149. idActiveChannel
  150. ========================
  151. */
  152. class idActiveChannel {
  153. public:
  154. idActiveChannel() :
  155. channel( NULL ),
  156. sortKey( 0 ) {}
  157. idActiveChannel( idSoundChannel * channel_, int sortKey_ ) :
  158. channel( channel_ ),
  159. sortKey( sortKey_ ) {}
  160. idSoundChannel * channel;
  161. int sortKey;
  162. };
  163. /*
  164. ========================
  165. MapVolumeFromFadeDB
  166. Ramp down volumes that are close to fadeDB so that fadeDB is DB_SILENCE
  167. ========================
  168. */
  169. float MapVolumeFromFadeDB( const float volumeDB, const float fadeDB ) {
  170. if ( volumeDB <= fadeDB ) {
  171. return DB_SILENCE;
  172. }
  173. const float fadeOver = s_cushionFadeOver.GetFloat();
  174. const float fadeFrom = fadeDB + fadeOver;
  175. if ( volumeDB >= fadeFrom ) {
  176. // unchanged
  177. return volumeDB;
  178. }
  179. const float fadeFraction = ( volumeDB - fadeDB ) / fadeOver;
  180. const float mappedDB = DB_SILENCE + ( fadeFrom - DB_SILENCE ) * fadeFraction;
  181. return mappedDB;
  182. }
  183. /*
  184. ========================
  185. AdjustForCushionChannels
  186. In the very common case of having more sounds that would contribute to the
  187. mix than there are available hardware voices, it can be an audible discontinuity
  188. when a channel initially gets a voice or loses a voice.
  189. To avoid this, make sure that the last few hardware voices are mixed with a volume
  190. of zero, so they won't make a difference as they come and go.
  191. It isn't obvious what the exact best volume ramping method should be, just that
  192. it smoothly change frame to frame.
  193. ========================
  194. */
  195. static float AdjustForCushionChannels( const idStaticList< idActiveChannel, MAX_HARDWARE_VOICES > &activeEmitterChannels,
  196. const int uncushionedChannels, const float currentCushionDB, const float driftRate ) {
  197. float targetCushionDB;
  198. if ( activeEmitterChannels.Num() <= uncushionedChannels ) {
  199. // we should be able to hear all of them
  200. targetCushionDB = DB_SILENCE;
  201. } else {
  202. // we should be able to hear all of them
  203. targetCushionDB = activeEmitterChannels[uncushionedChannels].channel->volumeDB;
  204. if( targetCushionDB < DB_SILENCE ) {
  205. targetCushionDB = DB_SILENCE;
  206. } else if ( targetCushionDB > s_cushionFadeLimit.GetFloat() ) {
  207. targetCushionDB = s_cushionFadeLimit.GetFloat();
  208. }
  209. }
  210. // linearly drift the currentTargetCushionDB towards targetCushionDB
  211. float driftedDB = currentCushionDB;
  212. if ( driftedDB < targetCushionDB ) {
  213. driftedDB += driftRate;
  214. if ( driftedDB > targetCushionDB ) {
  215. driftedDB = targetCushionDB;
  216. }
  217. } else {
  218. driftedDB -= driftRate;
  219. if ( driftedDB < targetCushionDB ) {
  220. driftedDB = targetCushionDB;
  221. }
  222. }
  223. // ramp the lower sound volumes down
  224. for ( int i = 0; i < activeEmitterChannels.Num(); i++ ) {
  225. idSoundChannel * chan = activeEmitterChannels[i].channel;
  226. chan->volumeDB = MapVolumeFromFadeDB( chan->volumeDB, driftedDB );
  227. }
  228. return driftedDB;
  229. }
  230. /*
  231. ========================
  232. idSoundWorldLocal::Update
  233. ========================
  234. */
  235. void idSoundWorldLocal::Update() {
  236. if ( s_noSound.GetBool() ) {
  237. return;
  238. }
  239. // ------------------
  240. // Update emitters
  241. //
  242. // Only loop through the list once to avoid extra cache misses
  243. // ------------------
  244. // The naming convention is weird here because we reuse the name "channel"
  245. // An idSoundChannel is a channel on an emitter, which may have an explicit channel assignment or SND_CHANNEL_ANY
  246. // A hardware channel is a channel from the sound file itself (IE: left, right, LFE)
  247. // We only allow MAX_HARDWARE_CHANNELS channels, which may wind up being a smaller number of idSoundChannels
  248. idStaticList< idActiveChannel, MAX_HARDWARE_VOICES > activeEmitterChannels;
  249. int maxEmitterChannels = s_maxEmitterChannels.GetInteger() + 1; // +1 to leave room for insert-before-sort
  250. if ( maxEmitterChannels > MAX_HARDWARE_VOICES ) {
  251. maxEmitterChannels = MAX_HARDWARE_VOICES;
  252. }
  253. int activeHardwareChannels = 0;
  254. int totalHardwareChannels = 0;
  255. int totalEmitterChannels = 0;
  256. int currentTime = GetSoundTime();
  257. for ( int e = emitters.Num() - 1; e >= 0; e-- ) {
  258. // check for freeing a one-shot emitter that is finished playing
  259. if ( emitters[e]->CheckForCompletion( currentTime ) ) {
  260. // do a fast list collapse by swapping the last element into
  261. // the slot we are deleting
  262. emitters[e]->Reset();
  263. emitterAllocator.Free( emitters[e] );
  264. int lastEmitter = emitters.Num() - 1;
  265. if ( e != lastEmitter ) {
  266. emitters[e] = emitters[lastEmitter];
  267. emitters[e]->index = e;
  268. }
  269. emitters.SetNum( lastEmitter );
  270. continue;
  271. }
  272. emitters[e]->Update( currentTime );
  273. totalEmitterChannels += emitters[e]->channels.Num();
  274. // sort the active channels into the hardware list
  275. for ( int i = 0; i < emitters[e]->channels.Num(); i++ ) {
  276. idSoundChannel * channel = emitters[e]->channels[i];
  277. // check if this channel contributes at all
  278. const bool canMute = channel->CanMute();
  279. if ( canMute && channel->volumeDB <= DB_SILENCE ) {
  280. channel->Mute();
  281. continue;
  282. }
  283. // Calculate the sort key.
  284. // VO can't be stopped and restarted accurately, so always keep VO channels by adding a large value to the sort key.
  285. const int sortKey = idMath::Ftoi( channel->volumeDB * 100.0f + ( canMute ? 0.0f : 100000.0f ) );
  286. // Keep track of the total number of hardware channels.
  287. // This is done after calculating the sort key to avoid a load-hit-store that
  288. // would occur when using the sort key in the loop below after the Ftoi above.
  289. const int sampleChannels = channel->leadinSample->NumChannels();
  290. totalHardwareChannels += sampleChannels;
  291. // Find the location to insert this channel based on the sort key.
  292. int insertIndex = 0;
  293. for ( insertIndex = 0; insertIndex < activeEmitterChannels.Num(); insertIndex++ ) {
  294. if ( sortKey > activeEmitterChannels[insertIndex].sortKey ) {
  295. break;
  296. }
  297. }
  298. // Only insert at the end if there is room.
  299. if ( insertIndex == activeEmitterChannels.Num() ) {
  300. // Always leave one spot free in the 'activeEmitterChannels' so there is room to insert sort a potentially louder sound later.
  301. if ( activeEmitterChannels.Num() + 1 >= activeEmitterChannels.Max() || activeHardwareChannels + sampleChannels > MAX_HARDWARE_CHANNELS ) {
  302. // We don't have enough voices to play this, so mute it if it was playing.
  303. channel->Mute();
  304. continue;
  305. }
  306. }
  307. // We want to insert the sound at this point.
  308. activeEmitterChannels.Insert( idActiveChannel( channel, sortKey ), insertIndex );
  309. activeHardwareChannels += sampleChannels;
  310. // If we are over our voice limit or at our channel limit, mute sounds until it fits.
  311. // If activeEmitterChannels is full, always remove the last one so there is room to insert sort a potentially louder sound later.
  312. while ( activeEmitterChannels.Num() == maxEmitterChannels || activeHardwareChannels > MAX_HARDWARE_CHANNELS ) {
  313. const int indexToRemove = activeEmitterChannels.Num() - 1;
  314. idSoundChannel * const channelToMute = activeEmitterChannels[ indexToRemove ].channel;
  315. channelToMute->Mute();
  316. activeHardwareChannels -= channelToMute->leadinSample->NumChannels();
  317. activeEmitterChannels.RemoveIndex( indexToRemove );
  318. }
  319. }
  320. }
  321. const float secondsPerFrame = 1.0f / com_engineHz_latched;
  322. // ------------------
  323. // In the very common case of having more sounds that would contribute to the
  324. // mix than there are available hardware voices, it can be an audible discontinuity
  325. // when a channel initially gets a voice or loses a voice.
  326. // To avoid this, make sure that the last few hardware voices are mixed with a volume
  327. // of zero, so they won't make a difference as they come and go.
  328. // It isn't obvious what the exact best volume ramping method should be, just that
  329. // it smoothly change frame to frame.
  330. // ------------------
  331. const int uncushionedChannels = maxEmitterChannels - s_cushionFadeChannels.GetInteger();
  332. currentCushionDB = AdjustForCushionChannels( activeEmitterChannels, uncushionedChannels,
  333. currentCushionDB, s_cushionFadeRate.GetFloat() * secondsPerFrame );
  334. // ------------------
  335. // Update Hardware
  336. // ------------------
  337. shakeAmp = 0.0f;
  338. idStr showVoiceTable;
  339. bool showVoices = s_showVoices.GetBool();
  340. if ( showVoices ) {
  341. showVoiceTable.Format( "currentCushionDB: %5.1f freeVoices: %i zombieVoices: %i buffers:%i/%i\n", currentCushionDB,
  342. soundSystemLocal.hardware.GetNumFreeVoices(), soundSystemLocal.hardware.GetNumZombieVoices(),
  343. soundSystemLocal.activeStreamBufferContexts.Num(), soundSystemLocal.freeStreamBufferContexts.Num() );
  344. }
  345. for ( int i = 0; i < activeEmitterChannels.Num(); i++ ) {
  346. idSoundChannel * chan = activeEmitterChannels[i].channel;
  347. chan->UpdateHardware( 0.0f, currentTime );
  348. if ( showVoices ) {
  349. idStr voiceLine;
  350. voiceLine.Format( "%5.1f db [%3i:%2i] %s", chan->volumeDB, chan->emitter->index, chan->logicalChannel, chan->CanMute() ? "" : " <CANT MUTE>\n" );
  351. idSoundSample * leadinSample = chan->leadinSample;
  352. idSoundSample * loopingSample = chan->loopingSample;
  353. if ( loopingSample == NULL ) {
  354. voiceLine.Append( va( "%ikhz*%i %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName() ) );
  355. } else if ( loopingSample == leadinSample ) {
  356. voiceLine.Append( va( "%ikhz*%i <LOOPING> %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName() ) );
  357. } else {
  358. voiceLine.Append( va( "%ikhz*%i %s | %ikhz*%i %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName(), loopingSample->SampleRate()/1000, loopingSample->NumChannels(), loopingSample->GetName() ) );
  359. }
  360. showVoiceTable += voiceLine;
  361. }
  362. // Calculate shakes
  363. if ( chan->hardwareVoice == NULL ) {
  364. continue;
  365. }
  366. shakeAmp += chan->parms.shakes * chan->hardwareVoice->GetGain() * chan->currentAmplitude;
  367. }
  368. if ( showVoices ) {
  369. static idOverlayHandle handle;
  370. console->PrintOverlay( handle, JUSTIFY_LEFT, showVoiceTable.c_str() );
  371. }
  372. if ( s_drawSounds.GetBool() && renderWorld != NULL ) {
  373. for ( int e = 0; e < emitters.Num(); e++ ) {
  374. idSoundEmitterLocal * emitter = emitters[e];
  375. bool audible = false;
  376. float maxGain = 0.0f;
  377. for ( int c = 0; c < emitter->channels.Num(); c++ ) {
  378. if ( emitter->channels[c]->hardwareVoice != NULL ) {
  379. audible = true;
  380. maxGain = Max( maxGain, emitter->channels[c]->hardwareVoice->GetGain() );
  381. }
  382. }
  383. if ( !audible ) {
  384. continue;
  385. }
  386. static const int lifetime = 20;
  387. idBounds ref;
  388. ref.Clear();
  389. ref.AddPoint( idVec3( -10.0f ) );
  390. ref.AddPoint( idVec3( 10.0f ) );
  391. // draw a box
  392. renderWorld->DebugBounds( idVec4( maxGain, maxGain, 1.0f, 1.0f ), ref, emitter->origin, lifetime );
  393. if ( emitter->origin != emitter->spatializedOrigin ) {
  394. renderWorld->DebugLine( idVec4( 1.0f, 0.0f, 0.0f, 1.0f ), emitter->origin, emitter->spatializedOrigin, lifetime );
  395. }
  396. // draw the index
  397. idVec3 textPos = emitter->origin;
  398. textPos.z -= 8;
  399. renderWorld->DrawText( va("%i", e), textPos, 0.1f, idVec4(1,0,0,1), listener.axis, 1, lifetime );
  400. textPos.z += 8;
  401. // run through all the channels
  402. for ( int k = 0; k < emitter->channels.Num(); k++ ) {
  403. idSoundChannel * chan = emitter->channels[k];
  404. float min = chan->parms.minDistance;
  405. float max = chan->parms.maxDistance;
  406. const char * defaulted = chan->leadinSample->IsDefault() ? " *DEFAULTED*" : "";
  407. idStr text;
  408. text.Format( "%s (%i %i/%i)%s", chan->soundShader->GetName(), idMath::Ftoi( emitter->spatializedDistance ), idMath::Ftoi( min ), idMath::Ftoi( max ), defaulted );
  409. renderWorld->DrawText( text, textPos, 0.1f, idVec4(1,0,0,1), listener.axis, 1, lifetime );
  410. textPos.z += 8;
  411. }
  412. }
  413. }
  414. }
  415. /*
  416. ========================
  417. idSoundWorldLocal::OnReloadSound
  418. ========================
  419. */
  420. void idSoundWorldLocal::OnReloadSound( const idDecl *shader ) {
  421. for ( int i = 0; i < emitters.Num(); i++ ) {
  422. emitters[i]->OnReloadSound( shader );
  423. }
  424. }
  425. /*
  426. ========================
  427. idSoundWorldLocal::EmitterForIndex
  428. ========================
  429. */
  430. idSoundEmitter *idSoundWorldLocal::EmitterForIndex( int index ) {
  431. // This is only used by save/load code which assumes index = 0 is invalid
  432. // Which is fine since we use index 0 for the local sound emitter anyway
  433. if ( index <= 0 ) {
  434. return NULL;
  435. }
  436. if ( index >= emitters.Num() ) {
  437. idLib::Error( "idSoundWorldLocal::EmitterForIndex: %i >= %i", index, emitters.Num() );
  438. }
  439. return emitters[index];
  440. }
  441. /*
  442. ========================
  443. idSoundWorldLocal::ClearAllSoundEmitters
  444. ========================
  445. */
  446. void idSoundWorldLocal::ClearAllSoundEmitters() {
  447. for ( int i = 0; i < emitters.Num(); i++ ) {
  448. emitters[i]->Reset();
  449. emitterAllocator.Free( emitters[i] );
  450. }
  451. emitters.Clear();
  452. localSound = AllocSoundEmitter();
  453. }
  454. /*
  455. ========================
  456. idSoundWorldLocal::StopAllSounds
  457. This is called from the main thread.
  458. ========================
  459. */
  460. void idSoundWorldLocal::StopAllSounds() {
  461. for ( int i = 0; i < emitters.Num(); i++ ) {
  462. emitters[i]->Reset();
  463. }
  464. }
  465. /*
  466. ========================
  467. idSoundWorldLocal::PlayShaderDirectly
  468. ========================
  469. */
  470. int idSoundWorldLocal::PlayShaderDirectly( const char * name, int channel ) {
  471. if ( name == NULL || name[0] == 0 ) {
  472. localSound->StopSound( channel );
  473. return 0;
  474. }
  475. const idSoundShader * shader = declManager->FindSound( name );
  476. if ( shader == NULL ) {
  477. localSound->StopSound( channel );
  478. return 0;
  479. } else {
  480. return localSound->StartSound( shader, channel, soundSystemLocal.random.RandomFloat(), SSF_GLOBAL, true );
  481. }
  482. }
  483. /*
  484. ========================
  485. idSoundWorldLocal::Skip
  486. ========================
  487. */
  488. void idSoundWorldLocal::Skip( int time ) {
  489. accumulatedPauseTime -= time;
  490. pauseFade.SetVolume( DB_SILENCE );
  491. pauseFade.Fade( 0.0f, s_unpauseFadeInTime.GetInteger(), GetSoundTime() );
  492. }
  493. /*
  494. ========================
  495. idSoundWorldLocal::Pause
  496. ========================
  497. */
  498. void idSoundWorldLocal::Pause() {
  499. if ( !isPaused ) {
  500. pausedTime = soundSystemLocal.SoundTime();
  501. isPaused = true;
  502. // just pause all unmutable voices (normally just voice overs)
  503. for ( int e = emitters.Num() - 1; e > 0; e-- ) {
  504. for ( int i = 0; i < emitters[e]->channels.Num(); i++ ) {
  505. idSoundChannel * channel = emitters[e]->channels[i];
  506. if ( !channel->CanMute() && channel->hardwareVoice != NULL ) {
  507. channel->hardwareVoice->Pause();
  508. }
  509. }
  510. }
  511. }
  512. }
  513. /*
  514. ========================
  515. idSoundWorldLocal::UnPause
  516. ========================
  517. */
  518. void idSoundWorldLocal::UnPause() {
  519. if ( isPaused ) {
  520. isPaused = false;
  521. accumulatedPauseTime += soundSystemLocal.SoundTime() - pausedTime;
  522. pauseFade.SetVolume( DB_SILENCE );
  523. pauseFade.Fade( 0.0f, s_unpauseFadeInTime.GetInteger(), GetSoundTime() );
  524. // just unpause all unmutable voices (normally just voice overs)
  525. for ( int e = emitters.Num() - 1; e > 0; e-- ) {
  526. for ( int i = 0; i < emitters[e]->channels.Num(); i++ ) {
  527. idSoundChannel * channel = emitters[e]->channels[i];
  528. if ( !channel->CanMute() && channel->hardwareVoice != NULL ) {
  529. channel->hardwareVoice->UnPause();
  530. }
  531. }
  532. }
  533. }
  534. }
  535. /*
  536. ========================
  537. idSoundWorldLocal::GetSoundTime
  538. ========================
  539. */
  540. int idSoundWorldLocal::GetSoundTime() {
  541. if ( isPaused ) {
  542. return pausedTime - accumulatedPauseTime;
  543. } else {
  544. return soundSystemLocal.SoundTime() - accumulatedPauseTime;
  545. }
  546. }
  547. /*
  548. ===================
  549. idSoundWorldLocal::ResolveOrigin
  550. Find out of the sound is completely occluded by a closed door portal, or
  551. the virtual sound origin position at the portal closest to the listener.
  552. this is called by the main thread
  553. dist is the distance from the orignial sound origin to the current portal that enters soundArea
  554. def->distance is the distance we are trying to reduce.
  555. If there is no path through open portals from the sound to the listener, def->spatializedDistance will remain
  556. set at maxDistance
  557. ===================
  558. */
  559. static const int MAX_PORTAL_TRACE_DEPTH = 10;
  560. void idSoundWorldLocal::ResolveOrigin( const int stackDepth, const soundPortalTrace_t *prevStack, const int soundArea, const float dist, const idVec3& soundOrigin, idSoundEmitterLocal *def ) {
  561. if ( dist >= def->spatializedDistance ) {
  562. // we can't possibly hear the sound through this chain of portals
  563. return;
  564. }
  565. if ( soundArea == listener.area ) {
  566. float fullDist = dist + (soundOrigin - listener.pos).LengthFast();
  567. if ( fullDist < def->spatializedDistance ) {
  568. def->spatializedDistance = fullDist;
  569. def->spatializedOrigin = soundOrigin;
  570. }
  571. return;
  572. }
  573. if ( stackDepth == MAX_PORTAL_TRACE_DEPTH ) {
  574. // don't spend too much time doing these calculations in big maps
  575. return;
  576. }
  577. soundPortalTrace_t newStack;
  578. newStack.portalArea = soundArea;
  579. newStack.prevStack = prevStack;
  580. int numPortals = renderWorld->NumPortalsInArea( soundArea );
  581. for( int p = 0; p < numPortals; p++ ) {
  582. exitPortal_t re = renderWorld->GetPortal( soundArea, p );
  583. float occlusionDistance = 0;
  584. // air blocking windows will block sound like closed doors
  585. if ( (re.blockingBits & ( PS_BLOCK_VIEW | PS_BLOCK_AIR ) ) ) {
  586. // we could just completely cut sound off, but reducing the volume works better
  587. // continue;
  588. occlusionDistance = s_doorDistanceAdd.GetFloat();
  589. }
  590. // what area are we about to go look at
  591. int otherArea = re.areas[0];
  592. if ( re.areas[0] == soundArea ) {
  593. otherArea = re.areas[1];
  594. }
  595. // if this area is already in our portal chain, don't bother looking into it
  596. const soundPortalTrace_t *prev;
  597. for ( prev = prevStack ; prev ; prev = prev->prevStack ) {
  598. if ( prev->portalArea == otherArea ) {
  599. break;
  600. }
  601. }
  602. if ( prev ) {
  603. continue;
  604. }
  605. // pick a point on the portal to serve as our virtual sound origin
  606. idVec3 source;
  607. idPlane pl;
  608. re.w->GetPlane( pl );
  609. float scale;
  610. idVec3 dir = listener.pos - soundOrigin;
  611. if ( !pl.RayIntersection( soundOrigin, dir, scale ) ) {
  612. source = re.w->GetCenter();
  613. } else {
  614. source = soundOrigin + scale * dir;
  615. // if this point isn't inside the portal edges, slide it in
  616. for ( int i = 0 ; i < re.w->GetNumPoints() ; i++ ) {
  617. int j = ( i + 1 ) % re.w->GetNumPoints();
  618. idVec3 edgeDir = (*(re.w))[j].ToVec3() - (*(re.w))[i].ToVec3();
  619. idVec3 edgeNormal;
  620. edgeNormal.Cross( pl.Normal(), edgeDir );
  621. idVec3 fromVert = source - (*(re.w))[j].ToVec3();
  622. float d = edgeNormal * fromVert;
  623. if ( d > 0 ) {
  624. // move it in
  625. float div = edgeNormal.Normalize();
  626. d /= div;
  627. source -= d * edgeNormal;
  628. }
  629. }
  630. }
  631. idVec3 tlen = source - soundOrigin;
  632. float tlenLength = tlen.LengthFast();
  633. ResolveOrigin( stackDepth+1, &newStack, otherArea, dist+tlenLength+occlusionDistance, source, def );
  634. }
  635. }
  636. /*
  637. ========================
  638. idSoundWorldLocal::StartWritingDemo
  639. ========================
  640. */
  641. void idSoundWorldLocal::StartWritingDemo( idDemoFile * demo ) {
  642. writeDemo = demo;
  643. writeDemo->WriteInt( DS_SOUND );
  644. writeDemo->WriteInt( SCMD_STATE );
  645. // use the normal save game code to archive all the emitters
  646. WriteToSaveGame( writeDemo );
  647. }
  648. /*
  649. ========================
  650. idSoundWorldLocal::StopWritingDemo
  651. ========================
  652. */
  653. void idSoundWorldLocal::StopWritingDemo() {
  654. writeDemo = NULL;
  655. }
  656. /*
  657. ========================
  658. idSoundWorldLocal::ProcessDemoCommand
  659. ========================
  660. */
  661. void idSoundWorldLocal::ProcessDemoCommand( idDemoFile * readDemo ) {
  662. if ( !readDemo ) {
  663. return;
  664. }
  665. int index;
  666. soundDemoCommand_t dc;
  667. if ( !readDemo->ReadInt( (int&)dc ) ) {
  668. return;
  669. }
  670. switch( dc ) {
  671. case SCMD_STATE:
  672. ReadFromSaveGame( readDemo );
  673. UnPause();
  674. break;
  675. case SCMD_PLACE_LISTENER:
  676. {
  677. idVec3 origin;
  678. idMat3 axis;
  679. int listenerId;
  680. readDemo->ReadVec3( origin );
  681. readDemo->ReadMat3( axis );
  682. readDemo->ReadInt( listenerId );
  683. PlaceListener( origin, axis, listenerId );
  684. };
  685. break;
  686. case SCMD_ALLOC_EMITTER:
  687. {
  688. readDemo->ReadInt( index );
  689. if ( index < 1 || index > emitters.Num() ) {
  690. common->Error( "idSoundWorldLocal::ProcessDemoCommand: bad emitter number" );
  691. }
  692. if ( index == emitters.Num() ) {
  693. // append a brand new one
  694. AllocSoundEmitter();
  695. }
  696. }
  697. break;
  698. case SCMD_FREE:
  699. {
  700. int immediate;
  701. readDemo->ReadInt( index );
  702. readDemo->ReadInt( immediate );
  703. EmitterForIndex( index )->Free( immediate != 0 );
  704. }
  705. break;
  706. case SCMD_UPDATE:
  707. {
  708. idVec3 origin;
  709. int listenerId;
  710. soundShaderParms_t parms;
  711. readDemo->ReadInt( index );
  712. readDemo->ReadVec3( origin );
  713. readDemo->ReadInt( listenerId );
  714. readDemo->ReadFloat( parms.minDistance );
  715. readDemo->ReadFloat( parms.maxDistance );
  716. readDemo->ReadFloat( parms.volume );
  717. readDemo->ReadFloat( parms.shakes );
  718. readDemo->ReadInt( parms.soundShaderFlags );
  719. readDemo->ReadInt( parms.soundClass );
  720. EmitterForIndex( index )->UpdateEmitter( origin, listenerId, &parms );
  721. }
  722. break;
  723. case SCMD_START:
  724. {
  725. const idSoundShader *shader;
  726. int channel;
  727. float diversity;
  728. int shaderFlags;
  729. readDemo->ReadInt( index );
  730. shader = declManager->FindSound( readDemo->ReadHashString() );
  731. readDemo->ReadInt( channel );
  732. readDemo->ReadFloat( diversity );
  733. readDemo->ReadInt( shaderFlags );
  734. EmitterForIndex( index )->StartSound( shader, (s_channelType)channel, diversity, shaderFlags );
  735. }
  736. break;
  737. case SCMD_MODIFY:
  738. {
  739. int channel;
  740. soundShaderParms_t parms;
  741. readDemo->ReadInt( index );
  742. readDemo->ReadInt( channel );
  743. readDemo->ReadFloat( parms.minDistance );
  744. readDemo->ReadFloat( parms.maxDistance );
  745. readDemo->ReadFloat( parms.volume );
  746. readDemo->ReadFloat( parms.shakes );
  747. readDemo->ReadInt( parms.soundShaderFlags );
  748. readDemo->ReadInt( parms.soundClass );
  749. EmitterForIndex( index )->ModifySound( (s_channelType)channel, &parms );
  750. }
  751. break;
  752. case SCMD_STOP:
  753. {
  754. int channel;
  755. readDemo->ReadInt( index );
  756. readDemo->ReadInt( channel );
  757. EmitterForIndex( index )->StopSound( (s_channelType)channel );
  758. }
  759. break;
  760. case SCMD_FADE:
  761. {
  762. int channel;
  763. float to, over;
  764. readDemo->ReadInt( index );
  765. readDemo->ReadInt( channel );
  766. readDemo->ReadFloat( to );
  767. readDemo->ReadFloat( over );
  768. EmitterForIndex( index )->FadeSound((s_channelType)channel, to, over );
  769. }
  770. break;
  771. }
  772. }
  773. /*
  774. =================
  775. idSoundWorldLocal::AVIOpen
  776. =================
  777. */
  778. void idSoundWorldLocal::AVIOpen( const char *, const char * ) {
  779. }
  780. /*
  781. =================
  782. idSoundWorldLocal::AVIClose
  783. =================
  784. */
  785. void idSoundWorldLocal::AVIClose() {
  786. }
  787. /*
  788. =================
  789. idSoundWorldLocal::WriteToSaveGame
  790. =================
  791. */
  792. void idSoundWorldLocal::WriteToSaveGame( idFile * savefile ) {
  793. struct helper {
  794. static void WriteSoundFade( idFile * savefile, idSoundFade & sf ) {
  795. savefile->WriteInt( sf.fadeStartTime );
  796. savefile->WriteInt( sf.fadeEndTime );
  797. savefile->WriteFloat( sf.fadeStartVolume );
  798. savefile->WriteFloat( sf.fadeEndVolume );
  799. }
  800. static void WriteShaderParms( idFile * savefile, soundShaderParms_t & parms ) {
  801. savefile->WriteFloat( parms.minDistance );
  802. savefile->WriteFloat( parms.maxDistance );
  803. savefile->WriteFloat( parms.volume );
  804. savefile->WriteFloat( parms.shakes );
  805. savefile->WriteInt( parms.soundShaderFlags );
  806. savefile->WriteInt( parms.soundClass );
  807. }
  808. };
  809. savefile->WriteInt( GetSoundTime() );
  810. helper::WriteSoundFade( savefile, volumeFade );
  811. for ( int c = 0; c < SOUND_MAX_CLASSES; c++ ) {
  812. helper::WriteSoundFade( savefile, soundClassFade[c] );
  813. }
  814. savefile->WriteFloat( slowmoSpeed );
  815. savefile->WriteBool( enviroSuitActive );
  816. savefile->WriteMat3( listener.axis );
  817. savefile->WriteVec3( listener.pos );
  818. savefile->WriteInt( listener.id );
  819. savefile->WriteInt( listener.area );
  820. savefile->WriteFloat( shakeAmp );
  821. int num = emitters.Num();
  822. savefile->WriteInt( num );
  823. // Start at 1 because the local sound emitter is not saved
  824. for ( int e = 1; e < emitters.Num(); e++ ) {
  825. idSoundEmitterLocal * emitter = emitters[e];
  826. savefile->WriteBool( emitter->canFree );
  827. savefile->WriteVec3( emitter->origin );
  828. savefile->WriteInt( emitter->emitterId );
  829. helper::WriteShaderParms( savefile, emitter->parms );
  830. savefile->WriteInt( emitter->channels.Num() );
  831. for ( int c = 0; c < emitter->channels.Num(); c++ ) {
  832. idSoundChannel * channel = emitter->channels[c];
  833. savefile->WriteInt( channel->startTime );
  834. savefile->WriteInt( channel->endTime );
  835. savefile->WriteInt( channel->logicalChannel );
  836. savefile->WriteBool( channel->allowSlow );
  837. helper::WriteShaderParms( savefile, channel->parms );
  838. helper::WriteSoundFade( savefile, channel->volumeFade );
  839. savefile->WriteString( channel->soundShader->GetName() );
  840. int leadin = -1;
  841. int looping = -1;
  842. for ( int i = 0; i < channel->soundShader->entries.Num(); i++ ) {
  843. if ( channel->soundShader->entries[i] == channel->leadinSample ) {
  844. leadin = i;
  845. }
  846. if ( channel->soundShader->entries[i] == channel->loopingSample ) {
  847. looping = i;
  848. }
  849. }
  850. savefile->WriteInt( leadin );
  851. savefile->WriteInt( looping );
  852. }
  853. }
  854. }
  855. /*
  856. =================
  857. idSoundWorldLocal::ReadFromSaveGame
  858. =================
  859. */
  860. void idSoundWorldLocal::ReadFromSaveGame( idFile * savefile ) {
  861. struct helper {
  862. static void ReadSoundFade( idFile * savefile, idSoundFade & sf, int timeDelta ) {
  863. savefile->ReadInt( sf.fadeStartTime );
  864. savefile->ReadInt( sf.fadeEndTime );
  865. savefile->ReadFloat( sf.fadeStartVolume );
  866. savefile->ReadFloat( sf.fadeEndVolume );
  867. if ( sf.fadeEndTime > 0 ) {
  868. sf.fadeStartTime += timeDelta;
  869. sf.fadeEndTime += timeDelta;
  870. }
  871. }
  872. static void ReadShaderParms( idFile * savefile, soundShaderParms_t & parms ) {
  873. savefile->ReadFloat( parms.minDistance );
  874. savefile->ReadFloat( parms.maxDistance );
  875. savefile->ReadFloat( parms.volume );
  876. savefile->ReadFloat( parms.shakes );
  877. savefile->ReadInt( parms.soundShaderFlags );
  878. savefile->ReadInt( parms.soundClass );
  879. }
  880. };
  881. int oldSoundTime = 0;
  882. savefile->ReadInt( oldSoundTime );
  883. int timeDelta = GetSoundTime() - oldSoundTime;
  884. helper::ReadSoundFade( savefile, volumeFade, timeDelta );
  885. for ( int c = 0; c < SOUND_MAX_CLASSES; c++ ) {
  886. helper::ReadSoundFade( savefile, soundClassFade[c], timeDelta );
  887. }
  888. savefile->ReadFloat( slowmoSpeed );
  889. savefile->ReadBool( enviroSuitActive );
  890. savefile->ReadMat3( listener.axis );
  891. savefile->ReadVec3( listener.pos );
  892. savefile->ReadInt( listener.id );
  893. savefile->ReadInt( listener.area );
  894. savefile->ReadFloat( shakeAmp );
  895. int numEmitters = 0;
  896. savefile->ReadInt( numEmitters );
  897. ClearAllSoundEmitters();
  898. idStr shaderName;
  899. // Start at 1 because the local sound emitter is not saved
  900. for ( int e = 1; e < numEmitters; e++ ) {
  901. idSoundEmitterLocal * emitter = (idSoundEmitterLocal *)AllocSoundEmitter();
  902. assert( emitter == emitters[e] );
  903. assert( emitter->index == e );
  904. assert( emitter->soundWorld == this );
  905. assert( emitter->channels.Num() == 0 );
  906. savefile->ReadBool( emitter->canFree );
  907. savefile->ReadVec3( emitter->origin );
  908. savefile->ReadInt( emitter->emitterId );
  909. helper::ReadShaderParms( savefile, emitter->parms );
  910. int numChannels = 0;
  911. savefile->ReadInt( numChannels );
  912. emitter->channels.SetNum( numChannels );
  913. for ( int c = 0; c < numChannels; c++ ) {
  914. idSoundChannel * channel = AllocSoundChannel();
  915. emitter->channels[c] = channel;
  916. channel->emitter = emitter;
  917. savefile->ReadInt( channel->startTime );
  918. savefile->ReadInt( channel->endTime );
  919. savefile->ReadInt( channel->logicalChannel );
  920. savefile->ReadBool( channel->allowSlow );
  921. helper::ReadShaderParms( savefile, channel->parms );
  922. helper::ReadSoundFade( savefile, channel->volumeFade, timeDelta );
  923. savefile->ReadString( shaderName );
  924. channel->soundShader = declManager->FindSound( shaderName );
  925. int leadin = 0;
  926. int looping = 0;
  927. savefile->ReadInt( leadin );
  928. savefile->ReadInt( looping );
  929. // If the leadin entry is not valid (possible if the shader changed after saving) then the looping entry can't be valid either
  930. if ( leadin >= 0 && leadin < channel->soundShader->entries.Num() ) {
  931. channel->leadinSample = channel->soundShader->entries[ leadin ];
  932. if ( looping >= 0 && looping < channel->soundShader->entries.Num() ) {
  933. channel->loopingSample = channel->soundShader->entries[ looping ];
  934. }
  935. } else {
  936. channel->leadinSample = NULL;
  937. channel->loopingSample = NULL;
  938. }
  939. channel->startTime += timeDelta;
  940. if ( channel->endTime == 0 ) {
  941. // Do nothing, endTime == 0 means loop forever
  942. } else if ( channel->endTime <= oldSoundTime ) {
  943. // Channel already stopped
  944. channel->endTime = 1;
  945. } else {
  946. channel->endTime += timeDelta;
  947. }
  948. }
  949. }
  950. }
  951. /*
  952. =================
  953. idSoundWorldLocal::FadeSoundClasses
  954. fade all sounds in the world with a given shader soundClass
  955. to is in Db, over is in seconds
  956. =================
  957. */
  958. void idSoundWorldLocal::FadeSoundClasses( const int soundClass, const float to, const float over ) {
  959. if ( soundClass < 0 || soundClass >= SOUND_MAX_CLASSES ) {
  960. common->Error( "idSoundWorldLocal::FadeSoundClasses: bad soundClass %i", soundClass );
  961. return;
  962. }
  963. soundClassFade[ soundClass ].Fade( to, SEC2MS( over ), GetSoundTime() );
  964. }
  965. /*
  966. =================
  967. idSoundWorldLocal::SetSlowmoSpeed
  968. =================
  969. */
  970. void idSoundWorldLocal::SetSlowmoSpeed( float speed ) {
  971. slowmoSpeed = speed;
  972. }
  973. /*
  974. =================
  975. idSoundWorldLocal::SetEnviroSuit
  976. =================
  977. */
  978. void idSoundWorldLocal::SetEnviroSuit( bool active ) {
  979. enviroSuitActive = active;
  980. }