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