snd_system.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "snd_local.h"
  23. #ifdef ID_DEDICATED
  24. idCVar idSoundSystemLocal::s_noSound( "s_noSound", "1", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "" );
  25. #else
  26. idCVar idSoundSystemLocal::s_noSound( "s_noSound", "0", CVAR_SOUND | CVAR_BOOL | CVAR_NOCHEAT, "" );
  27. #endif
  28. idCVar idSoundSystemLocal::s_quadraticFalloff( "s_quadraticFalloff", "1", CVAR_SOUND | CVAR_BOOL, "" );
  29. idCVar idSoundSystemLocal::s_drawSounds( "s_drawSounds", "0", CVAR_SOUND | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
  30. idCVar idSoundSystemLocal::s_showStartSound( "s_showStartSound", "0", CVAR_SOUND | CVAR_BOOL, "" );
  31. idCVar idSoundSystemLocal::s_useOcclusion( "s_useOcclusion", "1", CVAR_SOUND | CVAR_BOOL, "" );
  32. idCVar idSoundSystemLocal::s_maxSoundsPerShader( "s_maxSoundsPerShader", "0", CVAR_SOUND | CVAR_ARCHIVE, "", 0, 10, idCmdSystem::ArgCompletion_Integer<0,10> );
  33. idCVar idSoundSystemLocal::s_showLevelMeter( "s_showLevelMeter", "0", CVAR_SOUND | CVAR_BOOL, "" );
  34. idCVar idSoundSystemLocal::s_constantAmplitude( "s_constantAmplitude", "-1", CVAR_SOUND | CVAR_FLOAT, "" );
  35. idCVar idSoundSystemLocal::s_minVolume6( "s_minVolume6", "0", CVAR_SOUND | CVAR_FLOAT, "" );
  36. idCVar idSoundSystemLocal::s_dotbias6( "s_dotbias6", "0.8", CVAR_SOUND | CVAR_FLOAT, "" );
  37. idCVar idSoundSystemLocal::s_minVolume2( "s_minVolume2", "0.25", CVAR_SOUND | CVAR_FLOAT, "" );
  38. idCVar idSoundSystemLocal::s_dotbias2( "s_dotbias2", "1.1", CVAR_SOUND | CVAR_FLOAT, "" );
  39. idCVar idSoundSystemLocal::s_spatializationDecay( "s_spatializationDecay", "2", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "" );
  40. idCVar idSoundSystemLocal::s_reverse( "s_reverse", "0", CVAR_SOUND | CVAR_ARCHIVE | CVAR_BOOL, "" );
  41. idCVar idSoundSystemLocal::s_meterTopTime( "s_meterTopTime", "2000", CVAR_SOUND | CVAR_ARCHIVE | CVAR_INTEGER, "" );
  42. idCVar idSoundSystemLocal::s_volume( "s_volume_dB", "0", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume in dB" );
  43. idCVar idSoundSystemLocal::s_playDefaultSound( "s_playDefaultSound", "1", CVAR_SOUND | CVAR_ARCHIVE | CVAR_BOOL, "play a beep for missing sounds" );
  44. idCVar idSoundSystemLocal::s_subFraction( "s_subFraction", "0.75", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to subwoofer in 5.1" );
  45. idCVar idSoundSystemLocal::s_globalFraction( "s_globalFraction", "0.8", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to all speakers when not spatialized" );
  46. idCVar idSoundSystemLocal::s_doorDistanceAdd( "s_doorDistanceAdd", "150", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "reduce sound volume with this distance when going through a door" );
  47. idCVar idSoundSystemLocal::s_singleEmitter( "s_singleEmitter", "0", CVAR_SOUND | CVAR_INTEGER, "mute all sounds but this emitter" );
  48. idCVar idSoundSystemLocal::s_numberOfSpeakers( "s_numberOfSpeakers", "2", CVAR_SOUND | CVAR_ARCHIVE, "number of speakers" );
  49. idCVar idSoundSystemLocal::s_force22kHz( "s_force22kHz", "0", CVAR_SOUND | CVAR_BOOL, "" );
  50. idCVar idSoundSystemLocal::s_clipVolumes( "s_clipVolumes", "1", CVAR_SOUND | CVAR_BOOL, "" );
  51. idCVar idSoundSystemLocal::s_realTimeDecoding( "s_realTimeDecoding", "1", CVAR_SOUND | CVAR_BOOL | CVAR_INIT, "" );
  52. idCVar idSoundSystemLocal::s_slowAttenuate( "s_slowAttenuate", "1", CVAR_SOUND | CVAR_BOOL, "slowmo sounds attenuate over shorted distance" );
  53. idCVar idSoundSystemLocal::s_enviroSuitCutoffFreq( "s_enviroSuitCutoffFreq", "2000", CVAR_SOUND | CVAR_FLOAT, "" );
  54. idCVar idSoundSystemLocal::s_enviroSuitCutoffQ( "s_enviroSuitCutoffQ", "2", CVAR_SOUND | CVAR_FLOAT, "" );
  55. idCVar idSoundSystemLocal::s_reverbTime( "s_reverbTime", "1000", CVAR_SOUND | CVAR_FLOAT, "" );
  56. idCVar idSoundSystemLocal::s_reverbFeedback( "s_reverbFeedback", "0.333", CVAR_SOUND | CVAR_FLOAT, "" );
  57. idCVar idSoundSystemLocal::s_enviroSuitVolumeScale( "s_enviroSuitVolumeScale", "0.9", CVAR_SOUND | CVAR_FLOAT, "" );
  58. idCVar idSoundSystemLocal::s_skipHelltimeFX( "s_skipHelltimeFX", "0", CVAR_SOUND | CVAR_BOOL, "" );
  59. #if ID_OPENAL
  60. // off by default. OpenAL DLL gets loaded on-demand
  61. idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL DLL name/path" );
  62. idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use OpenAL" );
  63. idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use EAX reverb" );
  64. idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL, "mute eax reverb" );
  65. idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ARCHIVE, "specifies maximum uncompressed sample length in seconds" );
  66. #else
  67. idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL is not supported in this build" );
  68. idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "OpenAL is not supported in this build" );
  69. idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "EAX not available in this build" );
  70. idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "mute eax reverb" );
  71. idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ROM, "specifies maximum uncompressed sample length in seconds" );
  72. #endif
  73. bool idSoundSystemLocal::useOpenAL = false;
  74. bool idSoundSystemLocal::useEAXReverb = false;
  75. int idSoundSystemLocal::EAXAvailable = -1;
  76. idSoundSystemLocal soundSystemLocal;
  77. idSoundSystem *soundSystem = &soundSystemLocal;
  78. /*
  79. ===============
  80. SoundReloadSounds_f
  81. this is called from the main thread
  82. ===============
  83. */
  84. void SoundReloadSounds_f( const idCmdArgs &args ) {
  85. if ( !soundSystemLocal.soundCache ) {
  86. return;
  87. }
  88. bool force = false;
  89. if ( args.Argc() == 2 ) {
  90. force = true;
  91. }
  92. soundSystem->SetMute( true );
  93. soundSystemLocal.soundCache->ReloadSounds( force );
  94. soundSystem->SetMute( false );
  95. common->Printf( "sound: changed sounds reloaded\n" );
  96. }
  97. /*
  98. ===============
  99. ListSounds_f
  100. Optional parameter to only list sounds containing that string
  101. ===============
  102. */
  103. void ListSounds_f( const idCmdArgs &args ) {
  104. int i;
  105. const char *snd = args.Argv( 1 );
  106. if ( !soundSystemLocal.soundCache ) {
  107. common->Printf( "No sound.\n" );
  108. return;
  109. }
  110. int totalSounds = 0;
  111. int totalSamples = 0;
  112. int totalMemory = 0;
  113. int totalPCMMemory = 0;
  114. for( i = 0; i < soundSystemLocal.soundCache->GetNumObjects(); i++ ) {
  115. const idSoundSample *sample = soundSystemLocal.soundCache->GetObject(i);
  116. if ( !sample ) {
  117. continue;
  118. }
  119. if ( snd && sample->name.Find( snd, false ) < 0 ) {
  120. continue;
  121. }
  122. const waveformatex_t &info = sample->objectInfo;
  123. const char *stereo = ( info.nChannels == 2 ? "ST" : " " );
  124. const char *format = ( info.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
  125. const char *defaulted = ( sample->defaultSound ? "(DEFAULTED)" : sample->purged ? "(PURGED)" : "" );
  126. common->Printf( "%s %dkHz %6dms %5dkB %4s %s%s\n", stereo, sample->objectInfo.nSamplesPerSec / 1000,
  127. soundSystemLocal.SamplesToMilliseconds( sample->LengthIn44kHzSamples() ),
  128. sample->objectMemSize >> 10, format, sample->name.c_str(), defaulted );
  129. if ( !sample->purged ) {
  130. totalSamples += sample->objectSize;
  131. if ( info.wFormatTag != WAVE_FORMAT_TAG_OGG )
  132. totalPCMMemory += sample->objectMemSize;
  133. if ( !sample->hardwareBuffer )
  134. totalMemory += sample->objectMemSize;
  135. }
  136. totalSounds++;
  137. }
  138. common->Printf( "%8d total sounds\n", totalSounds );
  139. common->Printf( "%8d total samples loaded\n", totalSamples );
  140. common->Printf( "%8d kB total system memory used\n", totalMemory >> 10 );
  141. #if ID_OPENAL
  142. common->Printf( "%8d kB total OpenAL audio memory used\n", ( alGetInteger( alGetEnumValue( (ALubyte*)"AL_EAX_RAM_SIZE" ) ) - alGetInteger( alGetEnumValue( (ALubyte*)"AL_EAX_RAM_FREE" ) ) ) >> 10 );
  143. #endif
  144. }
  145. /*
  146. ===============
  147. ListSoundDecoders_f
  148. ===============
  149. */
  150. void ListSoundDecoders_f( const idCmdArgs &args ) {
  151. int i, j, numActiveDecoders, numWaitingDecoders;
  152. idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
  153. numActiveDecoders = numWaitingDecoders = 0;
  154. for ( i = 0; i < sw->emitters.Num(); i++ ) {
  155. idSoundEmitterLocal *sound = sw->emitters[i];
  156. if ( !sound ) {
  157. continue;
  158. }
  159. // run through all the channels
  160. for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
  161. idSoundChannel *chan = &sound->channels[j];
  162. if ( chan->decoder == NULL ) {
  163. continue;
  164. }
  165. idSoundSample *sample = chan->decoder->GetSample();
  166. if ( sample != NULL ) {
  167. continue;
  168. }
  169. const char *format = ( chan->leadinSample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
  170. common->Printf( "%3d waiting %s: %s\n", numWaitingDecoders, format, chan->leadinSample->name.c_str() );
  171. numWaitingDecoders++;
  172. }
  173. }
  174. for ( i = 0; i < sw->emitters.Num(); i++ ) {
  175. idSoundEmitterLocal *sound = sw->emitters[i];
  176. if ( !sound ) {
  177. continue;
  178. }
  179. // run through all the channels
  180. for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
  181. idSoundChannel *chan = &sound->channels[j];
  182. if ( chan->decoder == NULL ) {
  183. continue;
  184. }
  185. idSoundSample *sample = chan->decoder->GetSample();
  186. if ( sample == NULL ) {
  187. continue;
  188. }
  189. const char *format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
  190. int localTime = soundSystemLocal.GetCurrent44kHzTime() - chan->trigger44kHzTime;
  191. int sampleTime = sample->LengthIn44kHzSamples() * sample->objectInfo.nChannels;
  192. int percent;
  193. if ( localTime > sampleTime ) {
  194. if ( chan->parms.soundShaderFlags & SSF_LOOPING ) {
  195. percent = ( localTime % sampleTime ) * 100 / sampleTime;
  196. } else {
  197. percent = 100;
  198. }
  199. } else {
  200. percent = localTime * 100 / sampleTime;
  201. }
  202. common->Printf( "%3d decoding %3d%% %s: %s\n", numActiveDecoders, percent, format, sample->name.c_str() );
  203. numActiveDecoders++;
  204. }
  205. }
  206. common->Printf( "%d decoders\n", numWaitingDecoders + numActiveDecoders );
  207. common->Printf( "%d waiting decoders\n", numWaitingDecoders );
  208. common->Printf( "%d active decoders\n", numActiveDecoders );
  209. common->Printf( "%d kB decoder memory in %d blocks\n", idSampleDecoder::GetUsedBlockMemory() >> 10, idSampleDecoder::GetNumUsedBlocks() );
  210. }
  211. /*
  212. ===============
  213. TestSound_f
  214. this is called from the main thread
  215. ===============
  216. */
  217. void TestSound_f( const idCmdArgs &args ) {
  218. if ( args.Argc() != 2 ) {
  219. common->Printf( "Usage: testSound <file>\n" );
  220. return;
  221. }
  222. if ( soundSystemLocal.currentSoundWorld ) {
  223. soundSystemLocal.currentSoundWorld->PlayShaderDirectly( args.Argv( 1 ) );
  224. }
  225. }
  226. /*
  227. ===============
  228. SoundSystemRestart_f
  229. restart the sound thread
  230. this is called from the main thread
  231. ===============
  232. */
  233. void SoundSystemRestart_f( const idCmdArgs &args ) {
  234. soundSystem->SetMute( true );
  235. soundSystemLocal.ShutdownHW();
  236. soundSystemLocal.InitHW();
  237. soundSystem->SetMute( false );
  238. }
  239. /*
  240. ===============
  241. idSoundSystemLocal::Init
  242. initialize the sound system
  243. ===============
  244. */
  245. void idSoundSystemLocal::Init() {
  246. common->Printf( "----- Initializing Sound System ------\n" );
  247. isInitialized = false;
  248. muted = false;
  249. shutdown = false;
  250. currentSoundWorld = NULL;
  251. soundCache = NULL;
  252. olddwCurrentWritePos = 0;
  253. buffers = 0;
  254. CurrentSoundTime = 0;
  255. nextWriteBlock = 0xffffffff;
  256. memset( meterTops, 0, sizeof( meterTops ) );
  257. memset( meterTopsTime, 0, sizeof( meterTopsTime ) );
  258. for( int i = -600; i < 600; i++ ) {
  259. float pt = i * 0.1f;
  260. volumesDB[i+600] = pow( 2.0f,( pt * ( 1.0f / 6.0f ) ) );
  261. }
  262. // make a 16 byte aligned finalMixBuffer
  263. finalMixBuffer = (float *) ( ( ( (int)realAccum ) + 15 ) & ~15 );
  264. graph = NULL;
  265. if ( !s_noSound.GetBool() ) {
  266. idSampleDecoder::Init();
  267. soundCache = new idSoundCache();
  268. }
  269. // set up openal device and context
  270. common->StartupVariable( "s_useOpenAL", true );
  271. common->StartupVariable( "s_useEAXReverb", true );
  272. if ( idSoundSystemLocal::s_useOpenAL.GetBool() || idSoundSystemLocal::s_useEAXReverb.GetBool() ) {
  273. if ( !Sys_LoadOpenAL() ) {
  274. idSoundSystemLocal::s_useOpenAL.SetBool( false );
  275. } else {
  276. common->Printf( "Setup OpenAL device and context... " );
  277. openalDevice = alcOpenDevice( NULL );
  278. openalContext = alcCreateContext( openalDevice, NULL );
  279. alcMakeContextCurrent( openalContext );
  280. common->Printf( "Done.\n" );
  281. // try to obtain EAX extensions
  282. if ( idSoundSystemLocal::s_useEAXReverb.GetBool() && alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
  283. idSoundSystemLocal::s_useOpenAL.SetBool( true ); // EAX presence causes AL enable
  284. alEAXSet = (EAXSet)alGetProcAddress( ID_ALCHAR "EAXSet" );
  285. alEAXGet = (EAXGet)alGetProcAddress( ID_ALCHAR "EAXGet" );
  286. common->Printf( "OpenAL: found EAX 4.0 extension\n" );
  287. } else {
  288. common->Printf( "OpenAL: EAX 4.0 extension not found\n" );
  289. idSoundSystemLocal::s_useEAXReverb.SetBool( false );
  290. alEAXSet = (EAXSet)NULL;
  291. alEAXGet = (EAXGet)NULL;
  292. }
  293. // try to obtain EAX-RAM extension - not required for operation
  294. if ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) {
  295. alEAXSetBufferMode = (EAXSetBufferMode)alGetProcAddress( ID_ALCHAR "EAXSetBufferMode" );
  296. alEAXGetBufferMode = (EAXGetBufferMode)alGetProcAddress( ID_ALCHAR "EAXGetBufferMode" );
  297. 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 );
  298. } else {
  299. alEAXSetBufferMode = (EAXSetBufferMode)NULL;
  300. alEAXGetBufferMode = (EAXGetBufferMode)NULL;
  301. common->Printf( "OpenAL: no EAX-RAM extension\n" );
  302. }
  303. if ( !idSoundSystemLocal::s_useOpenAL.GetBool() ) {
  304. common->Printf( "OpenAL: disabling ( no EAX ). Using legacy mixer.\n" );
  305. alcMakeContextCurrent( NULL );
  306. alcDestroyContext( openalContext );
  307. openalContext = NULL;
  308. alcCloseDevice( openalDevice );
  309. openalDevice = NULL;
  310. } else {
  311. ALuint handle;
  312. openalSourceCount = 0;
  313. while ( openalSourceCount < 256 ) {
  314. alGetError();
  315. alGenSources( 1, &handle );
  316. if ( alGetError() != AL_NO_ERROR ) {
  317. break;
  318. } else {
  319. // store in source array
  320. openalSources[openalSourceCount].handle = handle;
  321. openalSources[openalSourceCount].startTime = 0;
  322. openalSources[openalSourceCount].chan = NULL;
  323. openalSources[openalSourceCount].inUse = false;
  324. openalSources[openalSourceCount].looping = false;
  325. // initialise sources
  326. alSourcef( handle, AL_ROLLOFF_FACTOR, 0.0f );
  327. // found one source
  328. openalSourceCount++;
  329. }
  330. }
  331. common->Printf( "OpenAL: found %s\n", alcGetString( openalDevice, ALC_DEVICE_SPECIFIER ) );
  332. common->Printf( "OpenAL: found %d hardware voices\n", openalSourceCount );
  333. // adjust source count to allow for at least eight stereo sounds to play
  334. openalSourceCount -= 8;
  335. EAXAvailable = 1;
  336. }
  337. }
  338. }
  339. useOpenAL = idSoundSystemLocal::s_useOpenAL.GetBool();
  340. useEAXReverb = idSoundSystemLocal::s_useEAXReverb.GetBool();
  341. cmdSystem->AddCommand( "listSounds", ListSounds_f, CMD_FL_SOUND, "lists all sounds" );
  342. cmdSystem->AddCommand( "listSoundDecoders", ListSoundDecoders_f, CMD_FL_SOUND, "list active sound decoders" );
  343. cmdSystem->AddCommand( "reloadSounds", SoundReloadSounds_f, CMD_FL_SOUND|CMD_FL_CHEAT, "reloads all sounds" );
  344. cmdSystem->AddCommand( "testSound", TestSound_f, CMD_FL_SOUND | CMD_FL_CHEAT, "tests a sound", idCmdSystem::ArgCompletion_SoundName );
  345. cmdSystem->AddCommand( "s_restart", SoundSystemRestart_f, CMD_FL_SOUND, "restarts the sound system" );
  346. common->Printf( "sound system initialized.\n" );
  347. common->Printf( "--------------------------------------\n" );
  348. }
  349. /*
  350. ===============
  351. idSoundSystemLocal::Shutdown
  352. ===============
  353. */
  354. void idSoundSystemLocal::Shutdown() {
  355. ShutdownHW();
  356. // EAX or not, the list needs to be cleared
  357. EFXDatabase.Clear();
  358. // destroy openal sources
  359. if ( useOpenAL ) {
  360. efxloaded = false;
  361. // adjust source count back up to allow for freeing of all resources
  362. openalSourceCount += 8;
  363. for ( ALsizei i = 0; i < openalSourceCount; i++ ) {
  364. // stop source
  365. alSourceStop( openalSources[i].handle );
  366. alSourcei( openalSources[i].handle, AL_BUFFER, 0 );
  367. // delete source
  368. alDeleteSources( 1, &openalSources[i].handle );
  369. // clear entry in source array
  370. openalSources[i].handle = NULL;
  371. openalSources[i].startTime = 0;
  372. openalSources[i].chan = NULL;
  373. openalSources[i].inUse = false;
  374. openalSources[i].looping = false;
  375. }
  376. }
  377. // destroy all the sounds (hardware buffers as well)
  378. delete soundCache;
  379. soundCache = NULL;
  380. // destroy openal device and context
  381. if ( useOpenAL ) {
  382. alcMakeContextCurrent( NULL );
  383. alcDestroyContext( openalContext );
  384. openalContext = NULL;
  385. alcCloseDevice( openalDevice );
  386. openalDevice = NULL;
  387. }
  388. Sys_FreeOpenAL();
  389. idSampleDecoder::Shutdown();
  390. }
  391. /*
  392. ===============
  393. idSoundSystemLocal::InitHW
  394. ===============
  395. */
  396. bool idSoundSystemLocal::InitHW() {
  397. if ( s_noSound.GetBool() ) {
  398. return false;
  399. }
  400. delete snd_audio_hw;
  401. snd_audio_hw = idAudioHardware::Alloc();
  402. if ( snd_audio_hw == NULL ) {
  403. return false;
  404. }
  405. if ( !useOpenAL ) {
  406. if ( !snd_audio_hw->Initialize() ) {
  407. delete snd_audio_hw;
  408. snd_audio_hw = NULL;
  409. return false;
  410. }
  411. if ( snd_audio_hw->GetNumberOfSpeakers() == 0 ) {
  412. return false;
  413. }
  414. // put the real number in there
  415. s_numberOfSpeakers.SetInteger( snd_audio_hw->GetNumberOfSpeakers() );
  416. }
  417. isInitialized = true;
  418. shutdown = false;
  419. return true;
  420. }
  421. /*
  422. ===============
  423. idSoundSystemLocal::ShutdownHW
  424. ===============
  425. */
  426. bool idSoundSystemLocal::ShutdownHW() {
  427. if ( !isInitialized ) {
  428. return false;
  429. }
  430. shutdown = true; // don't do anything at AsyncUpdate() time
  431. Sys_Sleep( 100 ); // sleep long enough to make sure any async sound talking to hardware has returned
  432. common->Printf( "Shutting down sound hardware\n" );
  433. delete snd_audio_hw;
  434. snd_audio_hw = NULL;
  435. isInitialized = false;
  436. if ( graph ) {
  437. Mem_Free( graph );
  438. graph = NULL;
  439. }
  440. return true;
  441. }
  442. /*
  443. ===============
  444. idSoundSystemLocal::GetCurrent44kHzTime
  445. ===============
  446. */
  447. int idSoundSystemLocal::GetCurrent44kHzTime( void ) const {
  448. if ( snd_audio_hw ) {
  449. return CurrentSoundTime;
  450. } else {
  451. // NOTE: this would overflow 31bits within about 1h20 ( not that important since we get a snd_audio_hw right away pbly )
  452. //return ( ( Sys_Milliseconds()*441 ) / 10 ) * 4;
  453. return idMath::FtoiFast( (float)Sys_Milliseconds() * 176.4f );
  454. }
  455. }
  456. /*
  457. ===================
  458. idSoundSystemLocal::ClearBuffer
  459. ===================
  460. */
  461. void idSoundSystemLocal::ClearBuffer( void ) {
  462. // check to make sure hardware actually exists
  463. if ( !snd_audio_hw ) {
  464. return;
  465. }
  466. short *fBlock;
  467. ulong fBlockLen;
  468. if ( !snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen ) ) {
  469. return;
  470. }
  471. if ( fBlock ) {
  472. SIMDProcessor->Memset( fBlock, 0, fBlockLen );
  473. snd_audio_hw->Unlock( fBlock, fBlockLen );
  474. }
  475. }
  476. /*
  477. ===================
  478. idSoundSystemLocal::AsyncMix
  479. Mac OSX version. The system uses it's own thread and an IOProc callback
  480. ===================
  481. */
  482. int idSoundSystemLocal::AsyncMix( int soundTime, float *mixBuffer ) {
  483. int inTime, numSpeakers;
  484. if ( !isInitialized || shutdown || !snd_audio_hw ) {
  485. return 0;
  486. }
  487. inTime = Sys_Milliseconds();
  488. numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
  489. // let the active sound world mix all the channels in unless muted or avi demo recording
  490. if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
  491. currentSoundWorld->MixLoop( soundTime, numSpeakers, mixBuffer );
  492. }
  493. CurrentSoundTime = soundTime;
  494. return Sys_Milliseconds() - inTime;
  495. }
  496. /*
  497. ===================
  498. idSoundSystemLocal::AsyncUpdate
  499. called from async sound thread when com_asyncSound == 1 ( Windows )
  500. ===================
  501. */
  502. int idSoundSystemLocal::AsyncUpdate( int inTime ) {
  503. if ( !isInitialized || shutdown || !snd_audio_hw ) {
  504. return 0;
  505. }
  506. ulong dwCurrentWritePos;
  507. dword dwCurrentBlock;
  508. // If not using openal, get actual playback position from sound hardware
  509. if ( useOpenAL ) {
  510. // here we do it in samples ( overflows in 27 hours or so )
  511. dwCurrentWritePos = idMath::Ftol( (float)Sys_Milliseconds() * 44.1f ) % ( MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER );
  512. dwCurrentBlock = dwCurrentWritePos / MIXBUFFER_SAMPLES;
  513. } else {
  514. // and here in bytes
  515. // get the current byte position in the buffer where the sound hardware is currently reading
  516. if ( !snd_audio_hw->GetCurrentPosition( &dwCurrentWritePos ) ) {
  517. return 0;
  518. }
  519. // mixBufferSize is in bytes
  520. dwCurrentBlock = dwCurrentWritePos / snd_audio_hw->GetMixBufferSize();
  521. }
  522. if ( nextWriteBlock == 0xffffffff ) {
  523. nextWriteBlock = dwCurrentBlock;
  524. }
  525. if ( dwCurrentBlock != nextWriteBlock ) {
  526. return 0;
  527. }
  528. // lock the buffer so we can actually write to it
  529. short *fBlock = NULL;
  530. ulong fBlockLen = 0;
  531. if ( !useOpenAL ) {
  532. snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen );
  533. if ( !fBlock ) {
  534. return 0;
  535. }
  536. }
  537. int j;
  538. soundStats.runs++;
  539. soundStats.activeSounds = 0;
  540. int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
  541. nextWriteBlock++;
  542. nextWriteBlock %= ROOM_SLICES_IN_BUFFER;
  543. int newPosition = nextWriteBlock * MIXBUFFER_SAMPLES;
  544. if ( newPosition < olddwCurrentWritePos ) {
  545. buffers++; // buffer wrapped
  546. }
  547. // nextWriteSample is in multi-channel samples inside the buffer
  548. int nextWriteSamples = nextWriteBlock * MIXBUFFER_SAMPLES;
  549. olddwCurrentWritePos = newPosition;
  550. // newSoundTime is in multi-channel samples since the sound system was started
  551. int newSoundTime = ( buffers * MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER ) + nextWriteSamples;
  552. // check for impending overflow
  553. // FIXME: we don't handle sound wrap-around correctly yet
  554. if ( newSoundTime > 0x6fffffff ) {
  555. buffers = 0;
  556. }
  557. if ( (newSoundTime - CurrentSoundTime) > (int)MIXBUFFER_SAMPLES ) {
  558. soundStats.missedWindow++;
  559. }
  560. if ( useOpenAL ) {
  561. // enable audio hardware caching
  562. alcSuspendContext( openalContext );
  563. } else {
  564. // clear the buffer for all the mixing output
  565. SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
  566. }
  567. // let the active sound world mix all the channels in unless muted or avi demo recording
  568. if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
  569. currentSoundWorld->MixLoop( newSoundTime, numSpeakers, finalMixBuffer );
  570. }
  571. if ( useOpenAL ) {
  572. // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
  573. alcProcessContext( openalContext );
  574. } else {
  575. short *dest = fBlock + nextWriteSamples * numSpeakers;
  576. SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
  577. // allow swapping the left / right speaker channels for people with miswired systems
  578. if ( numSpeakers == 2 && s_reverse.GetBool() ) {
  579. for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
  580. short temp = dest[j*2];
  581. dest[j*2] = dest[j*2+1];
  582. dest[j*2+1] = temp;
  583. }
  584. }
  585. snd_audio_hw->Unlock( fBlock, fBlockLen );
  586. }
  587. CurrentSoundTime = newSoundTime;
  588. soundStats.timeinprocess = Sys_Milliseconds() - inTime;
  589. return soundStats.timeinprocess;
  590. }
  591. /*
  592. ===================
  593. idSoundSystemLocal::AsyncUpdateWrite
  594. sound output using a write API. all the scheduling based on time
  595. we mix MIXBUFFER_SAMPLES at a time, but we feed the audio device with smaller chunks (and more often)
  596. called by the sound thread when com_asyncSound is 3 ( Linux )
  597. ===================
  598. */
  599. int idSoundSystemLocal::AsyncUpdateWrite( int inTime ) {
  600. if ( !isInitialized || shutdown || !snd_audio_hw ) {
  601. return 0;
  602. }
  603. if ( !useOpenAL ) {
  604. snd_audio_hw->Flush();
  605. }
  606. unsigned int dwCurrentBlock = (unsigned int)( inTime * 44.1f / MIXBUFFER_SAMPLES );
  607. if ( nextWriteBlock == 0xffffffff ) {
  608. nextWriteBlock = dwCurrentBlock;
  609. }
  610. if ( dwCurrentBlock < nextWriteBlock ) {
  611. return 0;
  612. }
  613. if ( nextWriteBlock != dwCurrentBlock ) {
  614. Sys_Printf( "missed %d sound updates\n", dwCurrentBlock - nextWriteBlock );
  615. }
  616. int sampleTime = dwCurrentBlock * MIXBUFFER_SAMPLES;
  617. int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
  618. if ( useOpenAL ) {
  619. // enable audio hardware caching
  620. alcSuspendContext( openalContext );
  621. } else {
  622. // clear the buffer for all the mixing output
  623. SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
  624. }
  625. // let the active sound world mix all the channels in unless muted or avi demo recording
  626. if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
  627. currentSoundWorld->MixLoop( sampleTime, numSpeakers, finalMixBuffer );
  628. }
  629. if ( useOpenAL ) {
  630. // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
  631. alcProcessContext( openalContext );
  632. } else {
  633. short *dest = snd_audio_hw->GetMixBuffer();
  634. SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
  635. // allow swapping the left / right speaker channels for people with miswired systems
  636. if ( numSpeakers == 2 && s_reverse.GetBool() ) {
  637. int j;
  638. for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
  639. short temp = dest[j*2];
  640. dest[j*2] = dest[j*2+1];
  641. dest[j*2+1] = temp;
  642. }
  643. }
  644. snd_audio_hw->Write( false );
  645. }
  646. // only move to the next block if the write was successful
  647. nextWriteBlock = dwCurrentBlock + 1;
  648. CurrentSoundTime = sampleTime;
  649. return Sys_Milliseconds() - inTime;
  650. }
  651. /*
  652. ===================
  653. idSoundSystemLocal::dB2Scale
  654. ===================
  655. */
  656. float idSoundSystemLocal::dB2Scale( const float val ) const {
  657. if ( val == 0.0f ) {
  658. return 1.0f; // most common
  659. } else if ( val <= -60.0f ) {
  660. return 0.0f;
  661. } else if ( val >= 60.0f ) {
  662. return powf( 2.0f, val * ( 1.0f / 6.0f ) );
  663. }
  664. int ival = (int)( ( val + 60.0f ) * 10.0f );
  665. return volumesDB[ival];
  666. }
  667. /*
  668. ===================
  669. idSoundSystemLocal::ImageForTime
  670. ===================
  671. */
  672. cinData_t idSoundSystemLocal::ImageForTime( const int milliseconds, const bool waveform ) {
  673. cinData_t ret;
  674. int i, j;
  675. if ( !isInitialized || !snd_audio_hw ) {
  676. memset( &ret, 0, sizeof( ret ) );
  677. return ret;
  678. }
  679. Sys_EnterCriticalSection();
  680. if ( !graph ) {
  681. graph = (dword *)Mem_Alloc( 256*128 * 4);
  682. }
  683. memset( graph, 0, 256*128 * 4 );
  684. float *accum = finalMixBuffer; // unfortunately, these are already clamped
  685. int time = Sys_Milliseconds();
  686. int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
  687. if ( !waveform ) {
  688. for( j = 0; j < numSpeakers; j++ ) {
  689. int meter = 0;
  690. for( i = 0; i < MIXBUFFER_SAMPLES; i++ ) {
  691. float result = idMath::Fabs(accum[i*numSpeakers+j]);
  692. if ( result > meter ) {
  693. meter = result;
  694. }
  695. }
  696. meter /= 256; // 32768 becomes 128
  697. if ( meter > 128 ) {
  698. meter = 128;
  699. }
  700. int offset;
  701. int xsize;
  702. if ( numSpeakers == 6 ) {
  703. offset = j * 40;
  704. xsize = 20;
  705. } else {
  706. offset = j * 128;
  707. xsize = 63;
  708. }
  709. int x,y;
  710. dword color = 0xff00ff00;
  711. for ( y = 0; y < 128; y++ ) {
  712. for ( x = 0; x < xsize; x++ ) {
  713. graph[(127-y)*256 + offset + x ] = color;
  714. }
  715. #if 0
  716. if ( y == 80 ) {
  717. color = 0xff00ffff;
  718. } else if ( y == 112 ) {
  719. color = 0xff0000ff;
  720. }
  721. #endif
  722. if ( y > meter ) {
  723. break;
  724. }
  725. }
  726. if ( meter > meterTops[j] ) {
  727. meterTops[j] = meter;
  728. meterTopsTime[j] = time + s_meterTopTime.GetInteger();
  729. } else if ( time > meterTopsTime[j] && meterTops[j] > 0 ) {
  730. meterTops[j]--;
  731. if (meterTops[j]) {
  732. meterTops[j]--;
  733. }
  734. }
  735. }
  736. for( j = 0; j < numSpeakers; j++ ) {
  737. int meter = meterTops[j];
  738. int offset;
  739. int xsize;
  740. if ( numSpeakers == 6 ) {
  741. offset = j*40;
  742. xsize = 20;
  743. } else {
  744. offset = j*128;
  745. xsize = 63;
  746. }
  747. int x,y;
  748. dword color;
  749. if ( meter <= 80 ) {
  750. color = 0xff007f00;
  751. } else if ( meter <= 112 ) {
  752. color = 0xff007f7f;
  753. } else {
  754. color = 0xff00007f;
  755. }
  756. for ( y = meter; y < 128 && y < meter + 4; y++ ) {
  757. for ( x = 0; x < xsize; x++ ) {
  758. graph[(127-y)*256 + offset + x ] = color;
  759. }
  760. }
  761. }
  762. } else {
  763. dword colors[] = { 0xff007f00, 0xff007f7f, 0xff00007f, 0xff00ff00, 0xff00ffff, 0xff0000ff };
  764. for( j = 0; j < numSpeakers; j++ ) {
  765. int xx = 0;
  766. float fmeter;
  767. int step = MIXBUFFER_SAMPLES / 256;
  768. for( i = 0; i < MIXBUFFER_SAMPLES; i += step ) {
  769. fmeter = 0.0f;
  770. for( int x = 0; x < step; x++ ) {
  771. float result = accum[(i+x)*numSpeakers+j];
  772. result = result / 32768.0f;
  773. fmeter += result;
  774. }
  775. fmeter /= 4.0f;
  776. if ( fmeter < -1.0f ) {
  777. fmeter = -1.0f;
  778. } else if ( fmeter > 1.0f ) {
  779. fmeter = 1.0f;
  780. }
  781. int meter = (fmeter * 63.0f);
  782. graph[ (meter + 64) * 256 + xx ] = colors[j];
  783. if ( meter < 0 ) {
  784. meter = -meter;
  785. }
  786. if ( meter > meterTops[xx] ) {
  787. meterTops[xx] = meter;
  788. meterTopsTime[xx] = time + 100;
  789. } else if ( time>meterTopsTime[xx] && meterTops[xx] > 0 ) {
  790. meterTops[xx]--;
  791. if ( meterTops[xx] ) {
  792. meterTops[xx]--;
  793. }
  794. }
  795. xx++;
  796. }
  797. }
  798. for( i = 0; i < 256; i++ ) {
  799. int meter = meterTops[i];
  800. for ( int y = -meter; y < meter; y++ ) {
  801. graph[ (y+64)*256 + i ] = colors[j];
  802. }
  803. }
  804. }
  805. ret.imageHeight = 128;
  806. ret.imageWidth = 256;
  807. ret.image = (unsigned char *)graph;
  808. Sys_LeaveCriticalSection();
  809. return ret;
  810. }
  811. /*
  812. ===================
  813. idSoundSystemLocal::GetSoundDecoderInfo
  814. ===================
  815. */
  816. int idSoundSystemLocal::GetSoundDecoderInfo( int index, soundDecoderInfo_t &decoderInfo ) {
  817. int i, j, firstEmitter, firstChannel;
  818. idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
  819. if ( index < 0 ) {
  820. firstEmitter = 0;
  821. firstChannel = 0;
  822. } else {
  823. firstEmitter = index / SOUND_MAX_CHANNELS;
  824. firstChannel = index - firstEmitter * SOUND_MAX_CHANNELS + 1;
  825. }
  826. for ( i = firstEmitter; i < sw->emitters.Num(); i++ ) {
  827. idSoundEmitterLocal *sound = sw->emitters[i];
  828. if ( !sound ) {
  829. continue;
  830. }
  831. // run through all the channels
  832. for ( j = firstChannel; j < SOUND_MAX_CHANNELS; j++ ) {
  833. idSoundChannel *chan = &sound->channels[j];
  834. if ( chan->decoder == NULL ) {
  835. continue;
  836. }
  837. idSoundSample *sample = chan->decoder->GetSample();
  838. if ( sample == NULL ) {
  839. continue;
  840. }
  841. decoderInfo.name = sample->name;
  842. decoderInfo.format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
  843. decoderInfo.numChannels = sample->objectInfo.nChannels;
  844. decoderInfo.numSamplesPerSecond = sample->objectInfo.nSamplesPerSec;
  845. decoderInfo.num44kHzSamples = sample->LengthIn44kHzSamples();
  846. decoderInfo.numBytes = sample->objectMemSize;
  847. decoderInfo.looping = ( chan->parms.soundShaderFlags & SSF_LOOPING ) != 0;
  848. decoderInfo.lastVolume = chan->lastVolume;
  849. decoderInfo.start44kHzTime = chan->trigger44kHzTime;
  850. decoderInfo.current44kHzTime = soundSystemLocal.GetCurrent44kHzTime();
  851. return ( i * SOUND_MAX_CHANNELS + j );
  852. }
  853. firstChannel = 0;
  854. }
  855. return -1;
  856. }
  857. /*
  858. ===================
  859. idSoundSystemLocal::AllocSoundWorld
  860. ===================
  861. */
  862. idSoundWorld *idSoundSystemLocal::AllocSoundWorld( idRenderWorld *rw ) {
  863. idSoundWorldLocal *local = new idSoundWorldLocal;
  864. local->Init( rw );
  865. return local;
  866. }
  867. /*
  868. ===================
  869. idSoundSystemLocal::SetMute
  870. ===================
  871. */
  872. void idSoundSystemLocal::SetMute( bool muteOn ) {
  873. muted = muteOn;
  874. }
  875. /*
  876. ===================
  877. idSoundSystemLocal::SamplesToMilliseconds
  878. ===================
  879. */
  880. int idSoundSystemLocal::SamplesToMilliseconds( int samples ) const {
  881. return ( samples / (PRIMARYFREQ/1000) );
  882. }
  883. /*
  884. ===================
  885. idSoundSystemLocal::SamplesToMilliseconds
  886. ===================
  887. */
  888. int idSoundSystemLocal::MillisecondsToSamples( int ms ) const {
  889. return ( ms * (PRIMARYFREQ/1000) );
  890. }
  891. /*
  892. ===================
  893. idSoundSystemLocal::SetPlayingSoundWorld
  894. specifying NULL will cause silence to be played
  895. ===================
  896. */
  897. void idSoundSystemLocal::SetPlayingSoundWorld( idSoundWorld *soundWorld ) {
  898. currentSoundWorld = static_cast<idSoundWorldLocal *>(soundWorld);
  899. }
  900. /*
  901. ===================
  902. idSoundSystemLocal::GetPlayingSoundWorld
  903. ===================
  904. */
  905. idSoundWorld *idSoundSystemLocal::GetPlayingSoundWorld( void ) {
  906. return currentSoundWorld;
  907. }
  908. /*
  909. ===================
  910. idSoundSystemLocal::BeginLevelLoad
  911. ===================
  912. */
  913. void idSoundSystemLocal::BeginLevelLoad() {
  914. if ( !isInitialized ) {
  915. return;
  916. }
  917. soundCache->BeginLevelLoad();
  918. if ( efxloaded ) {
  919. EFXDatabase.UnloadFile();
  920. efxloaded = false;
  921. }
  922. }
  923. /*
  924. ===================
  925. idSoundSystemLocal::EndLevelLoad
  926. ===================
  927. */
  928. void idSoundSystemLocal::EndLevelLoad( const char *mapstring ) {
  929. if ( !isInitialized ) {
  930. return;
  931. }
  932. soundCache->EndLevelLoad();
  933. idStr efxname( "efxs/" );
  934. idStr mapname( mapstring );
  935. mapname.SetFileExtension( ".efx" );
  936. mapname.StripPath();
  937. efxname += mapname;
  938. efxloaded = EFXDatabase.LoadFile( efxname );
  939. if ( efxloaded ) {
  940. common->Printf("sound: found %s\n", efxname.c_str() );
  941. } else {
  942. common->Printf("sound: missing %s\n", efxname.c_str() );
  943. }
  944. }
  945. /*
  946. ===================
  947. idSoundSystemLocal::AllocOpenALSource
  948. ===================
  949. */
  950. ALuint idSoundSystemLocal::AllocOpenALSource( idSoundChannel *chan, bool looping, bool stereo ) {
  951. int timeOldestZeroVolSingleShot = Sys_Milliseconds();
  952. int timeOldestZeroVolLooping = Sys_Milliseconds();
  953. int timeOldestSingle = Sys_Milliseconds();
  954. int iOldestZeroVolSingleShot = -1;
  955. int iOldestZeroVolLooping = -1;
  956. int iOldestSingle = -1;
  957. int iUnused = -1;
  958. int index = -1;
  959. ALsizei i;
  960. // Grab current msec time
  961. int time = Sys_Milliseconds();
  962. // Cycle through all sources
  963. for ( i = 0; i < openalSourceCount; i++ ) {
  964. // Use any unused source first,
  965. // Then find oldest single shot quiet source,
  966. // Then find oldest looping quiet source and
  967. // Lastly find oldest single shot non quiet source..
  968. if ( !openalSources[i].inUse ) {
  969. iUnused = i;
  970. break;
  971. } else if ( !openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
  972. if ( openalSources[i].startTime < timeOldestZeroVolSingleShot ) {
  973. timeOldestZeroVolSingleShot = openalSources[i].startTime;
  974. iOldestZeroVolSingleShot = i;
  975. }
  976. } else if ( openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
  977. if ( openalSources[i].startTime < timeOldestZeroVolLooping ) {
  978. timeOldestZeroVolLooping = openalSources[i].startTime;
  979. iOldestZeroVolLooping = i;
  980. }
  981. } else if ( !openalSources[i].looping ) {
  982. if ( openalSources[i].startTime < timeOldestSingle ) {
  983. timeOldestSingle = openalSources[i].startTime;
  984. iOldestSingle = i;
  985. }
  986. }
  987. }
  988. if ( iUnused != -1 ) {
  989. index = iUnused;
  990. } else if ( iOldestZeroVolSingleShot != - 1 ) {
  991. index = iOldestZeroVolSingleShot;
  992. } else if ( iOldestZeroVolLooping != -1 ) {
  993. index = iOldestZeroVolLooping;
  994. } else if ( iOldestSingle != -1 ) {
  995. index = iOldestSingle;
  996. }
  997. if ( index != -1 ) {
  998. // stop the channel that is being ripped off
  999. if ( openalSources[index].chan ) {
  1000. // stop the channel only when not looping
  1001. if ( !openalSources[index].looping ) {
  1002. openalSources[index].chan->Stop();
  1003. } else {
  1004. openalSources[index].chan->triggered = true;
  1005. }
  1006. // Free hardware resources
  1007. openalSources[index].chan->ALStop();
  1008. }
  1009. // Initialize structure
  1010. openalSources[index].startTime = time;
  1011. openalSources[index].chan = chan;
  1012. openalSources[index].inUse = true;
  1013. openalSources[index].looping = looping;
  1014. openalSources[index].stereo = stereo;
  1015. return openalSources[index].handle;
  1016. } else {
  1017. return NULL;
  1018. }
  1019. }
  1020. /*
  1021. ===================
  1022. idSoundSystemLocal::FreeOpenALSource
  1023. ===================
  1024. */
  1025. void idSoundSystemLocal::FreeOpenALSource( ALuint handle ) {
  1026. ALsizei i;
  1027. for ( i = 0; i < openalSourceCount; i++ ) {
  1028. if ( openalSources[i].handle == handle ) {
  1029. if ( openalSources[i].chan ) {
  1030. openalSources[i].chan->openalSource = NULL;
  1031. }
  1032. #if ID_OPENAL
  1033. // Reset source EAX ROOM level when freeing stereo source
  1034. if ( openalSources[i].stereo && alEAXSet ) {
  1035. long Room = EAXSOURCE_DEFAULTROOM;
  1036. alEAXSet( &EAXPROPERTYID_EAX_Source, EAXSOURCE_ROOM, openalSources[i].handle, &Room, sizeof(Room));
  1037. }
  1038. #endif
  1039. // Initialize structure
  1040. openalSources[i].startTime = 0;
  1041. openalSources[i].chan = NULL;
  1042. openalSources[i].inUse = false;
  1043. openalSources[i].looping = false;
  1044. openalSources[i].stereo = false;
  1045. }
  1046. }
  1047. }
  1048. /*
  1049. ============================================================
  1050. SoundFX and misc effects
  1051. ============================================================
  1052. */
  1053. /*
  1054. ===================
  1055. idSoundSystemLocal::ProcessSample
  1056. ===================
  1057. */
  1058. void SoundFX_Lowpass::ProcessSample( float* in, float* out ) {
  1059. float c, a1, a2, a3, b1, b2;
  1060. float resonance = idSoundSystemLocal::s_enviroSuitCutoffQ.GetFloat();
  1061. float cutoffFrequency = idSoundSystemLocal::s_enviroSuitCutoffFreq.GetFloat();
  1062. Initialize();
  1063. c = 1.0 / idMath::Tan16( idMath::PI * cutoffFrequency / 44100 );
  1064. // compute coefs
  1065. a1 = 1.0 / ( 1.0 + resonance * c + c * c );
  1066. a2 = 2* a1;
  1067. a3 = a1;
  1068. b1 = 2.0 * ( 1.0 - c * c) * a1;
  1069. b2 = ( 1.0 - resonance * c + c * c ) * a1;
  1070. // compute output value
  1071. out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
  1072. }
  1073. void SoundFX_LowpassFast::ProcessSample( float* in, float* out ) {
  1074. // compute output value
  1075. out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
  1076. }
  1077. void SoundFX_LowpassFast::SetParms( float p1, float p2, float p3 ) {
  1078. float c;
  1079. // set the vars
  1080. freq = p1;
  1081. res = p2;
  1082. // precompute the coefs
  1083. c = 1.0 / idMath::Tan( idMath::PI * freq / 44100 );
  1084. // compute coefs
  1085. a1 = 1.0 / ( 1.0 + res * c + c * c );
  1086. a2 = 2* a1;
  1087. a3 = a1;
  1088. b1 = 2.0 * ( 1.0 - c * c) * a1;
  1089. b2 = ( 1.0 - res * c + c * c ) * a1;
  1090. }
  1091. void SoundFX_Comb::Initialize() {
  1092. if ( initialized )
  1093. return;
  1094. initialized = true;
  1095. maxlen = 50000;
  1096. buffer = new float[maxlen];
  1097. currentTime = 0;
  1098. }
  1099. void SoundFX_Comb::ProcessSample( float* in, float* out ) {
  1100. float gain = idSoundSystemLocal::s_reverbFeedback.GetFloat();
  1101. int len = idSoundSystemLocal::s_reverbTime.GetFloat() + param;
  1102. Initialize();
  1103. // sum up and output
  1104. out[0] = buffer[currentTime];
  1105. buffer[currentTime] = buffer[currentTime] * gain + in[0];
  1106. // increment current time
  1107. currentTime++;
  1108. if ( currentTime >= len )
  1109. currentTime -= len;
  1110. }
  1111. /*
  1112. ===================
  1113. idSoundSystemLocal::DoEnviroSuit
  1114. ===================
  1115. */
  1116. void idSoundSystemLocal::DoEnviroSuit( float* samples, int numSamples, int numSpeakers ) {
  1117. float out[10000], *out_p = out + 2;
  1118. float in[10000], *in_p = in + 2;
  1119. assert( !idSoundSystemLocal::useOpenAL );
  1120. if ( !fxList.Num() ) {
  1121. for ( int i = 0; i < 6; i++ ) {
  1122. SoundFX* fx;
  1123. // lowpass filter
  1124. fx = new SoundFX_Lowpass();
  1125. fx->SetChannel( i );
  1126. fxList.Append( fx );
  1127. // comb
  1128. fx = new SoundFX_Comb();
  1129. fx->SetChannel( i );
  1130. fx->SetParameter( i * 100 );
  1131. fxList.Append( fx );
  1132. // comb
  1133. fx = new SoundFX_Comb();
  1134. fx->SetChannel( i );
  1135. fx->SetParameter( i * 100 + 5 );
  1136. fxList.Append( fx );
  1137. }
  1138. }
  1139. for ( int i = 0; i < numSpeakers; i++ ) {
  1140. int j;
  1141. // restore previous samples
  1142. memset( in, 0, 10000 * sizeof( float ) );
  1143. memset( out, 0, 10000 * sizeof( float ) );
  1144. // fx loop
  1145. for ( int k = 0; k < fxList.Num(); k++ ) {
  1146. SoundFX* fx = fxList[k];
  1147. // skip if we're not the right channel
  1148. if ( fx->GetChannel() != i )
  1149. continue;
  1150. // get samples and continuity
  1151. fx->GetContinuitySamples( in_p[-1], in_p[-2], out_p[-1], out_p[-2] );
  1152. for ( j = 0; j < numSamples; j++ ) {
  1153. in_p[j] = samples[j * numSpeakers + i] * s_enviroSuitVolumeScale.GetFloat();
  1154. }
  1155. // process fx loop
  1156. for ( j = 0; j < numSamples; j++ ) {
  1157. fx->ProcessSample( in_p + j, out_p + j );
  1158. }
  1159. // store samples and continuity
  1160. fx->SetContinuitySamples( in_p[numSamples-2], in_p[numSamples-3], out_p[numSamples-2], out_p[numSamples-3] );
  1161. for ( j = 0; j < numSamples; j++ ) {
  1162. samples[j * numSpeakers + i] = out_p[j];
  1163. }
  1164. }
  1165. }
  1166. }
  1167. /*
  1168. =================
  1169. idSoundSystemLocal::PrintMemInfo
  1170. =================
  1171. */
  1172. void idSoundSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
  1173. soundCache->PrintMemInfo( mi );
  1174. }
  1175. /*
  1176. ===============
  1177. idSoundSystemLocal::EAXAvailable
  1178. ===============
  1179. */
  1180. int idSoundSystemLocal::IsEAXAvailable( void ) {
  1181. #if !ID_OPENAL
  1182. return -1;
  1183. #else
  1184. ALCdevice *device;
  1185. ALCcontext *context;
  1186. if ( EAXAvailable != -1 ) {
  1187. return EAXAvailable;
  1188. }
  1189. if ( !Sys_LoadOpenAL() ) {
  1190. EAXAvailable = 2;
  1191. return 2;
  1192. }
  1193. // when dynamically loading the OpenAL subsystem, we need to get a context before alIsExtensionPresent would work
  1194. device = alcOpenDevice( NULL );
  1195. context = alcCreateContext( device, NULL );
  1196. alcMakeContextCurrent( context );
  1197. if ( alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
  1198. alcMakeContextCurrent( NULL );
  1199. alcDestroyContext( context );
  1200. alcCloseDevice( device );
  1201. EAXAvailable = 1;
  1202. return 1;
  1203. }
  1204. alcMakeContextCurrent( NULL );
  1205. alcDestroyContext( context );
  1206. alcCloseDevice( device );
  1207. EAXAvailable = 0;
  1208. return 0;
  1209. #endif
  1210. }