123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "snd_local.h"
- idCVar s_noSound( "s_noSound", "0", CVAR_BOOL, "returns NULL for all sounds loaded and does not update the sound rendering" );
- #ifdef ID_RETAIL
- idCVar s_useCompression( "s_useCompression", "1", CVAR_BOOL, "Use compressed sound files (mp3/xma)" );
- idCVar s_playDefaultSound( "s_playDefaultSound", "0", CVAR_BOOL, "play a beep for missing sounds" );
- idCVar s_maxSamples( "s_maxSamples", "5", CVAR_INTEGER, "max samples to load per shader" );
- #else
- idCVar s_useCompression( "s_useCompression", "1", CVAR_BOOL, "Use compressed sound files (mp3/xma)" );
- idCVar s_playDefaultSound( "s_playDefaultSound", "1", CVAR_BOOL, "play a beep for missing sounds" );
- idCVar s_maxSamples( "s_maxSamples", "5", CVAR_INTEGER, "max samples to load per shader" );
- #endif
- idCVar preLoad_Samples( "preLoad_Samples", "1", CVAR_SYSTEM | CVAR_BOOL, "preload samples during beginlevelload" );
- idSoundSystemLocal soundSystemLocal;
- idSoundSystem * soundSystem = &soundSystemLocal;
- /*
- ================================================================================================
- idSoundSystemLocal
- ================================================================================================
- */
- /*
- ========================
- TestSound_f
- This is called from the main thread.
- ========================
- */
- void TestSound_f( const idCmdArgs & args ) {
- if ( args.Argc() != 2 ) {
- idLib::Printf( "Usage: testSound <file>\n" );
- return;
- }
- if ( soundSystemLocal.currentSoundWorld ) {
- soundSystemLocal.currentSoundWorld->PlayShaderDirectly( args.Argv( 1 ) );
- }
- }
- /*
- ========================
- RestartSound_f
- ========================
- */
- void RestartSound_f( const idCmdArgs & args ) {
- soundSystemLocal.Restart();
- }
- /*
- ========================
- ListSamples_f
- ========================
- */
- void ListSamples_f( const idCmdArgs & args ) {
- idLib::Printf( "Sound samples\n-------------\n" );
- int totSize = 0;
- for ( int i = 0; i < soundSystemLocal.samples.Num(); i++ ) {
- idLib::Printf( "%05dkb\t%s\n", soundSystemLocal.samples[ i ]->BufferSize() / 1024, soundSystemLocal.samples[ i ]->GetName() );
- totSize += soundSystemLocal.samples[ i ]->BufferSize();
- }
- idLib::Printf( "--------------------------\n" );
- idLib::Printf( "%05dkb total size\n", totSize / 1024 );
- }
- /*
- ========================
- idSoundSystemLocal::Restart
- ========================
- */
- void idSoundSystemLocal::Restart() {
- // Mute all channels in all worlds
- for ( int i = 0; i < soundWorlds.Num(); i++ ) {
- idSoundWorldLocal * sw = soundWorlds[i];
- for ( int e = 0; e < sw->emitters.Num(); e++ ) {
- idSoundEmitterLocal * emitter = sw->emitters[e];
- for ( int c = 0; c < emitter->channels.Num(); c++ ) {
- emitter->channels[c]->Mute();
- }
- }
- }
- // Shutdown sound hardware
- hardware.Shutdown();
- // Reinitialize sound hardware
- if ( !s_noSound.GetBool() ) {
- hardware.Init();
- }
- InitStreamBuffers();
- }
- /*
- ========================
- idSoundSystemLocal::Init
- Initialize the SoundSystem.
- ========================
- */
- void idSoundSystemLocal::Init() {
- idLib::Printf( "----- Initializing Sound System ------\n" );
- soundTime = Sys_Milliseconds();
- random.SetSeed( soundTime );
- if ( !s_noSound.GetBool() ) {
- hardware.Init();
- InitStreamBuffers();
- }
- cmdSystem->AddCommand( "testSound", TestSound_f, 0, "tests a sound", idCmdSystem::ArgCompletion_SoundName );
- cmdSystem->AddCommand( "s_restart", RestartSound_f, 0, "restart sound system" );
- cmdSystem->AddCommand( "listSamples", ListSamples_f, 0, "lists all loaded sound samples" );
- idLib::Printf( "sound system initialized.\n" );
- idLib::Printf( "--------------------------------------\n" );
- }
- /*
- ========================
- idSoundSystemLocal::InitStreamBuffers
- ========================
- */
- void idSoundSystemLocal::InitStreamBuffers() {
- streamBufferMutex.Lock();
- const bool empty = ( bufferContexts.Num() == 0 );
- if ( empty ) {
- bufferContexts.SetNum( MAX_SOUND_BUFFERS );
- for ( int i = 0; i < MAX_SOUND_BUFFERS; i++ ) {
- freeStreamBufferContexts.Append( &( bufferContexts[ i ] ) );
- }
- } else {
- for ( int i = 0; i < activeStreamBufferContexts.Num(); i++ ) {
- freeStreamBufferContexts.Append( activeStreamBufferContexts[ i ] );
- }
- activeStreamBufferContexts.Clear();
- }
- assert( bufferContexts.Num() == MAX_SOUND_BUFFERS );
- assert( freeStreamBufferContexts.Num() == MAX_SOUND_BUFFERS );
- assert( activeStreamBufferContexts.Num() == 0 );
- streamBufferMutex.Unlock();
- }
- /*
- ========================
- idSoundSystemLocal::FreeStreamBuffers
- ========================
- */
- void idSoundSystemLocal::FreeStreamBuffers() {
- streamBufferMutex.Lock();
- bufferContexts.Clear();
- freeStreamBufferContexts.Clear();
- activeStreamBufferContexts.Clear();
- streamBufferMutex.Unlock();
- }
- /*
- ========================
- idSoundSystemLocal::Shutdown
- ========================
- */
- void idSoundSystemLocal::Shutdown() {
- hardware.Shutdown();
- FreeStreamBuffers();
- samples.DeleteContents( true );
- sampleHash.Free();
- }
- /*
- ========================
- idSoundSystemLocal::ObtainStreamBuffer
- Get a stream buffer from the free pool, returns NULL if none are available
- ========================
- */
- idSoundSystemLocal::bufferContext_t * idSoundSystemLocal::ObtainStreamBufferContext() {
- bufferContext_t * bufferContext = NULL;
- streamBufferMutex.Lock();
- if ( freeStreamBufferContexts.Num() != 0 ) {
- bufferContext = freeStreamBufferContexts[ freeStreamBufferContexts.Num() - 1 ];
- freeStreamBufferContexts.SetNum( freeStreamBufferContexts.Num() - 1 );
- activeStreamBufferContexts.Append( bufferContext );
- }
- streamBufferMutex.Unlock();
- return bufferContext;
- }
- /*
- ========================
- idSoundSystemLocal::ReleaseStreamBuffer
- Releases a stream buffer back to the free pool
- ========================
- */
- void idSoundSystemLocal::ReleaseStreamBufferContext( bufferContext_t * bufferContext ) {
- streamBufferMutex.Lock();
- if ( activeStreamBufferContexts.Remove( bufferContext ) ) {
- freeStreamBufferContexts.Append( bufferContext );
- }
- streamBufferMutex.Unlock();
- }
- /*
- ========================
- idSoundSystemLocal::AllocSoundWorld
- ========================
- */
- idSoundWorld * idSoundSystemLocal::AllocSoundWorld( idRenderWorld *rw ) {
- idSoundWorldLocal * local = new (TAG_AUDIO) idSoundWorldLocal;
- local->renderWorld = rw;
- soundWorlds.Append( local );
- return local;
- }
- /*
- ========================
- idSoundSystemLocal::FreeSoundWorld
- ========================
- */
- void idSoundSystemLocal::FreeSoundWorld( idSoundWorld *sw ) {
- idSoundWorldLocal *local = static_cast<idSoundWorldLocal*>( sw );
- soundWorlds.Remove( local );
- delete local;
- }
- /*
- ========================
- idSoundSystemLocal::SetPlayingSoundWorld
- Specifying NULL will cause silence to be played.
- ========================
- */
- void idSoundSystemLocal::SetPlayingSoundWorld( idSoundWorld *soundWorld ) {
- if ( currentSoundWorld == soundWorld ) {
- return;
- }
- idSoundWorldLocal * oldSoundWorld = currentSoundWorld;
- currentSoundWorld = static_cast<idSoundWorldLocal *>( soundWorld );
- if ( oldSoundWorld != NULL ) {
- oldSoundWorld->Update();
- }
- }
- /*
- ========================
- idSoundSystemLocal::GetPlayingSoundWorld
- ========================
- */
- idSoundWorld * idSoundSystemLocal::GetPlayingSoundWorld() {
- return currentSoundWorld;
- }
- /*
- ========================
- idSoundSystemLocal::Render
- ========================
- */
- void idSoundSystemLocal::Render() {
- if ( s_noSound.GetBool() ) {
- return;
- }
- if ( needsRestart ) {
- needsRestart = false;
- Restart();
- }
- SCOPED_PROFILE_EVENT( "SoundSystem::Render" );
- if ( currentSoundWorld != NULL ) {
- currentSoundWorld->Update();
- }
- hardware.Update();
- // The sound system doesn't use game time or anything like that because the sounds are decoded in real time.
- soundTime = Sys_Milliseconds();
- }
- /*
- ========================
- idSoundSystemLocal::OnReloadSound
- ========================
- */
- void idSoundSystemLocal::OnReloadSound( const idDecl* sound ) {
- for ( int i = 0; i < soundWorlds.Num(); i++ ) {
- soundWorlds[i]->OnReloadSound( sound );
- }
- }
- /*
- ========================
- idSoundSystemLocal::StopAllSounds
- ========================
- */
- void idSoundSystemLocal::StopAllSounds() {
- for ( int i = 0; i < soundWorlds.Num(); i++ ) {
- idSoundWorld *sw = soundWorlds[i];
- if ( sw ) {
- sw->StopAllSounds();
- }
- }
- hardware.Update();
- }
- /*
- ========================
- idSoundSystemLocal::GetIXAudio2
- ========================
- */
- void * idSoundSystemLocal::GetIXAudio2() const {
- return (void *)hardware.GetIXAudio2();
- }
- /*
- ========================
- idSoundSystemLocal::SoundTime
- ========================
- */
- int idSoundSystemLocal::SoundTime() const {
- return soundTime;
- }
- /*
- ========================
- idSoundSystemLocal::AllocateVoice
- ========================
- */
- idSoundVoice * idSoundSystemLocal::AllocateVoice( const idSoundSample * leadinSample, const idSoundSample * loopingSample ) {
- return hardware.AllocateVoice( leadinSample, loopingSample );
- }
- /*
- ========================
- idSoundSystemLocal::FreeVoice
- ========================
- */
- void idSoundSystemLocal::FreeVoice( idSoundVoice * voice ) {
- hardware.FreeVoice( voice );
- }
- /*
- ========================
- idSoundSystemLocal::LoadSample
- ========================
- */
- idSoundSample * idSoundSystemLocal::LoadSample( const char * name ) {
- idStrStatic< MAX_OSPATH > canonical = name;
- canonical.ToLower();
- canonical.BackSlashesToSlashes();
- canonical.StripFileExtension();
- int hashKey = idStr::Hash( canonical );
- for ( int i = sampleHash.First( hashKey ); i != -1; i = sampleHash.Next( i ) ) {
- if ( idStr::Cmp( samples[i]->GetName(), canonical ) == 0 ) {
- samples[i]->SetLevelLoadReferenced();
- return samples[i];
- }
- }
- idSoundSample * sample = new (TAG_AUDIO) idSoundSample;
- sample->SetName( canonical );
- sampleHash.Add( hashKey, samples.Append( sample ) );
- if ( !insideLevelLoad ) {
- // Sound sample referenced before any map is loaded
- sample->SetNeverPurge();
- sample->LoadResource();
- } else {
- sample->SetLevelLoadReferenced();
- }
- if ( cvarSystem->GetCVarBool( "fs_buildgame" ) ) {
- fileSystem->AddSamplePreload( canonical );
- }
- return sample;
- }
- /*
- ========================
- idSoundSystemLocal::StopVoicesWithSample
- A sample is about to be freed, make sure the hardware isn't mixing from it.
- ========================
- */
- void idSoundSystemLocal::StopVoicesWithSample( const idSoundSample * const sample ) {
- for ( int w = 0; w < soundWorlds.Num(); w++ ) {
- idSoundWorldLocal * sw = soundWorlds[w];
- if ( sw == NULL ) {
- continue;
- }
- for ( int e = 0; e < sw->emitters.Num(); e++ ) {
- idSoundEmitterLocal * emitter = sw->emitters[e];
- if ( emitter == NULL ) {
- continue;
- }
- for ( int i = 0; i < emitter->channels.Num(); i++ ) {
- if ( emitter->channels[i]->leadinSample == sample || emitter->channels[i]->loopingSample == sample ) {
- emitter->channels[i]->Mute();
- }
- }
- }
- }
- }
- /*
- ========================
- idSoundSystemLocal::FreeVoice
- ========================
- */
- cinData_t idSoundSystemLocal::ImageForTime( const int milliseconds, const bool waveform ) {
- cinData_t cd;
- cd.imageY = NULL;
- cd.imageCr = NULL;
- cd.imageCb = NULL;
- cd.imageWidth = 0;
- cd.imageHeight = 0;
- cd.status = FMV_IDLE;
- return cd;
- }
- /*
- ========================
- idSoundSystemLocal::BeginLevelLoad
- ========================
- */
- void idSoundSystemLocal::BeginLevelLoad() {
- insideLevelLoad = true;
- for ( int i = 0; i < samples.Num(); i++ ) {
- if ( samples[i]->GetNeverPurge() ) {
- continue;
- }
- samples[i]->FreeData();
- samples[i]->ResetLevelLoadReferenced();
- }
- }
- /*
- ========================
- idSoundSystemLocal::Preload
- ========================
- */
- void idSoundSystemLocal::Preload( idPreloadManifest & manifest ) {
-
- idStrStatic< MAX_OSPATH > filename;
-
- int start = Sys_Milliseconds();
- int numLoaded = 0;
- idList< preloadSort_t > preloadSort;
- preloadSort.Resize( manifest.NumResources() );
- for ( int i = 0; i < manifest.NumResources(); i++ ) {
- const preloadEntry_s & p = manifest.GetPreloadByIndex( i );
- idResourceCacheEntry rc;
- // FIXME: write these out sorted
- if ( p.resType == PRELOAD_SAMPLE ) {
- if ( p.resourceName.Find( "/vo/", false ) >= 0 ) {
- continue;
- }
- filename = "generated/";
- filename += p.resourceName;
- filename.SetFileExtension( "idwav" );
- if ( fileSystem->GetResourceCacheEntry( filename, rc ) ) {
- preloadSort_t ps = {};
- ps.idx = i;
- ps.ofs = rc.offset;
- preloadSort.Append( ps );
- }
- }
- }
- preloadSort.SortWithTemplate( idSort_Preload() );
- for ( int i = 0; i < preloadSort.Num(); i++ ) {
- const preloadSort_t & ps = preloadSort[ i ];
- const preloadEntry_s & p = manifest.GetPreloadByIndex( ps.idx );
- filename = p.resourceName;
- filename.Replace( "generated/", "" );
- numLoaded++;
- idSoundSample *sample = LoadSample( filename );
- if ( sample != NULL && !sample->IsLoaded() ) {
- sample->LoadResource();
- sample->SetLevelLoadReferenced();
- }
- }
- int end = Sys_Milliseconds();
- common->Printf( "%05d sounds preloaded in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 );
- common->Printf( "----------------------------------------\n" );
- }
- /*
- ========================
- idSoundSystemLocal::EndLevelLoad
- ========================
- */
- void idSoundSystemLocal::EndLevelLoad() {
- insideLevelLoad = false;
- common->Printf( "----- idSoundSystemLocal::EndLevelLoad -----\n" );
- int start = Sys_Milliseconds();
- int keepCount = 0;
- int loadCount = 0;
- idList< preloadSort_t > preloadSort;
- preloadSort.Resize( samples.Num() );
- for ( int i = 0; i < samples.Num(); i++ ) {
- common->UpdateLevelLoadPacifier();
- if ( samples[i]->GetNeverPurge() ) {
- continue;
- }
- if ( samples[i]->IsLoaded() ) {
- keepCount++;
- continue;
- }
- if ( samples[i]->GetLevelLoadReferenced() ) {
- idStrStatic< MAX_OSPATH > filename = "generated/";
- filename += samples[ i ]->GetName();
- filename.SetFileExtension( "idwav" );
- preloadSort_t ps = {};
- ps.idx = i;
- idResourceCacheEntry rc;
- if ( fileSystem->GetResourceCacheEntry( filename, rc ) ) {
- ps.ofs = rc.offset;
- } else {
- ps.ofs = 0;
- }
- preloadSort.Append( ps );
- loadCount++;
- }
- }
- preloadSort.SortWithTemplate( idSort_Preload() );
- for ( int i = 0; i < preloadSort.Num(); i++ ) {
- common->UpdateLevelLoadPacifier();
- samples[ preloadSort[ i ].idx ]->LoadResource();
- }
- int end = Sys_Milliseconds();
- common->Printf( "%5i sounds loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
- common->Printf( "----------------------------------------\n" );
- }
- /*
- ========================
- idSoundSystemLocal::FreeVoice
- ========================
- */
- void idSoundSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
- }
|