]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/sound/snd_emitter.cpp
hello world
[icculus/iodoom3.git] / neo / sound / snd_emitter.cpp
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 */
40 void idSoundFade::Clear() {
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 */
152 idSoundChannel::idSoundChannel( void ) {
153         decoder = NULL;
154         Clear();
155 }
156
157 /*
158 ===================
159 idSoundChannel::~idSoundChannel
160 ===================
161 */
162 idSoundChannel::~idSoundChannel( void ) {
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;
189         openalStreamingOffset = 0;
190         openalStreamingBuffer[0] = openalStreamingBuffer[1] = openalStreamingBuffer[2] = 0;
191         lastopenalStreamingBuffer[0] = lastopenalStreamingBuffer[1] = lastopenalStreamingBuffer[2] = 0;
192 }
193
194 /*
195 ===================
196 idSoundChannel::Start
197 ===================
198 */
199 void idSoundChannel::Start( void ) {
200         triggerState = true;
201         if ( decoder == NULL ) {
202                 decoder = idSampleDecoder::Alloc();
203         }
204 }
205
206 /*
207 ===================
208 idSoundChannel::Stop
209 ===================
210 */
211 void idSoundChannel::Stop( void ) {
212         triggerState = false;
213         if ( decoder != NULL ) {
214                 idSampleDecoder::Free( decoder );
215                 decoder = NULL;
216         }
217 }
218
219 /*
220 ===================
221 idSoundChannel::ALStop
222 ===================
223 */
224 void idSoundChannel::ALStop( void ) {
225         if ( idSoundSystemLocal::useOpenAL ) {
226
227                 if ( alIsSource( openalSource ) ) {
228                         alSourceStop( openalSource );
229                         alSourcei( openalSource, AL_BUFFER, 0 );
230                         soundSystemLocal.FreeOpenALSource( openalSource );
231                 }
232
233                 if ( openalStreamingBuffer[0] && openalStreamingBuffer[1] && openalStreamingBuffer[2] ) {
234                         alGetError();
235                         alDeleteBuffers( 3, &openalStreamingBuffer[0] );
236                         if ( alGetError() == AL_NO_ERROR ) {
237                                 openalStreamingBuffer[0] = openalStreamingBuffer[1] = openalStreamingBuffer[2] = 0;
238                         }
239                 }
240
241                 if ( lastopenalStreamingBuffer[0] && lastopenalStreamingBuffer[1] && lastopenalStreamingBuffer[2] ) {
242                         alGetError();
243                         alDeleteBuffers( 3, &lastopenalStreamingBuffer[0] );
244                         if ( alGetError() == AL_NO_ERROR ) {
245                                 lastopenalStreamingBuffer[0] = lastopenalStreamingBuffer[1] = lastopenalStreamingBuffer[2] = 0;
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 */
343 idSoundEmitterLocal::idSoundEmitterLocal( void ) {      
344         soundWorld = NULL;
345         Clear();
346 }
347
348 /*
349 ===============
350 idSoundEmitterLocal::~idSoundEmitterLocal
351 ===============
352 */
353 idSoundEmitterLocal::~idSoundEmitterLocal( void ) {
354         Clear();
355 }
356
357 /*
358 ===============
359 idSoundEmitterLocal::Clear
360 ===============
361 */
362 void idSoundEmitterLocal::Clear( void ) {
363         int i;
364
365         for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
366                 channels[i].ALStop();
367                 channels[i].Clear();
368         }
369
370         removeStatus = REMOVE_STATUS_SAMPLEFINISHED;
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
380         spatializedOrigin.Zero();
381
382         memset( &parms, 0, sizeof( parms ) );
383 }
384
385 /*
386 ==================
387 idSoundEmitterLocal::OverrideParms
388 ==================
389 */
390 void idSoundEmitterLocal::OverrideParms( const soundShaderParms_t *base, 
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         }
421         out->soundShaderFlags = base->soundShaderFlags | over->soundShaderFlags;
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
455                                 if ( idSoundSystemLocal::useOpenAL && alIsSource( chan->openalSource ) ) {
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 ) {
465                                                         chan->leadinSample->PurgeSoundSample();
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 ) {
477                                                 chan->leadinSample->PurgeSoundSample();
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;
499                 if ( removeStatus == REMOVE_STATUS_WAITSAMPLEFINISHED ) {
500                         // this can now be reused by the next request for a new soundEmitter
501                         removeStatus = REMOVE_STATUS_SAMPLEFINISHED;
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
542                 distance = realDistance;
543                 return;
544         }
545
546         //
547         // work out virtual origin and distance, which may be from a portal instead of the actual origin
548         //
549         distance = maxDistance * METERS_TO_DOOM;
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
558                                 distance = realDistance;
559                                 spatializedOrigin = origin;                     // sound is in our area
560                                 return;
561                         }
562                         soundInArea = lastValidPortalArea;
563                 }
564                 lastValidPortalArea = soundInArea;
565                 if ( soundInArea == listenerArea ) {
566                         distance = realDistance;
567                         spatializedOrigin = origin;                     // sound is in our area
568                         return;
569                 }
570
571                 soundWorld->ResolveOrigin( 0, NULL, soundInArea, 0.0f, origin, this );
572                 distance /= METERS_TO_DOOM;
573         } else {
574                 // no portals available
575                 distance = realDistance;
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 ) {
598                 soundWorld->writeDemo->WriteInt( DS_SOUND );
599                 soundWorld->writeDemo->WriteInt( SCMD_UPDATE );
600                 soundWorld->writeDemo->WriteInt( index );
601                 soundWorld->writeDemo->WriteVec3( origin );
602                 soundWorld->writeDemo->WriteInt( listenerId );
603                 soundWorld->writeDemo->WriteFloat( parms->minDistance );
604                 soundWorld->writeDemo->WriteFloat( parms->maxDistance );
605                 soundWorld->writeDemo->WriteFloat( parms->volume );
606                 soundWorld->writeDemo->WriteFloat( parms->shakes );
607                 soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
608                 soundWorld->writeDemo->WriteInt( parms->soundClass );
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 ) {
626         if ( removeStatus != REMOVE_STATUS_ALIVE ) {
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 ) {
634                 soundWorld->writeDemo->WriteInt( DS_SOUND );
635                 soundWorld->writeDemo->WriteInt( SCMD_FREE );
636                 soundWorld->writeDemo->WriteInt( index );
637                 soundWorld->writeDemo->WriteInt( immediate );
638         }
639
640         if ( !immediate ) {
641                 removeStatus = REMOVE_STATUS_WAITSAMPLEFINISHED;
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 ) {
666                 soundWorld->writeDemo->WriteInt( DS_SOUND );
667                 soundWorld->writeDemo->WriteInt( SCMD_START );
668                 soundWorld->writeDemo->WriteInt( index );
669
670                 soundWorld->writeDemo->WriteHashString( shader->GetName() );
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 {
695                 start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES;
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
757         Sys_EnterCriticalSection();
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();
773                                         chan->leadinSample->PurgeSoundSample();
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
791                 Sys_LeaveCriticalSection();
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] ) {
814                         start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES;
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;
835         chan->triggerGame44kHzTime = soundWorld->game44kHz;
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()
845         Spatialize( soundWorld->listenerPos, soundWorld->listenerArea, soundWorld->rw );
846
847         // return length of sound in milliseconds
848         int length = chan->leadinSample->LengthIn44kHzSamples();
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
866         Sys_LeaveCriticalSection();
867
868         return length;
869 }
870
871 /*
872 ===================
873 idSoundEmitterLocal::ModifySound
874 ===================
875 */
876 void idSoundEmitterLocal::ModifySound( const s_channelType channel, const soundShaderParms_t *parms ) {
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 ) {
884                 soundWorld->writeDemo->WriteInt( DS_SOUND );
885                 soundWorld->writeDemo->WriteInt( SCMD_MODIFY );
886                 soundWorld->writeDemo->WriteInt( index );
887                 soundWorld->writeDemo->WriteInt( channel );
888                 soundWorld->writeDemo->WriteFloat( parms->minDistance );
889                 soundWorld->writeDemo->WriteFloat( parms->maxDistance );
890                 soundWorld->writeDemo->WriteFloat( parms->volume );
891                 soundWorld->writeDemo->WriteFloat( parms->shakes );
892                 soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
893                 soundWorld->writeDemo->WriteInt( parms->soundClass );
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 ) {
909                         chan->soundShader->CheckShakesAndOgg();
910                 }
911         }
912 }
913
914 /*
915 ===================
916 idSoundEmitterLocal::StopSound
917
918 can pass SCHANNEL_ANY
919 ===================
920 */
921 void idSoundEmitterLocal::StopSound( const s_channelType channel ) {
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 ) {
929                 soundWorld->writeDemo->WriteInt( DS_SOUND );
930                 soundWorld->writeDemo->WriteInt( SCMD_STOP );
931                 soundWorld->writeDemo->WriteInt( index );
932                 soundWorld->writeDemo->WriteInt( channel );
933         }
934
935         Sys_EnterCriticalSection();
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 ) {
955                         chan->leadinSample->PurgeSoundSample();
956                 }
957
958                 chan->leadinSample = NULL;
959                 chan->soundShader = NULL;
960         }
961
962         Sys_LeaveCriticalSection();
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 ) {
980                 soundWorld->writeDemo->WriteInt( DS_SOUND );
981                 soundWorld->writeDemo->WriteInt( SCMD_FADE );
982                 soundWorld->writeDemo->WriteInt( index );
983                 soundWorld->writeDemo->WriteInt( channel );
984                 soundWorld->writeDemo->WriteFloat( to );
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 {
994                 start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES;
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 */
1028 bool idSoundEmitterLocal::CurrentlyPlaying( void ) const {
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 */
1049 float idSoundEmitterLocal::CurrentAmplitude( void ) {
1050         if ( idSoundSystemLocal::s_constantAmplitude.GetFloat() >= 0.0f ) {
1051                 return idSoundSystemLocal::s_constantAmplitude.GetFloat();
1052         }
1053
1054         if ( removeStatus > REMOVE_STATUS_WAITSAMPLEFINISHED ) {
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 */
1077 idSlowChannel idSoundEmitterLocal::GetSlowChannel( const idSoundChannel *chan ) {
1078         return slowChannels[chan - channels];
1079 }
1080
1081 /*
1082 ===================
1083 idSoundEmitterLocal::SetSlowChannel
1084 ===================
1085 */
1086 void idSoundEmitterLocal::SetSlowChannel( const idSoundChannel *chan, idSlowChannel slow ) {
1087         slowChannels[chan - channels] = slow;
1088 }
1089
1090 /*
1091 ===================
1092 idSoundEmitterLocal::ResetSlowChannel
1093 ===================
1094 */
1095 void idSoundEmitterLocal::ResetSlowChannel( const idSoundChannel *chan ) {
1096         int index = chan - channels;
1097         slowChannels[index].Reset();
1098 }
1099
1100 /*
1101 ===================
1102 idSlowChannel::Reset
1103 ===================
1104 */
1105 void idSlowChannel::Reset() {
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 */
1124 void idSlowChannel::AttachSoundChannel( const idSoundChannel *chan ) {
1125         this->chan = chan;
1126 }
1127
1128 /*
1129 ===================
1130 idSlowChannel::GetSlowmoSpeed
1131 ===================
1132 */
1133 float idSlowChannel::GetSlowmoSpeed() {
1134         idSoundWorldLocal *sw = static_cast<idSoundWorldLocal*>( soundSystemLocal.GetPlayingSoundWorld() );
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 ) {
1149         idSoundWorldLocal *sw = static_cast<idSoundWorldLocal*>( soundSystemLocal.GetPlayingSoundWorld() );
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 ) {
1220                 curPosition.Set( newSampleOffset );
1221         }
1222
1223         // set current vars
1224         curSampleOffset = newSampleOffset;
1225         newPosition = curPosition;
1226
1227         // do the slow processing
1228         GenerateSlowChannel( newPosition, sampleCount44k, dest );
1229
1230         // finish off
1231         if ( state == PLAYBACK_ADVANCING )
1232                 curPosition = newPosition;
1233 }