12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "snd_local.h"
- /* bc flite.
- extern "C"
- {
- cst_voice *register_cmu_us_rms();
- cst_voice *voice;
- };
- */
- #ifdef ID_DEDICATED
- idCVar idSoundSystemLocal::s_noSound( "s_noSound", "1", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "" );
- #else
- idCVar idSoundSystemLocal::s_noSound( "s_noSound", "0", CVAR_SOUND | CVAR_BOOL | CVAR_NOCHEAT, "" );
- #endif
- idCVar idSoundSystemLocal::s_quadraticFalloff( "s_quadraticFalloff", "1", CVAR_SOUND | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_drawSounds( "s_drawSounds", "0", CVAR_SOUND | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
- idCVar idSoundSystemLocal::s_showStartSound( "s_showStartSound", "0", CVAR_SOUND | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_useOcclusion( "s_useOcclusion", "1", CVAR_SOUND | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_maxSoundsPerShader( "s_maxSoundsPerShader", "0", CVAR_SOUND | CVAR_ARCHIVE, "", 0, 10, idCmdSystem::ArgCompletion_Integer<0,10> );
- idCVar idSoundSystemLocal::s_showLevelMeter( "s_showLevelMeter", "0", CVAR_SOUND | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_constantAmplitude( "s_constantAmplitude", "-1", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_minVolume6( "s_minVolume6", "0", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_dotbias6( "s_dotbias6", "0.8", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_minVolume2( "s_minVolume2", "0.25", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_dotbias2( "s_dotbias2", "1.1", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_spatializationDecay( "s_spatializationDecay", "2", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_reverse( "s_reverse", "0", CVAR_SOUND | CVAR_ARCHIVE | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_meterTopTime( "s_meterTopTime", "2000", CVAR_SOUND | CVAR_ARCHIVE | CVAR_INTEGER, "" );
- idCVar idSoundSystemLocal::s_volume( "s_volume_dB", "0", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume in dB" );
- idCVar idSoundSystemLocal::s_playDefaultSound( "s_playDefaultSound", "1", CVAR_SOUND | CVAR_ARCHIVE | CVAR_BOOL, "play a beep for missing sounds" );
- idCVar idSoundSystemLocal::s_subFraction( "s_subFraction", "0.75", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to subwoofer in 5.1" );
- idCVar idSoundSystemLocal::s_globalFraction( "s_globalFraction", "0.8", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "volume to all speakers when not spatialized" );
- idCVar idSoundSystemLocal::s_doorDistanceAdd( "s_doorDistanceAdd", "300", CVAR_SOUND | CVAR_ARCHIVE | CVAR_FLOAT, "reduce sound volume with this distance when going through a door" );
- idCVar idSoundSystemLocal::s_singleEmitter( "s_singleEmitter", "0", CVAR_SOUND | CVAR_INTEGER, "mute all sounds but this emitter" );
- idCVar idSoundSystemLocal::s_numberOfSpeakers( "s_numberOfSpeakers", "2", CVAR_SOUND | CVAR_ARCHIVE, "number of speakers" );
- idCVar idSoundSystemLocal::s_force22kHz( "s_force22kHz", "0", CVAR_SOUND | CVAR_BOOL, "" );
- idCVar idSoundSystemLocal::s_clipVolumes( "s_clipVolumes", "0", CVAR_SOUND | CVAR_BOOL, "" ); //BC was 1
- idCVar idSoundSystemLocal::s_realTimeDecoding( "s_realTimeDecoding", "1", CVAR_SOUND | CVAR_BOOL | CVAR_INIT, "" );
- idCVar idSoundSystemLocal::s_postprocessing( "s_postprocessing", "1", CVAR_SOUND | CVAR_ARCHIVE, "audio post-processing" );
- idCVar idSoundSystemLocal::s_slowAttenuate( "s_slowAttenuate", "1", CVAR_SOUND | CVAR_BOOL, "slowmo sounds attenuate over shorted distance" );
- idCVar idSoundSystemLocal::s_enviroSuitCutoffFreq( "s_enviroSuitCutoffFreq", "1200" , CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_enviroSuitCutoffQ( "s_enviroSuitCutoffQ", "2", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_reverbTime( "s_reverbTime", "1000", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_reverbFeedback( "s_reverbFeedback", "0.333", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_enviroSuitVolumeScale( "s_enviroSuitVolumeScale", "0.3", CVAR_SOUND | CVAR_FLOAT, "" );
- idCVar idSoundSystemLocal::s_skipHelltimeFX( "s_skipHelltimeFX", "0", CVAR_SOUND | CVAR_BOOL, "" );
- #if ID_OPENAL
- // off by default. OpenAL DLL gets loaded on-demand
- idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL DLL name/path" );
- idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use OpenAL" );
- idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "use EAX reverb" );
- idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL, "mute eax reverb" );
- idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ARCHIVE, "specifies maximum uncompressed sample length in seconds" );
- #else
- idCVar idSoundSystemLocal::s_libOpenAL( "s_libOpenAL", "openal32.dll", CVAR_SOUND | CVAR_ARCHIVE, "OpenAL is not supported in this build" );
- idCVar idSoundSystemLocal::s_useOpenAL( "s_useOpenAL", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "OpenAL is not supported in this build" );
- idCVar idSoundSystemLocal::s_useEAXReverb( "s_useEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "EAX not available in this build" );
- idCVar idSoundSystemLocal::s_muteEAXReverb( "s_muteEAXReverb", "0", CVAR_SOUND | CVAR_BOOL | CVAR_ROM, "mute eax reverb" );
- idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CVAR_SOUND | CVAR_INTEGER | CVAR_ROM, "specifies maximum uncompressed sample length in seconds" );
- #endif
- bool idSoundSystemLocal::useOpenAL = false;
- bool idSoundSystemLocal::useEAXReverb = false;
- int idSoundSystemLocal::EAXAvailable = -1;
- idSoundSystemLocal soundSystemLocal;
- idSoundSystem *soundSystem = &soundSystemLocal;
- /*
- ===============
- SoundReloadSounds_f
- this is called from the main thread
- ===============
- */
- void SoundReloadSounds_f( const idCmdArgs &args ) {
- if ( !soundSystemLocal.soundCache ) {
- return;
- }
- bool force = false;
- if ( args.Argc() == 2 ) {
- force = true;
- }
- soundSystem->SetMute( true );
- soundSystemLocal.soundCache->ReloadSounds( force );
- soundSystem->SetMute( false );
- common->Printf( "sound: changed sounds reloaded\n" );
- }
- /*
- ===============
- ListSounds_f
- Optional parameter to only list sounds containing that string
- ===============
- */
- void ListSounds_f( const idCmdArgs &args ) {
- int i;
- const char *snd = args.Argv( 1 );
- if ( !soundSystemLocal.soundCache ) {
- common->Printf( "No sound.\n" );
- return;
- }
- int totalSounds = 0;
- int totalSamples = 0;
- int totalMemory = 0;
- int totalPCMMemory = 0;
- for( i = 0; i < soundSystemLocal.soundCache->GetNumObjects(); i++ ) {
- const idSoundSample *sample = soundSystemLocal.soundCache->GetObject(i);
- if ( !sample ) {
- continue;
- }
- if ( snd && sample->name.Find( snd, false ) < 0 ) {
- continue;
- }
- const waveformatex_t &info = sample->objectInfo;
- const char *stereo = ( info.nChannels == 2 ? "ST" : " " );
- const char *format = ( info.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
- const char *defaulted = ( sample->defaultSound ? "(DEFAULTED)" : sample->purged ? "(PURGED)" : "" );
- common->Printf( "%s %dkHz %6dms %5dkB %4s %s%s\n", stereo, sample->objectInfo.nSamplesPerSec / 1000,
- soundSystemLocal.SamplesToMilliseconds( sample->LengthIn44kHzSamples() ),
- sample->objectMemSize >> 10, format, sample->name.c_str(), defaulted );
- if ( !sample->purged ) {
- totalSamples += sample->objectSize;
- if ( info.wFormatTag != WAVE_FORMAT_TAG_OGG )
- totalPCMMemory += sample->objectMemSize;
- if ( !sample->hardwareBuffer )
- totalMemory += sample->objectMemSize;
- }
- totalSounds++;
- }
- common->Printf( "%8d total sounds\n", totalSounds );
- common->Printf( "%8d total samples loaded\n", totalSamples );
- common->Printf( "%8d kB total system memory used\n", totalMemory >> 10 );
- #if ID_OPENAL && defined(_WIN32)
- 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 );
- #endif
- }
- /*
- ===============
- ListSoundDecoders_f
- ===============
- */
- void ListSoundDecoders_f( const idCmdArgs &args ) {
- int i, j, numActiveDecoders, numWaitingDecoders;
- idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
- numActiveDecoders = numWaitingDecoders = 0;
- for ( i = 0; i < sw->emitters.Num(); i++ ) {
- idSoundEmitterLocal *sound = sw->emitters[i];
- if ( !sound ) {
- continue;
- }
- // run through all the channels
- for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
- idSoundChannel *chan = &sound->channels[j];
- if ( chan->decoder == NULL ) {
- continue;
- }
- idSoundSample *sample = chan->decoder->GetSample();
- if ( sample != NULL ) {
- continue;
- }
- const char *format = ( chan->leadinSample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
- common->Printf( "%3d waiting %s: %s\n", numWaitingDecoders, format, chan->leadinSample->name.c_str() );
- numWaitingDecoders++;
- }
- }
- for ( i = 0; i < sw->emitters.Num(); i++ ) {
- idSoundEmitterLocal *sound = sw->emitters[i];
- if ( !sound ) {
- continue;
- }
- // run through all the channels
- for ( j = 0; j < SOUND_MAX_CHANNELS; j++ ) {
- idSoundChannel *chan = &sound->channels[j];
- if ( chan->decoder == NULL ) {
- continue;
- }
- idSoundSample *sample = chan->decoder->GetSample();
- if ( sample == NULL ) {
- continue;
- }
- const char *format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
- int localTime = soundSystemLocal.GetCurrent44kHzTime() - chan->trigger44kHzTime;
- int sampleTime = sample->LengthIn44kHzSamples() * sample->objectInfo.nChannels;
- int percent;
- if ( localTime > sampleTime ) {
- if ( chan->parms.soundShaderFlags & SSF_LOOPING ) {
- percent = ( localTime % sampleTime ) * 100 / sampleTime;
- } else {
- percent = 100;
- }
- } else {
- percent = localTime * 100 / sampleTime;
- }
- common->Printf( "%3d decoding %3d%% %s: %s\n", numActiveDecoders, percent, format, sample->name.c_str() );
- numActiveDecoders++;
- }
- }
- common->Printf( "%d decoders\n", numWaitingDecoders + numActiveDecoders );
- common->Printf( "%d waiting decoders\n", numWaitingDecoders );
- common->Printf( "%d active decoders\n", numActiveDecoders );
- common->Printf( "%d kB decoder memory in %d blocks\n", idSampleDecoder::GetUsedBlockMemory() >> 10, idSampleDecoder::GetNumUsedBlocks() );
- }
- /*
- ===============
- TestSound_f
- this is called from the main thread
- ===============
- */
- void TestSound_f( const idCmdArgs &args ) {
- if ( args.Argc() != 2 ) {
- common->Printf( "Usage: testSound <file>\n" );
- return;
- }
- if ( soundSystemLocal.currentSoundWorld ) {
- soundSystemLocal.currentSoundWorld->PlayShaderDirectly( args.Argv( 1 ) );
- }
- }
- /*
- ===============
- SoundSystemRestart_f
- restart the sound thread
- this is called from the main thread
- ===============
- */
- void SoundSystemRestart_f( const idCmdArgs &args ) {
- soundSystem->SetMute( true );
- soundSystemLocal.ShutdownHW();
- soundSystemLocal.InitHW();
- soundSystem->SetMute( false );
- }
- /*
- ===============
- idSoundSystemLocal::Init
- initialize the sound system
- ===============
- */
- void idSoundSystemLocal::Init() {
- common->Printf( "----- Initializing Sound System ------\n" );
-
- //setup Flite speech synthesis. (Brian)
- /* bc flite
- flite_init();
- voice = register_cmu_us_rms();
- */
- //for use with Flite streaming. (Brian)
- /*
- cst_audio_streaming_info *asi;
- asi = new_audio_streaming_info();
- asi->asc = example_audio_stream_chunk;
- flite_feat_set(
- voice->features,
- "streaming_info",
- audio_streaming_info_val(asi)
- );
- */
- isInitialized = false;
- muted = false;
- shutdown = false;
- currentSoundWorld = NULL;
- soundCache = NULL;
- olddwCurrentWritePos = 0;
- buffers = 0;
- CurrentSoundTime = 0;
- nextWriteBlock = 0xffffffff;
- memset( meterTops, 0, sizeof( meterTops ) );
- memset( meterTopsTime, 0, sizeof( meterTopsTime ) );
- for( int i = -600; i < 600; i++ ) {
- float pt = i * 0.1f;
- volumesDB[i+600] = pow( 2.0f,( pt * ( 1.0f / 6.0f ) ) );
- }
- // make a 16 byte aligned finalMixBuffer
- finalMixBuffer = (float *) ( ( ( (int)realAccum ) + 15 ) & ~15 );
- graph = NULL;
- if ( !s_noSound.GetBool() ) {
- idSampleDecoder::Init();
- soundCache = new idSoundCache();
- }
- // set up openal device and context
- common->StartupVariable( "s_useOpenAL", true );
- common->StartupVariable( "s_useEAXReverb", true );
- if ( idSoundSystemLocal::s_useOpenAL.GetBool() || idSoundSystemLocal::s_useEAXReverb.GetBool() ) {
- if ( !Sys_LoadOpenAL() ) {
- idSoundSystemLocal::s_useOpenAL.SetBool( false );
- } else {
- common->Printf( "Setup OpenAL device and context... " );
- openalDevice = alcOpenDevice( NULL );
- openalContext = alcCreateContext( openalDevice, NULL );
- alcMakeContextCurrent( openalContext );
- common->Printf( "Done.\n" );
- // try to obtain EAX extensions
- if ( idSoundSystemLocal::s_useEAXReverb.GetBool() && alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
- idSoundSystemLocal::s_useOpenAL.SetBool( true ); // EAX presence causes AL enable
- alEAXSet = (EAXSet)alGetProcAddress( ID_ALCHAR "EAXSet" );
- alEAXGet = (EAXGet)alGetProcAddress( ID_ALCHAR "EAXGet" );
- common->Printf( "OpenAL: found EAX 4.0 extension\n" );
- } else {
- common->Printf( "OpenAL: EAX 4.0 extension not found\n" );
- idSoundSystemLocal::s_useEAXReverb.SetBool( false );
- alEAXSet = (EAXSet)NULL;
- alEAXGet = (EAXGet)NULL;
- }
- // try to obtain EAX-RAM extension - not required for operation
- if ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) {
- alEAXSetBufferMode = (EAXSetBufferMode)alGetProcAddress( ID_ALCHAR "EAXSetBufferMode" );
- alEAXGetBufferMode = (EAXGetBufferMode)alGetProcAddress( ID_ALCHAR "EAXGetBufferMode" );
- 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 );
- } else {
- alEAXSetBufferMode = (EAXSetBufferMode)NULL;
- alEAXGetBufferMode = (EAXGetBufferMode)NULL;
- common->Printf( "OpenAL: no EAX-RAM extension\n" );
- }
- if ( !idSoundSystemLocal::s_useOpenAL.GetBool() ) {
- common->Printf( "OpenAL: disabling ( no EAX ). Using legacy mixer.\n" );
- alcMakeContextCurrent( NULL );
-
- alcDestroyContext( openalContext );
- openalContext = NULL;
-
- alcCloseDevice( openalDevice );
- openalDevice = NULL;
- } else {
- ALuint handle;
- openalSourceCount = 0;
-
- while ( openalSourceCount < 256 ) {
- alGetError();
- alGenSources( 1, &handle );
- if ( alGetError() != AL_NO_ERROR ) {
- break;
- } else {
- // store in source array
- openalSources[openalSourceCount].handle = handle;
- openalSources[openalSourceCount].startTime = 0;
- openalSources[openalSourceCount].chan = NULL;
- openalSources[openalSourceCount].inUse = false;
- openalSources[openalSourceCount].looping = false;
- // initialise sources
- alSourcef( handle, AL_ROLLOFF_FACTOR, 0.0f );
- // found one source
- openalSourceCount++;
- }
- }
- common->Printf( "OpenAL: found %s\n", alcGetString( openalDevice, ALC_DEVICE_SPECIFIER ) );
- common->Printf( "OpenAL: found %d hardware voices\n", openalSourceCount );
- // adjust source count to allow for at least eight stereo sounds to play
- openalSourceCount -= 8;
- EAXAvailable = 1;
- }
- }
- }
- useOpenAL = idSoundSystemLocal::s_useOpenAL.GetBool();
- useEAXReverb = idSoundSystemLocal::s_useEAXReverb.GetBool();
- cmdSystem->AddCommand( "listSounds", ListSounds_f, CMD_FL_SOUND, "lists all sounds" );
- cmdSystem->AddCommand( "listSoundDecoders", ListSoundDecoders_f, CMD_FL_SOUND, "list active sound decoders" );
- cmdSystem->AddCommand( "reloadSounds", SoundReloadSounds_f, CMD_FL_SOUND|CMD_FL_CHEAT, "reloads all sounds" );
- cmdSystem->AddCommand( "testSound", TestSound_f, CMD_FL_SOUND | CMD_FL_CHEAT, "tests a sound", idCmdSystem::ArgCompletion_SoundName );
- cmdSystem->AddCommand( "s_restart", SoundSystemRestart_f, CMD_FL_SOUND, "restarts the sound system" );
- common->Printf( "sound system initialized.\n" );
- common->Printf( "--------------------------------------\n" );
- }
- /*
- ===============
- idSoundSystemLocal::Shutdown
- ===============
- */
- void idSoundSystemLocal::Shutdown() {
- ShutdownHW();
- // EAX or not, the list needs to be cleared
- EFXDatabase.Clear();
- // destroy openal sources
- if ( useOpenAL ) {
-
- efxloaded = false;
- // adjust source count back up to allow for freeing of all resources
- openalSourceCount += 8;
- for ( ALsizei i = 0; i < openalSourceCount; i++ ) {
- // stop source
- alSourceStop( openalSources[i].handle );
- alSourcei( openalSources[i].handle, AL_BUFFER, 0 );
-
- // delete source
- alDeleteSources( 1, &openalSources[i].handle );
- // clear entry in source array
- openalSources[i].handle = NULL;
- openalSources[i].startTime = 0;
- openalSources[i].chan = NULL;
- openalSources[i].inUse = false;
- openalSources[i].looping = false;
- }
- }
- // destroy all the sounds (hardware buffers as well)
- delete soundCache;
- soundCache = NULL;
- // destroy openal device and context
- if ( useOpenAL ) {
- alcMakeContextCurrent( NULL );
-
- alcDestroyContext( openalContext );
- openalContext = NULL;
-
- alcCloseDevice( openalDevice );
- openalDevice = NULL;
- }
- Sys_FreeOpenAL();
- idSampleDecoder::Shutdown();
- }
- /*
- ===============
- idSoundSystemLocal::InitHW
- ===============
- */
- bool idSoundSystemLocal::InitHW() {
- if ( s_noSound.GetBool() ) {
- return false;
- }
- delete snd_audio_hw;
- snd_audio_hw = idAudioHardware::Alloc();
- if ( snd_audio_hw == NULL ) {
- return false;
- }
- if ( !useOpenAL ) {
- if ( !snd_audio_hw->Initialize() ) {
- delete snd_audio_hw;
- snd_audio_hw = NULL;
- return false;
- }
- if ( snd_audio_hw->GetNumberOfSpeakers() == 0 ) {
- return false;
- }
-
- // put the real number in there
-
- //BC 7-27-2016 prevent switching the user setting.
- //s_numberOfSpeakers.SetInteger( snd_audio_hw->GetNumberOfSpeakers() );
- }
- isInitialized = true;
- shutdown = false;
- return true;
- }
- /*
- ===============
- idSoundSystemLocal::ShutdownHW
- ===============
- */
- bool idSoundSystemLocal::ShutdownHW() {
- if ( !isInitialized ) {
- return false;
- }
- shutdown = true; // don't do anything at AsyncUpdate() time
- Sys_Sleep( 100 ); // sleep long enough to make sure any async sound talking to hardware has returned
- common->Printf( "Shutting down sound hardware\n" );
- delete snd_audio_hw;
- snd_audio_hw = NULL;
- isInitialized = false;
- if ( graph ) {
- Mem_Free( graph );
- graph = NULL;
- }
- return true;
- }
- /*
- ===============
- idSoundSystemLocal::GetCurrent44kHzTime
- ===============
- */
- int idSoundSystemLocal::GetCurrent44kHzTime( void ) const {
- if ( snd_audio_hw ) {
- return CurrentSoundTime;
- } else {
- // NOTE: this would overflow 31bits within about 1h20 ( not that important since we get a snd_audio_hw right away pbly )
- //return ( ( Sys_Milliseconds()*441 ) / 10 ) * 4;
- return idMath::FtoiFast( (float)Sys_Milliseconds() * 176.4f );
- }
- }
- /*
- ===================
- idSoundSystemLocal::ClearBuffer
- ===================
- */
- void idSoundSystemLocal::ClearBuffer( void ) {
- // check to make sure hardware actually exists
- if ( !snd_audio_hw ) {
- return;
- }
- short *fBlock;
- ulong fBlockLen;
- if ( !snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen ) ) {
- return;
- }
- if ( fBlock ) {
- SIMDProcessor->Memset( fBlock, 0, fBlockLen );
- snd_audio_hw->Unlock( fBlock, fBlockLen );
- }
- }
- /*
- ===================
- idSoundSystemLocal::AsyncMix
- Mac OSX version. The system uses it's own thread and an IOProc callback
- ===================
- */
- int idSoundSystemLocal::AsyncMix( int soundTime, float *mixBuffer ) {
- int inTime, numSpeakers;
- if ( !isInitialized || shutdown || !snd_audio_hw ) {
- return 0;
- }
- inTime = Sys_Milliseconds();
- numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
-
- // let the active sound world mix all the channels in unless muted or avi demo recording
- if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
- currentSoundWorld->MixLoop( soundTime, numSpeakers, mixBuffer );
- }
- CurrentSoundTime = soundTime;
-
- return Sys_Milliseconds() - inTime;
- }
- /*
- ===================
- idSoundSystemLocal::AsyncUpdate
- called from async sound thread when com_asyncSound == 1 ( Windows )
- ===================
- */
- int idSoundSystemLocal::AsyncUpdate( int inTime ) {
- if ( !isInitialized || shutdown || !snd_audio_hw ) {
- return 0;
- }
- ulong dwCurrentWritePos;
- dword dwCurrentBlock;
- // If not using openal, get actual playback position from sound hardware
- if ( useOpenAL ) {
- // here we do it in samples ( overflows in 27 hours or so )
- dwCurrentWritePos = idMath::Ftol( (float)Sys_Milliseconds() * 44.1f ) % ( MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER );
- dwCurrentBlock = dwCurrentWritePos / MIXBUFFER_SAMPLES;
- } else {
- // and here in bytes
- // get the current byte position in the buffer where the sound hardware is currently reading
- if ( !snd_audio_hw->GetCurrentPosition( &dwCurrentWritePos ) ) {
- return 0;
- }
- // mixBufferSize is in bytes
- dwCurrentBlock = dwCurrentWritePos / snd_audio_hw->GetMixBufferSize();
- }
- if ( nextWriteBlock == 0xffffffff ) {
- nextWriteBlock = dwCurrentBlock;
- }
- if ( dwCurrentBlock != nextWriteBlock ) {
- return 0;
- }
- // lock the buffer so we can actually write to it
- short *fBlock = NULL;
- ulong fBlockLen = 0;
- if ( !useOpenAL ) {
- snd_audio_hw->Lock( (void **)&fBlock, &fBlockLen );
- if ( !fBlock ) {
- return 0;
- }
- }
- int j;
- soundStats.runs++;
- soundStats.activeSounds = 0;
- int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
- nextWriteBlock++;
- nextWriteBlock %= ROOM_SLICES_IN_BUFFER;
- int newPosition = nextWriteBlock * MIXBUFFER_SAMPLES;
- if ( newPosition < olddwCurrentWritePos ) {
- buffers++; // buffer wrapped
- }
- // nextWriteSample is in multi-channel samples inside the buffer
- int nextWriteSamples = nextWriteBlock * MIXBUFFER_SAMPLES;
- olddwCurrentWritePos = newPosition;
- // newSoundTime is in multi-channel samples since the sound system was started
- int newSoundTime = ( buffers * MIXBUFFER_SAMPLES * ROOM_SLICES_IN_BUFFER ) + nextWriteSamples;
-
- // check for impending overflow
- // FIXME: we don't handle sound wrap-around correctly yet
- if ( newSoundTime > 0x6fffffff ) {
- buffers = 0;
- }
- if ( (newSoundTime - CurrentSoundTime) > (int)MIXBUFFER_SAMPLES ) {
- soundStats.missedWindow++;
- }
- if ( useOpenAL ) {
- // enable audio hardware caching
- alcSuspendContext( openalContext );
- } else {
- // clear the buffer for all the mixing output
- SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
- }
- // let the active sound world mix all the channels in unless muted or avi demo recording
- if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
- currentSoundWorld->MixLoop( newSoundTime, numSpeakers, finalMixBuffer );
- }
- if ( useOpenAL ) {
- // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
- alcProcessContext( openalContext );
- } else {
- short *dest = fBlock + nextWriteSamples * numSpeakers;
- SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
- // allow swapping the left / right speaker channels for people with miswired systems
- if ( numSpeakers == 2 && s_reverse.GetBool() ) {
- for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
- short temp = dest[j*2];
- dest[j*2] = dest[j*2+1];
- dest[j*2+1] = temp;
- }
- }
- snd_audio_hw->Unlock( fBlock, fBlockLen );
- }
- CurrentSoundTime = newSoundTime;
- soundStats.timeinprocess = Sys_Milliseconds() - inTime;
- return soundStats.timeinprocess;
- }
- /*
- ===================
- idSoundSystemLocal::AsyncUpdateWrite
- sound output using a write API. all the scheduling based on time
- we mix MIXBUFFER_SAMPLES at a time, but we feed the audio device with smaller chunks (and more often)
- called by the sound thread when com_asyncSound is 3 ( Linux )
- ===================
- */
- int idSoundSystemLocal::AsyncUpdateWrite( int inTime ) {
- if ( !isInitialized || shutdown || !snd_audio_hw ) {
- return 0;
- }
- if ( !useOpenAL ) {
- snd_audio_hw->Flush();
- }
- unsigned int dwCurrentBlock = (unsigned int)( inTime * 44.1f / MIXBUFFER_SAMPLES );
- if ( nextWriteBlock == 0xffffffff ) {
- nextWriteBlock = dwCurrentBlock;
- }
- if ( dwCurrentBlock < nextWriteBlock ) {
- return 0;
- }
- if ( nextWriteBlock != dwCurrentBlock ) {
- Sys_Printf( "missed %d sound updates\n", dwCurrentBlock - nextWriteBlock );
- }
- int sampleTime = dwCurrentBlock * MIXBUFFER_SAMPLES;
- int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
- if ( useOpenAL ) {
- // enable audio hardware caching
- alcSuspendContext( openalContext );
- } else {
- // clear the buffer for all the mixing output
- SIMDProcessor->Memset( finalMixBuffer, 0, MIXBUFFER_SAMPLES * sizeof(float) * numSpeakers );
- }
- // let the active sound world mix all the channels in unless muted or avi demo recording
- if ( !muted && currentSoundWorld && !currentSoundWorld->fpa[0] ) {
- currentSoundWorld->MixLoop( sampleTime, numSpeakers, finalMixBuffer );
- }
- if ( useOpenAL ) {
- // disable audio hardware caching (this updates ALL settings since last alcSuspendContext)
- alcProcessContext( openalContext );
- } else {
- short *dest = snd_audio_hw->GetMixBuffer();
- SIMDProcessor->MixedSoundToSamples( dest, finalMixBuffer, MIXBUFFER_SAMPLES * numSpeakers );
- // allow swapping the left / right speaker channels for people with miswired systems
- if ( numSpeakers == 2 && s_reverse.GetBool() ) {
- int j;
- for( j = 0; j < MIXBUFFER_SAMPLES; j++ ) {
- short temp = dest[j*2];
- dest[j*2] = dest[j*2+1];
- dest[j*2+1] = temp;
- }
- }
- snd_audio_hw->Write( false );
- }
- // only move to the next block if the write was successful
- nextWriteBlock = dwCurrentBlock + 1;
- CurrentSoundTime = sampleTime;
- return Sys_Milliseconds() - inTime;
- }
- /*
- ===================
- idSoundSystemLocal::dB2Scale
- ===================
- */
- float idSoundSystemLocal::dB2Scale( const float val ) const {
- if ( val == 0.0f ) {
- return 1.0f; // most common
- } else if ( val <= -60.0f ) {
- return 0.0f;
- } else if ( val >= 60.0f ) {
- return powf( 2.0f, val * ( 1.0f / 6.0f ) );
- }
- int ival = (int)( ( val + 60.0f ) * 10.0f );
- return volumesDB[ival];
- }
- /*
- ===================
- idSoundSystemLocal::ImageForTime
- ===================
- */
- cinData_t idSoundSystemLocal::ImageForTime( const int milliseconds, const bool waveform ) {
- cinData_t ret;
- int i, j;
- if ( !isInitialized || !snd_audio_hw ) {
- memset( &ret, 0, sizeof( ret ) );
- return ret;
- }
- Sys_EnterCriticalSection();
- if ( !graph ) {
- graph = (dword *)Mem_Alloc( 256*128 * 4);
- }
- memset( graph, 0, 256*128 * 4 );
- float *accum = finalMixBuffer; // unfortunately, these are already clamped
- int time = Sys_Milliseconds();
- int numSpeakers = snd_audio_hw->GetNumberOfSpeakers();
- if ( !waveform ) {
- for( j = 0; j < numSpeakers; j++ ) {
- int meter = 0;
- for( i = 0; i < MIXBUFFER_SAMPLES; i++ ) {
- float result = idMath::Fabs(accum[i*numSpeakers+j]);
- if ( result > meter ) {
- meter = result;
- }
- }
- meter /= 256; // 32768 becomes 128
- if ( meter > 128 ) {
- meter = 128;
- }
- int offset;
- int xsize;
- if ( numSpeakers == 6 ) {
- offset = j * 40;
- xsize = 20;
- } else {
- offset = j * 128;
- xsize = 63;
- }
- int x,y;
- dword color = 0xff00ff00;
- for ( y = 0; y < 128; y++ ) {
- for ( x = 0; x < xsize; x++ ) {
- graph[(127-y)*256 + offset + x ] = color;
- }
- #if 0
- if ( y == 80 ) {
- color = 0xff00ffff;
- } else if ( y == 112 ) {
- color = 0xff0000ff;
- }
- #endif
- if ( y > meter ) {
- break;
- }
- }
- if ( meter > meterTops[j] ) {
- meterTops[j] = meter;
- meterTopsTime[j] = time + s_meterTopTime.GetInteger();
- } else if ( time > meterTopsTime[j] && meterTops[j] > 0 ) {
- meterTops[j]--;
- if (meterTops[j]) {
- meterTops[j]--;
- }
- }
- }
- for( j = 0; j < numSpeakers; j++ ) {
- int meter = meterTops[j];
- int offset;
- int xsize;
- if ( numSpeakers == 6 ) {
- offset = j*40;
- xsize = 20;
- } else {
- offset = j*128;
- xsize = 63;
- }
- int x,y;
- dword color;
- if ( meter <= 80 ) {
- color = 0xff007f00;
- } else if ( meter <= 112 ) {
- color = 0xff007f7f;
- } else {
- color = 0xff00007f;
- }
- for ( y = meter; y < 128 && y < meter + 4; y++ ) {
- for ( x = 0; x < xsize; x++ ) {
- graph[(127-y)*256 + offset + x ] = color;
- }
- }
- }
- } else {
- dword colors[] = { 0xff007f00, 0xff007f7f, 0xff00007f, 0xff00ff00, 0xff00ffff, 0xff0000ff };
- for( j = 0; j < numSpeakers; j++ ) {
- int xx = 0;
- float fmeter;
- int step = MIXBUFFER_SAMPLES / 256;
- for( i = 0; i < MIXBUFFER_SAMPLES; i += step ) {
- fmeter = 0.0f;
- for( int x = 0; x < step; x++ ) {
- float result = accum[(i+x)*numSpeakers+j];
- result = result / 32768.0f;
- fmeter += result;
- }
- fmeter /= 4.0f;
- if ( fmeter < -1.0f ) {
- fmeter = -1.0f;
- } else if ( fmeter > 1.0f ) {
- fmeter = 1.0f;
- }
- int meter = (fmeter * 63.0f);
- graph[ (meter + 64) * 256 + xx ] = colors[j];
- if ( meter < 0 ) {
- meter = -meter;
- }
- if ( meter > meterTops[xx] ) {
- meterTops[xx] = meter;
- meterTopsTime[xx] = time + 100;
- } else if ( time>meterTopsTime[xx] && meterTops[xx] > 0 ) {
- meterTops[xx]--;
- if ( meterTops[xx] ) {
- meterTops[xx]--;
- }
- }
- xx++;
- }
- }
- for( i = 0; i < 256; i++ ) {
- int meter = meterTops[i];
- for ( int y = -meter; y < meter; y++ ) {
- graph[ (y+64)*256 + i ] = colors[j];
- }
- }
- }
- ret.imageHeight = 128;
- ret.imageWidth = 256;
- ret.image = (unsigned char *)graph;
- Sys_LeaveCriticalSection();
- return ret;
- }
- /*
- ===================
- idSoundSystemLocal::GetSoundDecoderInfo
- ===================
- */
- int idSoundSystemLocal::GetSoundDecoderInfo( int index, soundDecoderInfo_t &decoderInfo ) {
- int i, j, firstEmitter, firstChannel;
- idSoundWorldLocal *sw = soundSystemLocal.currentSoundWorld;
- if ( index < 0 ) {
- firstEmitter = 0;
- firstChannel = 0;
- } else {
- firstEmitter = index / SOUND_MAX_CHANNELS;
- firstChannel = index - firstEmitter * SOUND_MAX_CHANNELS + 1;
- }
- for ( i = firstEmitter; i < sw->emitters.Num(); i++ ) {
- idSoundEmitterLocal *sound = sw->emitters[i];
- if ( !sound ) {
- continue;
- }
- // run through all the channels
- for ( j = firstChannel; j < SOUND_MAX_CHANNELS; j++ ) {
- idSoundChannel *chan = &sound->channels[j];
- if ( chan->decoder == NULL ) {
- continue;
- }
- idSoundSample *sample = chan->decoder->GetSample();
- if ( sample == NULL ) {
- continue;
- }
- decoderInfo.name = sample->name;
- decoderInfo.format = ( sample->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) ? "OGG" : "WAV";
- decoderInfo.numChannels = sample->objectInfo.nChannels;
- decoderInfo.numSamplesPerSecond = sample->objectInfo.nSamplesPerSec;
- decoderInfo.num44kHzSamples = sample->LengthIn44kHzSamples();
- decoderInfo.numBytes = sample->objectMemSize;
- decoderInfo.looping = ( chan->parms.soundShaderFlags & SSF_LOOPING ) != 0;
- decoderInfo.lastVolume = chan->lastVolume;
- decoderInfo.start44kHzTime = chan->trigger44kHzTime;
- decoderInfo.current44kHzTime = soundSystemLocal.GetCurrent44kHzTime();
- return ( i * SOUND_MAX_CHANNELS + j );
- }
- firstChannel = 0;
- }
- return -1;
- }
- /*
- ===================
- idSoundSystemLocal::AllocSoundWorld
- ===================
- */
- idSoundWorld *idSoundSystemLocal::AllocSoundWorld( idRenderWorld *rw ) {
- idSoundWorldLocal *local = new idSoundWorldLocal;
- local->Init( rw );
- return local;
- }
- /*
- ===================
- idSoundSystemLocal::SetMute
- ===================
- */
- void idSoundSystemLocal::SetMute( bool muteOn ) {
- muted = muteOn;
- }
- /*
- ===================
- idSoundSystemLocal::SamplesToMilliseconds
- ===================
- */
- int idSoundSystemLocal::SamplesToMilliseconds( int samples ) const {
- return ( samples / (PRIMARYFREQ/1000) );
- }
- /*
- ===================
- idSoundSystemLocal::SamplesToMilliseconds
- ===================
- */
- int idSoundSystemLocal::MillisecondsToSamples( int ms ) const {
- return ( ms * (PRIMARYFREQ/1000) );
- }
- /*
- ===================
- idSoundSystemLocal::SetPlayingSoundWorld
- specifying NULL will cause silence to be played
- ===================
- */
- void idSoundSystemLocal::SetPlayingSoundWorld( idSoundWorld *soundWorld ) {
- currentSoundWorld = static_cast<idSoundWorldLocal *>(soundWorld);
- }
- /*
- ===================
- idSoundSystemLocal::GetPlayingSoundWorld
- ===================
- */
- idSoundWorld *idSoundSystemLocal::GetPlayingSoundWorld( void ) {
- return currentSoundWorld;
- }
- /*
- ===================
- idSoundSystemLocal::BeginLevelLoad
- ===================
- */
- void idSoundSystemLocal::BeginLevelLoad() {
- if ( !isInitialized ) {
- return;
- }
- soundCache->BeginLevelLoad();
-
- if ( efxloaded ) {
- EFXDatabase.UnloadFile();
- efxloaded = false;
- }
- }
- /*
- ===================
- idSoundSystemLocal::EndLevelLoad
- ===================
- */
- void idSoundSystemLocal::EndLevelLoad( const char *mapstring ) {
- if ( !isInitialized ) {
- return;
- }
- soundCache->EndLevelLoad();
- idStr efxname( "efxs/" );
- idStr mapname( mapstring );
- mapname.SetFileExtension( ".efx" );
- mapname.StripPath();
- efxname += mapname;
- efxloaded = EFXDatabase.LoadFile( efxname );
- if ( efxloaded ) {
- common->Printf("sound: found %s\n", efxname.c_str() );
- } else {
- common->Printf("sound: missing %s\n", efxname.c_str() );
- }
- }
- /*
- ===================
- idSoundSystemLocal::AllocOpenALSource
- ===================
- */
- ALuint idSoundSystemLocal::AllocOpenALSource( idSoundChannel *chan, bool looping, bool stereo ) {
- int timeOldestZeroVolSingleShot = Sys_Milliseconds();
- int timeOldestZeroVolLooping = Sys_Milliseconds();
- int timeOldestSingle = Sys_Milliseconds();
- int iOldestZeroVolSingleShot = -1;
- int iOldestZeroVolLooping = -1;
- int iOldestSingle = -1;
- int iUnused = -1;
- int index = -1;
- ALsizei i;
- // Grab current msec time
- int time = Sys_Milliseconds();
- // Cycle through all sources
- for ( i = 0; i < openalSourceCount; i++ ) {
- // Use any unused source first,
- // Then find oldest single shot quiet source,
- // Then find oldest looping quiet source and
- // Lastly find oldest single shot non quiet source..
- if ( !openalSources[i].inUse ) {
- iUnused = i;
- break;
- } else if ( !openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
- if ( openalSources[i].startTime < timeOldestZeroVolSingleShot ) {
- timeOldestZeroVolSingleShot = openalSources[i].startTime;
- iOldestZeroVolSingleShot = i;
- }
- } else if ( openalSources[i].looping && openalSources[i].chan->lastVolume < SND_EPSILON ) {
- if ( openalSources[i].startTime < timeOldestZeroVolLooping ) {
- timeOldestZeroVolLooping = openalSources[i].startTime;
- iOldestZeroVolLooping = i;
- }
- } else if ( !openalSources[i].looping ) {
- if ( openalSources[i].startTime < timeOldestSingle ) {
- timeOldestSingle = openalSources[i].startTime;
- iOldestSingle = i;
- }
- }
- }
- if ( iUnused != -1 ) {
- index = iUnused;
- } else if ( iOldestZeroVolSingleShot != - 1 ) {
- index = iOldestZeroVolSingleShot;
- } else if ( iOldestZeroVolLooping != -1 ) {
- index = iOldestZeroVolLooping;
- } else if ( iOldestSingle != -1 ) {
- index = iOldestSingle;
- }
- if ( index != -1 ) {
- // stop the channel that is being ripped off
- if ( openalSources[index].chan ) {
- // stop the channel only when not looping
- if ( !openalSources[index].looping ) {
- openalSources[index].chan->Stop();
- } else {
- openalSources[index].chan->triggered = true;
- }
- // Free hardware resources
- openalSources[index].chan->ALStop();
- }
- // Initialize structure
- openalSources[index].startTime = time;
- openalSources[index].chan = chan;
- openalSources[index].inUse = true;
- openalSources[index].looping = looping;
- openalSources[index].stereo = stereo;
- return openalSources[index].handle;
- } else {
- return NULL;
- }
- }
- /*
- ===================
- idSoundSystemLocal::FreeOpenALSource
- ===================
- */
- void idSoundSystemLocal::FreeOpenALSource( ALuint handle ) {
- ALsizei i;
- for ( i = 0; i < openalSourceCount; i++ ) {
- if ( openalSources[i].handle == handle ) {
- if ( openalSources[i].chan ) {
- openalSources[i].chan->openalSource = NULL;
- }
- #if ID_OPENAL
- // Reset source EAX ROOM level when freeing stereo source
- if ( openalSources[i].stereo && alEAXSet ) {
- long Room = EAXSOURCE_DEFAULTROOM;
- alEAXSet( &EAXPROPERTYID_EAX_Source, EAXSOURCE_ROOM, openalSources[i].handle, &Room, sizeof(Room));
- }
- #endif
- // Initialize structure
- openalSources[i].startTime = 0;
- openalSources[i].chan = NULL;
- openalSources[i].inUse = false;
- openalSources[i].looping = false;
- openalSources[i].stereo = false;
- }
- }
- }
- /*
- ============================================================
- SoundFX and misc effects
- ============================================================
- */
- /*
- ===================
- idSoundSystemLocal::ProcessSample
- ===================
- */
- void SoundFX_Lowpass::ProcessSample( float* in, float* out ) {
- float c, a1, a2, a3, b1, b2;
- float resonance = idSoundSystemLocal::s_enviroSuitCutoffQ.GetFloat();
- float cutoffFrequency = idSoundSystemLocal::s_enviroSuitCutoffFreq.GetFloat();
- Initialize();
- c = 1.0 / idMath::Tan16( idMath::PI * cutoffFrequency / 44100 );
- // compute coefs
- a1 = 1.0 / ( 1.0 + resonance * c + c * c );
- a2 = 2* a1;
- a3 = a1;
- b1 = 2.0 * ( 1.0 - c * c) * a1;
- b2 = ( 1.0 - resonance * c + c * c ) * a1;
- // compute output value
- out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
- }
- void SoundFX_LowpassFast::ProcessSample( float* in, float* out ) {
- // compute output value
- out[0] = a1 * in[0] + a2 * in[-1] + a3 * in[-2] - b1 * out[-1] - b2 * out[-2];
- }
- void SoundFX_LowpassFast::SetParms( float p1, float p2, float p3 ) {
- float c;
- // set the vars
- freq = p1;
- res = p2;
- // precompute the coefs
- c = 1.0 / idMath::Tan( idMath::PI * freq / 44100 );
- // compute coefs
- a1 = 1.0 / ( 1.0 + res * c + c * c );
- a2 = 2* a1;
- a3 = a1;
- b1 = 2.0 * ( 1.0 - c * c) * a1;
- b2 = ( 1.0 - res * c + c * c ) * a1;
- }
- void SoundFX_Comb::Initialize() {
- if ( initialized )
- return;
- initialized = true;
- maxlen = 50000;
- buffer = new float[maxlen];
- currentTime = 0;
- }
- void SoundFX_Comb::ProcessSample( float* in, float* out ) {
- float gain = idSoundSystemLocal::s_reverbFeedback.GetFloat();
- int len = idSoundSystemLocal::s_reverbTime.GetFloat() + param;
- Initialize();
- // sum up and output
- out[0] = buffer[currentTime];
- buffer[currentTime] = buffer[currentTime] * gain + in[0];
- // increment current time
- currentTime++;
- if ( currentTime >= len )
- currentTime -= len;
- }
- /*
- ===================
- idSoundSystemLocal::DoEnviroSuit
- ===================
- */
- void idSoundSystemLocal::DoEnviroSuit( float* samples, int numSamples, int numSpeakers )
- {
- float out[10000], *out_p = out + 2;
- float in[10000], *in_p = in + 2;
- assert( !idSoundSystemLocal::useOpenAL );
-
- if ( !fxList.Num() )
- {
- for ( int i = 0; i < 2/*bc was 6*/; i++ )
- {
- SoundFX* fx;
-
- // lowpass filter
- fx = new SoundFX_Lowpass();
- fx->SetChannel( i );
- fxList.Append( fx );
-
- /*
- // comb
- fx = new SoundFX_Comb();
- fx->SetChannel( i );
- fx->SetParameter( i * 100 );
- fxList.Append( fx );
-
- // comb
- fx = new SoundFX_Comb();
- fx->SetChannel( i );
- fx->SetParameter( i * 100 + 5 );
- fxList.Append( fx );
- */
- }
- }
-
- for ( int i = 0; i < numSpeakers; i++ )
- {
- int j;
- // restore previous samples
- memset( in, 0, 10000 * sizeof( float ) );
- memset( out, 0, 10000 * sizeof( float ) );
- // fx loop
- for ( int k = 0; k < fxList.Num(); k++ )
- {
- SoundFX* fx = fxList[k];
- // skip if we're not the right channel
- if ( fx->GetChannel() != i )
- continue;
- // get samples and continuity
- fx->GetContinuitySamples( in_p[-1], in_p[-2], out_p[-1], out_p[-2] );
- for ( j = 0; j < numSamples; j++ ) {
- in_p[j] = samples[j * numSpeakers + i] * s_enviroSuitVolumeScale.GetFloat();
- }
-
- // process fx loop
- for ( j = 0; j < numSamples; j++ )
- {
- fx->ProcessSample( in_p + j, out_p + j );
- }
-
- // store samples and continuity
- fx->SetContinuitySamples( in_p[numSamples-2], in_p[numSamples-3], out_p[numSamples-2], out_p[numSamples-3] );
- for ( j = 0; j < numSamples; j++ )
- {
- samples[j * numSpeakers + i] = out_p[j];
- }
- }
- }
- }
- /*
- =================
- idSoundSystemLocal::PrintMemInfo
- =================
- */
- void idSoundSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
- soundCache->PrintMemInfo( mi );
- }
- /*
- ===============
- idSoundSystemLocal::EAXAvailable
- ===============
- */
- int idSoundSystemLocal::IsEAXAvailable( void ) {
- #if !ID_OPENAL
- return -1;
- #else
- ALCdevice *device;
- ALCcontext *context;
- if ( EAXAvailable != -1 ) {
- return EAXAvailable;
- }
- if ( !Sys_LoadOpenAL() ) {
- EAXAvailable = 2;
- return 2;
- }
- // when dynamically loading the OpenAL subsystem, we need to get a context before alIsExtensionPresent would work
- device = alcOpenDevice( NULL );
- context = alcCreateContext( device, NULL );
- alcMakeContextCurrent( context );
- if ( alIsExtensionPresent( ID_ALCHAR "EAX4.0" ) ) {
- alcMakeContextCurrent( NULL );
- alcDestroyContext( context );
- alcCloseDevice( device );
- EAXAvailable = 1;
- return 1;
- }
- alcMakeContextCurrent( NULL );
- alcDestroyContext( context );
- alcCloseDevice( device );
- EAXAvailable = 0;
- return 0;
- #endif
- }
- /* bc flite
- void idSoundSystemLocal::SynthesizeSpeech( const char *input ) {
- //flite_text_to_speech(input, voice, "stream"); //synthesize sound via streaming method.
-
- cst_utterance *u;
- u = flite_synth_text(input,voice);
- if (u)
- {
- // Play or save (append) output to output file
- cst_wave *w;
- w = utt_wave(u);
- 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)
- cst_wave_save_riff(w, "base/sound/flite.wav");
- delete_utterance(u);
- }
- }
- */
- //for use with Flite streaming. (Brian)
- /*
- int example_audio_stream_chunk( const cst_wave *w, int start, int size, int last, void *user ) {
- common->Printf("audio_stream_chunk" );
- // Called with new samples from start for size samples
- // last is true if this is the last segment.
- // This is really just and example that you can copy for you streaming
- // function
- // This particular example is *not* thread safe
-
- int n;
- static cst_audiodev *ad = 0;
- if (start == 0)
- ad = audio_open(w->sample_rate,w->num_channels,CST_AUDIO_LINEAR16);
- n = audio_write(ad,&w->samples[start],size*sizeof(short));
- if (last == 1)
- {
- audio_close(ad);
- ad = NULL;
- }
-
- // if you want to stop return CST_AUDIO_STREAM_STOP
-
- return CST_AUDIO_STREAM_CONT;
- }
- */
|