doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
snd_emitter.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 ===================
37 idSoundFade::Clear
38 ===================
39 */
41  fadeStart44kHz = 0;
42  fadeEnd44kHz = 0;
43  fadeStartVolume = 0;
44  fadeEndVolume = 0;
45 }
46 
47 /*
48 ===================
49 idSoundFade::FadeDbAt44kHz
50 ===================
51 */
52 float idSoundFade::FadeDbAt44kHz( int current44kHz ) {
53  float fadeDb;
54 
55  if ( current44kHz >= fadeEnd44kHz ) {
56  fadeDb = fadeEndVolume;
57  } else if ( current44kHz > fadeStart44kHz ) {
58  float fraction = ( fadeEnd44kHz - fadeStart44kHz );
59  float over = ( current44kHz - fadeStart44kHz );
60  fadeDb = fadeStartVolume + ( fadeEndVolume - fadeStartVolume ) * over / fraction;
61  } else {
62  fadeDb = fadeStartVolume;
63  }
64  return fadeDb;
65 }
66 
67 //========================================================================
68 
69 
70 /*
71 =======================
72 GeneratePermutedList
73 
74 Fills in elements[0] .. elements[numElements-1] with a permutation of
75 0 .. numElements-1 based on the permute parameter
76 
77 numElements == 3
78 maxPermute = 6
79 permute 0 = 012
80 permute 1 = 021
81 permute 2 = 102
82 permute 3 = 120
83 permute 4 = 201
84 permute 5 = 210
85 =======================
86 */
87 void PermuteList_r( int *list, int listLength, int permute, int maxPermute ) {
88  if ( listLength < 2 ) {
89  return;
90  }
91  permute %= maxPermute;
92  int swap = permute * listLength / maxPermute;
93  int old = list[swap];
94  list[swap] = list[0];
95  list[0] = old;
96 
97  maxPermute /= listLength;
98  PermuteList_r( list + 1, listLength - 1, permute, maxPermute );
99 }
100 
101 int Factorial( int val ) {
102  int fact = val;
103  while ( val > 1 ) {
104  val--;
105  fact *= val;
106  }
107  return fact;
108 }
109 
110 void GeneratePermutedList( int *list, int listLength, int permute ) {
111  for ( int i = 0 ; i < listLength ; i++ ) {
112  list[i] = i;
113  }
114 
115  // we can't calculate > 12 factorial, so we can't easily build a permuted list
116  if ( listLength > 12 ) {
117  return;
118  }
119 
120  // calculate listLength factorial
121  int maxPermute = Factorial( listLength );
122 
123  // recursively permute
124  PermuteList_r( list, listLength, permute, maxPermute );
125 }
126 
127 void TestPermutations( void ) {
128  int list[SOUND_MAX_LIST_WAVS];
129 
130  for ( int len = 1 ; len < 5 ; len++ ) {
131  common->Printf( "list length: %i\n", len );
132 
133  int max = Factorial( len );
134  for ( int j = 0 ; j < max * 2 ; j++ ) {
135  GeneratePermutedList( list, len, j );
136  common->Printf( "%4i : ", j );
137  for ( int k = 0 ; k < len ; k++ ) {
138  common->Printf( "%i", list[k] );
139  }
140  common->Printf( "\n" );
141  }
142  }
143 }
144 
145 //=====================================================================================
146 
147 /*
148 ===================
149 idSoundChannel::idSoundChannel
150 ===================
151 */
153  decoder = NULL;
154  Clear();
155 }
156 
157 /*
158 ===================
159 idSoundChannel::~idSoundChannel
160 ===================
161 */
163  Clear();
164 }
165 
166 /*
167 ===================
168 idSoundChannel::Clear
169 ===================
170 */
171 void idSoundChannel::Clear( void ) {
172  int j;
173 
174  Stop();
175  soundShader = NULL;
176  lastVolume = 0.0f;
177  triggerChannel = SCHANNEL_ANY;
178  channelFade.Clear();
179  diversity = 0.0f;
180  leadinSample = NULL;
181  trigger44kHzTime = 0;
182  for( j = 0; j < 6; j++ ) {
183  lastV[j] = 0.0f;
184  }
185  memset( &parms, 0, sizeof(parms) );
186 
187  triggered = false;
188  openalSource = NULL;
192 }
193 
194 /*
195 ===================
196 idSoundChannel::Start
197 ===================
198 */
199 void idSoundChannel::Start( void ) {
200  triggerState = true;
201  if ( decoder == NULL ) {
203  }
204 }
205 
206 /*
207 ===================
208 idSoundChannel::Stop
209 ===================
210 */
211 void idSoundChannel::Stop( void ) {
212  triggerState = false;
213  if ( decoder != NULL ) {
215  decoder = NULL;
216  }
217 }
218 
219 /*
220 ===================
221 idSoundChannel::ALStop
222 ===================
223 */
226 
227  if ( alIsSource( openalSource ) ) {
231  }
232 
234  alGetError();
236  if ( alGetError() == AL_NO_ERROR ) {
238  }
239  }
240 
242  alGetError();
244  if ( alGetError() == AL_NO_ERROR ) {
246  }
247  }
248  }
249 }
250 
251 /*
252 ===================
253 idSoundChannel::GatherChannelSamples
254 
255 Will always return 44kHz samples for the given range, even if it deeply looped or
256 out of the range of the unlooped samples. Handles looping between multiple different
257 samples and leadins
258 ===================
259 */
260 void idSoundChannel::GatherChannelSamples( int sampleOffset44k, int sampleCount44k, float *dest ) const {
261  float *dest_p = dest;
262  int len;
263 
264 //Sys_DebugPrintf( "msec:%i sample:%i : %i : %i\n", Sys_Milliseconds(), soundSystemLocal.GetCurrent44kHzTime(), sampleOffset44k, sampleCount44k ); //!@#
265 
266  // negative offset times will just zero fill
267  if ( sampleOffset44k < 0 ) {
268  len = -sampleOffset44k;
269  if ( len > sampleCount44k ) {
270  len = sampleCount44k;
271  }
272  memset( dest_p, 0, len * sizeof( dest_p[0] ) );
273  dest_p += len;
274  sampleCount44k -= len;
275  sampleOffset44k += len;
276  }
277 
278  // grab part of the leadin sample
279  idSoundSample *leadin = leadinSample;
280  if ( !leadin || sampleOffset44k < 0 || sampleCount44k <= 0 ) {
281  memset( dest_p, 0, sampleCount44k * sizeof( dest_p[0] ) );
282  return;
283  }
284 
285  if ( sampleOffset44k < leadin->LengthIn44kHzSamples() ) {
286  len = leadin->LengthIn44kHzSamples() - sampleOffset44k;
287  if ( len > sampleCount44k ) {
288  len = sampleCount44k;
289  }
290 
291  // decode the sample
292  decoder->Decode( leadin, sampleOffset44k, len, dest_p );
293 
294  dest_p += len;
295  sampleCount44k -= len;
296  sampleOffset44k += len;
297  }
298 
299  // if not looping, zero fill any remaining spots
300  if ( !soundShader || !( parms.soundShaderFlags & SSF_LOOPING ) ) {
301  memset( dest_p, 0, sampleCount44k * sizeof( dest_p[0] ) );
302  return;
303  }
304 
305  // fill the remainder with looped samples
306  idSoundSample *loop = soundShader->entries[0];
307 
308  if ( !loop ) {
309  memset( dest_p, 0, sampleCount44k * sizeof( dest_p[0] ) );
310  return;
311  }
312 
313  sampleOffset44k -= leadin->LengthIn44kHzSamples();
314 
315  while( sampleCount44k > 0 ) {
316  int totalLen = loop->LengthIn44kHzSamples();
317 
318  sampleOffset44k %= totalLen;
319 
320  len = totalLen - sampleOffset44k;
321  if ( len > sampleCount44k ) {
322  len = sampleCount44k;
323  }
324 
325  // decode the sample
326  decoder->Decode( loop, sampleOffset44k, len, dest_p );
327 
328  dest_p += len;
329  sampleCount44k -= len;
330  sampleOffset44k += len;
331  }
332 }
333 
334 
335 //=====================================================================================
336 
337 /*
338 ===============
339 idSoundEmitterLocal::idSoundEmitterLocal
340 
341 ===============
342 */
344  soundWorld = NULL;
345  Clear();
346 }
347 
348 /*
349 ===============
350 idSoundEmitterLocal::~idSoundEmitterLocal
351 ===============
352 */
354  Clear();
355 }
356 
357 /*
358 ===============
359 idSoundEmitterLocal::Clear
360 ===============
361 */
363  int i;
364 
365  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
366  channels[i].ALStop();
367  channels[i].Clear();
368  }
369 
371  distance = 0.0f;
372 
373  lastValidPortalArea = -1;
374 
375  playing = false;
376  hasShakes = false;
377  ampTime = 0; // last time someone queried
378  amplitude = 0;
379  maxDistance = 10.0f; // meters
381 
382  memset( &parms, 0, sizeof( parms ) );
383 }
384 
385 /*
386 ==================
387 idSoundEmitterLocal::OverrideParms
388 ==================
389 */
391  const soundShaderParms_t *over, soundShaderParms_t *out ) {
392  if ( !over ) {
393  *out = *base;
394  return;
395  }
396  if ( over->minDistance ) {
397  out->minDistance = over->minDistance;
398  } else {
399  out->minDistance = base->minDistance;
400  }
401  if ( over->maxDistance ) {
402  out->maxDistance = over->maxDistance;
403  } else {
404  out->maxDistance = base->maxDistance;
405  }
406  if ( over->shakes ) {
407  out->shakes = over->shakes;
408  } else {
409  out->shakes = base->shakes;
410  }
411  if ( over->volume ) {
412  out->volume = over->volume;
413  } else {
414  out->volume = base->volume;
415  }
416  if ( over->soundClass ) {
417  out->soundClass = over->soundClass;
418  } else {
419  out->soundClass = base->soundClass;
420  }
422 }
423 
424 /*
425 ==================
426 idSoundEmitterLocal::CheckForCompletion
427 
428 Checks to see if all the channels have completed, clearing the playing flag if necessary.
429 Sets the playing and shakes bools.
430 ==================
431 */
432 void idSoundEmitterLocal::CheckForCompletion( int current44kHzTime ) {
433  bool hasActive;
434  int i;
435 
436  hasActive = false;
437  hasShakes = false;
438 
439  if ( playing ) {
440  for ( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
441  idSoundChannel *chan = &channels[i];
442 
443  if ( !chan->triggerState ) {
444  continue;
445  }
446  const idSoundShader *shader = chan->soundShader;
447  if ( !shader ) {
448  continue;
449  }
450 
451  // see if this channel has completed
452  if ( !( chan->parms.soundShaderFlags & SSF_LOOPING ) ) {
453  ALint state = AL_PLAYING;
454 
456  alGetSourcei( chan->openalSource, AL_SOURCE_STATE, &state );
457  }
458  idSlowChannel slow = GetSlowChannel( chan );
459 
460  if ( soundWorld->slowmoActive && slow.IsActive() ) {
461  if ( slow.GetCurrentPosition().time >= chan->leadinSample->LengthIn44kHzSamples() / 2 ) {
462  chan->Stop();
463  // if this was an onDemand sound, purge the sample now
464  if ( chan->leadinSample->onDemand ) {
466  }
467  continue;
468  }
469  } else if ( ( chan->trigger44kHzTime + chan->leadinSample->LengthIn44kHzSamples() < current44kHzTime ) || ( state == AL_STOPPED ) ) {
470  chan->Stop();
471 
472  // free hardware resources
473  chan->ALStop();
474 
475  // if this was an onDemand sound, purge the sample now
476  if ( chan->leadinSample->onDemand ) {
478  }
479  continue;
480  }
481  }
482 
483  // free decoder memory if no sound was decoded for a while
484  if ( chan->decoder != NULL && chan->decoder->GetLastDecodeTime() < current44kHzTime - SOUND_DECODER_FREE_DELAY ) {
485  chan->decoder->ClearDecoder();
486  }
487 
488  hasActive = true;
489 
490  if ( chan->parms.shakes > 0.0f ) {
491  hasShakes = true;
492  }
493  }
494  }
495 
496  // mark the entire sound emitter as non-playing if there aren't any active channels
497  if ( !hasActive ) {
498  playing = false;
500  // this can now be reused by the next request for a new soundEmitter
502  }
503  }
504 }
505 
506 /*
507 ===================
508 idSoundEmitterLocal::Spatialize
509 
510 Called once each sound frame by the main thread from idSoundWorldLocal::PlaceOrigin
511 ===================
512 */
513 void idSoundEmitterLocal::Spatialize( idVec3 listenerPos, int listenerArea, idRenderWorld *rw ) {
514  int i;
515  bool hasActive = false;
516 
517  //
518  // work out the maximum distance of all the playing channels
519  //
520  maxDistance = 0;
521 
522  for ( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
523  idSoundChannel *chan = &channels[i];
524 
525  if ( !chan->triggerState ) {
526  continue;
527  }
528  if ( chan->parms.maxDistance > maxDistance ) {
529  maxDistance = chan->parms.maxDistance;
530  }
531  }
532 
533  //
534  // work out where the sound comes from
535  //
536  idVec3 realOrigin = origin * DOOM_TO_METERS;
537  idVec3 len = listenerPos - realOrigin;
538  realDistance = len.LengthFast();
539 
540  if ( realDistance >= maxDistance ) {
541  // no way to possibly hear it
543  return;
544  }
545 
546  //
547  // work out virtual origin and distance, which may be from a portal instead of the actual origin
548  //
550  if ( listenerArea == -1 ) { // listener is outside the world
551  return;
552  }
553  if ( rw ) {
554  // we have a valid renderWorld
555  int soundInArea = rw->PointInArea( origin );
556  if ( soundInArea == -1 ) {
557  if ( lastValidPortalArea == -1 ) { // sound is outside the world
559  spatializedOrigin = origin; // sound is in our area
560  return;
561  }
562  soundInArea = lastValidPortalArea;
563  }
564  lastValidPortalArea = soundInArea;
565  if ( soundInArea == listenerArea ) {
567  spatializedOrigin = origin; // sound is in our area
568  return;
569  }
570 
571  soundWorld->ResolveOrigin( 0, NULL, soundInArea, 0.0f, origin, this );
573  } else {
574  // no portals available
576  spatializedOrigin = origin; // sound is in our area
577  }
578 }
579 
580 /*
581 ===========================================================================================
582 
583 PUBLIC FUNCTIONS
584 
585 ===========================================================================================
586 */
587 
588 /*
589 =====================
590 idSoundEmitterLocal::UpdateEmitter
591 =====================
592 */
593 void idSoundEmitterLocal::UpdateEmitter( const idVec3 &origin, int listenerId, const soundShaderParms_t *parms ) {
594  if ( !parms ) {
595  common->Error( "idSoundEmitterLocal::UpdateEmitter: NULL parms" );
596  }
597  if ( soundWorld && soundWorld->writeDemo ) {
601  soundWorld->writeDemo->WriteVec3( origin );
602  soundWorld->writeDemo->WriteInt( listenerId );
609  }
610 
611  this->origin = origin;
612  this->listenerId = listenerId;
613  this->parms = *parms;
614 
615  // FIXME: change values on all channels?
616 }
617 
618 /*
619 =====================
620 idSoundEmitterLocal::Free
621 
622 They are never truly freed, just marked so they can be reused by the soundWorld
623 =====================
624 */
625 void idSoundEmitterLocal::Free( bool immediate ) {
627  return;
628  }
629 
630  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
631  common->Printf( "FreeSound (%i,%i)\n", index, (int)immediate );
632  }
633  if ( soundWorld && soundWorld->writeDemo ) {
637  soundWorld->writeDemo->WriteInt( immediate );
638  }
639 
640  if ( !immediate ) {
642  } else {
643  Clear();
644  }
645 }
646 
647 /*
648 =====================
649 idSoundEmitterLocal::StartSound
650 
651 returns the length of the started sound in msec
652 =====================
653 */
654 int idSoundEmitterLocal::StartSound( const idSoundShader *shader, const s_channelType channel, float diversity, int soundShaderFlags, bool allowSlow ) {
655  int i;
656 
657  if ( !shader ) {
658  return 0;
659  }
660 
661  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
662  common->Printf( "StartSound %ims (%i,%i,%s) = ", soundWorld->gameMsec, index, (int)channel, shader->GetName() );
663  }
664 
665  if ( soundWorld && soundWorld->writeDemo ) {
669 
671 
672  soundWorld->writeDemo->WriteInt( channel );
673  soundWorld->writeDemo->WriteFloat( diversity );
674  soundWorld->writeDemo->WriteInt( soundShaderFlags );
675  }
676 
677  // build the channel parameters by taking the shader parms and optionally overriding
678  soundShaderParms_t chanParms;
679 
680  chanParms = shader->parms;
681  OverrideParms( &chanParms, &this->parms, &chanParms );
682  chanParms.soundShaderFlags |= soundShaderFlags;
683 
684  if ( chanParms.shakes > 0.0f ) {
685  shader->CheckShakesAndOgg();
686  }
687 
688  // this is the sample time it will be first mixed
689  int start44kHz;
690 
691  if ( soundWorld->fpa[0] ) {
692  // if we are recording an AVI demo, don't use hardware time
693  start44kHz = soundWorld->lastAVI44kHz + MIXBUFFER_SAMPLES;
694  } else {
696  }
697 
698  //
699  // pick which sound to play from the shader
700  //
701  if ( !shader->numEntries ) {
702  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
703  common->Printf( "no samples in sound shader\n" );
704  }
705  return 0; // no sounds
706  }
707  int choice;
708 
709  // pick a sound from the list based on the passed diversity
710  choice = (int)(diversity * shader->numEntries);
711  if ( choice < 0 || choice >= shader->numEntries ) {
712  choice = 0;
713  }
714 
715  // bump the choice if the exact sound was just played and we are NO_DUPS
716  if ( chanParms.soundShaderFlags & SSF_NO_DUPS ) {
717  idSoundSample *sample;
718  if ( shader->leadins[ choice ] ) {
719  sample = shader->leadins[ choice ];
720  } else {
721  sample = shader->entries[ choice ];
722  }
723  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
724  idSoundChannel *chan = &channels[i];
725  if ( chan->leadinSample == sample ) {
726  choice = ( choice + 1 ) % shader->numEntries;
727  break;
728  }
729  }
730  }
731 
732  // PLAY_ONCE sounds will never be restarted while they are running
733  if ( chanParms.soundShaderFlags & SSF_PLAY_ONCE ) {
734  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
735  idSoundChannel *chan = &channels[i];
736  if ( chan->triggerState && chan->soundShader == shader ) {
737  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
738  common->Printf( "PLAY_ONCE not restarting\n" );
739  }
740  return 0;
741  }
742  }
743  }
744 
745  // never play the same sound twice with the same starting time, even
746  // if they are on different channels
747  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
748  idSoundChannel *chan = &channels[i];
749  if ( chan->triggerState && chan->soundShader == shader && chan->trigger44kHzTime == start44kHz ) {
750  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
751  common->Printf( "already started this frame\n" );
752  }
753  return 0;
754  }
755  }
756 
758 
759  // kill any sound that is currently playing on this channel
760  if ( channel != SCHANNEL_ANY ) {
761  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
762  idSoundChannel *chan = &channels[i];
763  if ( chan->triggerState && chan->soundShader && chan->triggerChannel == channel ) {
764  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
765  common->Printf( "(override %s)", chan->soundShader->base->GetName() );
766  }
767 
768  chan->Stop();
769 
770  // if this was an onDemand sound, purge the sample now
771  if ( chan->leadinSample->onDemand ) {
772  chan->ALStop();
774  }
775  break;
776  }
777  }
778  }
779 
780  // find a free channel to play the sound on
781  idSoundChannel *chan;
782  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
783  chan = &channels[i];
784  if ( !chan->triggerState ) {
785  break;
786  }
787  }
788 
789  if ( i == SOUND_MAX_CHANNELS ) {
790  // we couldn't find a channel for it
792  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
793  common->Printf( "no channels available\n" );
794  }
795  return 0;
796  }
797 
798  chan = &channels[i];
799 
800  if ( shader->leadins[ choice ] ) {
801  chan->leadinSample = shader->leadins[ choice ];
802  } else {
803  chan->leadinSample = shader->entries[ choice ];
804  }
805 
806  // if the sample is onDemand (voice mails, etc), load it now
807  if ( chan->leadinSample->purged ) {
808  int start = Sys_Milliseconds();
809  chan->leadinSample->Load();
810  int end = Sys_Milliseconds();
811  session->TimeHitch( end - start );
812  // recalculate start44kHz, because loading may have taken a fair amount of time
813  if ( !soundWorld->fpa[0] ) {
815  }
816  }
817 
818  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
819  common->Printf( "'%s'\n", chan->leadinSample->name.c_str() );
820  }
821 
822  if ( idSoundSystemLocal::s_skipHelltimeFX.GetBool() ) {
823  chan->disallowSlow = true;
824  } else {
825  chan->disallowSlow = !allowSlow;
826  }
827 
828  ResetSlowChannel( chan );
829 
830  // the sound will start mixing in the next async mix block
831  chan->triggered = true;
832  chan->openalStreamingOffset = 0;
833  chan->trigger44kHzTime = start44kHz;
834  chan->parms = chanParms;
836  chan->soundShader = shader;
837  chan->triggerChannel = channel;
838  chan->Start();
839 
840  // we need to start updating the def and mixing it in
841  playing = true;
842 
843  // spatialize it immediately, so it will start the next mix block
844  // even if that happens before the next PlaceOrigin()
846 
847  // return length of sound in milliseconds
849 
850  if ( chan->leadinSample->objectInfo.nChannels == 2 ) {
851  length /= 2; // stereo samples
852  }
853 
854  // adjust the start time based on diversity for looping sounds, so they don't all start
855  // at the same point
856  if ( chan->parms.soundShaderFlags & SSF_LOOPING && !chan->leadinSample->LengthIn44kHzSamples() ) {
857  chan->trigger44kHzTime -= diversity * length;
858  chan->trigger44kHzTime &= ~7; // so we don't have to worry about the 22kHz and 11kHz expansions
859  // starting in fractional samples
860  chan->triggerGame44kHzTime -= diversity * length;
861  chan->triggerGame44kHzTime &= ~7;
862  }
863 
864  length *= 1000 / (float)PRIMARYFREQ;
865 
867 
868  return length;
869 }
870 
871 /*
872 ===================
873 idSoundEmitterLocal::ModifySound
874 ===================
875 */
877  if ( !parms ) {
878  common->Error( "idSoundEmitterLocal::ModifySound: NULL parms" );
879  }
880  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
881  common->Printf( "ModifySound(%i,%i)\n", index, channel );
882  }
883  if ( soundWorld && soundWorld->writeDemo ) {
887  soundWorld->writeDemo->WriteInt( channel );
894  }
895 
896  for ( int i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
897  idSoundChannel *chan = &channels[i];
898 
899  if ( !chan->triggerState ) {
900  continue;
901  }
902  if ( channel != SCHANNEL_ANY && chan->triggerChannel != channel ) {
903  continue;
904  }
905 
906  OverrideParms( &chan->parms, parms, &chan->parms );
907 
908  if ( chan->parms.shakes > 0.0f && chan->soundShader != NULL ) {
910  }
911  }
912 }
913 
914 /*
915 ===================
916 idSoundEmitterLocal::StopSound
917 
918 can pass SCHANNEL_ANY
919 ===================
920 */
922  int i;
923 
924  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
925  common->Printf( "StopSound(%i,%i)\n", index, channel );
926  }
927 
928  if ( soundWorld && soundWorld->writeDemo ) {
932  soundWorld->writeDemo->WriteInt( channel );
933  }
934 
936 
937  for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
938  idSoundChannel *chan = &channels[i];
939 
940  if ( !chan->triggerState ) {
941  continue;
942  }
943  if ( channel != SCHANNEL_ANY && chan->triggerChannel != channel ) {
944  continue;
945  }
946 
947  // stop it
948  chan->Stop();
949 
950  // free hardware resources
951  chan->ALStop();
952 
953  // if this was an onDemand sound, purge the sample now
954  if ( chan->leadinSample->onDemand ) {
956  }
957 
958  chan->leadinSample = NULL;
959  chan->soundShader = NULL;
960  }
961 
963 }
964 
965 /*
966 ===================
967 idSoundEmitterLocal::FadeSound
968 
969 to is in Db (sigh), over is in seconds
970 ===================
971 */
972 void idSoundEmitterLocal::FadeSound( const s_channelType channel, float to, float over ) {
973  if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) {
974  common->Printf( "FadeSound(%i,%i,%f,%f )\n", index, channel, to, over );
975  }
976  if ( !soundWorld ) {
977  return;
978  }
979  if ( soundWorld->writeDemo ) {
983  soundWorld->writeDemo->WriteInt( channel );
985  soundWorld->writeDemo->WriteFloat( over );
986  }
987 
988  int start44kHz;
989 
990  if ( soundWorld->fpa[0] ) {
991  // if we are recording an AVI demo, don't use hardware time
992  start44kHz = soundWorld->lastAVI44kHz + MIXBUFFER_SAMPLES;
993  } else {
995  }
996 
997  int length44kHz = soundSystemLocal.MillisecondsToSamples( over * 1000 );
998 
999  for( int i = 0; i < SOUND_MAX_CHANNELS ; i++ ) {
1000  idSoundChannel *chan = &channels[i];
1001 
1002  if ( !chan->triggerState ) {
1003  continue;
1004  }
1005  if ( channel != SCHANNEL_ANY && chan->triggerChannel != channel ) {
1006  continue;
1007  }
1008 
1009  // if it is already fading to this volume at this rate, don't change it
1010  if ( chan->channelFade.fadeEndVolume == to &&
1011  chan->channelFade.fadeEnd44kHz - chan->channelFade.fadeStart44kHz == length44kHz ) {
1012  continue;
1013  }
1014 
1015  // fade it
1016  chan->channelFade.fadeStartVolume = chan->channelFade.FadeDbAt44kHz( start44kHz );
1017  chan->channelFade.fadeStart44kHz = start44kHz;
1018  chan->channelFade.fadeEnd44kHz = start44kHz + length44kHz;
1019  chan->channelFade.fadeEndVolume = to;
1020  }
1021 }
1022 
1023 /*
1024 ===================
1025 idSoundEmitterLocal::CurrentlyPlaying
1026 ===================
1027 */
1029  return playing;
1030 }
1031 
1032 /*
1033 ===================
1034 idSoundEmitterLocal::Index
1035 ===================
1036 */
1037 int idSoundEmitterLocal::Index( void ) const {
1038  return index;
1039 }
1040 
1041 /*
1042 ===================
1043 idSoundEmitterLocal::CurrentAmplitude
1044 
1045 this is called from the main thread by the material shader system
1046 to allow lights and surface flares to vary with the sound amplitude
1047 ===================
1048 */
1050  if ( idSoundSystemLocal::s_constantAmplitude.GetFloat() >= 0.0f ) {
1052  }
1053 
1055  return 0.0;
1056  }
1057 
1058  int localTime = soundSystemLocal.GetCurrent44kHzTime();
1059 
1060  // see if we can use our cached value
1061  if ( ampTime == localTime ) {
1062  return amplitude;
1063  }
1064 
1065  // calculate a new value
1066  ampTime = localTime;
1067  amplitude = soundWorld->FindAmplitude( this, localTime, NULL, SCHANNEL_ANY, false );
1068 
1069  return amplitude;
1070 }
1071 
1072 /*
1073 ===================
1074 idSoundEmitterLocal::GetSlowChannel
1075 ===================
1076 */
1078  return slowChannels[chan - channels];
1079 }
1080 
1081 /*
1082 ===================
1083 idSoundEmitterLocal::SetSlowChannel
1084 ===================
1085 */
1087  slowChannels[chan - channels] = slow;
1088 }
1089 
1090 /*
1091 ===================
1092 idSoundEmitterLocal::ResetSlowChannel
1093 ===================
1094 */
1096  int index = chan - channels;
1098 }
1099 
1100 /*
1101 ===================
1102 idSlowChannel::Reset
1103 ===================
1104 */
1106  memset( this, 0, sizeof( *this ) );
1107 
1108  this->chan = chan;
1109 
1110  curPosition.Set( 0 );
1111  newPosition.Set( 0 );
1112 
1113  curSampleOffset = -10000;
1114  newSampleOffset = -10000;
1115 
1116  triggerOffset = 0;
1117 }
1118 
1119 /*
1120 ===================
1121 idSlowChannel::AttachSoundChannel
1122 ===================
1123 */
1125  this->chan = chan;
1126 }
1127 
1128 /*
1129 ===================
1130 idSlowChannel::GetSlowmoSpeed
1131 ===================
1132 */
1135 
1136  if ( sw ) {
1137  return sw->slowmoSpeed;
1138  } else {
1139  return 0;
1140  }
1141 }
1142 
1143 /*
1144 ===================
1145 idSlowChannel::GenerateSlowChannel
1146 ===================
1147 */
1148 void idSlowChannel::GenerateSlowChannel( FracTime& playPos, int sampleCount44k, float* finalBuffer ) {
1150  float in[MIXBUFFER_SAMPLES+3], out[MIXBUFFER_SAMPLES+3], *src, *spline, slowmoSpeed;
1151  int i, neededSamples, orgTime, zeroedPos, count = 0;
1152 
1153  src = in + 2;
1154  spline = out + 2;
1155 
1156  if ( sw ) {
1157  slowmoSpeed = sw->slowmoSpeed;
1158  }
1159  else {
1160  slowmoSpeed = 1;
1161  }
1162 
1163  neededSamples = sampleCount44k * slowmoSpeed + 4;
1164  orgTime = playPos.time;
1165 
1166  // get the channel's samples
1167  chan->GatherChannelSamples( playPos.time * 2, neededSamples, src );
1168  for ( i = 0; i < neededSamples >> 1; i++ ) {
1169  spline[i] = src[i*2];
1170  }
1171 
1172  // interpolate channel
1173  zeroedPos = playPos.time;
1174  playPos.time = 0;
1175 
1176  for ( i = 0; i < sampleCount44k >> 1; i++, count += 2 ) {
1177  float val;
1178  val = spline[playPos.time];
1179  src[i] = val;
1180  playPos.Increment( slowmoSpeed );
1181  }
1182 
1183  // lowpass filter
1184  float *in_p = in + 2, *out_p = out + 2;
1185  int numSamples = sampleCount44k >> 1;
1186 
1187  lowpass.GetContinuitySamples( in_p[-1], in_p[-2], out_p[-1], out_p[-2] );
1188  lowpass.SetParms( slowmoSpeed * 15000, 1.2f );
1189 
1190  for ( int i = 0, count = 0; i < numSamples; i++, count += 2 ) {
1191  lowpass.ProcessSample( in_p + i, out_p + i );
1192  finalBuffer[count] = finalBuffer[count+1] = out[i];
1193  }
1194 
1195  lowpass.SetContinuitySamples( in_p[numSamples-2], in_p[numSamples-3], out_p[numSamples-2], out_p[numSamples-3] );
1196 
1197  playPos.time += zeroedPos;
1198 }
1199 
1200 /*
1201 ===================
1202 idSlowChannel::GatherChannelSamples
1203 ===================
1204 */
1205 void idSlowChannel::GatherChannelSamples( int sampleOffset44k, int sampleCount44k, float *dest ) {
1206  int state = 0;
1207 
1208  // setup chan
1209  active = true;
1210  newSampleOffset = sampleOffset44k >> 1;
1211 
1212  // set state
1213  if ( newSampleOffset < curSampleOffset ) {
1214  state = PLAYBACK_RESET;
1215  } else if ( newSampleOffset > curSampleOffset ) {
1216  state = PLAYBACK_ADVANCING;
1217  }
1218 
1219  if ( state == PLAYBACK_RESET ) {
1221  }
1222 
1223  // set current vars
1226 
1227  // do the slow processing
1228  GenerateSlowChannel( newPosition, sampleCount44k, dest );
1229 
1230  // finish off
1231  if ( state == PLAYBACK_ADVANCING )
1233 }
idSlowChannel GetSlowChannel(const idSoundChannel *chan)
void Set(int val)
Definition: snd_local.h:359
soundShaderParms_t parms
Definition: snd_local.h:415
idSoundChannel channels[SOUND_MAX_CHANNELS]
Definition: snd_local.h:499
void GetContinuitySamples(float &in1, float &in2, float &out1, float &out2)
Definition: snd_local.h:325
int Factorial(int val)
static idSampleDecoder * Alloc(void)
void ALStop(void)
const idSoundShader * soundShader
Definition: snd_local.h:418
int ALint
OpenAL 32bit signed integer type.
Definition: altypes.h:48
float maxDistance
Definition: sound.h:62
float lastVolume
Definition: snd_local.h:421
word nChannels
Definition: snd_local.h:98
const float METERS_TO_DOOM
Definition: sound.h:43
virtual bool CurrentlyPlaying(void) const
void PermuteList_r(int *list, int listLength, int permute, int maxPermute)
Definition: snd_emitter.cpp:87
virtual void Free(bool immediate)
const idSoundChannel * chan
Definition: snd_local.h:372
float GetFloat(void) const
Definition: CVarSystem.h:144
void GatherChannelSamples(int sampleOffset44k, int sampleCount44k, float *dest)
virtual void UpdateEmitter(const idVec3 &origin, int listenerId, const soundShaderParms_t *parms)
const int MIXBUFFER_SAMPLES
Definition: Simd.h:84
FracTime curPosition
Definition: snd_local.h:380
int trigger44kHzTime
Definition: snd_local.h:413
float FindAmplitude(idSoundEmitterLocal *sound, const int localTime, const idVec3 *listenerPosition, const s_channelType channel, bool shakesOnly)
Definition: snd_world.cpp:1926
void FreeOpenALSource(ALuint handle)
virtual void ProcessSample(float *in, float *out)
int newSampleOffset
Definition: snd_local.h:378
int Sys_Milliseconds(void)
case const int
Definition: Callbacks.cpp:52
virtual void FadeSound(const s_channelType channel, float to, float over)
#define AL_STOPPED
Definition: altypes.h:229
#define alSourcei
Definition: idal.h:57
int MillisecondsToSamples(int ms) const
static idCVar s_skipHelltimeFX
Definition: snd_local.h:822
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
int GetCurrent44kHzTime(void) const
Definition: snd_system.cpp:559
virtual void ClearDecoder(void)=0
virtual void ModifySound(const s_channelType channel, const soundShaderParms_t *parms)
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
ALuint lastopenalStreamingBuffer[3]
Definition: snd_local.h:428
#define alGetSourcei
Definition: idal.h:40
idFile * fpa[6]
Definition: snd_local.h:648
int s_channelType
Definition: sound.h:147
#define AL_NO_ERROR
Errors: No Error.
Definition: altypes.h:265
GLuint src
Definition: glext.h:5390
void SetSlowChannel(const idSoundChannel *chan, idSlowChannel slow)
FracTime GetCurrentPosition()
Definition: snd_local.h:398
GLenum GLsizei len
Definition: glext.h:3472
int i
Definition: process.py:33
ALuint openalSource
Definition: snd_local.h:425
idSoundSample * leadins[SOUND_MAX_LIST_WAVS]
Definition: sound.h:125
float diversity
Definition: snd_local.h:420
bool IsActive()
Definition: snd_local.h:397
int LengthIn44kHzSamples() const
Definition: snd_cache.cpp:317
void SetParms(float p1=0, float p2=0, float p3=0)
float fadeEndVolume
Definition: snd_local.h:296
float lastV[6]
Definition: snd_local.h:422
void CheckForCompletion(int current44kHzTime)
soundShaderParms_t parms
Definition: sound.h:116
void ResetSlowChannel(const idSoundChannel *chan)
GLuint GLuint GLsizei count
Definition: glext.h:2845
virtual int WriteInt(const int value)
Definition: File.cpp:468
bool triggerState
Definition: snd_local.h:412
GLuint index
Definition: glext.h:3476
void Clear(void)
virtual bool CheckShakesAndOgg(void) const
Definition: snd_shader.cpp:377
idSlowChannel slowChannels[SOUND_MAX_CHANNELS]
Definition: snd_local.h:501
SoundFX_LowpassFast lowpass
Definition: snd_local.h:383
GLuint GLuint end
Definition: glext.h:2845
idSampleDecoder * decoder
Definition: snd_local.h:419
idCommon * common
Definition: Common.cpp:206
int fadeEnd44kHz
Definition: snd_local.h:294
static idCVar s_constantAmplitude
Definition: snd_local.h:795
#define NULL
Definition: Lib.h:88
removeStatus_t removeStatus
Definition: snd_local.h:479
ALuint openalStreamingOffset
Definition: snd_local.h:426
static void Free(idSampleDecoder *decoder)
idSoundFade channelFade
Definition: snd_local.h:423
void Start(void)
virtual const char * GetName(void) const =0
const float DOOM_TO_METERS
Definition: sound.h:42
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idSoundSample * leadinSample
Definition: snd_local.h:416
float shakes
Definition: sound.h:64
int numEntries
Definition: sound.h:128
void AttachSoundChannel(const idSoundChannel *chan)
#define alIsSource
Definition: idal.h:38
void Stop(void)
virtual void StopSound(const s_channelType channel)
virtual int GetLastDecodeTime(void) const =0
void Clear()
Definition: snd_emitter.cpp:40
#define AL_PLAYING
Definition: altypes.h:227
virtual int StartSound(const idSoundShader *shader, const s_channelType channel, float diversity=0, int shaderFlags=0, bool allowSlow=true)
idSoundSample * entries[SOUND_MAX_LIST_WAVS]
Definition: sound.h:127
float GetSlowmoSpeed()
void GeneratePermutedList(int *list, int listLength, int permute)
#define alDeleteBuffers
Definition: idal.h:48
idSoundSystemLocal soundSystemLocal
Definition: snd_system.cpp:91
void GatherChannelSamples(int sampleOffset44k, int sampleCount44k, float *dest) const
void GenerateSlowChannel(FracTime &playPos, int sampleCount44k, float *finalBuffer)
int triggerOffset
Definition: snd_local.h:375
tuple f
Definition: idal.py:89
GLuint in
Definition: glext.h:5388
virtual int WriteFloat(const float value)
Definition: File.cpp:526
void SetContinuitySamples(float in1, float in2, float out1, float out2)
Definition: snd_local.h:324
virtual idSoundWorld * GetPlayingSoundWorld(void)
ALuint openalStreamingBuffer[3]
Definition: snd_local.h:427
static bool useOpenAL
Definition: snd_local.h:775
int fadeStart44kHz
Definition: snd_local.h:293
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
#define AL_SOURCE_STATE
Source state information.
Definition: altypes.h:225
int curSampleOffset
Definition: snd_local.h:381
idDemoFile * writeDemo
Definition: snd_local.h:628
virtual int Index(void) const
#define alGetError
Definition: idal.h:36
int time
Definition: snd_local.h:356
const char * c_str(void) const
Definition: Str.h:487
float LengthFast(void) const
Definition: Vector.h:639
const int SOUND_DECODER_FREE_DELAY
Definition: snd_local.h:65
soundShaderParms_t parms
Definition: snd_local.h:483
idDeclBase * base
Definition: DeclManager.h:236
void PurgeSoundSample()
Definition: snd_cache.cpp:628
virtual void Decode(idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest)=0
#define AL_BUFFER
Indicate the buffer to provide sound samples.
Definition: altypes.h:142
idVec3 spatializedOrigin
Definition: snd_local.h:491
GLint j
Definition: qgl.h:264
virtual ~idSoundEmitterLocal(void)
idVec3 listenerPos
Definition: snd_local.h:631
idSession * session
Definition: Session.cpp:48
virtual int PointInArea(const idVec3 &point) const =0
const int SOUND_MAX_LIST_WAVS
Definition: sound.h:70
waveformatex_t objectInfo
Definition: snd_local.h:846
void TestPermutations(void)
#define max(x, y)
Definition: os.h:70
const int PRIMARYFREQ
Definition: snd_local.h:67
virtual void Error(const char *fmt,...) id_attribute((format(printf
FracTime newPosition
Definition: snd_local.h:377
virtual void TimeHitch(int msec)=0
bool disallowSlow
Definition: snd_local.h:430
static idCVar s_showStartSound
Definition: snd_local.h:789
idRenderWorld * rw
Definition: snd_local.h:627
void OverrideParms(const soundShaderParms_t *base, const soundShaderParms_t *over, soundShaderParms_t *out)
void Zero(void)
Definition: Vector.h:415
void Sys_LeaveCriticalSection(int index)
void Sys_EnterCriticalSection(int index)
idSoundWorldLocal * soundWorld
Definition: snd_local.h:476
void Spatialize(idVec3 listenerPos, int listenerArea, idRenderWorld *rw)
virtual int WriteVec3(const idVec3 &vec)
Definition: File.cpp:570
GLuint start
Definition: glext.h:2845
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
float minDistance
Definition: sound.h:61
const int SOUND_MAX_CHANNELS
Definition: snd_local.h:64
virtual float CurrentAmplitude(void)
void Increment(float val)
Definition: snd_local.h:360
float fadeStartVolume
Definition: snd_local.h:295
void WriteHashString(const char *str)
Definition: DemoFile.cpp:248