Advertisement
Guest User

Untitled

a guest
Sep 14th, 2014
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.02 KB | None | 0 0
  1. #include "sound_source_system.h"
  2.  
  3. #include "engine/component_factory.h"
  4. #include "engine/entity_filter.h"
  5. #include "engine/engine.h"
  6. #include "engine/entity.h"
  7. #include "engine/serialization.h"
  8. #include "engine/rng.h"
  9. #include "ogre/scene_node_system.h"
  10. #include "scripting/luabind.h"
  11.  
  12. #include "game.h"
  13.  
  14. #include <OgreOggISound.h>
  15. #include <OgreOggSoundManager.h>
  16.  
  17.  
  18. using namespace thrive;
  19.  
  20. static const int FADE_TIME = 5000; //5 seconds
  21.  
  22.  
  23. ////////////////////////////////////////////////////////////////////////////////
  24. // Sound
  25. ////////////////////////////////////////////////////////////////////////////////
  26.  
  27. luabind::scope
  28. Sound::luaBindings() {
  29. using namespace luabind;
  30. return class_<Sound>("Sound")
  31. .scope [
  32. class_<Properties, Touchable>("Properties")
  33. .def_readwrite("playState", &Properties::playState)
  34. .def_readwrite("loop", &Properties::loop)
  35. .def_readwrite("volume", &Properties::volume)
  36. .def_readwrite("maxDistance", &Properties::maxDistance)
  37. .def_readwrite("rolloffFactor", &Properties::rolloffFactor)
  38. .def_readwrite("referenceDistance", &Properties::referenceDistance)
  39. .def_readwrite("priority", &Properties::priority)
  40. ]
  41. .enum_("PlayState") [
  42. value("Play", PlayState::Play),
  43. value("Pause", PlayState::Pause),
  44. value("Stop", PlayState::Stop)
  45. ]
  46. .def(constructor<std::string, std::string>())
  47. .def("name", &Sound::name)
  48. .def("pause", &Sound::pause)
  49. .def("play", &Sound::play)
  50. .def("stop", &Sound::stop)
  51. .def_readonly("properties", &Sound::m_properties)
  52. ;
  53. }
  54.  
  55.  
  56. Sound::Sound()
  57. : Sound("", "")
  58. {
  59. }
  60.  
  61.  
  62. Sound::Sound(
  63. std::string name,
  64. std::string filename
  65. ) : m_filename(filename),
  66. m_name(name)
  67. {
  68. }
  69.  
  70.  
  71. std::string
  72. Sound::filename() const {
  73. return m_filename;
  74. }
  75.  
  76.  
  77. void
  78. Sound::load(
  79. const StorageContainer& storage
  80. ) {
  81. m_filename = storage.get<std::string>("filename");
  82. m_name = storage.get<std::string>("name");
  83. m_properties.playState = static_cast<PlayState>(
  84. storage.get<int16_t>("playState", PlayState::Stop)
  85. );
  86. m_properties.loop = storage.get<bool>("loop");
  87. m_properties.volume = storage.get<float>("volume");
  88. m_properties.maxDistance = storage.get<float>("maxDistance", -1.0f);
  89. m_properties.rolloffFactor = storage.get<float>("rolloffFactor", -1.0f);
  90. m_properties.referenceDistance = storage.get<float>("referenceDistance", 100.0f);
  91. m_properties.priority = storage.get<uint8_t>("priority");
  92. }
  93.  
  94.  
  95. std::string
  96. Sound::name() const {
  97. return m_name;
  98. }
  99.  
  100.  
  101. void
  102. Sound::play() {
  103. m_properties.playState = PlayState::Play;
  104. m_properties.touch();
  105. }
  106.  
  107.  
  108. void
  109. Sound::pause() {
  110. m_properties.playState = PlayState::Pause;
  111. m_properties.touch();
  112. }
  113.  
  114.  
  115. void
  116. Sound::stop() {
  117. m_properties.playState = PlayState::Stop;
  118. m_properties.touch();
  119. }
  120.  
  121.  
  122. StorageContainer
  123. Sound::storage() const {
  124. StorageContainer storage;
  125. storage.set("filename", m_filename);
  126. storage.set("name", m_name);
  127. storage.set<int16_t>("playState", m_properties.playState);
  128. storage.set("loop", m_properties.loop);
  129. storage.set("volume", m_properties.volume);
  130. storage.set("maxDistance", m_properties.maxDistance);
  131. storage.set("rolloffFactor", m_properties.rolloffFactor);
  132. storage.set("referenceDistance", m_properties.referenceDistance);
  133. storage.set("priority", m_properties.priority);
  134. return storage;
  135. }
  136.  
  137.  
  138. ////////////////////////////////////////////////////////////////////////////////
  139. // SoundSourceComponent
  140. ////////////////////////////////////////////////////////////////////////////////
  141.  
  142. //Luabind helper functions
  143. static bool
  144. SoundSourceComponent_getAmbientSoundSource(
  145. const SoundSourceComponent* self
  146. ) {
  147. return self->m_ambientSoundSource;
  148. }
  149.  
  150. static void
  151. SoundSourceComponent_setAmbientSoundSource(
  152. SoundSourceComponent* self,
  153. bool value
  154. ) {
  155. self->m_ambientSoundSource = value;
  156. }
  157.  
  158. static bool
  159. SoundSourceComponent_getAutoLoop(
  160. const SoundSourceComponent* self
  161. ) {
  162. return self->m_autoLoop;
  163. }
  164.  
  165. static void
  166. SoundSourceComponent_setAutoLoop(
  167. SoundSourceComponent* self,
  168. bool value
  169. ) {
  170. self->m_autoLoop = value;
  171. }
  172.  
  173. static float
  174. SoundSourceComponent_getVolumeMultiplier(
  175. const SoundSourceComponent* self
  176. ) {
  177. return self->m_volumeMultiplier;
  178. }
  179.  
  180. static void
  181. SoundSourceComponent_setVolumeMultiplier(
  182. SoundSourceComponent* self,
  183. float value
  184. ) {
  185. self->m_volumeMultiplier = value;
  186. }
  187.  
  188. luabind::scope
  189. SoundSourceComponent::luaBindings() {
  190. using namespace luabind;
  191. return class_<SoundSourceComponent, Component>("SoundSourceComponent")
  192. .enum_("ID") [
  193. value("TYPE_ID", SoundSourceComponent::TYPE_ID)
  194. ]
  195. .scope [
  196. def("TYPE_NAME", &SoundSourceComponent::TYPE_NAME)
  197. ]
  198. .def(constructor<>())
  199. .def("addSound", &SoundSourceComponent::addSound)
  200. .def("removeSound", &SoundSourceComponent::removeSound)
  201. .def("playSound", &SoundSourceComponent::playSound)
  202. .def("queueSound", &SoundSourceComponent::queueSound)
  203. .def("interpose", &SoundSourceComponent::interpose)
  204. .property("ambientSoundSource", SoundSourceComponent_getAmbientSoundSource, SoundSourceComponent_setAmbientSoundSource)
  205. .property("autoLoop", SoundSourceComponent_getAutoLoop, SoundSourceComponent_setAutoLoop)
  206. .property("volumeMultiplier", SoundSourceComponent_getVolumeMultiplier, SoundSourceComponent_setVolumeMultiplier)
  207. ;
  208. }
  209.  
  210. Sound*
  211. SoundSourceComponent::addSound(
  212. std::string name,
  213. std::string filename
  214. ) {
  215. auto sound = make_unique<Sound>(Game::instance().engine().currentGameState()->name() + name, filename);
  216. Sound* rawSound = sound.get();
  217. m_sounds.emplace(name, std::move(sound));
  218. m_addedSounds.push_back(rawSound);
  219. return rawSound;
  220. }
  221.  
  222.  
  223.  
  224. void
  225. SoundSourceComponent::removeSound(
  226. std::string name
  227. ) {
  228. auto iterator = m_sounds.find(name);
  229. if (iterator != m_sounds.end()) {
  230. m_removedSounds.push_back(iterator->second.get());
  231. m_sounds.erase(iterator);
  232. }
  233. }
  234.  
  235. void
  236. SoundSourceComponent::playSound(
  237. std::string name
  238. ){
  239. m_sounds.at(name).get()->play();
  240. }
  241.  
  242. void
  243. SoundSourceComponent::interpose(
  244. std::string name,
  245. int fadeTime
  246. ){
  247. queueSound(name);
  248. m_autoSoundCountdown = fadeTime;
  249. }
  250.  
  251.  
  252. void
  253. SoundSourceComponent::queueSound(
  254. std::string name
  255. ){
  256. m_queuedSound = m_sounds.at(name).get();
  257. }
  258.  
  259.  
  260. void
  261. SoundSourceComponent::load(
  262. const StorageContainer& storage
  263. ) {
  264. Component::load(storage);
  265. m_ambientSoundSource = storage.get<bool>("ambientSoundSource");
  266. m_autoLoop = storage.get<bool>("autoLoop");
  267. StorageList sounds = storage.get<StorageList>("sounds");
  268. for (const StorageContainer& soundStorage : sounds) {
  269. auto sound = make_unique<Sound>();
  270. sound->load(soundStorage);
  271. m_sounds.emplace(
  272. sound->name(),
  273. std::move(sound)
  274. );
  275. }
  276. }
  277.  
  278.  
  279.  
  280. StorageContainer
  281. SoundSourceComponent::storage() const {
  282. StorageContainer storage = Component::storage();
  283. storage.set("ambientSoundSource", m_ambientSoundSource.get());
  284. storage.set("autoLoop", m_autoLoop.get());
  285. StorageList sounds;
  286. sounds.reserve(m_sounds.size());
  287. for (const auto& pair : m_sounds) {
  288. sounds.push_back(pair.second->storage());
  289. }
  290. storage.set<StorageList>("sounds", sounds);
  291. return storage;
  292. }
  293.  
  294. REGISTER_COMPONENT(SoundSourceComponent)
  295.  
  296.  
  297. ////////////////////////////////////////////////////////////////////////////////
  298. // SoundSourceSystem
  299. ////////////////////////////////////////////////////////////////////////////////
  300.  
  301. luabind::scope
  302. SoundSourceSystem::luaBindings() {
  303. using namespace luabind;
  304. return class_<SoundSourceSystem, System>("SoundSourceSystem")
  305. .def(constructor<>())
  306. ;
  307. }
  308.  
  309.  
  310. struct SoundSourceSystem::Implementation {
  311.  
  312. //Destroys all sounds, freeing up memory
  313. void
  314. removeAllSounds() {
  315. for (const auto& item : m_entities) {
  316. EntityId entityId = item.first;
  317. this->removeSoundsForEntity(entityId);
  318. }
  319. m_sounds.clear();
  320. }
  321.  
  322. //Destroys all sounds for a specific entity (useful for when it is destroyed)
  323. void
  324. removeSoundsForEntity(
  325. EntityId entityId
  326. ) {
  327. EntityManager& entityManager = *m_entities.entityManager();
  328. SoundSourceComponent* soundSource = static_cast<SoundSourceComponent*>(entityManager.getComponent(entityId, SoundSourceComponent::TYPE_ID));
  329. if (soundSource) {
  330. for (const auto& pair : soundSource->m_sounds) {
  331. Sound* sound = pair.second.get();
  332. sound->m_sound = nullptr;
  333. }
  334. }
  335. for (const auto& pair : m_sounds[entityId]) {
  336. OgreOggSound::OgreOggISound* sound = pair.second;
  337. this->removeSound(sound);
  338. }
  339. m_sounds[entityId].clear();
  340. }
  341.  
  342. void
  343. removeSound(
  344. OgreOggSound::OgreOggISound* sound
  345. ) {
  346. auto& soundManager = OgreOggSound::OgreOggSoundManager::getSingleton();
  347. if (sound) {
  348. Ogre::SceneNode* sceneNode = sound->getParentSceneNode();
  349. if (sceneNode){
  350. sceneNode->detachObject(sound);
  351. }
  352. soundManager.destroySound(sound);
  353. }
  354. }
  355.  
  356. //Loads all sounds for all SoundSourceComponenet containing entities
  357. void
  358. restoreAllSounds() {
  359. for (const auto& item : m_entities) {
  360. EntityId entityId = item.first;
  361. SoundSourceComponent* soundSourceComponent = std::get<0>(item.second);
  362. OgreSceneNodeComponent* sceneNodeComponent = std::get<1>(item.second);
  363. for (const auto& pair : soundSourceComponent->m_sounds) {
  364. Sound* sound = pair.second.get();
  365. this->restoreSound(
  366. entityId,
  367. sceneNodeComponent,
  368. sound,
  369. soundSourceComponent->m_ambientSoundSource,
  370. soundSourceComponent->m_autoLoop,
  371. m_gameState
  372. );
  373. }
  374. }
  375. }
  376.  
  377. //Loads a sound and sets relevant properties
  378. void
  379. restoreSound(
  380. EntityId entityId,
  381. OgreSceneNodeComponent* sceneNodeComponent,
  382. Sound* sound,
  383. bool ambient,
  384. bool autoLoop,
  385. GameState* gameState
  386. ) {
  387. static const bool STREAM = true; //Streaming sound from file
  388. static const bool PREBUFFER = true; //Attaches soundsource on creation
  389. //3D sounds should not be attempted loaded before scenenodes are created
  390. if (not ambient && (not sceneNodeComponent || not sceneNodeComponent->m_sceneNode)){
  391. return;
  392. }
  393. auto& soundManager = OgreOggSound::OgreOggSoundManager::getSingleton();
  394. std::ostringstream soundName;
  395. soundName << sound->name() << "-" << entityId;
  396. OgreOggSound::OgreOggISound* ogreSound = soundManager.createSound(
  397. soundName.str(),
  398. sound->filename(),
  399. STREAM,
  400. sound->m_properties.loop,
  401. PREBUFFER,
  402. gameState->sceneManager()
  403. );
  404. if (ogreSound) {
  405. sound->m_sound = ogreSound;
  406. // ogreSound->disable3D(ambient);
  407. if (ambient) {
  408. std::cout << "disable 3d for sound " << sound->name() << std::endl;
  409. ogreSound->disable3D(true);
  410. }
  411. if (autoLoop) {
  412. // We want to manage looping ourselves
  413. sound->m_properties.loop = false;
  414. ogreSound->loop(false);
  415. }
  416. m_sounds[entityId].emplace(sound->name(), ogreSound);
  417. if (not ambient){
  418. sceneNodeComponent->m_sceneNode->attachObject(ogreSound);
  419. }
  420. sound->m_properties.touch();
  421. }
  422. else {
  423. Ogre::String msg = "*** SoundSourceSystem::restoreSound() - Sound with name: "+sound->filename()+" failed to load!";
  424. Ogre::LogManager::getSingleton().logMessage(msg);
  425. }
  426. }
  427.  
  428. EntityFilter<
  429. SoundSourceComponent,
  430. Optional<OgreSceneNodeComponent>
  431.  
  432. > m_entities = {true};
  433.  
  434. //Map of the sounds of all entities for destruction reference
  435. std::unordered_map<
  436. EntityId,
  437. std::unordered_map<std::string, OgreOggSound::OgreOggISound*>
  438. > m_sounds;
  439.  
  440. GameState* m_gameState = nullptr;
  441.  
  442. };
  443.  
  444.  
  445. SoundSourceSystem::SoundSourceSystem()
  446. : m_impl(new Implementation())
  447. {
  448.  
  449. }
  450.  
  451.  
  452. SoundSourceSystem::~SoundSourceSystem() {}
  453.  
  454.  
  455. void
  456. SoundSourceSystem::activate() {
  457. System::activate();
  458. auto& soundManager = OgreOggSound::OgreOggSoundManager::getSingleton();
  459. soundManager.setSceneManager(this->gameState()->sceneManager());
  460. m_impl->restoreAllSounds();
  461. if (Entity("player", gameState()).exists()){
  462. auto* sceneNode = static_cast<OgreSceneNodeComponent*>(Entity("player", gameState()).getComponent(OgreSceneNodeComponent::TYPE_ID));
  463. std::cout << "attach listener" << std::endl;
  464. if (sceneNode != nullptr){
  465. std::cout << "rte"<<std::endl;
  466. // sceneNode->attachSoundListener();
  467. }
  468. }
  469. }
  470.  
  471.  
  472. void
  473. SoundSourceSystem::deactivate() {
  474. if (this->engine()->isSystemTimedShutdown(*this)) {
  475. System::deactivate();
  476. m_impl->removeAllSounds();
  477. }
  478. else {
  479. for (auto& value : m_impl->m_entities) {
  480. std::get<0>(value.second)->m_autoSoundCountdown = 1500;
  481. }
  482. this->engine()->timedSystemShutdown(*this, 1500);
  483. }
  484. }
  485.  
  486.  
  487. void
  488. SoundSourceSystem::init(
  489. GameState* gameState
  490. ) {
  491. System::init(gameState);
  492. m_impl->m_entities.setEntityManager(&gameState->entityManager());
  493. m_impl->m_gameState = gameState;
  494. }
  495.  
  496.  
  497. void
  498. SoundSourceSystem::shutdown() {
  499. m_impl->m_entities.setEntityManager(nullptr);
  500. System::shutdown();
  501. }
  502.  
  503.  
  504. void
  505. SoundSourceSystem::update(int milliseconds) {
  506. for (EntityId entityId : m_impl->m_entities.removedEntities()) {
  507. m_impl->removeSoundsForEntity(entityId);
  508. }
  509. for (auto& value : m_impl->m_entities.addedEntities()) {
  510. //Load the songs for any new soundSourceComponent containing entities that have been created
  511. EntityId entityId = value.first;
  512. SoundSourceComponent* soundSourceComponent = std::get<0>(value.second);
  513. OgreSceneNodeComponent* sceneNodeComponent = std::get<1>(value.second);
  514. for (const auto& pair : soundSourceComponent->m_sounds) {
  515. Sound* sound = pair.second.get();
  516. if (not sound->m_sound) {
  517. m_impl->restoreSound(
  518. entityId,
  519. sceneNodeComponent,
  520. sound,
  521. soundSourceComponent->m_ambientSoundSource,
  522. soundSourceComponent->m_autoLoop,
  523. this->gameState()
  524. );
  525. }
  526. }
  527. }
  528. m_impl->m_entities.clearChanges();
  529. for (auto& value : m_impl->m_entities) {
  530. SoundSourceComponent* soundSourceComponent = std::get<0>(value.second);
  531. OgreSceneNodeComponent* sceneNodeComponent = std::get<1>(value.second);
  532. for (const auto& pair : soundSourceComponent->m_sounds) {
  533. Sound* sound = pair.second.get();
  534. assert(sound->m_sound && "Sound was not intialized");
  535. if (sound->m_properties.hasChanges()) {
  536. const auto& properties = sound->m_properties;
  537. OgreOggSound::OgreOggISound* ogreSound = sound->m_sound;
  538. ogreSound->loop(properties.loop and not soundSourceComponent->m_autoLoop);
  539. ogreSound->setVolume(properties.volume * soundSourceComponent->m_volumeMultiplier);
  540. std::cout << "sound: " << sound->name() << " setting props to: maxdist " << properties.maxDistance << ", rolloff " << properties.rolloffFactor << ", referencedist " << properties.referenceDistance << std::endl;
  541. ogreSound->setMaxDistance(properties.maxDistance);
  542. ogreSound->setRolloffFactor(properties.rolloffFactor);
  543. ogreSound->setReferenceDistance(properties.referenceDistance);
  544. ogreSound->setPriority(properties.priority);
  545. Ogre::Vector3 bla = ogreSound->getPosition();
  546. Ogre::Vector3 lispos = OgreOggSound::OgreOggSoundManager::getSingleton().getListener()->getPosition();
  547. switch(properties.playState) {
  548. case Sound::PlayState::Play:
  549. ogreSound->play();
  550.  
  551. std::cout << "playing sound " << sound->name() << " at pos " << bla.x << ", " << bla.y << std::endl;
  552. std::cout << "LISTENERPOS " << lispos.x << ", " << lispos.y << std::endl;
  553. break;
  554. case Sound::PlayState::Pause:
  555. ogreSound->pause();
  556. break;
  557. case Sound::PlayState::Stop:
  558. ogreSound->stop();
  559. break;
  560. default:
  561. // Shut up GCC
  562. break;
  563. }
  564. sound->m_properties.untouch();
  565. }
  566. }
  567. if (soundSourceComponent->m_ambientSoundSource.hasChanges()) {
  568. //Iterate through all existing sounds and set/unset ambience only properties
  569. for (const auto& pair : soundSourceComponent->m_sounds) {
  570. Sound* sound = pair.second.get();
  571. OgreOggSound::OgreOggISound* ogreSound = sound->m_sound;
  572. if (sound->m_sound) {
  573. if (soundSourceComponent->m_ambientSoundSource.get() || !sceneNodeComponent) {
  574. std::cout << "disable 3d for sound " << sound->name() << std::endl;
  575. ogreSound->disable3D(true);
  576. }
  577. if (soundSourceComponent->m_ambientSoundSource.get()) {
  578. sound->stop();
  579. }
  580. }
  581. }
  582. soundSourceComponent->m_ambientSoundSource.untouch();
  583. }
  584. if (soundSourceComponent->m_autoLoop.hasChanges()) {
  585. //Iterate through all existing sounds and set/unset ambience only properties
  586. for (const auto& pair : soundSourceComponent->m_sounds) {
  587. Sound* sound = pair.second.get();
  588. OgreOggSound::OgreOggISound* ogreSound = sound->m_sound;
  589. if (sound->m_sound) {
  590. if (soundSourceComponent->m_ambientSoundSource.get()) {
  591. ogreSound->loop(false);
  592. }
  593. else {
  594. ogreSound->loop(sound->m_properties.loop);
  595. }
  596. }
  597. }
  598. soundSourceComponent->m_autoLoop.untouch();
  599. }
  600. // If the current soundsource is an ambient soundsource
  601. if (soundSourceComponent->m_autoLoop.get()) {
  602. //Automatically manage looping of ambient sounds randomly
  603. // (This would have unintended effects on ambient soundsources not meant for background music
  604. // and would result in overlap with multiple simultanious ambient soundsource entities
  605. // a redesign will be necessary if either of those two optiosn are desired)
  606. soundSourceComponent->m_autoSoundCountdown -= milliseconds;
  607. if (soundSourceComponent->m_autoSoundCountdown < FADE_TIME) {
  608. if (soundSourceComponent->m_autoActiveSound && not soundSourceComponent->m_isTransitioningAuto && soundSourceComponent->m_autoSoundCountdown > 0){
  609. soundSourceComponent->m_isTransitioningAuto = true;
  610. soundSourceComponent->m_autoActiveSound->m_sound->startFade(false, (soundSourceComponent->m_autoSoundCountdown)/1000.0f);
  611. }
  612. if (soundSourceComponent->m_autoSoundCountdown <= 0){
  613. // We want to stop the active song instantly, so we can't reply only on the Sound::stop(), we need to call it on the ogresound directly as well.
  614. if (soundSourceComponent->m_autoActiveSound) {
  615. soundSourceComponent->m_autoActiveSound->m_sound->stop();
  616. soundSourceComponent->m_autoActiveSound->stop();
  617. }
  618. Sound* newSound = nullptr;
  619. if (soundSourceComponent->m_queuedSound){
  620. //If a sound was queued up to be next, then pick that one
  621. newSound = soundSourceComponent->m_queuedSound;
  622. }
  623. else {
  624. //Otherwise pick a sound by random from the avaliable sounds
  625. int numOfSounds = soundSourceComponent->m_sounds.size();
  626. if (numOfSounds > 0){
  627. if (soundSourceComponent->m_queuedSound){
  628. newSound = soundSourceComponent->m_queuedSound;
  629. }
  630. else {
  631. do {
  632. int randSoundIndex = Game::instance().engine().rng().getInt(0, numOfSounds-1);
  633. std::unordered_map<std::string, std::unique_ptr<Sound>>::iterator soundPointer
  634. = soundSourceComponent->m_sounds.begin();
  635. for (int i = 0; i < randSoundIndex; ++i)
  636. soundPointer++;
  637. newSound = soundPointer->second.get();
  638. } while (newSound == soundSourceComponent->m_autoActiveSound && numOfSounds > 1); //Ensure we don't play the same song twice
  639. }
  640. }
  641. }
  642. float soundLength = newSound->m_sound->getAudioLength();
  643. // Soundlength will return 0 for a while after initialization (I think it's due to multi-threaded sound init) so we need to handle that
  644. if (soundLength > 0){
  645. soundSourceComponent->m_autoActiveSound = newSound;
  646. soundSourceComponent->m_autoSoundCountdown = newSound->m_sound->getAudioLength()*1000;
  647. newSound->play();
  648. soundSourceComponent->m_queuedSound = nullptr;
  649. //newSound->m_sound->startFade(true, 5000); // In case we want to fade-in themes instead of just playing them.
  650. }
  651. soundSourceComponent->m_isTransitioningAuto = false;
  652. }
  653.  
  654. }
  655. }
  656. }
  657. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement