snd_world.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "snd_local.h"
  23. /*
  24. ==================
  25. idSoundWorldLocal::Init
  26. ==================
  27. */
  28. void idSoundWorldLocal::Init( idRenderWorld *renderWorld ) {
  29. rw = renderWorld;
  30. writeDemo = NULL;
  31. listenerAxis.Identity();
  32. listenerPos.Zero();
  33. listenerPrivateId = 0;
  34. listenerQU.Zero();
  35. listenerArea = 0;
  36. listenerAreaName = "Undefined";
  37. listenerEnvironmentID = -2;
  38. gameMsec = 0;
  39. game44kHz = 0;
  40. pause44kHz = -1;
  41. lastAVI44kHz = 0;
  42. for ( int i = 0 ; i < SOUND_MAX_CLASSES ; i++ ) {
  43. soundClassFade[i].Clear();
  44. }
  45. // fill in the 0 index spot
  46. idSoundEmitterLocal *placeHolder = new idSoundEmitterLocal;
  47. emitters.Append( placeHolder );
  48. fpa[0] = fpa[1] = fpa[2] = fpa[3] = fpa[4] = fpa[5] = NULL;
  49. aviDemoPath = "";
  50. aviDemoName = "";
  51. localSound = NULL;
  52. slowmoActive = false;
  53. slowmoSpeed = 0;
  54. enviroSuitActive = false;
  55. }
  56. /*
  57. ===============
  58. idSoundWorldLocal::idSoundWorldLocal
  59. ===============
  60. */
  61. idSoundWorldLocal::idSoundWorldLocal() {
  62. }
  63. /*
  64. ===============
  65. idSoundWorldLocal::~idSoundWorldLocal
  66. ===============
  67. */
  68. idSoundWorldLocal::~idSoundWorldLocal() {
  69. Shutdown();
  70. }
  71. /*
  72. ===============
  73. idSoundWorldLocal::Shutdown
  74. this is called from the main thread
  75. ===============
  76. */
  77. void idSoundWorldLocal::Shutdown() {
  78. int i;
  79. if ( soundSystemLocal.currentSoundWorld == this ) {
  80. soundSystemLocal.currentSoundWorld = NULL;
  81. }
  82. AVIClose();
  83. for ( i = 0; i < emitters.Num(); i++ ) {
  84. if ( emitters[i] ) {
  85. delete emitters[i];
  86. emitters[i] = NULL;
  87. }
  88. }
  89. localSound = NULL;
  90. }
  91. /*
  92. ===================
  93. idSoundWorldLocal::ClearAllSoundEmitters
  94. ===================
  95. */
  96. void idSoundWorldLocal::ClearAllSoundEmitters() {
  97. int i;
  98. Sys_EnterCriticalSection();
  99. AVIClose();
  100. for ( i = 0; i < emitters.Num(); i++ ) {
  101. idSoundEmitterLocal *sound = emitters[i];
  102. sound->Clear();
  103. }
  104. localSound = NULL;
  105. Sys_LeaveCriticalSection();
  106. }
  107. /*
  108. ===================
  109. idSoundWorldLocal::AllocLocalSoundEmitter
  110. ===================
  111. */
  112. idSoundEmitterLocal *idSoundWorldLocal::AllocLocalSoundEmitter() {
  113. int i, index;
  114. idSoundEmitterLocal *def = NULL;
  115. index = -1;
  116. // never use the 0 index spot
  117. for ( i = 1 ; i < emitters.Num() ; i++ ) {
  118. def = emitters[i];
  119. // check for a completed and freed spot
  120. if ( def->removeStatus >= REMOVE_STATUS_SAMPLEFINISHED ) {
  121. index = i;
  122. if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
  123. common->Printf( "sound: recycling sound def %d\n", i );
  124. }
  125. break;
  126. }
  127. }
  128. if ( index == -1 ) {
  129. // append a brand new one
  130. def = new idSoundEmitterLocal;
  131. // we need to protect this from the async thread
  132. Sys_EnterCriticalSection();
  133. index = emitters.Append( def );
  134. Sys_LeaveCriticalSection();
  135. if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
  136. common->Printf( "sound: appended new sound def %d\n", index );
  137. }
  138. }
  139. def->Clear();
  140. def->index = index;
  141. def->removeStatus = REMOVE_STATUS_ALIVE;
  142. def->soundWorld = this;
  143. return def;
  144. }
  145. /*
  146. ===================
  147. idSoundWorldLocal::AllocSoundEmitter
  148. this is called from the main thread
  149. ===================
  150. */
  151. idSoundEmitter *idSoundWorldLocal::AllocSoundEmitter() {
  152. idSoundEmitterLocal *emitter = AllocLocalSoundEmitter();
  153. if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
  154. common->Printf( "AllocSoundEmitter = %i\n", emitter->index );
  155. }
  156. if ( writeDemo ) {
  157. writeDemo->WriteInt( DS_SOUND );
  158. writeDemo->WriteInt( SCMD_ALLOC_EMITTER );
  159. writeDemo->WriteInt( emitter->index );
  160. }
  161. return emitter;
  162. }
  163. /*
  164. ===================
  165. idSoundWorldLocal::StartWritingDemo
  166. this is called from the main thread
  167. ===================
  168. */
  169. void idSoundWorldLocal::StartWritingDemo( idDemoFile *demo ) {
  170. writeDemo = demo;
  171. writeDemo->WriteInt( DS_SOUND );
  172. writeDemo->WriteInt( SCMD_STATE );
  173. // use the normal save game code to archive all the emitters
  174. WriteToSaveGame( writeDemo );
  175. }
  176. /*
  177. ===================
  178. idSoundWorldLocal::StopWritingDemo
  179. this is called from the main thread
  180. ===================
  181. */
  182. void idSoundWorldLocal::StopWritingDemo() {
  183. writeDemo = NULL;
  184. }
  185. /*
  186. ===================
  187. idSoundWorldLocal::ProcessDemoCommand
  188. this is called from the main thread
  189. ===================
  190. */
  191. void idSoundWorldLocal::ProcessDemoCommand( idDemoFile *readDemo ) {
  192. int index;
  193. idSoundEmitterLocal *def;
  194. if ( !readDemo ) {
  195. return;
  196. }
  197. soundDemoCommand_t dc;
  198. if ( !readDemo->ReadInt( (int&)dc ) ) {
  199. return;
  200. }
  201. switch( dc ) {
  202. case SCMD_STATE:
  203. // we need to protect this from the async thread
  204. // other instances of calling idSoundWorldLocal::ReadFromSaveGame do this while the sound code is muted
  205. // setting muted and going right in may not be good enough here, as we async thread may already be in an async tick (in which case we could still race to it)
  206. Sys_EnterCriticalSection();
  207. ReadFromSaveGame( readDemo );
  208. Sys_LeaveCriticalSection();
  209. UnPause();
  210. break;
  211. case SCMD_PLACE_LISTENER:
  212. {
  213. idVec3 origin;
  214. idMat3 axis;
  215. int listenerId;
  216. int gameTime;
  217. readDemo->ReadVec3( origin );
  218. readDemo->ReadMat3( axis );
  219. readDemo->ReadInt( listenerId );
  220. readDemo->ReadInt( gameTime );
  221. PlaceListener( origin, axis, listenerId, gameTime, "" );
  222. };
  223. break;
  224. case SCMD_ALLOC_EMITTER:
  225. readDemo->ReadInt( index );
  226. if ( index < 1 || index > emitters.Num() ) {
  227. common->Error( "idSoundWorldLocal::ProcessDemoCommand: bad emitter number" );
  228. }
  229. if ( index == emitters.Num() ) {
  230. // append a brand new one
  231. def = new idSoundEmitterLocal;
  232. emitters.Append( def );
  233. }
  234. def = emitters[ index ];
  235. def->Clear();
  236. def->index = index;
  237. def->removeStatus = REMOVE_STATUS_ALIVE;
  238. def->soundWorld = this;
  239. break;
  240. case SCMD_FREE:
  241. {
  242. int immediate;
  243. readDemo->ReadInt( index );
  244. readDemo->ReadInt( immediate );
  245. EmitterForIndex( index )->Free( immediate != 0 );
  246. }
  247. break;
  248. case SCMD_UPDATE:
  249. {
  250. idVec3 origin;
  251. int listenerId;
  252. soundShaderParms_t parms;
  253. readDemo->ReadInt( index );
  254. readDemo->ReadVec3( origin );
  255. readDemo->ReadInt( listenerId );
  256. readDemo->ReadFloat( parms.minDistance );
  257. readDemo->ReadFloat( parms.maxDistance );
  258. readDemo->ReadFloat( parms.volume );
  259. readDemo->ReadFloat( parms.shakes );
  260. readDemo->ReadInt( parms.soundShaderFlags );
  261. readDemo->ReadInt( parms.soundClass );
  262. EmitterForIndex( index )->UpdateEmitter( origin, listenerId, &parms );
  263. }
  264. break;
  265. case SCMD_START:
  266. {
  267. const idSoundShader *shader;
  268. int channel;
  269. float diversity;
  270. int shaderFlags;
  271. readDemo->ReadInt( index );
  272. shader = declManager->FindSound( readDemo->ReadHashString() );
  273. readDemo->ReadInt( channel );
  274. readDemo->ReadFloat( diversity );
  275. readDemo->ReadInt( shaderFlags );
  276. EmitterForIndex( index )->StartSound( shader, (s_channelType)channel, diversity, shaderFlags );
  277. }
  278. break;
  279. case SCMD_MODIFY:
  280. {
  281. int channel;
  282. soundShaderParms_t parms;
  283. readDemo->ReadInt( index );
  284. readDemo->ReadInt( channel );
  285. readDemo->ReadFloat( parms.minDistance );
  286. readDemo->ReadFloat( parms.maxDistance );
  287. readDemo->ReadFloat( parms.volume );
  288. readDemo->ReadFloat( parms.shakes );
  289. readDemo->ReadInt( parms.soundShaderFlags );
  290. readDemo->ReadInt( parms.soundClass );
  291. EmitterForIndex( index )->ModifySound( (s_channelType)channel, &parms );
  292. }
  293. break;
  294. case SCMD_STOP:
  295. {
  296. int channel;
  297. readDemo->ReadInt( index );
  298. readDemo->ReadInt( channel );
  299. EmitterForIndex( index )->StopSound( (s_channelType)channel );
  300. }
  301. break;
  302. case SCMD_FADE:
  303. {
  304. int channel;
  305. float to, over;
  306. readDemo->ReadInt( index );
  307. readDemo->ReadInt( channel );
  308. readDemo->ReadFloat( to );
  309. readDemo->ReadFloat( over );
  310. EmitterForIndex( index )->FadeSound((s_channelType)channel, to, over );
  311. }
  312. break;
  313. }
  314. }
  315. /*
  316. ===================
  317. idSoundWorldLocal::CurrentShakeAmplitudeForPosition
  318. this is called from the main thread
  319. ===================
  320. */
  321. float idSoundWorldLocal::CurrentShakeAmplitudeForPosition( const int time, const idVec3 &listererPosition ) {
  322. float amp = 0.0f;
  323. int localTime;
  324. if ( idSoundSystemLocal::s_constantAmplitude.GetFloat() >= 0.0f ) {
  325. return 0.0f;
  326. }
  327. localTime = soundSystemLocal.GetCurrent44kHzTime();
  328. for ( int i = 1; i < emitters.Num(); i++ ) {
  329. idSoundEmitterLocal *sound = emitters[i];
  330. if ( !sound->hasShakes ) {
  331. continue;
  332. }
  333. amp += FindAmplitude( sound, localTime, &listererPosition, SCHANNEL_ANY, true );
  334. }
  335. return amp;
  336. }
  337. /*
  338. ===================
  339. idSoundWorldLocal::MixLoop
  340. Sum all sound contributions into finalMixBuffer, an unclamped float buffer holding
  341. all output channels. MIXBUFFER_SAMPLES samples will be created, with each sample consisting
  342. of 2 or 6 floats depending on numSpeakers.
  343. this is normally called from the sound thread, but also from the main thread
  344. for AVIdemo writing
  345. ===================
  346. */
  347. void idSoundWorldLocal::MixLoop( int current44kHz, int numSpeakers, float *finalMixBuffer ) {
  348. int i, j;
  349. idSoundEmitterLocal *sound;
  350. // if noclip flying outside the world, leave silence
  351. if ( listenerArea == -1 ) {
  352. if ( idSoundSystemLocal::useOpenAL )
  353. alListenerf( AL_GAIN, 0.0f );
  354. return;
  355. }
  356. // update the listener position and orientation
  357. if ( idSoundSystemLocal::useOpenAL ) {
  358. ALfloat listenerPosition[3];
  359. listenerPosition[0] = -listenerPos.y;
  360. listenerPosition[1] = listenerPos.z;
  361. listenerPosition[2] = -listenerPos.x;
  362. ALfloat listenerOrientation[6];
  363. listenerOrientation[0] = -listenerAxis[0].y;
  364. listenerOrientation[1] = listenerAxis[0].z;
  365. listenerOrientation[2] = -listenerAxis[0].x;
  366. listenerOrientation[3] = -listenerAxis[2].y;
  367. listenerOrientation[4] = listenerAxis[2].z;
  368. listenerOrientation[5] = -listenerAxis[2].x;
  369. alListenerf( AL_GAIN, 1.0f );
  370. alListenerfv( AL_POSITION, listenerPosition );
  371. alListenerfv( AL_ORIENTATION, listenerOrientation );
  372. #if ID_OPENAL
  373. if ( soundSystemLocal.s_useEAXReverb.GetBool() ) {
  374. if ( soundSystemLocal.efxloaded ) {
  375. idSoundEffect *effect = NULL;
  376. int EnvironmentID = -1;
  377. idStr defaultStr( "default" );
  378. idStr listenerAreaStr( listenerArea );
  379. soundSystemLocal.EFXDatabase.FindEffect( listenerAreaStr, &effect, &EnvironmentID );
  380. if (!effect)
  381. soundSystemLocal.EFXDatabase.FindEffect( listenerAreaName, &effect, &EnvironmentID );
  382. if (!effect)
  383. soundSystemLocal.EFXDatabase.FindEffect( defaultStr, &effect, &EnvironmentID );
  384. // only update if change in settings
  385. if ( soundSystemLocal.s_muteEAXReverb.GetBool() || ( listenerEnvironmentID != EnvironmentID ) ) {
  386. EAXREVERBPROPERTIES EnvironmentParameters;
  387. // get area reverb setting from EAX Manager
  388. if ( ( effect ) && ( effect->data) && ( memcpy( &EnvironmentParameters, effect->data, effect->datasize ) ) ) {
  389. if ( soundSystemLocal.s_muteEAXReverb.GetBool() ) {
  390. EnvironmentParameters.lRoom = -10000;
  391. EnvironmentID = -2;
  392. }
  393. if ( soundSystemLocal.alEAXSet ) {
  394. soundSystemLocal.alEAXSet( &EAXPROPERTYID_EAX_FXSlot0, EAXREVERB_ALLPARAMETERS, 0, &EnvironmentParameters, sizeof( EnvironmentParameters ) );
  395. }
  396. }
  397. listenerEnvironmentID = EnvironmentID;
  398. }
  399. }
  400. }
  401. #endif
  402. }
  403. // debugging option to mute all but a single soundEmitter
  404. if ( idSoundSystemLocal::s_singleEmitter.GetInteger() > 0 && idSoundSystemLocal::s_singleEmitter.GetInteger() < emitters.Num() ) {
  405. sound = emitters[idSoundSystemLocal::s_singleEmitter.GetInteger()];
  406. if ( sound && sound->playing ) {
  407. // run through all the channels
  408. for ( j = 0; j < SOUND_MAX_CHANNELS ; j++ ) {
  409. idSoundChannel *chan = &sound->channels[j];
  410. // see if we have a sound triggered on this channel
  411. if ( !chan->triggerState ) {
  412. chan->ALStop();
  413. continue;
  414. }
  415. AddChannelContribution( sound, chan, current44kHz, numSpeakers, finalMixBuffer );
  416. }
  417. }
  418. return;
  419. }
  420. for ( i = 1; i < emitters.Num(); i++ ) {
  421. sound = emitters[i];
  422. if ( !sound ) {
  423. continue;
  424. }
  425. // if no channels are active, do nothing
  426. if ( !sound->playing ) {
  427. continue;
  428. }
  429. // run through all the channels
  430. for ( j = 0; j < SOUND_MAX_CHANNELS ; j++ ) {
  431. idSoundChannel *chan = &sound->channels[j];
  432. // see if we have a sound triggered on this channel
  433. if ( !chan->triggerState ) {
  434. chan->ALStop();
  435. continue;
  436. }
  437. AddChannelContribution( sound, chan, current44kHz, numSpeakers, finalMixBuffer );
  438. }
  439. }
  440. if ( !idSoundSystemLocal::useOpenAL && enviroSuitActive && soundSystemLocal.s_postprocessing.GetBool() /*bc allow disabling of this audio effect.*/)
  441. {
  442. soundSystemLocal.DoEnviroSuit( finalMixBuffer, MIXBUFFER_SAMPLES, numSpeakers );
  443. }
  444. }
  445. //==============================================================================
  446. /*
  447. ===================
  448. idSoundWorldLocal::AVIOpen
  449. this is called by the main thread
  450. ===================
  451. */
  452. void idSoundWorldLocal::AVIOpen( const char *path, const char *name ) {
  453. aviDemoPath = path;
  454. aviDemoName = name;
  455. lastAVI44kHz = game44kHz - game44kHz % MIXBUFFER_SAMPLES;
  456. if ( soundSystemLocal.snd_audio_hw->GetNumberOfSpeakers() == 6 ) {
  457. fpa[0] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_left.raw" );
  458. fpa[1] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_right.raw" );
  459. fpa[2] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_center.raw" );
  460. fpa[3] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_lfe.raw" );
  461. fpa[4] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_backleft.raw" );
  462. fpa[5] = fileSystem->OpenFileWrite( aviDemoPath + "channel_51_backright.raw" );
  463. } else {
  464. fpa[0] = fileSystem->OpenFileWrite( aviDemoPath + "channel_left.raw" );
  465. fpa[1] = fileSystem->OpenFileWrite( aviDemoPath + "channel_right.raw" );
  466. }
  467. soundSystemLocal.SetMute( true );
  468. }
  469. /*
  470. ===================
  471. idSoundWorldLocal::AVIUpdate
  472. this is called by the main thread
  473. writes one block of sound samples if enough time has passed
  474. This can be used to write wave files even if no sound hardware exists
  475. ===================
  476. */
  477. void idSoundWorldLocal::AVIUpdate() {
  478. int numSpeakers;
  479. if ( game44kHz - lastAVI44kHz < MIXBUFFER_SAMPLES ) {
  480. return;
  481. }
  482. if ( !soundSystemLocal.snd_audio_hw ) {
  483. numSpeakers = 2;
  484. } else {
  485. numSpeakers = soundSystemLocal.snd_audio_hw->GetNumberOfSpeakers();
  486. }
  487. float mix[MIXBUFFER_SAMPLES*6+16];
  488. float *mix_p = (float *)((( int)mix + 15 ) & ~15); // SIMD align
  489. SIMDProcessor->Memset( mix_p, 0, MIXBUFFER_SAMPLES*sizeof(float)*numSpeakers );
  490. MixLoop( lastAVI44kHz, numSpeakers, mix_p );
  491. for ( int i = 0; i < numSpeakers; i++ ) {
  492. short outD[MIXBUFFER_SAMPLES];
  493. for( int j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
  494. float s = mix_p[ j*numSpeakers + i];
  495. if ( s < -32768.0f ) {
  496. outD[j] = -32768;
  497. } else if ( s > 32767.0f ) {
  498. outD[j] = 32767;
  499. } else {
  500. outD[j] = idMath::FtoiFast( s );
  501. }
  502. }
  503. // write to file
  504. fpa[i]->Write( outD, MIXBUFFER_SAMPLES*sizeof(short) );
  505. }
  506. lastAVI44kHz += MIXBUFFER_SAMPLES;
  507. return;
  508. }
  509. /*
  510. ===================
  511. idSoundWorldLocal::AVIClose
  512. ===================
  513. */
  514. void idSoundWorldLocal::AVIClose( void ) {
  515. int i;
  516. if ( !fpa[0] ) {
  517. return;
  518. }
  519. // make sure the final block is written
  520. game44kHz += MIXBUFFER_SAMPLES;
  521. AVIUpdate();
  522. game44kHz -= MIXBUFFER_SAMPLES;
  523. for ( i = 0; i < 6; i++ ) {
  524. if ( fpa[i] != NULL ) {
  525. fileSystem->CloseFile( fpa[i] );
  526. fpa[i] = NULL;
  527. }
  528. }
  529. if ( soundSystemLocal.snd_audio_hw->GetNumberOfSpeakers() == 2 ) {
  530. // convert it to a wave file
  531. idFile *rL, *lL, *wO;
  532. idStr name;
  533. name = aviDemoPath + aviDemoName + ".wav";
  534. wO = fileSystem->OpenFileWrite( name );
  535. if ( !wO ) {
  536. common->Error( "Couldn't write %s", name.c_str() );
  537. }
  538. name = aviDemoPath + "channel_right.raw";
  539. rL = fileSystem->OpenFileRead( name );
  540. if ( !rL ) {
  541. common->Error( "Couldn't open %s", name.c_str() );
  542. }
  543. name = aviDemoPath + "channel_left.raw";
  544. lL = fileSystem->OpenFileRead( name );
  545. if ( !lL ) {
  546. common->Error( "Couldn't open %s", name.c_str() );
  547. }
  548. int numSamples = rL->Length()/2;
  549. mminfo_t info;
  550. pcmwaveformat_t format;
  551. info.ckid = fourcc_riff;
  552. info.fccType = mmioFOURCC( 'W', 'A', 'V', 'E' );
  553. info.cksize = (rL->Length()*2) - 8 + 4 + 16 + 8 + 8;
  554. info.dwDataOffset = 12;
  555. wO->Write( &info, 12 );
  556. info.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
  557. info.cksize = 16;
  558. wO->Write( &info, 8 );
  559. format.wBitsPerSample = 16;
  560. format.wf.nAvgBytesPerSec = 44100*4; // sample rate * block align
  561. format.wf.nChannels = 2;
  562. format.wf.nSamplesPerSec = 44100;
  563. format.wf.wFormatTag = WAVE_FORMAT_TAG_PCM;
  564. format.wf.nBlockAlign = 4; // channels * bits/sample / 8
  565. wO->Write( &format, 16 );
  566. info.ckid = mmioFOURCC( 'd', 'a', 't', 'a' );
  567. info.cksize = rL->Length() * 2;
  568. wO->Write( &info, 8 );
  569. short s0, s1;
  570. for( i = 0; i < numSamples; i++ ) {
  571. lL->Read( &s0, 2 );
  572. rL->Read( &s1, 2 );
  573. wO->Write( &s0, 2 );
  574. wO->Write( &s1, 2 );
  575. }
  576. fileSystem->CloseFile( wO );
  577. fileSystem->CloseFile( lL );
  578. fileSystem->CloseFile( rL );
  579. fileSystem->RemoveFile( aviDemoPath + "channel_right.raw" );
  580. fileSystem->RemoveFile( aviDemoPath + "channel_left.raw" );
  581. }
  582. soundSystemLocal.SetMute( false );
  583. }
  584. //==============================================================================
  585. /*
  586. ===================
  587. idSoundWorldLocal::ResolveOrigin
  588. Find out of the sound is completely occluded by a closed door portal, or
  589. the virtual sound origin position at the portal closest to the listener.
  590. this is called by the main thread
  591. dist is the distance from the orignial sound origin to the current portal that enters soundArea
  592. def->distance is the distance we are trying to reduce.
  593. If there is no path through open portals from the sound to the listener, def->distance will remain
  594. set at maxDistance
  595. ===================
  596. */
  597. static const int MAX_PORTAL_TRACE_DEPTH = 10;
  598. void idSoundWorldLocal::ResolveOrigin( const int stackDepth, const soundPortalTrace_t *prevStack, const int soundArea, const float dist, const idVec3& soundOrigin, idSoundEmitterLocal *def ) {
  599. if ( dist >= def->distance ) {
  600. // we can't possibly hear the sound through this chain of portals
  601. return;
  602. }
  603. if ( soundArea == listenerArea ) {
  604. float fullDist = dist + (soundOrigin - listenerQU).LengthFast();
  605. if ( fullDist < def->distance ) {
  606. def->distance = fullDist;
  607. def->spatializedOrigin = soundOrigin;
  608. }
  609. return;
  610. }
  611. if ( stackDepth == MAX_PORTAL_TRACE_DEPTH ) {
  612. // don't spend too much time doing these calculations in big maps
  613. return;
  614. }
  615. soundPortalTrace_t newStack;
  616. newStack.portalArea = soundArea;
  617. newStack.prevStack = prevStack;
  618. int numPortals = rw->NumPortalsInArea( soundArea );
  619. for( int p = 0; p < numPortals; p++ ) {
  620. exitPortal_t re = rw->GetPortal( soundArea, p );
  621. float occlusionDistance = 0;
  622. // air blocking windows will block sound like closed doors
  623. if ( (re.blockingBits & ( PS_BLOCK_VIEW | PS_BLOCK_AIR ) ) ) {
  624. // we could just completely cut sound off, but reducing the volume works better
  625. // continue;
  626. occlusionDistance = idSoundSystemLocal::s_doorDistanceAdd.GetFloat();
  627. }
  628. // what area are we about to go look at
  629. int otherArea = re.areas[0];
  630. if ( re.areas[0] == soundArea ) {
  631. otherArea = re.areas[1];
  632. }
  633. // if this area is already in our portal chain, don't bother looking into it
  634. const soundPortalTrace_t *prev;
  635. for ( prev = prevStack ; prev ; prev = prev->prevStack ) {
  636. if ( prev->portalArea == otherArea ) {
  637. break;
  638. }
  639. }
  640. if ( prev ) {
  641. continue;
  642. }
  643. // pick a point on the portal to serve as our virtual sound origin
  644. #if 1
  645. idVec3 source;
  646. idPlane pl;
  647. re.w->GetPlane( pl );
  648. float scale;
  649. idVec3 dir = listenerQU - soundOrigin;
  650. if ( !pl.RayIntersection( soundOrigin, dir, scale ) ) {
  651. source = re.w->GetCenter();
  652. } else {
  653. source = soundOrigin + scale * dir;
  654. // if this point isn't inside the portal edges, slide it in
  655. for ( int i = 0 ; i < re.w->GetNumPoints() ; i++ ) {
  656. int j = ( i + 1 ) % re.w->GetNumPoints();
  657. idVec3 edgeDir = (*(re.w))[j].ToVec3() - (*(re.w))[i].ToVec3();
  658. idVec3 edgeNormal;
  659. edgeNormal.Cross( pl.Normal(), edgeDir );
  660. idVec3 fromVert = source - (*(re.w))[j].ToVec3();
  661. float d = edgeNormal * fromVert;
  662. if ( d > 0 ) {
  663. // move it in
  664. float div = edgeNormal.Normalize();
  665. d /= div;
  666. source -= d * edgeNormal;
  667. }
  668. }
  669. }
  670. #else
  671. // clip the ray from the listener to the center of the portal by
  672. // all the portal edge planes, then project that point (or the original if not clipped)
  673. // onto the portal plane to get the spatialized origin
  674. idVec3 start = listenerQU;
  675. idVec3 mid = re.w->GetCenter();
  676. bool wasClipped = false;
  677. for ( int i = 0 ; i < re.w->GetNumPoints() ; i++ ) {
  678. int j = ( i + 1 ) % re.w->GetNumPoints();
  679. idVec3 v1 = (*(re.w))[j].ToVec3() - soundOrigin;
  680. idVec3 v2 = (*(re.w))[i].ToVec3() - soundOrigin;
  681. v1.Normalize();
  682. v2.Normalize();
  683. idVec3 edgeNormal;
  684. edgeNormal.Cross( v1, v2 );
  685. idVec3 fromVert = start - soundOrigin;
  686. float d1 = edgeNormal * fromVert;
  687. if ( d1 > 0.0f ) {
  688. fromVert = mid - (*(re.w))[j].ToVec3();
  689. float d2 = edgeNormal * fromVert;
  690. // move it in
  691. float f = d1 / ( d1 - d2 );
  692. idVec3 clipped = start * ( 1.0f - f ) + mid * f;
  693. start = clipped;
  694. wasClipped = true;
  695. }
  696. }
  697. idVec3 source;
  698. if ( wasClipped ) {
  699. // now project it onto the portal plane
  700. idPlane pl;
  701. re.w->GetPlane( pl );
  702. float f1 = pl.Distance( start );
  703. float f2 = pl.Distance( soundOrigin );
  704. float f = f1 / ( f1 - f2 );
  705. source = start * ( 1.0f - f ) + soundOrigin * f;
  706. } else {
  707. source = soundOrigin;
  708. }
  709. #endif
  710. idVec3 tlen = source - soundOrigin;
  711. float tlenLength = tlen.LengthFast();
  712. ResolveOrigin( stackDepth+1, &newStack, otherArea, dist+tlenLength+occlusionDistance, source, def );
  713. }
  714. }
  715. /*
  716. ===================
  717. idSoundWorldLocal::PlaceListener
  718. this is called by the main thread
  719. ===================
  720. */
  721. void idSoundWorldLocal::PlaceListener( const idVec3& origin, const idMat3& axis,
  722. const int listenerId, const int gameTime, const idStr& areaName ) {
  723. int current44kHzTime;
  724. if ( !soundSystemLocal.isInitialized ) {
  725. return;
  726. }
  727. if ( pause44kHz >= 0 ){
  728. return;
  729. }
  730. if ( writeDemo ) {
  731. writeDemo->WriteInt( DS_SOUND );
  732. writeDemo->WriteInt( SCMD_PLACE_LISTENER );
  733. writeDemo->WriteVec3( origin );
  734. writeDemo->WriteMat3( axis );
  735. writeDemo->WriteInt( listenerId );
  736. writeDemo->WriteInt( gameTime );
  737. }
  738. current44kHzTime = soundSystemLocal.GetCurrent44kHzTime();
  739. // we usually expect gameTime to be increasing by 16 or 32 msec, but when
  740. // a cinematic is fast-forward skipped through, it can jump by a significant
  741. // amount, while the hardware 44kHz position will not have changed accordingly,
  742. // which would make sounds (like long character speaches) continue from the
  743. // old time. Fix this by killing all non-looping sounds
  744. if ( gameTime > gameMsec + 500 ) {
  745. OffsetSoundTime( - ( gameTime - gameMsec ) * 0.001f * 44100.0f );
  746. }
  747. gameMsec = gameTime;
  748. if ( fpa[0] ) {
  749. // exactly 30 fps so the wave file can be used for exact video frames
  750. game44kHz = idMath::FtoiFast( gameMsec * ( ( 1000.0f / 60.0f ) / 16.0f ) * 0.001f * 44100.0f );
  751. } else {
  752. // the normal 16 msec / frame
  753. game44kHz = idMath::FtoiFast( gameMsec * 0.001f * 44100.0f );
  754. }
  755. listenerPrivateId = listenerId;
  756. listenerQU = origin; // Doom units
  757. listenerPos = origin * DOOM_TO_METERS; // meters
  758. listenerAxis = axis;
  759. listenerAreaName = areaName;
  760. listenerAreaName.ToLower();
  761. if ( rw ) {
  762. listenerArea = rw->PointInArea( listenerQU ); // where are we?
  763. } else {
  764. listenerArea = 0;
  765. }
  766. if ( listenerArea < 0 ) {
  767. return;
  768. }
  769. ForegroundUpdate( current44kHzTime );
  770. }
  771. /*
  772. ==================
  773. idSoundWorldLocal::ForegroundUpdate
  774. ==================
  775. */
  776. void idSoundWorldLocal::ForegroundUpdate( int current44kHzTime ) {
  777. int j, k;
  778. idSoundEmitterLocal *def;
  779. if ( !soundSystemLocal.isInitialized ) {
  780. return;
  781. }
  782. Sys_EnterCriticalSection();
  783. // if we are recording an AVI demo, don't use hardware time
  784. if ( fpa[0] ) {
  785. current44kHzTime = lastAVI44kHz;
  786. }
  787. //
  788. // check to see if each sound is visible or not
  789. // speed up by checking maxdistance to origin
  790. // although the sound may still need to play if it has
  791. // just become occluded so it can ramp down to 0
  792. //
  793. for ( j = 1; j < emitters.Num(); j++ ) {
  794. def = emitters[j];
  795. if ( def->removeStatus >= REMOVE_STATUS_SAMPLEFINISHED ) {
  796. continue;
  797. }
  798. // see if our last channel just finished
  799. def->CheckForCompletion( current44kHzTime );
  800. if ( !def->playing ) {
  801. continue;
  802. }
  803. // update virtual origin / distance, etc
  804. def->Spatialize( listenerPos, listenerArea, rw );
  805. // per-sound debug options
  806. if ( idSoundSystemLocal::s_drawSounds.GetInteger() && rw ) {
  807. if ( def->distance < def->maxDistance || idSoundSystemLocal::s_drawSounds.GetInteger() > 1 ) {
  808. idBounds ref;
  809. ref.Clear();
  810. ref.AddPoint( idVec3( -10, -10, -10 ) );
  811. ref.AddPoint( idVec3( 10, 10, 10 ) );
  812. float vis = (1.0f - (def->distance / def->maxDistance));
  813. // draw a box
  814. rw->DebugBounds( idVec4( vis, 0.25f, vis, vis ), ref, def->origin );
  815. // draw an arrow to the audible position, possible a portal center
  816. if ( def->origin != def->spatializedOrigin ) {
  817. rw->DebugArrow( colorRed, def->origin, def->spatializedOrigin, 4 );
  818. }
  819. // draw the index
  820. idVec3 textPos = def->origin;
  821. textPos[2] -= 8;
  822. rw->DrawText( va("%i", def->index), textPos, 0.1f, idVec4(1,0,0,1), listenerAxis );
  823. textPos[2] += 8;
  824. // run through all the channels
  825. for ( k = 0; k < SOUND_MAX_CHANNELS ; k++ ) {
  826. idSoundChannel *chan = &def->channels[k];
  827. // see if we have a sound triggered on this channel
  828. if ( !chan->triggerState ) {
  829. continue;
  830. }
  831. char text[1024];
  832. float min = chan->parms.minDistance;
  833. float max = chan->parms.maxDistance;
  834. const char *defaulted = chan->leadinSample->defaultSound ? "(DEFAULTED)" : "";
  835. sprintf( text, "%s (%i/%i %i/%i)%s", chan->soundShader->GetName(), (int)def->distance,
  836. (int)def->realDistance, (int)min, (int)max, defaulted );
  837. rw->DrawText( text, textPos, 0.1f, idVec4(1,0,0,1), listenerAxis );
  838. textPos[2] += 8;
  839. }
  840. }
  841. }
  842. }
  843. Sys_LeaveCriticalSection();
  844. //
  845. // the sound meter
  846. //
  847. if ( idSoundSystemLocal::s_showLevelMeter.GetInteger() ) {
  848. const idMaterial *gui = declManager->FindMaterial( "guis/assets/soundmeter/audiobg", false );
  849. if ( gui ) {
  850. const shaderStage_t *foo = gui->GetStage(0);
  851. if ( !foo->texture.cinematic ) {
  852. ((shaderStage_t *)foo)->texture.cinematic = new idSndWindow;
  853. }
  854. }
  855. }
  856. //
  857. // optionally dump out the generated sound
  858. //
  859. if ( fpa[0] ) {
  860. AVIUpdate();
  861. }
  862. }
  863. /*
  864. ===================
  865. idSoundWorldLocal::OffsetSoundTime
  866. ===================
  867. */
  868. void idSoundWorldLocal::OffsetSoundTime( int offset44kHz ) {
  869. int i, j;
  870. for ( i = 0; i < emitters.Num(); i++ ) {
  871. if ( emitters[i] == NULL ) {
  872. continue;
  873. }
  874. for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
  875. idSoundChannel *chan = &emitters[i]->channels[ j ];
  876. if ( !chan->triggerState ) {
  877. continue;
  878. }
  879. chan->trigger44kHzTime += offset44kHz;
  880. }
  881. }
  882. }
  883. /*
  884. ===================
  885. idSoundWorldLocal::WriteToSaveGame
  886. ===================
  887. */
  888. void idSoundWorldLocal::WriteToSaveGame( idFile *savefile ) {
  889. int i, j, num, currentSoundTime;
  890. const char *name;
  891. // the game soundworld is always paused at this point, save that time down
  892. if ( pause44kHz > 0 ) {
  893. currentSoundTime = pause44kHz;
  894. } else {
  895. currentSoundTime = soundSystemLocal.GetCurrent44kHzTime();
  896. }
  897. // write listener data
  898. savefile->WriteVec3(listenerQU);
  899. savefile->WriteMat3(listenerAxis);
  900. savefile->WriteInt(listenerPrivateId);
  901. savefile->WriteInt(gameMsec);
  902. savefile->WriteInt(game44kHz);
  903. savefile->WriteInt(currentSoundTime);
  904. num = emitters.Num();
  905. savefile->WriteInt(num);
  906. for ( i = 1; i < emitters.Num(); i++ ) {
  907. idSoundEmitterLocal *def = emitters[i];
  908. if ( def->removeStatus != REMOVE_STATUS_ALIVE ) {
  909. int skip = -1;
  910. savefile->Write( &skip, sizeof( skip ) );
  911. continue;
  912. }
  913. savefile->WriteInt(i);
  914. // Write the emitter data
  915. savefile->WriteVec3( def->origin );
  916. savefile->WriteInt( def->listenerId );
  917. WriteToSaveGameSoundShaderParams( savefile, &def->parms );
  918. savefile->WriteFloat( def->amplitude );
  919. savefile->WriteInt( def->ampTime );
  920. for (int k = 0; k < SOUND_MAX_CHANNELS; k++)
  921. WriteToSaveGameSoundChannel( savefile, &def->channels[k] );
  922. savefile->WriteFloat( def->distance );
  923. savefile->WriteBool( def->hasShakes );
  924. savefile->WriteInt( def->lastValidPortalArea );
  925. savefile->WriteFloat( def->maxDistance );
  926. savefile->WriteBool( def->playing );
  927. savefile->WriteFloat( def->realDistance );
  928. savefile->WriteInt( def->removeStatus );
  929. savefile->WriteVec3( def->spatializedOrigin );
  930. // write the channel data
  931. for( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
  932. idSoundChannel *chan = &def->channels[ j ];
  933. // Write out any sound commands for this def
  934. if ( chan->triggerState && chan->soundShader && chan->leadinSample ) {
  935. savefile->WriteInt( j );
  936. // write the pointers out separately
  937. name = chan->soundShader->GetName();
  938. savefile->WriteString( name );
  939. name = chan->leadinSample->name;
  940. savefile->WriteString( name );
  941. }
  942. }
  943. // End active channels with -1
  944. int end = -1;
  945. savefile->WriteInt( end );
  946. }
  947. // new in Doom3 v1.2
  948. savefile->Write( &slowmoActive, sizeof( slowmoActive ) );
  949. savefile->Write( &slowmoSpeed, sizeof( slowmoSpeed ) );
  950. savefile->Write( &enviroSuitActive, sizeof( enviroSuitActive ) );
  951. }
  952. /*
  953. ===================
  954. idSoundWorldLocal::WriteToSaveGameSoundShaderParams
  955. ===================
  956. */
  957. void idSoundWorldLocal::WriteToSaveGameSoundShaderParams( idFile *saveGame, soundShaderParms_t *params ) {
  958. saveGame->WriteFloat(params->minDistance);
  959. saveGame->WriteFloat(params->maxDistance);
  960. saveGame->WriteFloat(params->volume);
  961. saveGame->WriteFloat(params->shakes);
  962. saveGame->WriteInt(params->soundShaderFlags);
  963. saveGame->WriteInt(params->soundClass);
  964. }
  965. /*
  966. ===================
  967. idSoundWorldLocal::WriteToSaveGameSoundChannel
  968. ===================
  969. */
  970. void idSoundWorldLocal::WriteToSaveGameSoundChannel( idFile *saveGame, idSoundChannel *ch ) {
  971. saveGame->WriteBool( ch->triggerState );
  972. saveGame->WriteUnsignedChar( 0 );
  973. saveGame->WriteUnsignedChar( 0 );
  974. saveGame->WriteUnsignedChar( 0 );
  975. saveGame->WriteInt( ch->trigger44kHzTime );
  976. saveGame->WriteInt( ch->triggerGame44kHzTime );
  977. WriteToSaveGameSoundShaderParams( saveGame, &ch->parms );
  978. saveGame->WriteInt( (int)ch->leadinSample );
  979. saveGame->WriteInt( ch->triggerChannel );
  980. saveGame->WriteInt( (int)ch->soundShader );
  981. saveGame->WriteInt( (int)ch->decoder );
  982. saveGame->WriteFloat(ch->diversity );
  983. saveGame->WriteFloat(ch->lastVolume );
  984. for (int m = 0; m < 6; m++)
  985. saveGame->WriteFloat( ch->lastV[m] );
  986. saveGame->WriteInt( ch->channelFade.fadeStart44kHz );
  987. saveGame->WriteInt( ch->channelFade.fadeEnd44kHz );
  988. saveGame->WriteFloat( ch->channelFade.fadeStartVolume );
  989. saveGame->WriteFloat( ch->channelFade.fadeEndVolume );
  990. }
  991. /*
  992. ===================
  993. idSoundWorldLocal::ReadFromSaveGame
  994. ===================
  995. */
  996. void idSoundWorldLocal::ReadFromSaveGame( idFile *savefile ) {
  997. int i, num, handle, listenerId, gameTime, channel;
  998. int savedSoundTime, currentSoundTime, soundTimeOffset;
  999. idSoundEmitterLocal *def;
  1000. idVec3 origin;
  1001. idMat3 axis;
  1002. idStr soundShader;
  1003. ClearAllSoundEmitters();
  1004. savefile->ReadVec3( origin );
  1005. savefile->ReadMat3( axis );
  1006. savefile->ReadInt( listenerId );
  1007. savefile->ReadInt( gameTime );
  1008. savefile->ReadInt( game44kHz );
  1009. savefile->ReadInt( savedSoundTime );
  1010. // we will adjust the sound starting times from those saved with the demo
  1011. currentSoundTime = soundSystemLocal.GetCurrent44kHzTime();
  1012. soundTimeOffset = currentSoundTime - savedSoundTime;
  1013. // at the end of the level load we unpause the sound world and adjust the sound starting times once more
  1014. pause44kHz = currentSoundTime;
  1015. // place listener
  1016. PlaceListener( origin, axis, listenerId, gameTime, "Undefined" );
  1017. // make sure there are enough
  1018. // slots to read the saveGame in. We don't shrink the list
  1019. // if there are extras.
  1020. savefile->ReadInt( num );
  1021. while( emitters.Num() < num ) {
  1022. def = new idSoundEmitterLocal;
  1023. def->index = emitters.Append( def );
  1024. def->soundWorld = this;
  1025. }
  1026. // read in the state
  1027. for ( i = 1; i < num; i++ ) {
  1028. savefile->ReadInt( handle );
  1029. if ( handle < 0 ) {
  1030. continue;
  1031. }
  1032. if ( handle != i ) {
  1033. common->Error( "idSoundWorldLocal::ReadFromSaveGame: index mismatch" );
  1034. }
  1035. def = emitters[i];
  1036. def->removeStatus = REMOVE_STATUS_ALIVE;
  1037. def->playing = true; // may be reset by the first UpdateListener
  1038. savefile->ReadVec3( def->origin );
  1039. savefile->ReadInt( def->listenerId );
  1040. ReadFromSaveGameSoundShaderParams( savefile, &def->parms );
  1041. savefile->ReadFloat( def->amplitude );
  1042. savefile->ReadInt( def->ampTime );
  1043. for (int k = 0; k < SOUND_MAX_CHANNELS; k++)
  1044. ReadFromSaveGameSoundChannel( savefile, &def->channels[k] );
  1045. savefile->ReadFloat( def->distance );
  1046. savefile->ReadBool( def->hasShakes );
  1047. savefile->ReadInt( def->lastValidPortalArea );
  1048. savefile->ReadFloat( def->maxDistance );
  1049. savefile->ReadBool( def->playing );
  1050. savefile->ReadFloat( def->realDistance );
  1051. savefile->ReadInt( (int&)def->removeStatus );
  1052. savefile->ReadVec3( def->spatializedOrigin );
  1053. // read the individual channels
  1054. savefile->ReadInt( channel );
  1055. while ( channel >= 0 ) {
  1056. if ( channel > SOUND_MAX_CHANNELS ) {
  1057. common->Error( "idSoundWorldLocal::ReadFromSaveGame: channel > SOUND_MAX_CHANNELS" );
  1058. }
  1059. idSoundChannel *chan = &def->channels[channel];
  1060. if ( chan->decoder != NULL ) {
  1061. // The pointer in the save file is not valid, so we grab a new one
  1062. chan->decoder = idSampleDecoder::Alloc();
  1063. }
  1064. savefile->ReadString( soundShader );
  1065. chan->soundShader = declManager->FindSound( soundShader );
  1066. savefile->ReadString( soundShader );
  1067. // load savegames with s_noSound 1
  1068. if ( soundSystemLocal.soundCache ) {
  1069. chan->leadinSample = soundSystemLocal.soundCache->FindSound( soundShader, false );
  1070. } else {
  1071. chan->leadinSample = NULL;
  1072. }
  1073. // adjust the hardware start time
  1074. chan->trigger44kHzTime += soundTimeOffset;
  1075. // make sure we start up the hardware voice if needed
  1076. chan->triggered = chan->triggerState;
  1077. chan->openalStreamingOffset = currentSoundTime - chan->trigger44kHzTime;
  1078. // adjust the hardware fade time
  1079. if ( chan->channelFade.fadeStart44kHz != 0 ) {
  1080. chan->channelFade.fadeStart44kHz += soundTimeOffset;
  1081. chan->channelFade.fadeEnd44kHz += soundTimeOffset;
  1082. }
  1083. // next command
  1084. savefile->ReadInt( channel );
  1085. }
  1086. }
  1087. if ( session->GetSaveGameVersion() >= 17 ) {
  1088. savefile->Read( &slowmoActive, sizeof( slowmoActive ) );
  1089. savefile->Read( &slowmoSpeed, sizeof( slowmoSpeed ) );
  1090. savefile->Read( &enviroSuitActive, sizeof( enviroSuitActive ) );
  1091. } else {
  1092. slowmoActive = false;
  1093. slowmoSpeed = 0;
  1094. enviroSuitActive = false;
  1095. }
  1096. }
  1097. /*
  1098. ===================
  1099. idSoundWorldLocal::ReadFromSaveGameSoundShaderParams
  1100. ===================
  1101. */
  1102. void idSoundWorldLocal::ReadFromSaveGameSoundShaderParams( idFile *saveGame, soundShaderParms_t *params ) {
  1103. saveGame->ReadFloat(params->minDistance);
  1104. saveGame->ReadFloat(params->maxDistance);
  1105. saveGame->ReadFloat(params->volume);
  1106. saveGame->ReadFloat(params->shakes);
  1107. saveGame->ReadInt(params->soundShaderFlags);
  1108. saveGame->ReadInt(params->soundClass);
  1109. }
  1110. /*
  1111. ===================
  1112. idSoundWorldLocal::ReadFromSaveGameSoundChannel
  1113. ===================
  1114. */
  1115. void idSoundWorldLocal::ReadFromSaveGameSoundChannel( idFile *saveGame, idSoundChannel *ch ) {
  1116. saveGame->ReadBool( ch->triggerState );
  1117. char tmp;
  1118. saveGame->ReadChar( tmp );
  1119. saveGame->ReadChar( tmp );
  1120. saveGame->ReadChar( tmp );
  1121. saveGame->ReadInt( ch->trigger44kHzTime );
  1122. saveGame->ReadInt( ch->triggerGame44kHzTime );
  1123. ReadFromSaveGameSoundShaderParams( saveGame, &ch->parms );
  1124. saveGame->ReadInt( (int&)ch->leadinSample );
  1125. saveGame->ReadInt( ch->triggerChannel );
  1126. saveGame->ReadInt( (int&)ch->soundShader );
  1127. saveGame->ReadInt( (int&)ch->decoder );
  1128. saveGame->ReadFloat(ch->diversity );
  1129. saveGame->ReadFloat(ch->lastVolume );
  1130. for (int m = 0; m < 6; m++)
  1131. saveGame->ReadFloat( ch->lastV[m] );
  1132. saveGame->ReadInt( ch->channelFade.fadeStart44kHz );
  1133. saveGame->ReadInt( ch->channelFade.fadeEnd44kHz );
  1134. saveGame->ReadFloat( ch->channelFade.fadeStartVolume );
  1135. saveGame->ReadFloat( ch->channelFade.fadeEndVolume );
  1136. }
  1137. /*
  1138. ===================
  1139. idSoundWorldLocal::EmitterForIndex
  1140. ===================
  1141. */
  1142. idSoundEmitter *idSoundWorldLocal::EmitterForIndex( int index ) {
  1143. if ( index == 0 ) {
  1144. return NULL;
  1145. }
  1146. if ( index >= emitters.Num() ) {
  1147. common->Error( "idSoundWorldLocal::EmitterForIndex: %i > %i", index, emitters.Num() );
  1148. }
  1149. return emitters[index];
  1150. }
  1151. /*
  1152. ===============
  1153. idSoundWorldLocal::StopAllSounds
  1154. this is called from the main thread
  1155. ===============
  1156. */
  1157. void idSoundWorldLocal::StopAllSounds() {
  1158. for ( int i = 0; i < emitters.Num(); i++ ) {
  1159. idSoundEmitterLocal * def = emitters[i];
  1160. def->StopSound( SCHANNEL_ANY );
  1161. }
  1162. }
  1163. /*
  1164. ===============
  1165. idSoundWorldLocal::Pause
  1166. ===============
  1167. */
  1168. void idSoundWorldLocal::Pause( void ) {
  1169. if ( pause44kHz >= 0 ) {
  1170. common->Warning( "idSoundWorldLocal::Pause: already paused" );
  1171. return;
  1172. }
  1173. pause44kHz = soundSystemLocal.GetCurrent44kHzTime();
  1174. }
  1175. /*
  1176. ===============
  1177. idSoundWorldLocal::UnPause
  1178. ===============
  1179. */
  1180. void idSoundWorldLocal::UnPause( void ) {
  1181. int offset44kHz;
  1182. if ( pause44kHz < 0 ) {
  1183. common->Warning( "idSoundWorldLocal::UnPause: not paused" );
  1184. return;
  1185. }
  1186. offset44kHz = soundSystemLocal.GetCurrent44kHzTime() - pause44kHz;
  1187. OffsetSoundTime( offset44kHz );
  1188. pause44kHz = -1;
  1189. }
  1190. /*
  1191. ===============
  1192. idSoundWorldLocal::IsPaused
  1193. ===============
  1194. */
  1195. bool idSoundWorldLocal::IsPaused( void ) {
  1196. return ( pause44kHz >= 0 );
  1197. }
  1198. /*
  1199. ===============
  1200. idSoundWorldLocal::PlayShaderDirectly
  1201. start a music track
  1202. this is called from the main thread
  1203. ===============
  1204. */
  1205. void idSoundWorldLocal::PlayShaderDirectly( const char *shaderName, int channel ) {
  1206. if ( localSound && channel == -1 ) {
  1207. localSound->StopSound( SCHANNEL_ANY );
  1208. } else if ( localSound ) {
  1209. localSound->StopSound( channel );
  1210. }
  1211. if ( !shaderName || !shaderName[0] ) {
  1212. return;
  1213. }
  1214. const idSoundShader *shader = declManager->FindSound( shaderName );
  1215. if ( !shader ) {
  1216. return;
  1217. }
  1218. if ( !localSound ) {
  1219. localSound = AllocLocalSoundEmitter();
  1220. }
  1221. static idRandom rnd;
  1222. float diversity = rnd.RandomFloat();
  1223. localSound->StartSound( shader, ( channel == -1 ) ? SCHANNEL_ONE : channel , diversity, SSF_GLOBAL );
  1224. // in case we are at the console without a game doing updates, force an update
  1225. ForegroundUpdate( soundSystemLocal.GetCurrent44kHzTime() );
  1226. }
  1227. /*
  1228. ===============
  1229. idSoundWorldLocal::CalcEars
  1230. Determine the volumes from each speaker for a given sound emitter
  1231. ===============
  1232. */
  1233. void idSoundWorldLocal::CalcEars( int numSpeakers, idVec3 spatializedOrigin, idVec3 listenerPos,
  1234. idMat3 listenerAxis, float ears[6], float spatialize ) {
  1235. idVec3 svec = spatializedOrigin - listenerPos;
  1236. idVec3 ovec;
  1237. ovec[0] = svec * listenerAxis[0];
  1238. ovec[1] = svec * listenerAxis[1];
  1239. ovec[2] = svec * listenerAxis[2];
  1240. ovec.Normalize();
  1241. if ( numSpeakers == 6 ) {
  1242. static idVec3 speakerVector[6] = {
  1243. idVec3( 0.707f, 0.707f, 0.0f ), // front left
  1244. idVec3( 0.707f, -0.707f, 0.0f ), // front right
  1245. idVec3( 0.707f, 0.0f, 0.0f ), // front center
  1246. idVec3( 0.0f, 0.0f, 0.0f ), // sub
  1247. idVec3( -0.707f, 0.707f, 0.0f ), // rear left
  1248. idVec3( -0.707f, -0.707f, 0.0f ) // rear right
  1249. };
  1250. for ( int i = 0 ; i < 6 ; i++ ) {
  1251. if ( i == 3 ) {
  1252. ears[i] = idSoundSystemLocal::s_subFraction.GetFloat(); // subwoofer
  1253. continue;
  1254. }
  1255. float dot = ovec * speakerVector[i];
  1256. ears[i] = (idSoundSystemLocal::s_dotbias6.GetFloat() + dot) / ( 1.0f + idSoundSystemLocal::s_dotbias6.GetFloat() );
  1257. if ( ears[i] < idSoundSystemLocal::s_minVolume6.GetFloat() ) {
  1258. ears[i] = idSoundSystemLocal::s_minVolume6.GetFloat();
  1259. }
  1260. }
  1261. } else {
  1262. float dot = ovec.y;
  1263. float dotBias = idSoundSystemLocal::s_dotbias2.GetFloat();
  1264. // when we are inside the minDistance, start reducing the amount of spatialization
  1265. // so NPC voices right in front of us aren't quieter that off to the side
  1266. dotBias += ( idSoundSystemLocal::s_spatializationDecay.GetFloat() - dotBias ) * ( 1.0f - spatialize );
  1267. ears[0] = (idSoundSystemLocal::s_dotbias2.GetFloat() + dot) / ( 1.0f + dotBias );
  1268. ears[1] = (idSoundSystemLocal::s_dotbias2.GetFloat() - dot) / ( 1.0f + dotBias );
  1269. if ( ears[0] < idSoundSystemLocal::s_minVolume2.GetFloat() ) {
  1270. ears[0] = idSoundSystemLocal::s_minVolume2.GetFloat();
  1271. }
  1272. if ( ears[1] < idSoundSystemLocal::s_minVolume2.GetFloat() ) {
  1273. ears[1] = idSoundSystemLocal::s_minVolume2.GetFloat();
  1274. }
  1275. ears[2] =
  1276. ears[3] =
  1277. ears[4] =
  1278. ears[5] = 0.0f;
  1279. }
  1280. }
  1281. /*
  1282. ===============
  1283. idSoundWorldLocal::AddChannelContribution
  1284. Adds the contribution of a single sound channel to finalMixBuffer
  1285. this is called from the async thread
  1286. Mixes MIXBUFFER_SAMPLES samples starting at current44kHz sample time into
  1287. finalMixBuffer
  1288. ===============
  1289. */
  1290. void idSoundWorldLocal::AddChannelContribution( idSoundEmitterLocal *sound, idSoundChannel *chan,
  1291. int current44kHz, int numSpeakers, float *finalMixBuffer ) {
  1292. int j;
  1293. float volume;
  1294. //
  1295. // get the sound definition and parameters from the entity
  1296. //
  1297. soundShaderParms_t *parms = &chan->parms;
  1298. // assume we have a sound triggered on this channel
  1299. assert( chan->triggerState );
  1300. // fetch the actual wave file and see if it's valid
  1301. idSoundSample *sample = chan->leadinSample;
  1302. if ( sample == NULL ) {
  1303. return;
  1304. }
  1305. // if you don't want to hear all the beeps from missing sounds
  1306. if ( sample->defaultSound && !idSoundSystemLocal::s_playDefaultSound.GetBool() ) {
  1307. return;
  1308. }
  1309. // get the actual shader
  1310. const idSoundShader *shader = chan->soundShader;
  1311. // this might happen if the foreground thread just deleted the sound emitter
  1312. if ( !shader ) {
  1313. return;
  1314. }
  1315. float maxd = parms->maxDistance;
  1316. float mind = parms->minDistance;
  1317. int mask = shader->speakerMask;
  1318. bool omni = ( parms->soundShaderFlags & SSF_OMNIDIRECTIONAL) != 0;
  1319. bool looping = ( parms->soundShaderFlags & SSF_LOOPING ) != 0;
  1320. bool global = ( parms->soundShaderFlags & SSF_GLOBAL ) != 0;
  1321. bool noOcclusion = ( parms->soundShaderFlags & SSF_NO_OCCLUSION ) || !idSoundSystemLocal::s_useOcclusion.GetBool();
  1322. // speed goes from 1 to 0.2
  1323. if ( idSoundSystemLocal::s_slowAttenuate.GetBool() && slowmoActive && !chan->disallowSlow ) {
  1324. maxd *= slowmoSpeed;
  1325. }
  1326. // stereo samples are always omni
  1327. if ( sample->objectInfo.nChannels == 2 ) {
  1328. omni = true;
  1329. }
  1330. // if the sound is playing from the current listener, it will not be spatialized at all
  1331. if ( sound->listenerId == listenerPrivateId ) {
  1332. global = true;
  1333. }
  1334. //
  1335. // see if it's in range
  1336. //
  1337. // convert volumes from decibels to float scale
  1338. // leadin volume scale for shattering lights
  1339. // this isn't exactly correct, because the modified volume will get applied to
  1340. // some initial chunk of the loop as well, because the volume is scaled for the
  1341. // entire mix buffer
  1342. if ( shader->leadinVolume && current44kHz - chan->trigger44kHzTime < sample->LengthIn44kHzSamples() ) {
  1343. volume = soundSystemLocal.dB2Scale( shader->leadinVolume );
  1344. } else {
  1345. volume = soundSystemLocal.dB2Scale( parms->volume );
  1346. }
  1347. // global volume scale
  1348. volume *= soundSystemLocal.dB2Scale( idSoundSystemLocal::s_volume.GetFloat() );
  1349. // volume fading
  1350. float fadeDb = chan->channelFade.FadeDbAt44kHz( current44kHz );
  1351. volume *= soundSystemLocal.dB2Scale( fadeDb );
  1352. fadeDb = soundClassFade[parms->soundClass].FadeDbAt44kHz( current44kHz );
  1353. volume *= soundSystemLocal.dB2Scale( fadeDb );
  1354. //
  1355. // if it's a global sound then
  1356. // it's not affected by distance or occlusion
  1357. //
  1358. float spatialize = 1;
  1359. idVec3 spatializedOriginInMeters;
  1360. if ( !global ) {
  1361. float dlen;
  1362. if ( noOcclusion ) {
  1363. // use the real origin and distance
  1364. spatializedOriginInMeters = sound->origin * DOOM_TO_METERS;
  1365. dlen = sound->realDistance;
  1366. } else {
  1367. // use the possibly portal-occluded origin and distance
  1368. spatializedOriginInMeters = sound->spatializedOrigin * DOOM_TO_METERS;
  1369. dlen = sound->distance;
  1370. }
  1371. // reduce volume based on distance
  1372. if ( dlen >= maxd ) {
  1373. volume = 0.0f;
  1374. } else if ( dlen > mind ) {
  1375. float frac = idMath::ClampFloat( 0.0f, 1.0f, 1.0f - ((dlen - mind) / (maxd - mind)));
  1376. if ( idSoundSystemLocal::s_quadraticFalloff.GetBool() ) {
  1377. frac *= frac;
  1378. }
  1379. volume *= frac;
  1380. } else if ( mind > 0.0f ) {
  1381. // we tweak the spatialization bias when you are inside the minDistance
  1382. spatialize = dlen / mind;
  1383. }
  1384. }
  1385. //
  1386. // if it is a private sound, set the volume to zero
  1387. // unless we match the listenerId
  1388. //
  1389. if ( parms->soundShaderFlags & SSF_PRIVATE_SOUND ) {
  1390. if ( sound->listenerId != listenerPrivateId ) {
  1391. volume = 0;
  1392. }
  1393. }
  1394. if ( parms->soundShaderFlags & SSF_ANTI_PRIVATE_SOUND ) {
  1395. if ( sound->listenerId == listenerPrivateId ) {
  1396. volume = 0;
  1397. }
  1398. }
  1399. //
  1400. // do we have anything to add?
  1401. //
  1402. if ( volume < SND_EPSILON && chan->lastVolume < SND_EPSILON ) {
  1403. return;
  1404. }
  1405. chan->lastVolume = volume;
  1406. //
  1407. // fetch the sound from the cache as 44kHz, 16 bit samples
  1408. //
  1409. int offset = current44kHz - chan->trigger44kHzTime;
  1410. float inputSamples[MIXBUFFER_SAMPLES*2+16];
  1411. float *alignedInputSamples = (float *) ( ( ( (int)inputSamples ) + 15 ) & ~15 );
  1412. //
  1413. // allocate and initialize hardware source
  1414. //
  1415. if ( idSoundSystemLocal::useOpenAL && sound->removeStatus < REMOVE_STATUS_SAMPLEFINISHED ) {
  1416. if ( !alIsSource( chan->openalSource ) ) {
  1417. chan->openalSource = soundSystemLocal.AllocOpenALSource( chan, !chan->leadinSample->hardwareBuffer || !chan->soundShader->entries[0]->hardwareBuffer || looping, chan->leadinSample->objectInfo.nChannels == 2 );
  1418. }
  1419. if ( alIsSource( chan->openalSource ) ) {
  1420. // stop source if needed..
  1421. if ( chan->triggered ) {
  1422. alSourceStop( chan->openalSource );
  1423. }
  1424. // update source parameters
  1425. if ( global || omni ) {
  1426. alSourcei( chan->openalSource, AL_SOURCE_RELATIVE, AL_TRUE);
  1427. alSource3f( chan->openalSource, AL_POSITION, 0.0f, 0.0f, 0.0f );
  1428. alSourcef( chan->openalSource, AL_GAIN, ( volume ) < ( 1.0f ) ? ( volume ) : ( 1.0f ) );
  1429. } else {
  1430. alSourcei( chan->openalSource, AL_SOURCE_RELATIVE, AL_FALSE);
  1431. alSource3f( chan->openalSource, AL_POSITION, -spatializedOriginInMeters.y, spatializedOriginInMeters.z, -spatializedOriginInMeters.x );
  1432. alSourcef( chan->openalSource, AL_GAIN, ( volume ) < ( 1.0f ) ? ( volume ) : ( 1.0f ) );
  1433. }
  1434. alSourcei( chan->openalSource, AL_LOOPING, ( looping && chan->soundShader->entries[0]->hardwareBuffer ) ? AL_TRUE : AL_FALSE );
  1435. #if !defined(MACOS_X)
  1436. alSourcef( chan->openalSource, AL_REFERENCE_DISTANCE, mind );
  1437. alSourcef( chan->openalSource, AL_MAX_DISTANCE, maxd );
  1438. #endif
  1439. alSourcef( chan->openalSource, AL_PITCH, ( slowmoActive && !chan->disallowSlow ) ? ( slowmoSpeed ) : ( 1.0f ) );
  1440. #if ID_OPENAL
  1441. long lOcclusion = ( enviroSuitActive ? -1150 : 0);
  1442. if ( soundSystemLocal.alEAXSet ) {
  1443. soundSystemLocal.alEAXSet( &EAXPROPERTYID_EAX_Source, EAXSOURCE_OCCLUSION, chan->openalSource, &lOcclusion, sizeof(lOcclusion) );
  1444. }
  1445. #endif
  1446. if ( ( !looping && chan->leadinSample->hardwareBuffer ) || ( looping && chan->soundShader->entries[0]->hardwareBuffer ) ) {
  1447. // handle uncompressed (non streaming) single shot and looping sounds
  1448. if ( chan->triggered ) {
  1449. alSourcei( chan->openalSource, AL_BUFFER, looping ? chan->soundShader->entries[0]->openalBuffer : chan->leadinSample->openalBuffer );
  1450. }
  1451. } else {
  1452. ALint finishedbuffers;
  1453. ALuint buffers[3];
  1454. // handle streaming sounds (decode on the fly) both single shot AND looping
  1455. if ( chan->triggered ) {
  1456. alSourcei( chan->openalSource, AL_BUFFER, NULL );
  1457. alDeleteBuffers( 3, &chan->lastopenalStreamingBuffer[0] );
  1458. chan->lastopenalStreamingBuffer[0] = chan->openalStreamingBuffer[0];
  1459. chan->lastopenalStreamingBuffer[1] = chan->openalStreamingBuffer[1];
  1460. chan->lastopenalStreamingBuffer[2] = chan->openalStreamingBuffer[2];
  1461. alGenBuffers( 3, &chan->openalStreamingBuffer[0] );
  1462. if ( soundSystemLocal.alEAXSetBufferMode ) {
  1463. soundSystemLocal.alEAXSetBufferMode( 3, &chan->openalStreamingBuffer[0], alGetEnumValue( ID_ALCHAR "AL_STORAGE_ACCESSIBLE" ) );
  1464. }
  1465. buffers[0] = chan->openalStreamingBuffer[0];
  1466. buffers[1] = chan->openalStreamingBuffer[1];
  1467. buffers[2] = chan->openalStreamingBuffer[2];
  1468. finishedbuffers = 3;
  1469. } else {
  1470. alGetSourcei( chan->openalSource, AL_BUFFERS_PROCESSED, &finishedbuffers );
  1471. alSourceUnqueueBuffers( chan->openalSource, finishedbuffers, &buffers[0] );
  1472. if ( finishedbuffers == 3 ) {
  1473. chan->triggered = true;
  1474. }
  1475. }
  1476. for ( j = 0; j < finishedbuffers; j++ ) {
  1477. chan->GatherChannelSamples( chan->openalStreamingOffset * sample->objectInfo.nChannels, MIXBUFFER_SAMPLES * sample->objectInfo.nChannels, alignedInputSamples );
  1478. for ( int i = 0; i < ( MIXBUFFER_SAMPLES * sample->objectInfo.nChannels ); i++ ) {
  1479. if ( alignedInputSamples[i] < -32768.0f )
  1480. ((short *)alignedInputSamples)[i] = -32768;
  1481. else if ( alignedInputSamples[i] > 32767.0f )
  1482. ((short *)alignedInputSamples)[i] = 32767;
  1483. else
  1484. ((short *)alignedInputSamples)[i] = idMath::FtoiFast( alignedInputSamples[i] );
  1485. }
  1486. alBufferData( buffers[j], chan->leadinSample->objectInfo.nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, alignedInputSamples, MIXBUFFER_SAMPLES * sample->objectInfo.nChannels * sizeof( short ), 44100 );
  1487. chan->openalStreamingOffset += MIXBUFFER_SAMPLES;
  1488. }
  1489. if ( finishedbuffers ) {
  1490. alSourceQueueBuffers( chan->openalSource, finishedbuffers, &buffers[0] );
  1491. }
  1492. }
  1493. // (re)start if needed..
  1494. if ( chan->triggered ) {
  1495. alSourcePlay( chan->openalSource );
  1496. chan->triggered = false;
  1497. }
  1498. }
  1499. } else {
  1500. if ( slowmoActive && !chan->disallowSlow ) {
  1501. idSlowChannel slow = sound->GetSlowChannel( chan );
  1502. slow.AttachSoundChannel( chan );
  1503. if ( sample->objectInfo.nChannels == 2 ) {
  1504. // need to add a stereo path, but very few samples go through this
  1505. memset( alignedInputSamples, 0, sizeof( alignedInputSamples[0] ) * MIXBUFFER_SAMPLES * 2 );
  1506. } else {
  1507. slow.GatherChannelSamples( offset, MIXBUFFER_SAMPLES, alignedInputSamples );
  1508. }
  1509. sound->SetSlowChannel( chan, slow );
  1510. } else {
  1511. sound->ResetSlowChannel( chan );
  1512. // if we are getting a stereo sample adjust accordingly
  1513. if ( sample->objectInfo.nChannels == 2 ) {
  1514. // we should probably check to make sure any looping is also to a stereo sample...
  1515. chan->GatherChannelSamples( offset*2, MIXBUFFER_SAMPLES*2, alignedInputSamples );
  1516. } else {
  1517. chan->GatherChannelSamples( offset, MIXBUFFER_SAMPLES, alignedInputSamples );
  1518. }
  1519. }
  1520. //
  1521. // work out the left / right ear values
  1522. //
  1523. float ears[6];
  1524. if ( global || omni ) {
  1525. // same for all speakers
  1526. for ( int i = 0 ; i < 6 ; i++ ) {
  1527. ears[i] = idSoundSystemLocal::s_globalFraction.GetFloat() * volume;
  1528. }
  1529. ears[3] = idSoundSystemLocal::s_subFraction.GetFloat() * volume; // subwoofer
  1530. } else {
  1531. CalcEars( numSpeakers, spatializedOriginInMeters, listenerPos, listenerAxis, ears, spatialize );
  1532. for ( int i = 0 ; i < 6 ; i++ ) {
  1533. ears[i] *= volume;
  1534. }
  1535. }
  1536. // if the mask is 0, it really means do every channel
  1537. if ( !mask ) {
  1538. mask = 255;
  1539. }
  1540. // cleared mask bits set the mix volume to zero
  1541. for ( int i = 0 ; i < 6 ; i++ ) {
  1542. if ( !(mask & ( 1 << i ) ) ) {
  1543. ears[i] = 0;
  1544. }
  1545. }
  1546. // if sounds are generally normalized, using a mixing volume over 1.0 will
  1547. // almost always cause clipping noise. If samples aren't normalized, there
  1548. // is a good call to allow overvolumes
  1549. if ( idSoundSystemLocal::s_clipVolumes.GetBool() && !( parms->soundShaderFlags & SSF_UNCLAMPED ) ) {
  1550. for ( int i = 0 ; i < 6 ; i++ ) {
  1551. if ( ears[i] > 1.0f ) {
  1552. ears[i] = 1.0f;
  1553. }
  1554. }
  1555. }
  1556. // if this is the very first mixing block, set the lastV
  1557. // to the current volume
  1558. if ( current44kHz == chan->trigger44kHzTime ) {
  1559. for ( j = 0 ; j < 6 ; j++ ) {
  1560. chan->lastV[j] = ears[j];
  1561. }
  1562. }
  1563. if ( numSpeakers == 6 ) {
  1564. if ( sample->objectInfo.nChannels == 1 ) {
  1565. SIMDProcessor->MixSoundSixSpeakerMono( finalMixBuffer, alignedInputSamples, MIXBUFFER_SAMPLES, chan->lastV, ears );
  1566. } else {
  1567. SIMDProcessor->MixSoundSixSpeakerStereo( finalMixBuffer, alignedInputSamples, MIXBUFFER_SAMPLES, chan->lastV, ears );
  1568. }
  1569. } else {
  1570. if ( sample->objectInfo.nChannels == 1 ) {
  1571. SIMDProcessor->MixSoundTwoSpeakerMono( finalMixBuffer, alignedInputSamples, MIXBUFFER_SAMPLES, chan->lastV, ears );
  1572. } else {
  1573. SIMDProcessor->MixSoundTwoSpeakerStereo( finalMixBuffer, alignedInputSamples, MIXBUFFER_SAMPLES, chan->lastV, ears );
  1574. }
  1575. }
  1576. for ( j = 0 ; j < 6 ; j++ ) {
  1577. chan->lastV[j] = ears[j];
  1578. }
  1579. }
  1580. soundSystemLocal.soundStats.activeSounds++;
  1581. }
  1582. /*
  1583. ===============
  1584. idSoundWorldLocal::FindAmplitude
  1585. this is called from the main thread
  1586. if listenerPosition is NULL, this is being used for shader parameters,
  1587. like flashing lights and glows based on sound level. Otherwise, it is being used for
  1588. the screen-shake on a player.
  1589. This doesn't do the portal-occlusion currently, because it would have to reset all the defs
  1590. which would be problematic in multiplayer
  1591. ===============
  1592. */
  1593. float idSoundWorldLocal::FindAmplitude( idSoundEmitterLocal *sound, const int localTime, const idVec3 *listenerPosition,
  1594. const s_channelType channel, bool shakesOnly ) {
  1595. int i, j;
  1596. soundShaderParms_t *parms;
  1597. float volume;
  1598. int activeChannelCount;
  1599. static const int AMPLITUDE_SAMPLES = MIXBUFFER_SAMPLES/8;
  1600. float sourceBuffer[AMPLITUDE_SAMPLES];
  1601. float sumBuffer[AMPLITUDE_SAMPLES];
  1602. // work out the distance from the listener to the emitter
  1603. float dlen;
  1604. if ( !sound->playing ) {
  1605. return 0;
  1606. }
  1607. if ( listenerPosition ) {
  1608. // this doesn't do the portal spatialization
  1609. idVec3 dist = sound->origin - *listenerPosition;
  1610. dlen = dist.Length();
  1611. dlen *= DOOM_TO_METERS;
  1612. } else {
  1613. dlen = 1;
  1614. }
  1615. activeChannelCount = 0;
  1616. for ( i = 0; i < SOUND_MAX_CHANNELS ; i++ ) {
  1617. idSoundChannel *chan = &sound->channels[ i ];
  1618. if ( !chan->triggerState ) {
  1619. continue;
  1620. }
  1621. if ( channel != SCHANNEL_ANY && chan->triggerChannel != channel) {
  1622. continue;
  1623. }
  1624. parms = &chan->parms;
  1625. int localTriggerTimes = chan->trigger44kHzTime;
  1626. bool looping = ( parms->soundShaderFlags & SSF_LOOPING ) != 0;
  1627. // check for screen shakes
  1628. float shakes = parms->shakes;
  1629. if ( shakesOnly && shakes <= 0.0f ) {
  1630. continue;
  1631. }
  1632. //
  1633. // calculate volume
  1634. //
  1635. if ( !listenerPosition ) {
  1636. // just look at the raw wav data for light shader evaluation
  1637. volume = 1.0;
  1638. } else {
  1639. volume = parms->volume;
  1640. volume = soundSystemLocal.dB2Scale( volume );
  1641. if ( shakesOnly ) {
  1642. volume *= shakes;
  1643. }
  1644. if ( listenerPosition && !( parms->soundShaderFlags & SSF_GLOBAL ) ) {
  1645. // check for overrides
  1646. float maxd = parms->maxDistance;
  1647. float mind = parms->minDistance;
  1648. if ( dlen >= maxd ) {
  1649. volume = 0.0f;
  1650. } else if ( dlen > mind ) {
  1651. float frac = idMath::ClampFloat( 0, 1, 1.0f - ((dlen - mind) / (maxd - mind)));
  1652. if ( idSoundSystemLocal::s_quadraticFalloff.GetBool() ) {
  1653. frac *= frac;
  1654. }
  1655. volume *= frac;
  1656. }
  1657. }
  1658. }
  1659. if ( volume <= 0 ) {
  1660. continue;
  1661. }
  1662. //
  1663. // fetch the sound from the cache
  1664. // this doesn't handle stereo samples correctly...
  1665. //
  1666. if ( !listenerPosition && chan->parms.soundShaderFlags & SSF_NO_FLICKER ) {
  1667. // the NO_FLICKER option is to allow a light to still play a sound, but
  1668. // not have it effect the intensity
  1669. for ( j = 0 ; j < (AMPLITUDE_SAMPLES); j++ ) {
  1670. sourceBuffer[j] = j & 1 ? 32767.0f : -32767.0f;
  1671. }
  1672. } else {
  1673. int offset = (localTime - localTriggerTimes); // offset in samples
  1674. int size = ( looping ? chan->soundShader->entries[0]->LengthIn44kHzSamples() : chan->leadinSample->LengthIn44kHzSamples() );
  1675. short *amplitudeData = (short *)( looping ? chan->soundShader->entries[0]->amplitudeData : chan->leadinSample->amplitudeData );
  1676. if ( amplitudeData ) {
  1677. // when the amplitudeData is present use that fill a dummy sourceBuffer
  1678. // this is to allow for amplitude based effect on hardware audio solutions
  1679. if ( looping ) offset %= size;
  1680. if ( offset < size ) {
  1681. for ( j = 0 ; j < (AMPLITUDE_SAMPLES); j++ ) {
  1682. sourceBuffer[j] = j & 1 ? amplitudeData[ ( offset / 512 ) * 2 ] : amplitudeData[ ( offset / 512 ) * 2 + 1 ];
  1683. }
  1684. }
  1685. } else {
  1686. // get actual sample data
  1687. chan->GatherChannelSamples( offset, AMPLITUDE_SAMPLES, sourceBuffer );
  1688. }
  1689. }
  1690. activeChannelCount++;
  1691. if ( activeChannelCount == 1 ) {
  1692. // store to the buffer
  1693. for( j = 0; j < AMPLITUDE_SAMPLES; j++ ) {
  1694. sumBuffer[ j ] = volume * sourceBuffer[ j ];
  1695. }
  1696. } else {
  1697. // add to the buffer
  1698. for( j = 0; j < AMPLITUDE_SAMPLES; j++ ) {
  1699. sumBuffer[ j ] += volume * sourceBuffer[ j ];
  1700. }
  1701. }
  1702. }
  1703. if ( activeChannelCount == 0 ) {
  1704. return 0.0;
  1705. }
  1706. float high = -32767.0f;
  1707. float low = 32767.0f;
  1708. // use a 20th of a second
  1709. for( i = 0; i < (AMPLITUDE_SAMPLES); i++ ) {
  1710. float fabval = sumBuffer[i];
  1711. if ( high < fabval ) {
  1712. high = fabval;
  1713. }
  1714. if ( low > fabval ) {
  1715. low = fabval;
  1716. }
  1717. }
  1718. float sout;
  1719. sout = atan( (high - low) / 32767.0f) / DEG2RAD(45);
  1720. return sout;
  1721. }
  1722. /*
  1723. =================
  1724. idSoundWorldLocal::FadeSoundClasses
  1725. fade all sounds in the world with a given shader soundClass
  1726. to is in Db (sigh), over is in seconds
  1727. =================
  1728. */
  1729. void idSoundWorldLocal::FadeSoundClasses( const int soundClass, const float to, const float over ) {
  1730. if ( soundClass < 0 || soundClass >= SOUND_MAX_CLASSES ) {
  1731. common->Error( "idSoundWorldLocal::FadeSoundClasses: bad soundClass %i", soundClass );
  1732. }
  1733. idSoundFade *fade = &soundClassFade[ soundClass ];
  1734. int length44kHz = soundSystemLocal.MillisecondsToSamples( over * 1000 );
  1735. // if it is already fading to this volume at this rate, don't change it
  1736. if ( fade->fadeEndVolume == to &&
  1737. fade->fadeEnd44kHz - fade->fadeStart44kHz == length44kHz ) {
  1738. return;
  1739. }
  1740. int start44kHz;
  1741. if ( fpa[0] ) {
  1742. // if we are recording an AVI demo, don't use hardware time
  1743. start44kHz = lastAVI44kHz + MIXBUFFER_SAMPLES;
  1744. } else {
  1745. start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES;
  1746. }
  1747. // fade it
  1748. fade->fadeStartVolume = fade->FadeDbAt44kHz( start44kHz );
  1749. fade->fadeStart44kHz = start44kHz;
  1750. fade->fadeEnd44kHz = start44kHz + length44kHz;
  1751. fade->fadeEndVolume = to;
  1752. }
  1753. /*
  1754. =================
  1755. idSoundWorldLocal::SetSlowmo
  1756. =================
  1757. */
  1758. void idSoundWorldLocal::SetSlowmo( bool active ) {
  1759. slowmoActive = active;
  1760. }
  1761. /*
  1762. =================
  1763. idSoundWorldLocal::SetSlowmoSpeed
  1764. =================
  1765. */
  1766. void idSoundWorldLocal::SetSlowmoSpeed( float speed ) {
  1767. slowmoSpeed = speed;
  1768. }
  1769. /*
  1770. =================
  1771. idSoundWorldLocal::SetEnviroSuit
  1772. =================
  1773. */
  1774. void idSoundWorldLocal::SetEnviroSuit( bool active ) {
  1775. enviroSuitActive = active;
  1776. }