void SoundSystem::StopAllSounds( SoundObjectId _id, char *_eventName ) { for( int i = 0; i < m_sounds.Size(); ++i ) { if( m_sounds.ValidIndex(i) ) { SoundInstance *instance = m_sounds[i]; if( instance->m_objId == _id ) { if( !_eventName || stricmp(instance->m_eventName, _eventName) == 0 ) { if( instance->IsPlaying() ) { instance->BeginRelease(true); } else { ShutdownSound( instance ); } } } } } }
void SoundSystem::Advance() { if( !m_channels ) { return; } float timeNow = GetHighResTime(); if( timeNow >= m_timeSync ) { m_timeSync = timeNow + SOUNDSYSTEM_UPDATEPERIOD; START_PROFILE("SoundSystem"); #ifndef TARGET_MSVC ((SoundLibrary2dSDL *)g_soundLibrary2d)->m_callbackLock.Lock(); #endif // // Resync with blueprints (changed by editor) START_PROFILE("Propagate Blueprints" ); if( m_propagateBlueprints ) { PropagateBlueprints(); } END_PROFILE("Propagate Blueprints" ); // // First pass : Recalculate all Perceived Sound Volumes // Throw away sounds that have had their chance // Build a list of instanceIDs for sorting START_PROFILE("Allocate Sorted Array" ); static int sortedArraySize = 128; static SoundInstanceId *sortedIds = NULL; if( m_sounds.NumUsed() > sortedArraySize ) { delete [] sortedIds; sortedIds = NULL; while( sortedArraySize < m_sounds.NumUsed() ) sortedArraySize *= 2; } if( !sortedIds ) { sortedIds = new SoundInstanceId[ sortedArraySize ]; } int numSortedIds = 0; END_PROFILE("Allocate Sorted Array" ); START_PROFILE("Perceived Volumes" ); for( int i = 0; i < m_sounds.Size(); ++i ) { if( m_sounds.ValidIndex(i) ) { SoundInstance *instance = m_sounds[i]; if( !instance->IsPlaying() && !instance->m_loopType ) instance->m_restartAttempts--; if( instance->m_restartAttempts < 0 ) { ShutdownSound( instance ); } else if( instance->m_positionType == SoundInstance::Type3DAttachedToObject && !instance->GetAttachedObject().IsValid() ) { ShutdownSound( instance ); } else { instance->CalculatePerceivedVolume(); sortedIds[numSortedIds] = instance->m_id; numSortedIds++; } } } END_PROFILE("Perceived Volumes" ); // // Sort sounds into perceived volume order // NOTE : There are exactly numSortedId elements in sortedIds. // NOTE : It isn't safe to assume numSortedIds == m_sounds.NumUsed() START_PROFILE("Sort Samples" ); qsort( sortedIds, numSortedIds, sizeof(SoundInstanceId), SoundInstanceCompare ); END_PROFILE("Sort Samples" ); // // Second pass : Recalculate all Sound Priorities starting with the nearest sounds // Reduce priorities as more of the same sounds are played BTree<float> existingInstances; // // Also look out for the highest priority new sound to swap in START_PROFILE("Recalculate Priorities" ); LList<SoundInstance *> newInstances; SoundInstance *newInstance = NULL; float highestInstancePriority = 0.0f; for( int i = 0; i < numSortedIds; ++i ) { SoundInstanceId id = sortedIds[i]; SoundInstance *instance = GetSoundInstance( id ); AppDebugAssert( instance ); instance->m_calculatedPriority = instance->m_perceivedVolume; BTree<float> *existingInstance = existingInstances.LookupTree( instance->m_eventName ); if( existingInstance ) { instance->m_calculatedPriority *= existingInstance->data; existingInstance->data *= 0.75f; } else { existingInstances.PutData( instance->m_eventName, 0.75f ); } if( !instance->IsPlaying() ) { if( instance->m_positionType == SoundInstance::TypeMusic ) { newInstances.PutData( instance ); } else if( instance->m_calculatedPriority > highestInstancePriority ) { newInstance = instance; highestInstancePriority = instance->m_calculatedPriority; } } } if( newInstance ) { newInstances.PutData( newInstance ); } END_PROFILE("Recalculate Priorities" ); for( int i = 0; i < newInstances.Size(); ++i ) { SoundInstance *newInstance = newInstances[i]; bool isMusic = (newInstance->m_positionType == SoundInstance::TypeMusic); // Find worst old sound to get rid of START_PROFILE("Find best Channel" ); int bestAvailableChannel = FindBestAvailableChannel( isMusic ); END_PROFILE("Find best Channel" ); // FindBestAvailableChannel can return -1, so let's not access an invalid index later on. if ( bestAvailableChannel < 0 ) continue; START_PROFILE("Stop Old Sound" ); // Stop the old sound SoundInstance *existingInstance = GetSoundInstance( m_channels[bestAvailableChannel] ); if( existingInstance && !existingInstance->m_loopType ) { ShutdownSound( existingInstance ); } else if( existingInstance ) { existingInstance->StopPlaying(); } END_PROFILE("Stop Old Sound" ); START_PROFILE( "Start New Sound" ); // Start the new sound bool success = newInstance->StartPlaying( bestAvailableChannel ); if( success ) { m_channels[bestAvailableChannel] = newInstance->m_id; } else { // This is fairly bad, the sound failed to play // Which means it failed to load, or to go into a channel ShutdownSound( newInstance ); } END_PROFILE("Start New Sound" ); START_PROFILE("Reset Channel" ); g_soundLibrary3d->ResetChannel( bestAvailableChannel); END_PROFILE("Reset Channel" ); } // // Advance all sound channels START_PROFILE("Advance All Channels" ); for( int i = 0; i < m_numChannels; ++i ) { SoundInstanceId soundId = m_channels[i]; SoundInstance *currentSound = GetSoundInstance( soundId ); if( currentSound ) { bool amIDone = currentSound->Advance(); if( amIDone ) { START_PROFILE("Shutdown Sound" ); ShutdownSound( currentSound ); END_PROFILE("Shutdown Sound" ); } } } END_PROFILE("Advance All Channels" ); // // Update our listener position START_PROFILE("UpdateListener" ); Vector3<float> camPos, camVel, camUp, camFront; bool cameraDefined = m_interface->GetCameraPosition( camPos, camFront, camUp, camVel ); if( cameraDefined ) { if( g_preferences->GetInt("SoundSwapStereo",0) == 0 ) { camUp *= -1.0f; } g_soundLibrary3d->SetListenerPosition( camPos, camFront, camUp, camVel ); } END_PROFILE("UpdateListener" ); // // Advance our sound library START_PROFILE("SoundLibrary3d Advance" ); g_soundLibrary3d->Advance(); END_PROFILE("SoundLibrary3d Advance" ); #ifdef SOUNDSYSTEM_VERIFY RuntimeVerify(); #endif #ifndef TARGET_MSVC ((SoundLibrary2dSDL *)g_soundLibrary2d)->m_callbackLock.Unlock(); #endif END_PROFILE("SoundSystem"); } }