doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
snd_system.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 #ifdef ID_DEDICATED
36 #else
38 #endif
39 idCVar idSoundSystemLocal::s_quadraticFalloff( "s_quadraticFalloff", "1", CVAR_SOUND | CVAR_BOOL, "" );
40 idCVar idSoundSystemLocal::s_drawSounds( "s_drawSounds", "0", CVAR_SOUND | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
41 idCVar idSoundSystemLocal::s_showStartSound( "s_showStartSound", "0", CVAR_SOUND | CVAR_BOOL, "" );
42 idCVar idSoundSystemLocal::s_useOcclusion( "s_useOcclusion", "1", CVAR_SOUND | CVAR_BOOL, "" );
43 idCVar idSoundSystemLocal::s_maxSoundsPerShader( "s_maxSoundsPerShader", "0", CVAR_SOUND | CVAR_ARCHIVE, "", 0, 10, idCmdSystem::ArgCompletion_Integer<0,10> );
44 idCVar idSoundSystemLocal::s_showLevelMeter( "s_showLevelMeter", "0", CVAR_SOUND | CVAR_BOOL, "" );
45 idCVar idSoundSystemLocal::s_constantAmplitude( "s_constantAmplitude", "-1", CVAR_SOUND | CVAR_FLOAT, "" );
46 idCVar idSoundSystemLocal::s_minVolume6( "s_minVolume6", "0", CVAR_SOUND | CVAR_FLOAT, "" );
47 idCVar idSoundSystemLocal::s_dotbias6( "s_dotbias6", "0.8", CVAR_SOUND | CVAR_FLOAT, "" );
48 idCVar idSoundSystemLocal::s_minVolume2( "s_minVolume2", "0.25", CVAR_SOUND | CVAR_FLOAT, "" );
49 idCVar idSoundSystemLocal::s_dotbias2( "s_dotbias2", "1.1", CVAR_SOUND | CVAR_FLOAT, "" );
53 idCVar idSoundSystemLocal::s_volume( "s_volume_dB", "0", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume in dB" );
54 idCVar idSoundSystemLocal::s_playDefaultSound( "s_playDefaultSound", "1", CVAR_SOUND | CVAR_ARCHIVE | CVAR_BOOL, "play a beep for missing sounds" );
55 idCVar idSoundSystemLocal::s_subFraction( "s_subFraction", "0.75", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to subwoofer in 5.1" );
56 idCVar idSoundSystemLocal::s_globalFraction( "s_globalFraction", "0.8", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to all speakers when not spatialized" );
57 idCVar idSoundSystemLocal::s_doorDistanceAdd( "s_doorDistanceAdd", "150", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "reduce sound volume with this distance when going through a door" );
58 idCVar idSoundSystemLocal::s_singleEmitter( "s_singleEmitter", "0", CVAR_SOUND | CVAR_INTEGER, "mute all sounds but this emitter" );
59 idCVar idSoundSystemLocal::s_numberOfSpeakers( "s_numberOfSpeakers", "2", CVAR_SOUND | CVAR_ARCHIVE, "number of speakers" );
60 idCVar idSoundSystemLocal::s_force22kHz( "s_force22kHz", "0", CVAR_SOUND | CVAR_BOOL, "" );
61 idCVar idSoundSystemLocal::s_clipVolumes( "s_clipVolumes", "1", CVAR_SOUND | CVAR_BOOL, "" );
62 idCVar idSoundSystemLocal::s_realTimeDecoding( "s_realTimeDecoding", "1", CVAR_SOUND | CVAR_BOOL | CVAR_INIT, "" );
63 
64 idCVar idSoundSystemLocal::s_slowAttenuate( "s_slowAttenuate", "1", CVAR_SOUND | CVAR_BOOL, "slowmo sounds attenuate over shorted distance" );
65 idCVar idSoundSystemLocal::s_enviroSuitCutoffFreq( "s_enviroSuitCutoffFreq", "2000", CVAR_SOUND | CVAR_FLOAT, "" );
66 idCVar idSoundSystemLocal::s_enviroSuitCutoffQ( "s_enviroSuitCutoffQ", "2", CVAR_SOUND | CVAR_FLOAT, "" );
67 idCVar idSoundSystemLocal::s_reverbTime( "s_reverbTime", "1000", CVAR_SOUND | CVAR_FLOAT, "" );
68 idCVar idSoundSystemLocal::s_reverbFeedback( "s_reverbFeedback", "0.333", CVAR_SOUND | CVAR_FLOAT, "" );
69 idCVar idSoundSystemLocal::s_enviroSuitVolumeScale( "s_enviroSuitVolumeScale", "0.9", CVAR_SOUND | CVAR_FLOAT, "" );
70 idCVar idSoundSystemLocal::s_skipHelltimeFX( "s_skipHelltimeFX", "0", CVAR_SOUND | CVAR_BOOL, "" );
71 
72 #if ID_OPENAL
73 // off by default. OpenAL DLL gets loaded on-demand
74 idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL DLL name/path" );
75 idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use OpenAL" );
76 idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use EAX reverb" );
77 idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL, "mute eax reverb" );
78 idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ARCHIVE, "specifies maximum uncompressed sample length in seconds" );
79 #else
80 idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL is not supported in this build" );
81 idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "OpenAL is not supported in this build" );
82 idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "EAX not available in this build" );
83 idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "mute eax reverb" );
84 idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ROM, "specifies maximum uncompressed sample length in seconds" );
85 #endif
86 
90 
93 
94 /*
95 ===============
96 SoundReloadSounds_f
97 
98  this is called from the main thread
99 ===============
100 */
101 void SoundReloadSounds_f( const idCmdArgs &args ) {
102  if ( !soundSystemLocal.soundCache ) {
103  return;
104  }
105  bool force = false;
106  if ( args.Argc() == 2 ) {
107  force = true;
108  }
109  soundSystem->SetMute( true );
110  soundSystemLocal.soundCache->ReloadSounds( force );
111  soundSystem->SetMute( false );
112  common->Printf( "sound: changed sounds reloaded\n" );
113 }
114 
115 /*
116 ===============
117 ListSounds_f
118 
119 Optional parameter to only list sounds containing that string
120 ===============
121 */
122 void ListSounds_f( const idCmdArgs &args ) {
123  int i;
124  const char *snd = args.Argv( 1 );
125 
126  if ( !soundSystemLocal.soundCache ) {
127  common->Printf( "No sound.\n" );
128  return;
129  }
130 
131  int totalSounds = 0;
132  int totalSamples = 0;
133  int totalMemory = 0;
134  int totalPCMMemory = 0;
135  for( i = 0; i < soundSystemLocal.soundCache->GetNumObjects(); i++ ) {
136  const idSoundSample *sample = soundSystemLocal.soundCache->GetObject(i);
137  if ( !sample ) {
138  continue;
139  }
140  if ( snd && sample->name.Find( snd, false ) < 0 ) {
141  continue;
142  }
143 
144  const waveformatex_t &info = sample->objectInfo;
145 
146  const char *stereo = ( info.nChannels == 2 ? "ST" : " " );
147  const char *format = ( info.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
148  const char *defaulted = ( sample->defaultSound ? "(DEFAULTED)" : sample->purged ? "(PURGED)" : "" );
149 
150  common->Printf( "%s %dkHz %6dms %5dkB %4s %s%s\n", stereo, sample->objectInfo.nSamplesPerSec / 1000,
151  soundSystemLocal.SamplesToMilliseconds( sample->LengthIn44kHzSamples() ),
152  sample->objectMemSize >> 10, format, sample->name.c_str(), defaulted );
153 
154  if ( !sample->purged ) {
155  totalSamples += sample->objectSize;
156  if ( info.wFormatTag != WAVE_FORMAT_TAG_OGG )
157  totalPCMMemory += sample->objectMemSize;
158  if ( !sample->hardwareBuffer )
159  totalMemory += sample->objectMemSize;
160  }
161  totalSounds++;
162  }
163  common->Printf( "%8d total sounds\n", totalSounds );
164  common->Printf( "%8d total samples loaded\n", totalSamples );
165  common->Printf( "%8d kB total system memory used\n", totalMemory >> 10 );
166 #if ID_OPENAL
167  common->Printf( "%8d kB total OpenAL audio memory used\n", ( alGetInteger( alGetEnumValue( "AL_EAX_RAM_SIZE" ) ) - alGetInteger( alGetEnumValue( "AL_EAX_RAM_FREE" ) ) ) >> 10 );
168 #endif
169 }
170 
171 /*
172 ===============
173 ListSoundDecoders_f
174 ===============
175 */
176 void ListSoundDecoders_f( const idCmdArgs &args ) {
177  int i, j, numActiveDecoders, numWaitingDecoders;
178  idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
179 
180  numActiveDecoders = numWaitingDecoders = 0;
181 
182  for ( i = 0; i < sw->emitters.Num(); i++ ) {
183  idSoundEmitterLocal *sound = sw->emitters[i];
184 
185  if ( !sound ) {
186  continue;
187  }
188 
189  // run through all the channels
190  for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
191  idSoundChannel *chan = &sound->channels[j];
192 
193  if ( chan->decoder == NULL ) {
194  continue;
195  }
196 
197  idSoundSample *sample = chan->decoder->GetSample();
198 
199  if ( sample != NULL ) {
200  continue;
201  }
202 
203  const char *format = ( chan->leadinSample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
204  common->Printf( "%3d waiting %s: %s\n", numWaitingDecoders, format, chan->leadinSample->name.c_str() );
205 
206  numWaitingDecoders++;
207  }
208  }
209 
210  for ( i = 0; i < sw->emitters.Num(); i++ ) {
211  idSoundEmitterLocal *sound = sw->emitters[i];
212 
213  if ( !sound ) {
214  continue;
215  }
216 
217  // run through all the channels
218  for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
219  idSoundChannel *chan = &sound->channels[j];
220 
221  if ( chan->decoder == NULL ) {
222  continue;
223  }
224 
225  idSoundSample *sample = chan->decoder->GetSample();
226 
227  if ( sample == NULL ) {
228  continue;
229  }
230 
231  const char *format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
232 
233  int localTime = soundSystemLocal.GetCurrent44kHzTime() - chan->trigger44kHzTime;
234  int sampleTime = sample->LengthIn44kHzSamples() * sample->objectInfo.nChannels;
235  int percent;
236  if ( localTime > sampleTime ) {
237  if ( chan->parms.soundShaderFlags & SSF_LOOPING ) {
238  percent = ( localTime % sampleTime ) * 100 / sampleTime;
239  } else {
240  percent = 100;
241  }
242  } else {
243  percent = localTime * 100 / sampleTime;
244  }
245 
246  common->Printf( "%3d decoding %3d%% %s: %s\n", numActiveDecoders, percent, format, sample->name.c_str() );
247 
248  numActiveDecoders++;
249  }
250  }
251 
252  common->Printf( "%d decoders\n", numWaitingDecoders + numActiveDecoders );
253  common->Printf( "%d waiting decoders\n", numWaitingDecoders );
254  common->Printf( "%d active decoders\n", numActiveDecoders );
255  common->Printf( "%d kB decoder memory in %d blocks\n", idSampleDecoder::GetUsedBlockMemory() >> 10, idSampleDecoder::GetNumUsedBlocks() );
256 }
257 
258 /*
259 ===============
260 TestSound_f
261 
262  this is called from the main thread
263 ===============
264 */
265 void TestSound_f( const idCmdArgs &args ) {
266  if ( args.Argc() != 2 ) {
267  common->Printf( "Usage: testSound <file>\n" );
268  return;
269  }
270  if ( soundSystemLocal.currentSoundWorld ) {
271  soundSystemLocal.currentSoundWorld->PlayShaderDirectly( args.Argv( 1 ) );
272  }
273 }
274 
275 /*
276 ===============
277 SoundSystemRestart_f
278 
279 restart the sound thread
280 
281  this is called from the main thread
282 ===============
283 */
284 void SoundSystemRestart_f( const idCmdArgs &args ) {
285  soundSystem->SetMute( true );
286  soundSystemLocal.ShutdownHW();
287  soundSystemLocal.InitHW();
288  soundSystem->SetMute( false );
289 }
290 
291 /*
292 ===============
293 idSoundSystemLocal::Init
294 
295 initialize the sound system
296 ===============
297 */
299 
300  common->Printf( "----- Initializing Sound System ------\n" );
301 
302  isInitialized = false;
303  muted = false;
304  shutdown = false;
305 
307  soundCache = NULL;
308 
310  buffers = 0;
311  CurrentSoundTime = 0;
312 
313  nextWriteBlock = 0xffffffff;
314 
315  memset( meterTops, 0, sizeof( meterTops ) );
316  memset( meterTopsTime, 0, sizeof( meterTopsTime ) );
317 
318  for( int i = -600; i < 600; i++ ) {
319  float pt = i * 0.1f;
320  volumesDB[i+600] = pow( 2.0f,( pt * ( 1.0f / 6.0f ) ) );
321  }
322 
323  // make a 16 byte aligned finalMixBuffer
324  finalMixBuffer = (float *) ( ( ( (int)realAccum ) + 15 ) & ~15 );
325 
326  graph = NULL;
327 
328  if ( !s_noSound.GetBool() ) {
330  soundCache = new idSoundCache();
331  }
332 
333  // set up openal device and context
334  common->StartupVariable( "s_useOpenAL", true );
335  common->StartupVariable( "s_useEAXReverb", true );
336 
338  if ( !Sys_LoadOpenAL() ) {
340  } else {
341  common->Printf( "Setup OpenAL device and context... " );
345  common->Printf( "Done.\n" );
346 
347  // try to obtain EAX extensions
348  if ( idSoundSystemLocal::s_useEAXReverb.GetBool() && alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
349  idSoundSystemLocal::s_useOpenAL.SetBool( true ); // EAX presence causes AL enable
350  alEAXSet = (EAXSet)alGetProcAddress( ID_ALCHAR "EAXSet" );
351  alEAXGet = (EAXGet)alGetProcAddress( ID_ALCHAR "EAXGet" );
352  common->Printf( "OpenAL: found EAX 4.0 extension\n" );
353  } else {
354  common->Printf( "OpenAL: EAX 4.0 extension not found\n" );
356  alEAXSet = (EAXSet)NULL;
357  alEAXGet = (EAXGet)NULL;
358  }
359 
360  // try to obtain EAX-RAM extension - not required for operation
361  if ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) {
362  alEAXSetBufferMode = (EAXSetBufferMode)alGetProcAddress( ID_ALCHAR "EAXSetBufferMode" );
363  alEAXGetBufferMode = (EAXGetBufferMode)alGetProcAddress( ID_ALCHAR "EAXGetBufferMode" );
364  common->Printf( "OpenAL: found EAX-RAM extension, %dkB\\%dkB\n", alGetInteger( alGetEnumValue( ID_ALCHAR "AL_EAX_RAM_FREE" ) ) / 1024, alGetInteger( alGetEnumValue( ID_ALCHAR "AL_EAX_RAM_SIZE" ) ) / 1024 );
365  } else {
366  alEAXSetBufferMode = (EAXSetBufferMode)NULL;
367  alEAXGetBufferMode = (EAXGetBufferMode)NULL;
368  common->Printf( "OpenAL: no EAX-RAM extension\n" );
369  }
370 
371  if ( !idSoundSystemLocal::s_useOpenAL.GetBool() ) {
372  common->Printf( "OpenAL: disabling ( no EAX ). Using legacy mixer.\n" );
373 
375 
378 
380  openalDevice = NULL;
381  } else {
382 
383  ALuint handle;
384  openalSourceCount = 0;
385 
386  while ( openalSourceCount < 256 ) {
387  alGetError();
388  alGenSources( 1, &handle );
389  if ( alGetError() != AL_NO_ERROR ) {
390  break;
391  } else {
392  // store in source array
398 
399  // initialise sources
400  alSourcef( handle, AL_ROLLOFF_FACTOR, 0.0f );
401 
402  // found one source
404  }
405  }
406 
407  common->Printf( "OpenAL: found %s\n", alcGetString( openalDevice, ALC_DEVICE_SPECIFIER ) );
408  common->Printf( "OpenAL: found %d hardware voices\n", openalSourceCount );
409 
410  // adjust source count to allow for at least eight stereo sounds to play
411  openalSourceCount -= 8;
412 
413  EAXAvailable = 1;
414  }
415  }
416  }
417 
420 
421  cmdSystem->AddCommand( "listSounds", ListSounds_f, CMD_FL_SOUND, "lists all sounds" );
422  cmdSystem->AddCommand( "listSoundDecoders", ListSoundDecoders_f, CMD_FL_SOUND, "list active sound decoders" );
423  cmdSystem->AddCommand( "reloadSounds", SoundReloadSounds_f, CMD_FL_SOUND|CMD_FL_CHEAT, "reloads all sounds" );
425  cmdSystem->AddCommand( "s_restart", SoundSystemRestart_f, CMD_FL_SOUND, "restarts the sound system" );
426 
427  common->Printf( "sound system initialized.\n" );
428  common->Printf( "--------------------------------------\n" );
429 }
430 
431 /*
432 ===============
433 idSoundSystemLocal::Shutdown
434 ===============
435 */
437  ShutdownHW();
438 
439  // EAX or not, the list needs to be cleared
440  EFXDatabase.Clear();
441 
442  // destroy openal sources
443  if ( useOpenAL ) {
444 
445  efxloaded = false;
446 
447  // adjust source count back up to allow for freeing of all resources
448  openalSourceCount += 8;
449 
450  for ( ALsizei i = 0; i < openalSourceCount; i++ ) {
451  // stop source
452  alSourceStop( openalSources[i].handle );
453  alSourcei( openalSources[i].handle, AL_BUFFER, 0 );
454 
455  // delete source
456  alDeleteSources( 1, &openalSources[i].handle );
457 
458  // clear entry in source array
462  openalSources[i].inUse = false;
463  openalSources[i].looping = false;
464 
465  }
466  }
467 
468  // destroy all the sounds (hardware buffers as well)
469  delete soundCache;
470  soundCache = NULL;
471 
472  // destroy openal device and context
473  if ( useOpenAL ) {
475 
478 
480  openalDevice = NULL;
481  }
482 
483  Sys_FreeOpenAL();
484 
486 }
487 
488 /*
489 ===============
490 idSoundSystemLocal::InitHW
491 ===============
492 */
494 
495  if ( s_noSound.GetBool() ) {
496  return false;
497  }
498 
499  delete snd_audio_hw;
501 
502  if ( snd_audio_hw == NULL ) {
503  return false;
504  }
505 
506  if ( !useOpenAL ) {
507  if ( !snd_audio_hw->Initialize() ) {
508  delete snd_audio_hw;
509  snd_audio_hw = NULL;
510  return false;
511  }
512 
513  if ( snd_audio_hw->GetNumberOfSpeakers() == 0 ) {
514  return false;
515  }
516  // put the real number in there
518  }
519 
520  isInitialized = true;
521  shutdown = false;
522 
523  return true;
524 }
525 
526 /*
527 ===============
528 idSoundSystemLocal::ShutdownHW
529 ===============
530 */
532  if ( !isInitialized ) {
533  return false;
534  }
535 
536  shutdown = true; // don't do anything at AsyncUpdate() time
537  Sys_Sleep( 100 ); // sleep long enough to make sure any async sound talking to hardware has returned
538 
539  common->Printf( "Shutting down sound hardware\n" );
540 
541  delete snd_audio_hw;
542  snd_audio_hw = NULL;
543 
544  isInitialized = false;
545 
546  if ( graph ) {
547  Mem_Free( graph );
548  graph = NULL;
549  }
550 
551  return true;
552 }
553 
554 /*
555 ===============
556 idSoundSystemLocal::GetCurrent44kHzTime
557 ===============
558 */
560  if ( snd_audio_hw ) {
561  return CurrentSoundTime;
562  } else {
563  // NOTE: this would overflow 31bits within about 1h20 ( not that important since we get a snd_audio_hw right away pbly )
564  //return ( ( Sys_Milliseconds()*441 ) / 10 ) * 4;
565  return idMath::FtoiFast( (float)Sys_Milliseconds() * 176.4f );
566  }
567 }
568 
569 /*
570 ===================
571 idSoundSystemLocal::ClearBuffer
572 ===================
573 */
575 
576  // check to make sure hardware actually exists
577  if ( !snd_audio_hw ) {
578  return;
579  }
580 
581  short *fBlock;
582  ulong fBlockLen;
583 
584  if ( !snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen ) ) {
585  return;
586  }
587 
588  if ( fBlock ) {
589  SIMDProcessor->Memset( fBlock, 0, fBlockLen );
590  snd_audio_hw->Unlock( fBlock, fBlockLen );
591  }
592 }
593 
594 /*
595 ===================
596 idSoundSystemLocal::AsyncMix
597 Mac OSX version. The system uses it's own thread and an IOProc callback
598 ===================
599 */
600 int idSoundSystemLocal::AsyncMix( int soundTime, float *mixBuffer ) {
601  int inTime, numSpeakers;
602 
603  if ( !isInitialized || shutdown || !snd_audio_hw ) {
604  return 0;
605  }
606 
607  inTime = Sys_Milliseconds();
608  numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
609 
610  // let the active sound world mix all the channels in unless muted or avi demo recording
611  if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
612  currentSoundWorld->MixLoop( soundTime, numSpeakers, mixBuffer );
613  }
614 
615  CurrentSoundTime = soundTime;
616 
617  return Sys_Milliseconds() - inTime;
618 }
619 
620 /*
621 ===================
622 idSoundSystemLocal::AsyncUpdate
623 called from async sound thread when com_asyncSound == 1 ( Windows )
624 ===================
625 */
627 
628  if ( !isInitialized || shutdown || !snd_audio_hw ) {
629  return 0;
630  }
631 
632  ulong dwCurrentWritePos;
633  dword dwCurrentBlock;
634 
635  // If not using openal, get actual playback position from sound hardware
636  if ( useOpenAL ) {
637  // here we do it in samples ( overflows in 27 hours or so )
638  dwCurrentWritePos = idMath::Ftol( (float)Sys_Milliseconds() * 44.1f ) % ( MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER );
639  dwCurrentBlock = dwCurrentWritePos / MIXBUFFER_SAMPLES;
640  } else {
641  // and here in bytes
642  // get the current byte position in the buffer where the sound hardware is currently reading
643  if ( !snd_audio_hw->GetCurrentPosition( &dwCurrentWritePos ) ) {
644  return 0;
645  }
646  // mixBufferSize is in bytes
647  dwCurrentBlock = dwCurrentWritePos / snd_audio_hw->GetMixBufferSize();
648  }
649 
650  if ( nextWriteBlock == 0xffffffff ) {
651  nextWriteBlock = dwCurrentBlock;
652  }
653 
654  if ( dwCurrentBlock != nextWriteBlock ) {
655  return 0;
656  }
657 
658  // lock the buffer so we can actually write to it
659  short *fBlock = NULL;
660  ulong fBlockLen = 0;
661  if ( !useOpenAL ) {
662  snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen );
663  if ( !fBlock ) {
664  return 0;
665  }
666  }
667 
668  int j;
669  soundStats.runs++;
671 
672  int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
673 
674  nextWriteBlock++;
676 
677  int newPosition = nextWriteBlock * MIXBUFFER_SAMPLES;
678 
679  if ( newPosition < olddwCurrentWritePos ) {
680  buffers++; // buffer wrapped
681  }
682 
683  // nextWriteSample is in multi-channel samples inside the buffer
684  int nextWriteSamples = nextWriteBlock * MIXBUFFER_SAMPLES;
685 
686  olddwCurrentWritePos = newPosition;
687 
688  // newSoundTime is in multi-channel samples since the sound system was started
689  int newSoundTime = ( buffers * MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER ) + nextWriteSamples;
690 
691  // check for impending overflow
692  // FIXME: we don't handle sound wrap-around correctly yet
693  if ( newSoundTime > 0x6fffffff ) {
694  buffers = 0;
695  }
696 
697  if ( (newSoundTime - CurrentSoundTime) > (int)MIXBUFFER_SAMPLES ) {
699  }
700 
701  if ( useOpenAL ) {
702  // enable audio hardware caching
704  } else {
705  // clear the buffer for all the mixing output
706  SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
707  }
708 
709  // let the active sound world mix all the channels in unless muted or avi demo recording
710  if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
711  currentSoundWorld->MixLoop( newSoundTime, numSpeakers, finalMixBuffer );
712  }
713 
714  if ( useOpenAL ) {
715  // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
717  } else {
718  short *dest = fBlock + nextWriteSamples * numSpeakers;
719 
720  SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
721 
722  // allow swapping the left / right speaker channels for people with miswired systems
723  if ( numSpeakers == 2 && s_reverse.GetBool() ) {
724  for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
725  short temp = dest[j*2];
726  dest[j*2] = dest[j*2+1];
727  dest[j*2+1] = temp;
728  }
729  }
730  snd_audio_hw->Unlock( fBlock, fBlockLen );
731  }
732 
733  CurrentSoundTime = newSoundTime;
734 
736 
737  return soundStats.timeinprocess;
738 }
739 
740 /*
741 ===================
742 idSoundSystemLocal::AsyncUpdateWrite
743 sound output using a write API. all the scheduling based on time
744 we mix MIXBUFFER_SAMPLES at a time, but we feed the audio device with smaller chunks (and more often)
745 called by the sound thread when com_asyncSound is 3 ( Linux )
746 ===================
747 */
749 
750  if ( !isInitialized || shutdown || !snd_audio_hw ) {
751  return 0;
752  }
753 
754  if ( !useOpenAL ) {
755  snd_audio_hw->Flush();
756  }
757 
758  unsigned int dwCurrentBlock = (unsigned int)( inTime * 44.1f / MIXBUFFER_SAMPLES );
759 
760  if ( nextWriteBlock == 0xffffffff ) {
761  nextWriteBlock = dwCurrentBlock;
762  }
763 
764  if ( dwCurrentBlock < nextWriteBlock ) {
765  return 0;
766  }
767 
768  if ( nextWriteBlock != dwCurrentBlock ) {
769  Sys_Printf( "missed %d sound updates\n", dwCurrentBlock - nextWriteBlock );
770  }
771 
772  int sampleTime = dwCurrentBlock * MIXBUFFER_SAMPLES;
773  int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
774 
775  if ( useOpenAL ) {
776  // enable audio hardware caching
778  } else {
779  // clear the buffer for all the mixing output
780  SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
781  }
782 
783  // let the active sound world mix all the channels in unless muted or avi demo recording
784  if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
785  currentSoundWorld->MixLoop( sampleTime, numSpeakers, finalMixBuffer );
786  }
787 
788  if ( useOpenAL ) {
789  // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
791  } else {
792  short *dest = snd_audio_hw->GetMixBuffer();
793 
794  SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
795 
796  // allow swapping the left / right speaker channels for people with miswired systems
797  if ( numSpeakers == 2 && s_reverse.GetBool() ) {
798  int j;
799  for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
800  short temp = dest[j*2];
801  dest[j*2] = dest[j*2+1];
802  dest[j*2+1] = temp;
803  }
804  }
805  snd_audio_hw->Write( false );
806  }
807 
808  // only move to the next block if the write was successful
809  nextWriteBlock = dwCurrentBlock + 1;
810  CurrentSoundTime = sampleTime;
811 
812  return Sys_Milliseconds() - inTime;
813 }
814 
815 /*
816 ===================
817 idSoundSystemLocal::dB2Scale
818 ===================
819 */
820 float idSoundSystemLocal::dB2Scale( const float val ) const {
821  if ( val == 0.0f ) {
822  return 1.0f; // most common
823  } else if ( val <= -60.0f ) {
824  return 0.0f;
825  } else if ( val >= 60.0f ) {
826  return powf( 2.0f, val * ( 1.0f / 6.0f ) );
827  }
828  int ival = (int)( ( val + 60.0f ) * 10.0f );
829  return volumesDB[ival];
830 }
831 
832 /*
833 ===================
834 idSoundSystemLocal::ImageForTime
835 ===================
836 */
837 cinData_t idSoundSystemLocal::ImageForTime( const int milliseconds, const bool waveform ) {
838  cinData_t ret;
839  int i, j;
840 
841  if ( !isInitialized || !snd_audio_hw ) {
842  memset( &ret, 0, sizeof( ret ) );
843  return ret;
844  }
845 
847 
848  if ( !graph ) {
849  graph = (dword *)Mem_Alloc( 256*128 * 4);
850  }
851  memset( graph, 0, 256*128 * 4 );
852  float *accum = finalMixBuffer; // unfortunately, these are already clamped
853  int time = Sys_Milliseconds();
854 
855  int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
856 
857  if ( !waveform ) {
858  for( j = 0; j < numSpeakers; j++ ) {
859  int meter = 0;
860  for( i = 0; i < MIXBUFFER_SAMPLES; i++ ) {
861  float result = idMath::Fabs(accum[i*numSpeakers+j]);
862  if ( result > meter ) {
863  meter = result;
864  }
865  }
866 
867  meter /= 256; // 32768 becomes 128
868  if ( meter > 128 ) {
869  meter = 128;
870  }
871  int offset;
872  int xsize;
873  if ( numSpeakers == 6 ) {
874  offset = j * 40;
875  xsize = 20;
876  } else {
877  offset = j * 128;
878  xsize = 63;
879  }
880  int x,y;
881  dword color = 0xff00ff00;
882  for ( y = 0; y < 128; y++ ) {
883  for ( x = 0; x < xsize; x++ ) {
884  graph[(127-y)*256 + offset + x ] = color;
885  }
886 #if 0
887  if ( y == 80 ) {
888  color = 0xff00ffff;
889  } else if ( y == 112 ) {
890  color = 0xff0000ff;
891  }
892 #endif
893  if ( y > meter ) {
894  break;
895  }
896  }
897 
898  if ( meter > meterTops[j] ) {
899  meterTops[j] = meter;
901  } else if ( time > meterTopsTime[j] && meterTops[j] > 0 ) {
902  meterTops[j]--;
903  if (meterTops[j]) {
904  meterTops[j]--;
905  }
906  }
907  }
908 
909  for( j = 0; j < numSpeakers; j++ ) {
910  int meter = meterTops[j];
911 
912  int offset;
913  int xsize;
914  if ( numSpeakers == 6 ) {
915  offset = j*40;
916  xsize = 20;
917  } else {
918  offset = j*128;
919  xsize = 63;
920  }
921  int x,y;
922  dword color;
923  if ( meter <= 80 ) {
924  color = 0xff007f00;
925  } else if ( meter <= 112 ) {
926  color = 0xff007f7f;
927  } else {
928  color = 0xff00007f;
929  }
930  for ( y = meter; y < 128 && y < meter + 4; y++ ) {
931  for ( x = 0; x < xsize; x++ ) {
932  graph[(127-y)*256 + offset + x ] = color;
933  }
934  }
935  }
936  } else {
937  dword colors[] = { 0xff007f00, 0xff007f7f, 0xff00007f, 0xff00ff00, 0xff00ffff, 0xff0000ff };
938 
939  for( j = 0; j < numSpeakers; j++ ) {
940  int xx = 0;
941  float fmeter;
942  int step = MIXBUFFER_SAMPLES / 256;
943  for( i = 0; i < MIXBUFFER_SAMPLES; i += step ) {
944  fmeter = 0.0f;
945  for( int x = 0; x < step; x++ ) {
946  float result = accum[(i+x)*numSpeakers+j];
947  result = result / 32768.0f;
948  fmeter += result;
949  }
950  fmeter /= 4.0f;
951  if ( fmeter < -1.0f ) {
952  fmeter = -1.0f;
953  } else if ( fmeter > 1.0f ) {
954  fmeter = 1.0f;
955  }
956  int meter = (fmeter * 63.0f);
957  graph[ (meter + 64) * 256 + xx ] = colors[j];
958 
959  if ( meter < 0 ) {
960  meter = -meter;
961  }
962  if ( meter > meterTops[xx] ) {
963  meterTops[xx] = meter;
964  meterTopsTime[xx] = time + 100;
965  } else if ( time>meterTopsTime[xx] && meterTops[xx] > 0 ) {
966  meterTops[xx]--;
967  if ( meterTops[xx] ) {
968  meterTops[xx]--;
969  }
970  }
971  xx++;
972  }
973  }
974  for( i = 0; i < 256; i++ ) {
975  int meter = meterTops[i];
976  for ( int y = -meter; y < meter; y++ ) {
977  graph[ (y+64)*256 + i ] = colors[j];
978  }
979  }
980  }
981  ret.imageHeight = 128;
982  ret.imageWidth = 256;
983  ret.image = (unsigned char *)graph;
984 
986 
987  return ret;
988 }
989 
990 /*
991 ===================
992 idSoundSystemLocal::GetSoundDecoderInfo
993 ===================
994 */
996  int i, j, firstEmitter, firstChannel;
997  idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
998 
999  if ( index < 0 ) {
1000  firstEmitter = 0;
1001  firstChannel = 0;
1002  } else {
1003  firstEmitter = index / SOUND_MAX_CHANNELS;
1004  firstChannel = index - firstEmitter * SOUND_MAX_CHANNELS + 1;
1005  }
1006 
1007  for ( i = firstEmitter; i < sw->emitters.Num(); i++ ) {
1008  idSoundEmitterLocal *sound = sw->emitters[i];
1009 
1010  if ( !sound ) {
1011  continue;
1012  }
1013 
1014  // run through all the channels
1015  for ( j = firstChannel; j < SOUND_MAX_CHANNELS; j++ ) {
1016  idSoundChannel *chan = &sound->channels[j];
1017 
1018  if ( chan->decoder == NULL ) {
1019  continue;
1020  }
1021 
1022  idSoundSample *sample = chan->decoder->GetSample();
1023 
1024  if ( sample == NULL ) {
1025  continue;
1026  }
1027 
1028  decoderInfo.name = sample->name;
1029  decoderInfo.format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
1030  decoderInfo.numChannels = sample->objectInfo.nChannels;
1031  decoderInfo.numSamplesPerSecond = sample->objectInfo.nSamplesPerSec;
1032  decoderInfo.num44kHzSamples = sample->LengthIn44kHzSamples();
1033  decoderInfo.numBytes = sample->objectMemSize;
1034  decoderInfo.looping = ( chan->parms.soundShaderFlags & SSF_LOOPING ) != 0;
1035  decoderInfo.lastVolume = chan->lastVolume;
1036  decoderInfo.start44kHzTime = chan->trigger44kHzTime;
1037  decoderInfo.current44kHzTime = soundSystemLocal.GetCurrent44kHzTime();
1038 
1039  return ( i * SOUND_MAX_CHANNELS + j );
1040  }
1041 
1042  firstChannel = 0;
1043  }
1044  return -1;
1045 }
1046 
1047 /*
1048 ===================
1049 idSoundSystemLocal::AllocSoundWorld
1050 ===================
1051 */
1053  idSoundWorldLocal *local = new idSoundWorldLocal;
1054 
1055  local->Init( rw );
1056 
1057  return local;
1058 }
1059 
1060 /*
1061 ===================
1062 idSoundSystemLocal::SetMute
1063 ===================
1064 */
1065 void idSoundSystemLocal::SetMute( bool muteOn ) {
1066  muted = muteOn;
1067 }
1068 
1069 /*
1070 ===================
1071 idSoundSystemLocal::SamplesToMilliseconds
1072 ===================
1073 */
1075  return ( samples / (PRIMARYFREQ/1000) );
1076 }
1077 
1078 /*
1079 ===================
1080 idSoundSystemLocal::SamplesToMilliseconds
1081 ===================
1082 */
1084  return ( ms * (PRIMARYFREQ/1000) );
1085 }
1086 
1087 /*
1088 ===================
1089 idSoundSystemLocal::SetPlayingSoundWorld
1090 
1091 specifying NULL will cause silence to be played
1092 ===================
1093 */
1095  currentSoundWorld = static_cast<idSoundWorldLocal *>(soundWorld);
1096 }
1097 
1098 /*
1099 ===================
1100 idSoundSystemLocal::GetPlayingSoundWorld
1101 ===================
1102 */
1104  return currentSoundWorld;
1105 }
1106 
1107 /*
1108 ===================
1109 idSoundSystemLocal::BeginLevelLoad
1110 ===================
1111 */
1112 
1114  if ( !isInitialized ) {
1115  return;
1116  }
1118 
1119  if ( efxloaded ) {
1121  efxloaded = false;
1122  }
1123 }
1124 
1125 /*
1126 ===================
1127 idSoundSystemLocal::EndLevelLoad
1128 ===================
1129 */
1130 void idSoundSystemLocal::EndLevelLoad( const char *mapstring ) {
1131  if ( !isInitialized ) {
1132  return;
1133  }
1135 
1136  idStr efxname( "efxs/" );
1137  idStr mapname( mapstring );
1138 
1139  mapname.SetFileExtension( ".efx" );
1140  mapname.StripPath();
1141  efxname += mapname;
1142 
1143  efxloaded = EFXDatabase.LoadFile( efxname );
1144 
1145  if ( efxloaded ) {
1146  common->Printf("sound: found %s\n", efxname.c_str() );
1147  } else {
1148  common->Printf("sound: missing %s\n", efxname.c_str() );
1149  }
1150 }
1151 
1152 /*
1153 ===================
1154 idSoundSystemLocal::AllocOpenALSource
1155 ===================
1156 */
1157 ALuint idSoundSystemLocal::AllocOpenALSource( idSoundChannel *chan, bool looping, bool stereo ) {
1158  int timeOldestZeroVolSingleShot = Sys_Milliseconds();
1159  int timeOldestZeroVolLooping = Sys_Milliseconds();
1160  int timeOldestSingle = Sys_Milliseconds();
1161  int iOldestZeroVolSingleShot = -1;
1162  int iOldestZeroVolLooping = -1;
1163  int iOldestSingle = -1;
1164  int iUnused = -1;
1165  int index = -1;
1166  ALsizei i;
1167 
1168  // Grab current msec time
1169  int time = Sys_Milliseconds();
1170 
1171  // Cycle through all sources
1172  for ( i = 0; i < openalSourceCount; i++ ) {
1173  // Use any unused source first,
1174  // Then find oldest single shot quiet source,
1175  // Then find oldest looping quiet source and
1176  // Lastly find oldest single shot non quiet source..
1177  if ( !openalSources[i].inUse ) {
1178  iUnused = i;
1179  break;
1180  } else if ( !openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
1181  if ( openalSources[i].startTime < timeOldestZeroVolSingleShot ) {
1182  timeOldestZeroVolSingleShot = openalSources[i].startTime;
1183  iOldestZeroVolSingleShot = i;
1184  }
1185  } else if ( openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
1186  if ( openalSources[i].startTime < timeOldestZeroVolLooping ) {
1187  timeOldestZeroVolLooping = openalSources[i].startTime;
1188  iOldestZeroVolLooping = i;
1189  }
1190  } else if ( !openalSources[i].looping ) {
1191  if ( openalSources[i].startTime < timeOldestSingle ) {
1192  timeOldestSingle = openalSources[i].startTime;
1193  iOldestSingle = i;
1194  }
1195  }
1196  }
1197 
1198  if ( iUnused != -1 ) {
1199  index = iUnused;
1200  } else if ( iOldestZeroVolSingleShot != - 1 ) {
1201  index = iOldestZeroVolSingleShot;
1202  } else if ( iOldestZeroVolLooping != -1 ) {
1203  index = iOldestZeroVolLooping;
1204  } else if ( iOldestSingle != -1 ) {
1205  index = iOldestSingle;
1206  }
1207 
1208  if ( index != -1 ) {
1209  // stop the channel that is being ripped off
1210  if ( openalSources[index].chan ) {
1211  // stop the channel only when not looping
1212  if ( !openalSources[index].looping ) {
1214  } else {
1215  openalSources[index].chan->triggered = true;
1216  }
1217 
1218  // Free hardware resources
1220  }
1221 
1222  // Initialize structure
1223  openalSources[index].startTime = time;
1224  openalSources[index].chan = chan;
1225  openalSources[index].inUse = true;
1226  openalSources[index].looping = looping;
1227  openalSources[index].stereo = stereo;
1228 
1229  return openalSources[index].handle;
1230  } else {
1231  return NULL;
1232  }
1233 }
1234 
1235 /*
1236 ===================
1237 idSoundSystemLocal::FreeOpenALSource
1238 ===================
1239 */
1241  ALsizei i;
1242  for ( i = 0; i < openalSourceCount; i++ ) {
1243  if ( openalSources[i].handle == handle ) {
1244  if ( openalSources[i].chan ) {
1246  }
1247 #if ID_OPENAL
1248  // Reset source EAX ROOM level when freeing stereo source
1249  if ( openalSources[i].stereo && alEAXSet ) {
1250  long Room = EAXSOURCE_DEFAULTROOM;
1251  alEAXSet( &EAXPROPERTYID_EAX_Source, EAXSOURCE_ROOM, openalSources[i].handle, &Room, sizeof(Room));
1252  }
1253 #endif
1254  // Initialize structure
1255  openalSources[i].startTime = 0;
1256  openalSources[i].chan = NULL;
1257  openalSources[i].inUse = false;
1258  openalSources[i].looping = false;
1259  openalSources[i].stereo = false;
1260  }
1261  }
1262 }
1263 
1264 /*
1265 ============================================================
1266 SoundFX and misc effects
1267 ============================================================
1268 */
1269 
1270 /*
1271 ===================
1272 idSoundSystemLocal::ProcessSample
1273 ===================
1274 */
1275 void SoundFX_Lowpass::ProcessSample( float* in, float* out ) {
1276  float c, a1, a2, a3, b1, b2;
1278  float cutoffFrequency = idSoundSystemLocal::s_enviroSuitCutoffFreq.GetFloat();
1279 
1280  Initialize();
1281 
1282  c = 1.0 / idMath::Tan16( idMath::PI * cutoffFrequency / 44100 );
1283 
1284  // compute coefs
1285  a1 = 1.0 / ( 1.0 + resonance * c + c * c );
1286  a2 = 2* a1;
1287  a3 = a1;
1288  b1 = 2.0 * ( 1.0 - c * c) * a1;
1289  b2 = ( 1.0 - resonance * c + c * c ) * a1;
1290 
1291  // compute output value
1292  out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
1293 }
1294 
1295 void SoundFX_LowpassFast::ProcessSample( float* in, float* out ) {
1296  // compute output value
1297  out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
1298 }
1299 
1300 void SoundFX_LowpassFast::SetParms( float p1, float p2, float p3 ) {
1301  float c;
1302 
1303  // set the vars
1304  freq = p1;
1305  res = p2;
1306 
1307  // precompute the coefs
1308  c = 1.0 / idMath::Tan( idMath::PI * freq / 44100 );
1309 
1310  // compute coefs
1311  a1 = 1.0 / ( 1.0 + res * c + c * c );
1312  a2 = 2* a1;
1313  a3 = a1;
1314 
1315  b1 = 2.0 * ( 1.0 - c * c) * a1;
1316  b2 = ( 1.0 - res * c + c * c ) * a1;
1317 }
1318 
1320  if ( initialized )
1321  return;
1322 
1323  initialized = true;
1324  maxlen = 50000;
1325  buffer = new float[maxlen];
1326  currentTime = 0;
1327 }
1328 
1329 void SoundFX_Comb::ProcessSample( float* in, float* out ) {
1332 
1333  Initialize();
1334 
1335  // sum up and output
1336  out[0] = buffer[currentTime];
1337  buffer[currentTime] = buffer[currentTime] * gain + in[0];
1338 
1339  // increment current time
1340  currentTime++;
1341  if ( currentTime >= len )
1342  currentTime -= len;
1343 }
1344 
1345 /*
1346 ===================
1347 idSoundSystemLocal::DoEnviroSuit
1348 ===================
1349 */
1350 void idSoundSystemLocal::DoEnviroSuit( float* samples, int numSamples, int numSpeakers ) {
1351  float out[10000], *out_p = out + 2;
1352  float in[10000], *in_p = in + 2;
1353 
1355 
1356  if ( !fxList.Num() ) {
1357  for ( int i = 0; i < 6; i++ ) {
1358  SoundFX* fx;
1359 
1360  // lowpass filter
1361  fx = new SoundFX_Lowpass();
1362  fx->SetChannel( i );
1363  fxList.Append( fx );
1364 
1365  // comb
1366  fx = new SoundFX_Comb();
1367  fx->SetChannel( i );
1368  fx->SetParameter( i * 100 );
1369  fxList.Append( fx );
1370 
1371  // comb
1372  fx = new SoundFX_Comb();
1373  fx->SetChannel( i );
1374  fx->SetParameter( i * 100 + 5 );
1375  fxList.Append( fx );
1376  }
1377  }
1378 
1379  for ( int i = 0; i < numSpeakers; i++ ) {
1380  int j;
1381 
1382  // restore previous samples
1383  memset( in, 0, 10000 * sizeof( float ) );
1384  memset( out, 0, 10000 * sizeof( float ) );
1385 
1386  // fx loop
1387  for ( int k = 0; k < fxList.Num(); k++ ) {
1388  SoundFX* fx = fxList[k];
1389 
1390  // skip if we're not the right channel
1391  if ( fx->GetChannel() != i )
1392  continue;
1393 
1394  // get samples and continuity
1395  fx->GetContinuitySamples( in_p[-1], in_p[-2], out_p[-1], out_p[-2] );
1396  for ( j = 0; j < numSamples; j++ ) {
1397  in_p[j] = samples[j * numSpeakers + i] * s_enviroSuitVolumeScale.GetFloat();
1398  }
1399 
1400  // process fx loop
1401  for ( j = 0; j < numSamples; j++ ) {
1402  fx->ProcessSample( in_p + j, out_p + j );
1403  }
1404 
1405  // store samples and continuity
1406  fx->SetContinuitySamples( in_p[numSamples-2], in_p[numSamples-3], out_p[numSamples-2], out_p[numSamples-3] );
1407 
1408  for ( j = 0; j < numSamples; j++ ) {
1409  samples[j * numSpeakers + i] = out_p[j];
1410  }
1411  }
1412  }
1413 }
1414 
1415 /*
1416 =================
1417 idSoundSystemLocal::PrintMemInfo
1418 =================
1419 */
1421  soundCache->PrintMemInfo( mi );
1422 }
1423 
1424 /*
1425 ===============
1426 idSoundSystemLocal::EAXAvailable
1427 ===============
1428 */
1430 #if !ID_OPENAL
1431  return -1;
1432 #else
1433  ALCdevice *device;
1435 
1436  if ( EAXAvailable != -1 ) {
1437  return EAXAvailable;
1438  }
1439 
1440  if ( !Sys_LoadOpenAL() ) {
1441  EAXAvailable = 2;
1442  return 2;
1443  }
1444  // when dynamically loading the OpenAL subsystem, we need to get a context before alIsExtensionPresent would work
1445  device = alcOpenDevice( NULL );
1446  context = alcCreateContext( device, NULL );
1447  alcMakeContextCurrent( context );
1448  if ( alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
1450  alcDestroyContext( context );
1451  alcCloseDevice( device );
1452  EAXAvailable = 1;
1453  return 1;
1454  }
1456  alcDestroyContext( context );
1457  alcCloseDevice( device );
1458  EAXAvailable = 0;
1459  return 0;
1460 #endif
1461 }
#define EAXSOURCE_DEFAULTROOM
Definition: eax4.h:510
#define alcGetString
Definition: idal.h:46
idSoundWorldLocal * currentSoundWorld
Definition: snd_local.h:738
soundShaderParms_t parms
Definition: snd_local.h:415
byte color[4]
Definition: MegaTexture.cpp:54
static idCVar s_force22kHz
Definition: snd_local.h:803
idSoundChannel * chan
Definition: snd_local.h:670
idSoundChannel channels[SOUND_MAX_CHANNELS]
Definition: snd_local.h:499
virtual void SetPlayingSoundWorld(idSoundWorld *soundWorld)
void GetContinuitySamples(float &in1, float &in2, float &out1, float &out2)
Definition: snd_local.h:325
unsigned int dword
Definition: Lib.h:77
virtual int AsyncUpdate(int time)
Definition: snd_system.cpp:626
void SetChannel(int chan)
Definition: snd_local.h:321
#define alGetEnumValue
Definition: idal.h:51
virtual bool Initialize()=0
void ALStop(void)
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
virtual bool Flush(void)=0
float param
Definition: snd_local.h:312
assert(prefInfo.fullscreenBtn)
EAXGetBufferMode alEAXGetBufferMode
Definition: snd_local.h:771
void ListSounds_f(const idCmdArgs &args)
Definition: snd_system.cpp:122
ALuint handle
Definition: snd_local.h:668
static idCVar s_enviroSuitCutoffFreq
Definition: snd_local.h:814
float lastVolume
Definition: snd_local.h:421
static idCVar s_meterTopTime
Definition: snd_local.h:793
word nChannels
Definition: snd_local.h:98
virtual void ClearBuffer(void)
Definition: snd_system.cpp:574
idList< idSoundEmitterLocal * > emitters
Definition: snd_local.h:643
static idCVar s_reverbTime
Definition: snd_local.h:819
int meterTops[256]
Definition: snd_local.h:755
static bool useEAXReverb
Definition: snd_local.h:776
int meterTopsTime[256]
Definition: snd_local.h:756
virtual void ProcessSample(float *in, float *out)
GLenum GLsizei GLenum format
Definition: glext.h:2846
static idCVar s_numberOfSpeakers
Definition: snd_local.h:802
static float Tan16(float a)
Definition: Math.h:463
float GetFloat(void) const
Definition: CVarSystem.h:144
const int GetNumObjects(void)
Definition: snd_local.h:909
virtual bool Lock(void **pDSLockedBuffer, ulong *dwDSLockedBufferSize)=0
int GetChannel()
Definition: snd_local.h:322
const int MIXBUFFER_SAMPLES
Definition: Simd.h:84
float dB2Scale(const float val) const
Definition: snd_system.cpp:820
void Sys_FreeOpenAL(void)
int trigger44kHzTime
Definition: snd_local.h:413
bool hardwareBuffer
Definition: snd_local.h:852
int runs
Definition: snd_local.h:535
void Sys_Printf(const char *msg,...)
void FreeOpenALSource(ALuint handle)
static const float PI
Definition: Math.h:205
GLenum GLint GLint y
Definition: glext.h:2849
virtual void ProcessSample(float *in, float *out)
int currentTime
Definition: snd_local.h:347
int Sys_Milliseconds(void)
case const int
Definition: Callbacks.cpp:52
virtual idSoundSample * GetSample(void) const =0
static int GetNumUsedBlocks(void)
static idCVar s_libOpenAL
Definition: snd_local.h:806
#define alSourcei
Definition: idal.h:57
const GLuint * buffers
Definition: glext.h:3109
virtual cinData_t ImageForTime(const int milliseconds, const bool waveform)
Definition: snd_system.cpp:837
void UnloadFile(void)
int MillisecondsToSamples(int ms) const
static idCVar s_skipHelltimeFX
Definition: snd_local.h:822
#define alGenSources
Definition: idal.h:62
int objectMemSize
Definition: snd_local.h:848
static int EAXAvailable
Definition: snd_local.h:778
static idCVar s_dotbias6
Definition: snd_local.h:785
int GetCurrent44kHzTime(void) const
Definition: snd_system.cpp:559
void ReloadSounds(bool force)
Definition: snd_cache.cpp:137
void DoEnviroSuit(float *samples, int numSamples, int numSpeakers)
void SoundSystemRestart_f(const idCmdArgs &args)
Definition: snd_system.cpp:284
static idCVar s_spatializationDecay
Definition: snd_local.h:788
idAudioHardware * snd_audio_hw
Definition: snd_local.h:735
static idCVar s_slowAttenuate
Definition: snd_local.h:812
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
void EndLevelLoad()
Definition: snd_cache.cpp:184
void Sys_Sleep(const int time)
Definition: macosx_sys.mm:67
idFile * fpa[6]
Definition: snd_local.h:648
static idCVar s_muteEAXReverb
Definition: snd_local.h:809
static idCVar s_dotbias2
Definition: snd_local.h:787
#define AL_NO_ERROR
Errors: No Error.
Definition: altypes.h:265
virtual void VPCALL Memset(void *dst, const int val, const int count)=0
GLenum GLsizei len
Definition: glext.h:3472
virtual idSoundWorld * AllocSoundWorld(idRenderWorld *rw)
GLenum GLint x
Definition: glext.h:2849
static idCVar s_decompressionLimit
Definition: snd_local.h:810
virtual int GetNumberOfSpeakers(void)=0
int i
Definition: process.py:33
void TestSound_f(const idCmdArgs &args)
Definition: snd_system.cpp:265
static idCVar s_useOcclusion
Definition: snd_local.h:797
GLintptr offset
Definition: glext.h:3113
static idCVar s_quadraticFalloff
Definition: snd_local.h:782
Boolean result
void SoundReloadSounds_f(const idCmdArgs &args)
Definition: snd_system.cpp:101
int current44kHzTime
Definition: sound.h:279
#define ID_ALCHAR
Definition: snd_local.h:46
ALuint openalSource
Definition: snd_local.h:425
static idCVar s_playDefaultSound
Definition: snd_local.h:796
virtual bool Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize)=0
const int ROOM_SLICES_IN_BUFFER
Definition: snd_local.h:70
idStr & StripPath(void)
Definition: Str.cpp:885
virtual void Shutdown(void)
Definition: snd_system.cpp:436
unsigned ALuint
OpenAL 32bit unsigned integer type.
Definition: altypes.h:45
#define AL_TRUE
Definition: altypes.h:75
virtual void Initialize()
int LengthIn44kHzSamples() const
Definition: snd_cache.cpp:317
virtual void Init(void)
Definition: snd_system.cpp:298
void SetParms(float p1=0, float p2=0, float p3=0)
unsigned int ALsizei
OpenAL 32bit type.
Definition: altypes.h:57
s_stats soundStats
Definition: snd_local.h:753
int start44kHzTime
Definition: sound.h:278
float volumesDB[1200]
Definition: snd_local.h:760
void BeginLevelLoad()
Definition: snd_cache.cpp:158
#define ALC_DEVICE_SPECIFIER
Definition: alctypes.h:83
static int GetUsedBlockMemory(void)
bool LoadFile(const char *filename, bool OSPath=false)
virtual void Initialize()
Definition: snd_local.h:318
void ListSoundDecoders_f(const idCmdArgs &args)
Definition: snd_system.cpp:176
void PrintMemInfo(MemInfo_t *mi)
Definition: snd_cache.cpp:222
idEFXFile EFXDatabase
Definition: snd_local.h:772
int num44kHzSamples
Definition: sound.h:274
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
void Init(idRenderWorld *rw)
Definition: snd_world.cpp:39
static void Shutdown(void)
virtual int IsEAXAvailable(void)
void MixLoop(int current44kHz, int numSpeakers, float *finalMixBuffer)
Definition: snd_world.cpp:420
int numSamplesPerSecond
Definition: sound.h:273
static int FtoiFast(float f)
Definition: Math.h:801
#define alcCloseDevice
Definition: idal.h:59
idSampleDecoder * decoder
Definition: snd_local.h:419
static float Fabs(float f)
Definition: Math.h:779
virtual void SetMute(bool mute)
static idCVar s_enviroSuitCutoffQ
Definition: snd_local.h:815
idCommon * common
Definition: Common.cpp:206
static idCVar s_constantAmplitude
Definition: snd_local.h:795
#define NULL
Definition: Lib.h:88
dword nSamplesPerSec
Definition: snd_local.h:99
static idCVar s_useOpenAL
Definition: snd_local.h:807
void SetInteger(const int value)
Definition: CVarSystem.h:148
GLuint buffer
Definition: glext.h:3108
int GetInteger(void) const
Definition: CVarSystem.h:143
ALCvoid ALCdevice
Definition: alc.h:28
static idCVar s_reverbFeedback
Definition: snd_local.h:820
virtual bool GetCurrentPosition(ulong *pdwCurrentWriteCursor)=0
idList< SoundFX * > fxList
Definition: snd_local.h:762
virtual bool InitHW(void)
Definition: snd_system.cpp:493
void SetParameter(float val)
Definition: snd_local.h:327
int Argc(void) const
Definition: CmdArgs.h:48
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
const byte * image
Definition: Cinematic.h:57
float lastVolume
Definition: sound.h:277
static idCVar s_drawSounds
Definition: snd_local.h:783
static idCVar s_clipVolumes
Definition: snd_local.h:804
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
#define alcProcessContext
Definition: idal.h:44
virtual void EndLevelLoad(const char *mapString)
static float Tan(float a)
Definition: Math.h:459
const float SND_EPSILON
Definition: snd_local.h:68
static idCVar s_showLevelMeter
Definition: snd_local.h:792
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idSoundSample * leadinSample
Definition: snd_local.h:416
#define context
Definition: getdate.c:236
static void Init(void)
#define alIsExtensionPresent
Definition: idal.h:49
#define alcDestroyContext
Definition: idal.h:45
virtual short * GetMixBuffer(void)=0
static idCVar s_volume
Definition: snd_local.h:794
virtual void StartupVariable(const char *match, bool once)=0
virtual void ProcessSample(float *in, float *out)=0
void Stop(void)
static void ArgCompletion_SoundName(const idCmdArgs &args, void(*callback)(const char *s))
Definition: CmdSystem.h:164
bool defaultSound
Definition: snd_local.h:853
#define alcMakeContextCurrent
Definition: idal.h:43
virtual void BeginLevelLoad(void)
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
virtual void SetMute(bool mute)=0
int Append(const type &obj)
Definition: List.h:646
static idCVar s_minVolume2
Definition: snd_local.h:786
idSoundSystemLocal soundSystemLocal
Definition: snd_system.cpp:91
int missedWindow
Definition: snd_local.h:537
float realAccum[6 *MIXBUFFER_SAMPLES+16]
Definition: snd_local.h:746
bool GetBool(void) const
Definition: CVarSystem.h:142
virtual int GetMixBufferSize(void)=0
tuple f
Definition: idal.py:89
virtual void Write(bool flushing)=0
GLuint in
Definition: glext.h:5388
static unsigned long Ftol(float f)
Definition: Math.h:829
bool initialized
Definition: snd_local.h:304
int Num(void) const
Definition: List.h:265
static idCVar s_enviroSuitVolumeScale
Definition: snd_local.h:821
static idCVar s_maxSoundsPerShader
Definition: snd_local.h:790
idSoundCache * soundCache
Definition: snd_local.h:736
idSoundSystem * soundSystem
Definition: snd_system.cpp:92
bool Sys_LoadOpenAL(void)
Definition: sound.cpp:396
ALCvoid ALCcontext
Definition: alc.h:29
openalSource_t openalSources[256]
Definition: snd_local.h:767
void SetContinuitySamples(float in1, float in2, float out1, float out2)
Definition: snd_local.h:324
#define AL_ROLLOFF_FACTOR
Indicate the rolloff factor for the source.
Definition: altypes.h:193
#define alGetProcAddress
Definition: idal.h:52
#define EAXPROPERTYID_EAX_Source
Definition: eax4.h:436
const idSoundSample * GetObject(const int index) const
Definition: snd_cache.cpp:72
#define alSourcef
Definition: idal.h:63
virtual idSoundWorld * GetPlayingSoundWorld(void)
Definition: Str.h:116
static bool useOpenAL
Definition: snd_local.h:775
virtual void PlayShaderDirectly(const char *name, int channel=-1)
Definition: snd_world.cpp:1466
#define alGetError
Definition: idal.h:36
#define alGetInteger
Definition: idal.h:41
virtual void VPCALL MixedSoundToSamples(short *samples, const float *mixBuffer, const int numSamples)=0
const char * c_str(void) const
Definition: Str.h:487
static idCVar s_reverse
Definition: snd_local.h:791
virtual bool ShutdownHW(void)
Definition: snd_system.cpp:531
#define alDeleteSources
Definition: idal.h:50
#define alcOpenDevice
Definition: idal.h:54
static idCVar s_globalFraction
Definition: snd_local.h:799
void SetBool(const bool value)
Definition: CVarSystem.h:147
static idCVar s_subFraction
Definition: snd_local.h:798
#define alcCreateContext
Definition: idal.h:53
float * finalMixBuffer
Definition: snd_local.h:747
GLuint res
Definition: glext.h:5385
const char * Argv(int arg) const
Definition: CmdArgs.h:50
virtual int AsyncMix(int soundTime, float *mixBuffer)
Definition: snd_system.cpp:600
ALsizei openalSourceCount
Definition: snd_local.h:766
#define AL_BUFFER
Indicate the buffer to provide sound samples.
Definition: altypes.h:142
unsigned long ulong
Definition: Lib.h:79
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
int maxlen
Definition: snd_local.h:307
int SamplesToMilliseconds(int samples) const
ALuint AllocOpenALSource(idSoundChannel *chan, bool looping, bool stereo)
ALCcontext * openalContext
Definition: snd_local.h:765
int GetSoundDecoderInfo(int index, soundDecoderInfo_t &decoderInfo)
Definition: snd_system.cpp:995
static idCVar s_noSound
Definition: snd_local.h:781
static idAudioHardware * Alloc()
Definition: sound.cpp:52
waveformatex_t objectInfo
Definition: snd_local.h:846
const int PRIMARYFREQ
Definition: snd_local.h:67
static idCVar s_showStartSound
Definition: snd_local.h:789
virtual int AsyncUpdateWrite(int time)
Definition: snd_system.cpp:748
void Sys_LeaveCriticalSection(int index)
void Sys_EnterCriticalSection(int index)
virtual void ProcessSample(float *in, float *out)
static idCVar s_realTimeDecoding
Definition: snd_local.h:805
ALCdevice * openalDevice
Definition: snd_local.h:764
int timeinprocess
Definition: snd_local.h:536
int imageWidth
Definition: Cinematic.h:56
int soundShaderFlags
Definition: sound.h:65
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
int imageHeight
Definition: Cinematic.h:56
virtual void PrintMemInfo(MemInfo_t *mi)
#define alSourceStop
Definition: idal.h:39
void Clear(void)
Definition: snd_efxfile.cpp:45
static idCVar s_singleEmitter
Definition: snd_local.h:801
#define alcSuspendContext
Definition: idal.h:42
static idCVar s_minVolume6
Definition: snd_local.h:784
const int SOUND_MAX_CHANNELS
Definition: snd_local.h:64
int activeSounds
Definition: snd_local.h:539
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
word wFormatTag
Definition: snd_local.h:97
unsigned int nextWriteBlock
Definition: snd_local.h:744