//============================================================================= // Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. // // File: soundloader.cpp // // Description: Implement SoundLoader class, which makes sure that sounds // required in the game are allocated and resident in sound memory // // History: 26/06/2002 + Created -- Darren // //============================================================================= //======================================== // System Includes //======================================== //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include #include #include #include #include //****************************************************************************** // // Global Data, Local Data, Local Classes // //****************************************************************************** // // Names of sound clusters. Used so that the loading manager can tell us // when it's our turn to loading something. Should correspond to SoundClusterName // enumeration // static const char* s_clusterNames[] = { "permanent", "frontend", "ingame", "suburbs", "downtown", "seaside", "level1", "level2", "level3", "level4", "level5", "level6", "level7", "minigame", "huh?", "apu", "bart", "homer", "lisa", "marge", "bart_v", "apu_v", "snake_v", "homer_v", "famil_v", "gramp_v", "cletu_v", "wiggu_v", "empty1", "marge_v", "empty2", "empty3", "smith_v", "empty4", "empty5", "empty6", "zombi_v", "empty7", "empty8", "cVan", "compactA", "comic_v", "skinn_v", "cCola", "cSedan", "cPolice", "cCellA", "cCellB", "cCellC", "cCellD", "minivanA_v", "pickupA", "taxiA_v", "sportsA", "sportsB", "SUVA", "wagonA", "hbike_v", "burns_v", "honor_v", "cArmor", "cCurator", "cHears", "cKlimo", "cLimo", "cNerd", "frink_v", "cMilk", "cDonut", "bbman_v", "bookb_v", "carhom_v", "elect_v", "fone_v", "gramR_v", "moe_v", "mrplo_v", "otto_v", "plowk_v", "scorp_v", "willi_v", "sedanA", "sedanB", "cBlbart", "cCube", "cDuff", "cNonup", "lisa_v", "krust_v", "coffin", "hallo", "ship", "witchcar", "huska", "atv_v", "dune_v", "hype_v", "knigh_v", "mono_v", "oblit_v", "rocke_v", "ambul", "burnsarm", "fishtruc", "garbage", "icecream", "istruck", "nuctruck", "pizza", "schoolbu", "votetruc", "glastruc", "cfire_v", "cBone", "redbrick" }; static const int NumScriptNames = sizeof( s_clusterNames ) / sizeof( const char* ); // // Indices of character namespaces for each level. // // TODO: I don't like these tables, there must be a more data-driven way to do // this. // 0 == Apu // 1 == Bart // 2 == Homer // 3 == Lisa // 4 == Marge // static unsigned int s_charNamespaceIndices[] = { 2, 1, 3, 4, 0, 1, 2, 0 }; static VehicleEnum::VehicleID s_carIndices[] = { VehicleEnum::FAMIL_V, VehicleEnum::HONOR_V, VehicleEnum::LISA_V, VehicleEnum::MARGE_V, VehicleEnum::APU_V, VehicleEnum::BART_V, VehicleEnum::HOMER_V, VehicleEnum::FAMIL_V, }; static unsigned int s_levelIndices[] = { 0, 1, 2, 0, 1, 2, 0, 0 }; //****************************************************************************** // // Public Member Functions // //****************************************************************************** //============================================================================== // SoundLoader::SoundLoader //============================================================================== // Description: Constructor. // // Parameters: None. // // Return: N/A. // //============================================================================== SoundLoader::SoundLoader() : m_currentCluster( SC_ALWAYS_LOADED ) { unsigned int i; SoundClusterName clusterIndex; Sound::daSoundRenderingManager* renderingMgr = Sound::daSoundRenderingManagerGet(); for( i = 0; i < SC_MAX_CLUSTERS; i++ ) { m_clusterList[i] = NULL; } for( clusterIndex = SC_ALWAYS_LOADED; clusterIndex < SC_CHAR_APU; clusterIndex = static_cast( clusterIndex + 1 ) ) { m_clusterList[clusterIndex] = new(GMA_PERSISTENT) SoundCluster( clusterIndex, renderingMgr->GetSoundNamespace() ); } for( clusterIndex = SC_CHAR_APU; clusterIndex < SC_CAR_BASE; clusterIndex = static_cast( clusterIndex + 1 ) ) { m_clusterList[clusterIndex] = new(GMA_PERSISTENT) SoundCluster( clusterIndex, renderingMgr->GetCharacterNamespace( clusterIndex - SC_CHAR_APU ) ); } for( clusterIndex = SC_CAR_BASE; clusterIndex < SC_MAX_CLUSTERS; clusterIndex = static_cast( clusterIndex + 1 ) ) { m_clusterList[clusterIndex] = new(GMA_PERSISTENT) SoundCluster( clusterIndex, renderingMgr->GetSoundNamespace() ); } // // Register event listeners // GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_START ); } //============================================================================== // SoundLoader::~SoundLoader //============================================================================== // Description: Destructor. // // Parameters: None. // // Return: N/A. // //============================================================================== SoundLoader::~SoundLoader() { unsigned int i; for( i = 0; i < SC_MAX_CLUSTERS; i++ ) { if( m_clusterList[i] != NULL ) { m_clusterList[i]->Release(); } } GetEventManager()->RemoveAll( this ); } //============================================================================= // SoundLoader::LevelLoad //============================================================================= // Description: Loads the sound cluster for a particular level // // Parameters: RenderEnums::LevelEnum level - // enumeration indicating the level whose sound cluster // is to be loaded // // Return: void // //============================================================================= void SoundLoader::LevelLoad( RenderEnums::LevelEnum level ) { IRadNameSpace* charNamespace; unsigned int levelNum; clusterUnload( SC_FRONTEND ); queueLoad( SC_INGAME ); if( GetGameplayManager()->IsSuperSprint() ) { queueLoad( SC_MINIGAME ); } else { rAssert( level <= RenderEnums::numLevels ); levelNum = static_cast(level); queueLoad( static_cast( SC_LEVEL_SUBURBS + s_levelIndices[levelNum] ) ); queueLoad( static_cast( SC_CHAR_APU + s_charNamespaceIndices[levelNum] ) ); queueLoad( static_cast( SC_CAR_BASE + s_carIndices[levelNum] ) ); queueLoad( static_cast( SC_LEVEL1 + levelNum ) ); charNamespace = m_clusterList[SC_CHAR_APU + s_charNamespaceIndices[level]]->GetMyNamespace(); rAssert( charNamespace != NULL ); // // We need to do this for RadTuner, since we've got duplicate names and // it won't necessarily find the correct character otherwise // charNamespace->MoveToFront(); } } //============================================================================= // SoundLoader::LevelUnload //============================================================================= // Description: Unloads the sound cluster for a particular level // // Parameters: RenderEnums::LevelEnum level - // enumeration indicating the level whose sound cluster // is to be unloaded // // Return: void // //============================================================================= void SoundLoader::LevelUnload( bool goingToFe ) { SoundClusterName clusterIndex; // // Unload everything that's not permanent // for( clusterIndex = SC_INGAME; clusterIndex < SC_MAX_CLUSTERS; clusterIndex = static_cast( clusterIndex + 1 ) ) { if( m_clusterList[clusterIndex]->IsLoaded() ) { clusterUnload( clusterIndex ); } } if( goingToFe ) { queueLoad( SC_FRONTEND ); } } //============================================================================= // SoundLoader::MissionLoad //============================================================================= // Description: Loads the sound cluster for a particular mission // // Parameters: RenderEnums::MissionEnum mission - // enumeration indicating the mission whose sound cluster // is to be loaded // // Return: void // //============================================================================= void SoundLoader::MissionLoad( RenderEnums::MissionEnum mission ) { } //============================================================================= // SoundLoader::MissionUnload //============================================================================= // Description: Unloads the sound cluster for a particular mission // // Parameters: RenderEnums::MissionEnum mission - // enumeration indicating the mission whose sound cluster // is to be unloaded // // Return: void // //============================================================================= void SoundLoader::MissionUnload( RenderEnums::MissionEnum mission ) { } void SoundLoader::LoadCarSound( Vehicle* theCar, bool unloadOtherCars ) { rAssert( theCar ); SoundClusterName clusterIndex; SoundClusterName newCarCluster = static_cast(SC_CAR_BASE + theCar->mVehicleID); bool validCar = ( SC_CAR_BASE + theCar->mVehicleID ) < NumScriptNames; rAssertMsg( validCar, "A new vehicle has been added that the sound system does not have a script for. Tell Esan.\n" ); // // Have we loaded this car already? // if( !validCar || m_clusterList[newCarCluster]->IsLoaded() ) { return; } // // Unload the existing car sound // if( unloadOtherCars ) { for( clusterIndex = SC_CAR_BASE; clusterIndex < SC_MAX_CLUSTERS; clusterIndex = static_cast( clusterIndex + 1 ) ) { if( m_clusterList[clusterIndex]->IsLoaded() ) { clusterUnload( clusterIndex ); } } } // // Load the new car // queueLoad( newCarCluster ); } //============================================================================= // SoundLoader::IsSoundLoaded //============================================================================= // Description: Indicate whether a particular sound resource has been loaded // // Parameters: soundKey - hashed name of the sound resource to look for // // Return: true if loaded, falsed otherwise // //============================================================================= bool SoundLoader::IsSoundLoaded( Sound::daResourceKey soundKey ) { unsigned int i; for( i = 0; i < SC_MAX_CLUSTERS; i++ ) { if( ( m_clusterList[i] != NULL ) && ( m_clusterList[i]->ContainsResource( soundKey ) ) ) { return( m_clusterList[i]->IsLoaded() ); } } return( false ); } //============================================================================= // SoundLoader::LoadClusterByName //============================================================================= // Description: Given a cluster name from the loading manager, load the // desired cluster // // Parameters: clusterName - text name for the cluster // callbackObj - loading file handler to notify on completion // // Return: true if cluster already loaded, false otherwise // //============================================================================= bool SoundLoader::LoadClusterByName( const char* clusterName, SoundFileHandler* callbackObj ) { const char* shortName; unsigned int i; // Strip out the "sound:" prefix rAssert( strlen( clusterName ) > 6 ); shortName = &(clusterName[6]); // // Find the matching cluster name // for( i = 0; i < SC_MAX_CLUSTERS; i++ ) { if( strcmp( shortName, s_clusterNames[i] ) == 0 ) { return( clusterLoad( static_cast( i ), callbackObj ) ); } } // // If we get here, cluster not found // rAssert( false ); return( false ); } //============================================================================= // SoundLoader::HandleEvent //============================================================================= // Description: Comment // // Parameters: ( EventEnum id, void* pEventData ) // // Return: void // //============================================================================= void SoundLoader::HandleEvent( EventEnum id, void* pEventData ) { Character* theCharacter; Vehicle* theCar; switch( id ) { case EVENT_GETINTOVEHICLE_START: // // Make sure we've got the correct car sound for this vehicle // theCharacter = static_cast(pEventData); rAssert( theCharacter != NULL ); theCar = theCharacter->GetTargetVehicle(); rAssert( theCar != NULL ); LoadCarSound( theCar, true ); break; default: rAssert( false ); break; } } //****************************************************************************** // // Private Member Functions // //****************************************************************************** //============================================================================= // SoundLoader::queueLoad //============================================================================= // Description: Queue a cluster load with the loading manager // // Parameters: cluster - name of cluster to queue // // Return: void // //============================================================================= void SoundLoader::queueLoad( SoundClusterName cluster ) { char fakeFilename[50]; // // Create a pseudo filename that we'll give to the loading manager. // Content doesn't really matter, we'll just throw it out when the // loading manager passes it back // if( cluster >= NumScriptNames ) { // // Just load Bart for now // cluster = SC_CAR_BASE; } sprintf( fakeFilename, "sound:%s", s_clusterNames[cluster] ); GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, fakeFilename, GMA_LEVEL_AUDIO ); } //============================================================================= // SoundLoader::clusterLoad //============================================================================= // Description: Find the specified sound cluster and direct it to load sounds // // Parameters: SoundClusterName name - specifies which cluster to load // // Return: false if cluster not yet loaded, true otherwise // //============================================================================= bool SoundLoader::clusterLoad( SoundClusterName name, SoundFileHandler* callbackObj ) { bool loaded; rAssert( name < SC_MAX_CLUSTERS ); loaded = m_clusterList[name]->IsLoaded(); if( !loaded ) { m_clusterList[name]->LoadSounds( callbackObj ); } return( loaded ); } void SoundLoader::clusterUnload( SoundClusterName name ) { rAssert( name < SC_MAX_CLUSTERS ); if( m_clusterList[name]->IsLoaded() ) { m_clusterList[name]->UnloadSounds(); } }