sfxSoundscape.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "sfx/sfxSoundscape.h"
  23. #include "sfx/sfxAmbience.h"
  24. #include "sfx/sfxEnvironment.h"
  25. #include "sfx/sfxState.h"
  26. #include "sfx/sfxSource.h"
  27. #include "sfx/sfxSystem.h"
  28. //#define DEBUG_SPEW
  29. //FIXME: fix reverb resetting
  30. //=============================================================================
  31. // SFXSoundscape.
  32. //=============================================================================
  33. // MARK: ---- SFXSoundscape ----
  34. //-----------------------------------------------------------------------------
  35. SFXSoundscape::SFXSoundscape( SFXAmbience* ambience )
  36. : mAmbience( ambience )
  37. {
  38. mDirtyBits.set( AmbienceDirty );
  39. mFlags.set( FlagUnique );
  40. dMemset( mStates, 0, sizeof( mStates ) );
  41. }
  42. //-----------------------------------------------------------------------------
  43. void SFXSoundscape::setAmbience( SFXAmbience* ambience )
  44. {
  45. AssertFatal( ambience != NULL, "SFXSoundscape::setAmbience - ambience cannot be NULL!" );
  46. mDirtyBits.set( AmbienceDirty );
  47. mAmbience = ambience;
  48. }
  49. //=============================================================================
  50. // SFXSoundscapeManager.
  51. //=============================================================================
  52. // MARK: ---- SFXSoundscapeManager ----
  53. //-----------------------------------------------------------------------------
  54. SFXSoundscapeManager::SFXSoundscapeManager()
  55. : mCurrentReverbIndex( -1 )
  56. {
  57. VECTOR_SET_ASSOCIATION( mStack );
  58. VECTOR_SET_ASSOCIATION( mFadeStack );
  59. #ifndef TORQUE_SHIPPING
  60. // Hook on to the ambience change signal (used
  61. // to respond to editing of ambiences).
  62. SFXAmbience::getChangeSignal().notify
  63. ( this, &SFXSoundscapeManager::_notifyAmbienceChanged );
  64. #endif
  65. // Push the global ambience.
  66. mDefaultGlobalAmbience = new SFXAmbience;
  67. SFXSoundscape* global = mChunker.alloc();
  68. constructInPlace( global, mDefaultGlobalAmbience );
  69. mStack.push_back( global );
  70. }
  71. //-----------------------------------------------------------------------------
  72. SFXSoundscapeManager::~SFXSoundscapeManager()
  73. {
  74. #ifndef TORQUE_SHIPPING
  75. // Remove the hook on the ambience change signal.
  76. SFXAmbience::getChangeSignal().remove
  77. ( this, &SFXSoundscapeManager::_notifyAmbienceChanged );
  78. #endif
  79. mDefaultGlobalAmbience->deleteObject();
  80. }
  81. //-----------------------------------------------------------------------------
  82. void SFXSoundscapeManager::update()
  83. {
  84. // Make sure the topmost reverb on the stack is active.
  85. S32 reverbIndex = _findTopmostReverbOnStack( mStack );
  86. if( mCurrentReverbIndex != reverbIndex )
  87. {
  88. if( reverbIndex == -1 )
  89. {
  90. // No ambience on the stack has reverb settings so reset
  91. // to default.
  92. SFX->setReverb( SFXReverbProperties() );
  93. }
  94. else
  95. {
  96. SFXAmbience* ambience = mStack[ reverbIndex ]->getAmbience();
  97. AssertFatal( ambience->getEnvironment(), "SFXSoundscapeManager::update - Reverb lookup return ambience without reverb!" );
  98. SFX->setRolloffFactor( ambience->getRolloffFactor() );
  99. SFX->setDopplerFactor( ambience->getDopplerFactor() );
  100. SFX->setReverb( ambience->getEnvironment()->getReverb() );
  101. }
  102. mCurrentReverbIndex = reverbIndex;
  103. }
  104. // Update the active soundscapes.
  105. for( U32 i = 0; i < mStack.size(); ++ i )
  106. {
  107. SFXSoundscape* soundscape = mStack[ i ];
  108. // If the soundscape's associated ambience has changed
  109. if( soundscape->mDirtyBits.test( SFXSoundscape::AmbienceDirty ) )
  110. {
  111. SFXAmbience* ambience = soundscape->getAmbience();
  112. // Start playing the ambient audio track if it isn't
  113. // already playing and if the soundscape isn't overridden
  114. // by an instance lower down the stack.
  115. if( !soundscape->_isOverridden() )
  116. {
  117. SFXTrack* track = ambience->getSoundTrackProfile();
  118. if( !soundscape->mSource || soundscape->mSource->getTrack() != track )
  119. {
  120. if( soundscape->mSource != NULL )
  121. {
  122. soundscape->mSource->stop();
  123. soundscape->mSource = NULL;
  124. }
  125. if( track )
  126. soundscape->mSource = SFX->playOnce( track );
  127. }
  128. else if( soundscape->mSource != NULL )
  129. {
  130. // Make sure to revert a fade-out running on the source
  131. // if it has been taken from the fade stack.
  132. soundscape->mSource->play();
  133. }
  134. }
  135. // Activate SFXStates on the ambience. For state slots that
  136. // have changed, deactivate states that we have already activated.
  137. for( U32 ambState = 0; ambState < SFXAmbience::MaxStates; ++ambState)
  138. {
  139. SFXState* state = ambience->getState(ambState);
  140. if( soundscape->mStates[ambState] != state )
  141. {
  142. if( soundscape->mStates[ambState] )
  143. soundscape->mStates[ambState]->deactivate();
  144. if( state )
  145. state->activate();
  146. soundscape->mStates[ambState] = state;
  147. }
  148. }
  149. soundscape->mDirtyBits.clear( SFXSoundscape::AmbienceDirty );
  150. }
  151. }
  152. // Clean out the fade stack.
  153. for( U32 i = 0; i < mFadeStack.size(); )
  154. if( mFadeStack[ i ]->mSource == NULL )
  155. {
  156. SFXSoundscape* soundscape = mFadeStack[ i ];
  157. mFadeStack.erase_fast( i );
  158. #ifdef DEBUG_SPEW
  159. Platform::outputDebugString( "[SFXSoundscapeManager] Deleting faded instance of '%s'",
  160. soundscape->getAmbience()->getName() );
  161. #endif
  162. // Free the soundscape.
  163. destructInPlace( soundscape );
  164. mChunker.free( soundscape );
  165. }
  166. else
  167. ++ i;
  168. }
  169. //-----------------------------------------------------------------------------
  170. SFXSoundscape* SFXSoundscapeManager::insertSoundscape( U32 index, SFXAmbience* ambience )
  171. {
  172. AssertFatal( index <= mStack.size(), "SFXSoundscapeManager::insertSoundscape - index out of range" );
  173. AssertFatal( index != 0, "SFXSoundscapeManager::insertSoundscape - cannot insert before global soundscape" );
  174. AssertFatal( ambience != NULL, "SFXSoundscapeManager::insertSoundscape - got a NULL ambience" );
  175. // Look for an existing soundscape that is assigned the
  176. // same ambience.
  177. S32 ambientInstanceIndex = _findOnStack( ambience, mStack );
  178. // Push a soundscape unto the stack. If there is an instance
  179. // on the fade stack that is tied to the given ambience, bring that
  180. // soundscape over to the active stack. Otherwise create a new
  181. // soundscape instance.
  182. SFXSoundscape* soundscape = NULL;
  183. if( ambientInstanceIndex == -1 )
  184. {
  185. S32 fadeIndex = _findOnStack( ambience, mFadeStack );
  186. if( fadeIndex != -1 )
  187. {
  188. soundscape = mFadeStack[ fadeIndex ];
  189. mFadeStack.erase_fast( fadeIndex );
  190. // Make sure the soundscape will get re-evaluated
  191. // on the next update.
  192. soundscape->mDirtyBits.set( SFXSoundscape::AmbienceDirty );
  193. #ifdef DEBUG_SPEW
  194. Platform::outputDebugString( "[SFXSoundscapeManager] Moving ambience '%s' from fade stack to #%i (total: %i)",
  195. ambience->getName(), index, mStack.size() + 1 );
  196. #endif
  197. }
  198. }
  199. if( !soundscape )
  200. {
  201. #ifdef DEBUG_SPEW
  202. Platform::outputDebugString( "[SFXSoundscapeManager] Adding new instance for '%s' at #%i (total: %i)",
  203. ambience->getName(), index, mStack.size() + 1 );
  204. #endif
  205. soundscape = mChunker.alloc();
  206. constructInPlace( soundscape, ambience );
  207. }
  208. mStack.insert( index, soundscape );
  209. // If there is an existing soundscape that is assigned the
  210. // same ambience and it is lower on the stack, steal its sound
  211. // source if it has one. If it is higher up the stack, simply
  212. // mark this soundscape as being overridden.
  213. if( ambientInstanceIndex != -1 )
  214. {
  215. SFXSoundscape* existingSoundscape = mStack[ ambientInstanceIndex ];
  216. existingSoundscape->mFlags.clear( SFXSoundscape::FlagUnique );
  217. soundscape->mFlags.clear( SFXSoundscape::FlagUnique );
  218. if( ambientInstanceIndex < index )
  219. {
  220. existingSoundscape->mFlags.set( SFXSoundscape::FlagOverridden );
  221. SFXSource* source = existingSoundscape->mSource;
  222. existingSoundscape->mSource = NULL;
  223. if( source && source->isPlaying() )
  224. soundscape->mSource = source;
  225. }
  226. else
  227. {
  228. soundscape->mFlags.set( SFXSoundscape::FlagOverridden );
  229. }
  230. }
  231. return soundscape;
  232. }
  233. //-----------------------------------------------------------------------------
  234. void SFXSoundscapeManager::removeSoundscape( SFXSoundscape* soundscape )
  235. {
  236. AssertFatal( soundscape != getGlobalSoundscape(),
  237. "SFXSoundscapeManager::removeSoundscape() - trying to remove the global soundscape" );
  238. // Find the soundscape on the stack.
  239. U32 index = 1;
  240. for( ; index < mStack.size(); ++ index )
  241. if( mStack[ index ] == soundscape )
  242. break;
  243. AssertFatal( index < mStack.size(),
  244. "SFXSoundscapeManager::removeSoundscape() - soundscape not on stack" );
  245. // Find out if the soundscape has the current reverb
  246. // environment. If so, we need to change the reverb to
  247. // the next one higher up the stack.
  248. const bool isCurrentReverb = ( _findTopmostReverbOnStack( mStack ) == index );
  249. // Remove the soundscape from the stack.
  250. mStack.erase( index );
  251. // Update reverb, if necessary.
  252. if( isCurrentReverb )
  253. {
  254. S32 reverbIndex = _findTopmostReverbOnStack( mStack );
  255. if( reverbIndex != -1 )
  256. SFX->setReverb( mStack[ reverbIndex ]->getAmbience()->getEnvironment()->getReverb() );
  257. }
  258. // Deactivate states.
  259. for( U32 i = 0; i < SFXAmbience::MaxStates; ++ i )
  260. if( soundscape->mStates[ i ] )
  261. {
  262. soundscape->mStates[ i ]->deactivate();
  263. soundscape->mStates[ i ] = NULL;
  264. }
  265. // If the soundscape is the only instance of its ambience, move
  266. // it to the fade stack. Otherwise delete the soundscape.
  267. if( soundscape->_isUnique() && soundscape->mSource != NULL )
  268. {
  269. #ifdef DEBUG_SPEW
  270. Platform::outputDebugString( "[SFXSoundscapeManager] Moving ambience '%s' at index #%i to fade stack",
  271. soundscape->getAmbience()->getName(), index );
  272. #endif
  273. soundscape->mSource->stop();
  274. mFadeStack.push_back( soundscape );
  275. }
  276. else
  277. {
  278. if( !soundscape->_isUnique() )
  279. {
  280. // If this is the overriding soundscape, transfer its state
  281. // to the ambient instance lower down the stack.
  282. if( !soundscape->_isOverridden() )
  283. {
  284. S32 overrideeIndex = index - 1;
  285. for( ; overrideeIndex >= 0; -- overrideeIndex )
  286. if( soundscape->getAmbience() == mStack[ overrideeIndex ]->getAmbience() )
  287. break;
  288. AssertFatal( overrideeIndex >= 0,
  289. "SFXSoundscapeManager::removeSoundscape() - could not find ambience being overridden on stack" );
  290. // Pass the source on to the previous soundscape.
  291. mStack[ overrideeIndex ]->mSource = soundscape->mSource;
  292. soundscape->mSource = NULL;
  293. }
  294. #ifdef DEBUG_SPEW
  295. Platform::outputDebugString( "[SFXSoundscapeManager] Removing instance of '%s' at index #%i",
  296. soundscape->getAmbience()->getName(), index );
  297. #endif
  298. // If there's only one instance of this ambience is
  299. // left, mark it as being unique now.
  300. U32 numInstances = 0;
  301. for( U32 i = 0; i < mStack.size(); ++ i )
  302. if( mStack[ i ]->getAmbience() == soundscape->getAmbience() )
  303. ++ numInstances;
  304. if( numInstances == 1 )
  305. mStack[ _findOnStack( soundscape->getAmbience(), mStack ) ]->mFlags.set( SFXSoundscape::FlagUnique );
  306. }
  307. // Free the soundscape.
  308. destructInPlace( soundscape );
  309. mChunker.free( soundscape );
  310. }
  311. }
  312. //-----------------------------------------------------------------------------
  313. S32 SFXSoundscapeManager::_findOnStack( SFXAmbience* ambience, const Vector< SFXSoundscape* >& stack )
  314. {
  315. // Search the stack top to bottom so we always find
  316. // the uppermost instance of the ambience on the stack.
  317. for( S32 i = stack.size() - 1; i >= 0; -- i )
  318. if( stack[ i ]->getAmbience() == ambience )
  319. return i;
  320. return -1;
  321. }
  322. //-----------------------------------------------------------------------------
  323. S32 SFXSoundscapeManager::_findTopmostReverbOnStack( const Vector< SFXSoundscape* >& stack )
  324. {
  325. for( S32 i = stack.size() - 1; i >= 0; -- i )
  326. if( stack[ i ]->getAmbience()->getEnvironment() )
  327. return i;
  328. return -1;
  329. }
  330. //-----------------------------------------------------------------------------
  331. void SFXSoundscapeManager::_notifyAmbienceChanged( SFXAmbience* ambience )
  332. {
  333. //RDTODO: fade stack?
  334. // Set the ambience dirty bit on all soundscapes
  335. // tied to the given ambience.
  336. for( U32 i = 0; i < mStack.size(); ++ i )
  337. if( mStack[ i ]->getAmbience() == ambience )
  338. {
  339. mStack[ i ]->mDirtyBits.set( SFXSoundscape::AmbienceDirty );
  340. #ifdef DEBUG_SPEW
  341. Platform::outputDebugString( "[SFXSoundscapeManager] Ambience '%s' at #%i changed",
  342. ambience->getName(), i );
  343. #endif
  344. }
  345. }