sfxSoundscape.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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()
  36. : mAmbience( NULL )
  37. {
  38. }
  39. //-----------------------------------------------------------------------------
  40. SFXSoundscape::SFXSoundscape( SFXAmbience* ambience )
  41. : mAmbience( ambience )
  42. {
  43. mDirtyBits.set( AmbienceDirty );
  44. mFlags.set( FlagUnique );
  45. dMemset( mStates, 0, sizeof( mStates ) );
  46. }
  47. //-----------------------------------------------------------------------------
  48. void SFXSoundscape::setAmbience( SFXAmbience* ambience )
  49. {
  50. AssertFatal( ambience != NULL, "SFXSoundscape::setAmbience - ambience cannot be NULL!" );
  51. mDirtyBits.set( AmbienceDirty );
  52. mAmbience = ambience;
  53. }
  54. //=============================================================================
  55. // SFXSoundscapeManager.
  56. //=============================================================================
  57. // MARK: ---- SFXSoundscapeManager ----
  58. //-----------------------------------------------------------------------------
  59. SFXSoundscapeManager::SFXSoundscapeManager()
  60. : mCurrentReverbIndex( -1 )
  61. {
  62. VECTOR_SET_ASSOCIATION( mStack );
  63. VECTOR_SET_ASSOCIATION( mFadeStack );
  64. #ifndef TORQUE_SHIPPING
  65. // Hook on to the ambience change signal (used
  66. // to respond to editing of ambiences).
  67. SFXAmbience::getChangeSignal().notify
  68. ( this, &SFXSoundscapeManager::_notifyAmbienceChanged );
  69. #endif
  70. // Push the global ambience.
  71. mDefaultGlobalAmbience = new SFXAmbience;
  72. SFXSoundscape* global = mChunker.alloc();
  73. constructInPlace( global, mDefaultGlobalAmbience );
  74. mStack.push_back( global );
  75. }
  76. //-----------------------------------------------------------------------------
  77. SFXSoundscapeManager::~SFXSoundscapeManager()
  78. {
  79. #ifndef TORQUE_SHIPPING
  80. // Remove the hook on the ambience change signal.
  81. SFXAmbience::getChangeSignal().remove
  82. ( this, &SFXSoundscapeManager::_notifyAmbienceChanged );
  83. #endif
  84. mDefaultGlobalAmbience->deleteObject();
  85. }
  86. //-----------------------------------------------------------------------------
  87. void SFXSoundscapeManager::update()
  88. {
  89. // Make sure the topmost reverb on the stack is active.
  90. S32 reverbIndex = _findTopmostReverbOnStack( mStack );
  91. if( mCurrentReverbIndex != reverbIndex )
  92. {
  93. if( reverbIndex == -1 )
  94. {
  95. // No ambience on the stack has reverb settings so reset
  96. // to default.
  97. SFX->setReverb( SFXReverbProperties() );
  98. }
  99. else
  100. {
  101. SFXAmbience* ambience = mStack[ reverbIndex ]->getAmbience();
  102. AssertFatal( ambience->getEnvironment(), "SFXSoundscapeManager::update - Reverb lookup return ambience without reverb!" );
  103. SFX->setRolloffFactor( ambience->getRolloffFactor() );
  104. SFX->setDopplerFactor( ambience->getDopplerFactor() );
  105. SFX->setReverb( ambience->getEnvironment()->getReverb() );
  106. }
  107. mCurrentReverbIndex = reverbIndex;
  108. }
  109. // Update the active soundscapes.
  110. for( U32 i = 0; i < mStack.size(); ++ i )
  111. {
  112. SFXSoundscape* soundscape = mStack[ i ];
  113. // If the soundscape's associated ambience has changed
  114. if( soundscape->mDirtyBits.test( SFXSoundscape::AmbienceDirty ) )
  115. {
  116. SFXAmbience* ambience = soundscape->getAmbience();
  117. // Start playing the ambient audio track if it isn't
  118. // already playing and if the soundscape isn't overridden
  119. // by an instance lower down the stack.
  120. if( !soundscape->_isOverridden() )
  121. {
  122. SFXTrack* track = ambience->getSoundTrackProfile();
  123. if( !soundscape->mSource || soundscape->mSource->getTrack() != track )
  124. {
  125. if( soundscape->mSource != NULL )
  126. {
  127. soundscape->mSource->stop();
  128. soundscape->mSource = NULL;
  129. }
  130. if( track )
  131. soundscape->mSource = SFX->playOnce( track );
  132. }
  133. else if( soundscape->mSource != NULL )
  134. {
  135. // Make sure to revert a fade-out running on the source
  136. // if it has been taken from the fade stack.
  137. soundscape->mSource->play();
  138. }
  139. }
  140. // Activate SFXStates on the ambience. For state slots that
  141. // have changed, deactivate states that we have already activated.
  142. for( U32 ambState = 0; ambState < SFXAmbience::MaxStates; ++ambState)
  143. {
  144. SFXState* state = ambience->getState(ambState);
  145. if( soundscape->mStates[ambState] != state )
  146. {
  147. if( soundscape->mStates[ambState] )
  148. soundscape->mStates[ambState]->deactivate();
  149. if( state )
  150. state->activate();
  151. soundscape->mStates[ambState] = state;
  152. }
  153. }
  154. soundscape->mDirtyBits.clear( SFXSoundscape::AmbienceDirty );
  155. }
  156. }
  157. // Clean out the fade stack.
  158. for( U32 i = 0; i < mFadeStack.size(); )
  159. if( mFadeStack[ i ]->mSource == NULL )
  160. {
  161. SFXSoundscape* soundscape = mFadeStack[ i ];
  162. mFadeStack.erase_fast( i );
  163. #ifdef DEBUG_SPEW
  164. Platform::outputDebugString( "[SFXSoundscapeManager] Deleting faded instance of '%s'",
  165. soundscape->getAmbience()->getName() );
  166. #endif
  167. // Free the soundscape.
  168. destructInPlace( soundscape );
  169. mChunker.free( soundscape );
  170. }
  171. else
  172. ++ i;
  173. }
  174. //-----------------------------------------------------------------------------
  175. SFXSoundscape* SFXSoundscapeManager::insertSoundscape( U32 index, SFXAmbience* ambience )
  176. {
  177. AssertFatal( index <= mStack.size(), "SFXSoundscapeManager::insertSoundscape - index out of range" );
  178. AssertFatal( index != 0, "SFXSoundscapeManager::insertSoundscape - cannot insert before global soundscape" );
  179. AssertFatal( ambience != NULL, "SFXSoundscapeManager::insertSoundscape - got a NULL ambience" );
  180. // Look for an existing soundscape that is assigned the
  181. // same ambience.
  182. S32 ambientInstanceIndex = _findOnStack( ambience, mStack );
  183. // Push a soundscape unto the stack. If there is an instance
  184. // on the fade stack that is tied to the given ambience, bring that
  185. // soundscape over to the active stack. Otherwise create a new
  186. // soundscape instance.
  187. SFXSoundscape* soundscape = NULL;
  188. if( ambientInstanceIndex == -1 )
  189. {
  190. S32 fadeIndex = _findOnStack( ambience, mFadeStack );
  191. if( fadeIndex != -1 )
  192. {
  193. soundscape = mFadeStack[ fadeIndex ];
  194. mFadeStack.erase_fast( fadeIndex );
  195. // Make sure the soundscape will get re-evaluated
  196. // on the next update.
  197. soundscape->mDirtyBits.set( SFXSoundscape::AmbienceDirty );
  198. #ifdef DEBUG_SPEW
  199. Platform::outputDebugString( "[SFXSoundscapeManager] Moving ambience '%s' from fade stack to #%i (total: %i)",
  200. ambience->getName(), index, mStack.size() + 1 );
  201. #endif
  202. }
  203. }
  204. if( !soundscape )
  205. {
  206. #ifdef DEBUG_SPEW
  207. Platform::outputDebugString( "[SFXSoundscapeManager] Adding new instance for '%s' at #%i (total: %i)",
  208. ambience->getName(), index, mStack.size() + 1 );
  209. #endif
  210. soundscape = mChunker.alloc();
  211. constructInPlace( soundscape, ambience );
  212. }
  213. mStack.insert( index, soundscape );
  214. // If there is an existing soundscape that is assigned the
  215. // same ambience and it is lower on the stack, steal its sound
  216. // source if it has one. If it is higher up the stack, simply
  217. // mark this soundscape as being overridden.
  218. if( ambientInstanceIndex != -1 )
  219. {
  220. SFXSoundscape* existingSoundscape = mStack[ ambientInstanceIndex ];
  221. existingSoundscape->mFlags.clear( SFXSoundscape::FlagUnique );
  222. soundscape->mFlags.clear( SFXSoundscape::FlagUnique );
  223. if( ambientInstanceIndex < index )
  224. {
  225. existingSoundscape->mFlags.set( SFXSoundscape::FlagOverridden );
  226. SFXSource* source = existingSoundscape->mSource;
  227. existingSoundscape->mSource = NULL;
  228. if( source && source->isPlaying() )
  229. soundscape->mSource = source;
  230. }
  231. else
  232. {
  233. soundscape->mFlags.set( SFXSoundscape::FlagOverridden );
  234. }
  235. }
  236. return soundscape;
  237. }
  238. //-----------------------------------------------------------------------------
  239. void SFXSoundscapeManager::removeSoundscape( SFXSoundscape* soundscape )
  240. {
  241. AssertFatal( soundscape != getGlobalSoundscape(),
  242. "SFXSoundscapeManager::removeSoundscape() - trying to remove the global soundscape" );
  243. // Find the soundscape on the stack.
  244. U32 index = 1;
  245. for( ; index < mStack.size(); ++ index )
  246. if( mStack[ index ] == soundscape )
  247. break;
  248. AssertFatal( index < mStack.size(),
  249. "SFXSoundscapeManager::removeSoundscape() - soundscape not on stack" );
  250. // Find out if the soundscape has the current reverb
  251. // environment. If so, we need to change the reverb to
  252. // the next one higher up the stack.
  253. const bool isCurrentReverb = ( _findTopmostReverbOnStack( mStack ) == index );
  254. // Remove the soundscape from the stack.
  255. mStack.erase( index );
  256. // Update reverb, if necessary.
  257. if( isCurrentReverb )
  258. {
  259. S32 reverbIndex = _findTopmostReverbOnStack( mStack );
  260. if( reverbIndex != -1 )
  261. SFX->setReverb( mStack[ reverbIndex ]->getAmbience()->getEnvironment()->getReverb() );
  262. }
  263. // Deactivate states.
  264. for( U32 i = 0; i < SFXAmbience::MaxStates; ++ i )
  265. if( soundscape->mStates[ i ] )
  266. {
  267. soundscape->mStates[ i ]->deactivate();
  268. soundscape->mStates[ i ] = NULL;
  269. }
  270. // If the soundscape is the only instance of its ambience, move
  271. // it to the fade stack. Otherwise delete the soundscape.
  272. if( soundscape->_isUnique() && soundscape->mSource != NULL )
  273. {
  274. #ifdef DEBUG_SPEW
  275. Platform::outputDebugString( "[SFXSoundscapeManager] Moving ambience '%s' at index #%i to fade stack",
  276. soundscape->getAmbience()->getName(), index );
  277. #endif
  278. soundscape->mSource->stop();
  279. mFadeStack.push_back( soundscape );
  280. }
  281. else
  282. {
  283. if( !soundscape->_isUnique() )
  284. {
  285. // If this is the overriding soundscape, transfer its state
  286. // to the ambient instance lower down the stack.
  287. if( !soundscape->_isOverridden() )
  288. {
  289. S32 overrideeIndex = index - 1;
  290. for( ; overrideeIndex >= 0; -- overrideeIndex )
  291. if( soundscape->getAmbience() == mStack[ overrideeIndex ]->getAmbience() )
  292. break;
  293. AssertFatal( overrideeIndex >= 0,
  294. "SFXSoundscapeManager::removeSoundscape() - could not find ambience being overridden on stack" );
  295. // Pass the source on to the previous soundscape.
  296. mStack[ overrideeIndex ]->mSource = soundscape->mSource;
  297. soundscape->mSource = NULL;
  298. }
  299. #ifdef DEBUG_SPEW
  300. Platform::outputDebugString( "[SFXSoundscapeManager] Removing instance of '%s' at index #%i",
  301. soundscape->getAmbience()->getName(), index );
  302. #endif
  303. // If there's only one instance of this ambience is
  304. // left, mark it as being unique now.
  305. U32 numInstances = 0;
  306. for( U32 i = 0; i < mStack.size(); ++ i )
  307. if( mStack[ i ]->getAmbience() == soundscape->getAmbience() )
  308. ++ numInstances;
  309. if( numInstances == 1 )
  310. mStack[ _findOnStack( soundscape->getAmbience(), mStack ) ]->mFlags.set( SFXSoundscape::FlagUnique );
  311. }
  312. // Free the soundscape.
  313. destructInPlace( soundscape );
  314. mChunker.free( soundscape );
  315. }
  316. }
  317. //-----------------------------------------------------------------------------
  318. S32 SFXSoundscapeManager::_findOnStack( SFXAmbience* ambience, const Vector< SFXSoundscape* >& stack )
  319. {
  320. // Search the stack top to bottom so we always find
  321. // the uppermost instance of the ambience on the stack.
  322. for( S32 i = stack.size() - 1; i >= 0; -- i )
  323. if( stack[ i ]->getAmbience() == ambience )
  324. return i;
  325. return -1;
  326. }
  327. //-----------------------------------------------------------------------------
  328. S32 SFXSoundscapeManager::_findTopmostReverbOnStack( const Vector< SFXSoundscape* >& stack )
  329. {
  330. for( S32 i = stack.size() - 1; i >= 0; -- i )
  331. if( stack[ i ]->getAmbience()->getEnvironment() )
  332. return i;
  333. return -1;
  334. }
  335. //-----------------------------------------------------------------------------
  336. void SFXSoundscapeManager::_notifyAmbienceChanged( SFXAmbience* ambience )
  337. {
  338. //RDTODO: fade stack?
  339. // Set the ambience dirty bit on all soundscapes
  340. // tied to the given ambience.
  341. for( U32 i = 0; i < mStack.size(); ++ i )
  342. if( mStack[ i ]->getAmbience() == ambience )
  343. {
  344. mStack[ i ]->mDirtyBits.set( SFXSoundscape::AmbienceDirty );
  345. #ifdef DEBUG_SPEW
  346. Platform::outputDebugString( "[SFXSoundscapeManager] Ambience '%s' at #%i changed",
  347. ambience->getName(), i );
  348. #endif
  349. }
  350. }