snd_system.cpp 45 KB

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