AudioSystemImpl_wwise.cpp 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/PlatformIncl.h>
  9. #include <AudioSystemImpl_wwise.h>
  10. #include <platform.h>
  11. #include <AzCore/AzCore_Traits_Platform.h>
  12. #include <AzCore/Console/ILogger.h>
  13. #include <AzCore/Debug/Profiler.h>
  14. #include <AzCore/std/containers/set.h>
  15. #include <AzCore/std/string/conversions.h>
  16. #include <AzCore/StringFunc/StringFunc.h>
  17. #include <IAudioSystem.h>
  18. #include <AudioAllocators.h>
  19. #include <AudioSourceManager.h>
  20. #include <AudioSystemImplCVars.h>
  21. #include <Common_wwise.h>
  22. #include <Config_wwise.h>
  23. #include <FileIOHandler_wwise.h>
  24. #include <AK/SoundEngine/Common/AkMemoryMgr.h> // Memory Manager
  25. #include <AK/SoundEngine/Common/AkModule.h> // Memory and Stream Manager interfaces
  26. #include <AK/SoundEngine/Common/AkSoundEngine.h> // Sound Engine
  27. #include <AK/SpatialAudio/Common/AkSpatialAudio.h> // Spatial Audio
  28. #include <AK/MusicEngine/Common/AkMusicEngine.h> // Music Engine
  29. #include <PluginRegistration_wwise.h> // Registration of default set of plugins, customize this header to your needs.
  30. #include <inttypes.h>
  31. #if !defined(WWISE_RELEASE)
  32. #include <AK/Comm/AkCommunication.h> // Communication between Wwise and the game (excluded in release build)
  33. #include <AK/Tools/Common/AkMonitorError.h>
  34. #include <AkPlatformFuncs_Platform.h>
  35. #endif // WWISE_RELEASE
  36. #if defined(AK_MAX_AUX_PER_OBJ)
  37. #define LY_MAX_AUX_PER_OBJ AK_MAX_AUX_PER_OBJ
  38. #else
  39. #define LY_MAX_AUX_PER_OBJ (4)
  40. #endif
  41. namespace Audio
  42. {
  43. namespace Platform
  44. {
  45. void InitializeMemory();
  46. void SetupAkSoundEngine(AkPlatformInitSettings& platformInitSettings);
  47. }
  48. /////////////////////////////////////////////////////////////////////////////////
  49. // AK MEMORY HOOKS SETUP
  50. namespace Wwise::MemHooks
  51. {
  52. void* Malloc(AkMemPoolId memId, size_t size)
  53. {
  54. size_t memCategory = memId & AkMemID_MASK;
  55. AZ_Assert(memCategory < AkMemID_NUM, "Wwise::MemHooks::Malloc - Bad AkMemPoolId passed: %zu", memCategory);
  56. return AZ::AllocatorInstance<AudioImplAllocator>::Get().Allocate(size, 0, 0,
  57. (memCategory < AkMemID_NUM) ? MemoryManagerCategories[memCategory] : nullptr);
  58. }
  59. void* Malign(AkMemPoolId memId, size_t size, AkUInt32 alignment)
  60. {
  61. size_t memCategory = memId & AkMemID_MASK;
  62. AZ_Assert(memCategory < AkMemID_NUM, "WWise::MemHooks::Malign - Bad AkMemPoolId passed: %zu", memCategory);
  63. return AZ::AllocatorInstance<AudioImplAllocator>::Get().Allocate(size, alignment, 0,
  64. (memCategory < AkMemID_NUM) ? MemoryManagerCategories[memCategory] : nullptr);
  65. }
  66. void* Realloc([[maybe_unused]] AkMemPoolId memId, void* address, size_t size)
  67. {
  68. return AZ::AllocatorInstance<AudioImplAllocator>::Get().ReAllocate(address, size, 0);
  69. }
  70. void* ReallocAligned([[maybe_unused]] AkMemPoolId memId, void* address, size_t size, AkUInt32 alignment)
  71. {
  72. return AZ::AllocatorInstance<AudioImplAllocator>::Get().ReAllocate(address, size, alignment);
  73. }
  74. void Free([[maybe_unused]] AkMemPoolId memId, void* address)
  75. {
  76. AZ::AllocatorInstance<AudioImplAllocator>::Get().DeAllocate(address);
  77. }
  78. size_t TotalReservedMemorySize()
  79. {
  80. return AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().Capacity();
  81. }
  82. size_t SizeOfMemory([[maybe_unused]] AkMemPoolId memId, void* address)
  83. {
  84. return AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().AllocationSize(address);
  85. }
  86. } // namespace Wwise::MemHooks
  87. const char* const CAudioSystemImpl_wwise::WwiseImplSubPath = "wwise/";
  88. const char* const CAudioSystemImpl_wwise::WwiseGlobalAudioObjectName = "GlobalAudioObject";
  89. const float CAudioSystemImpl_wwise::ObstructionOcclusionMin = 0.0f;
  90. const float CAudioSystemImpl_wwise::ObstructionOcclusionMax = 1.0f;
  91. static bool audioDeviceInitializationEvent = false;
  92. ///////////////////////////////////////////////////////////////////////////////////////////////////
  93. // AK callbacks
  94. void WwiseEventCallback(AkCallbackType callbackType, AkCallbackInfo* callbackInfo)
  95. {
  96. if (callbackType == AK_EndOfEvent)
  97. {
  98. auto const eventData = static_cast<SATLEventData_wwise*>(callbackInfo->pCookie);
  99. if (eventData)
  100. {
  101. Audio::CallbackRequest::ReportFinishedEvent reportFinishedEvent;
  102. reportFinishedEvent.m_eventId = eventData->nATLID;
  103. AZ::Interface<IAudioSystem>::Get()->PushRequest(AZStd::move(reportFinishedEvent));
  104. if (eventData->nSourceId != INVALID_AUDIO_SOURCE_ID)
  105. {
  106. AkPlayingID playingId = AudioSourceManager::Get().FindPlayingSource(eventData->nSourceId);
  107. AudioSourceManager::Get().DeactivateSource(playingId);
  108. }
  109. }
  110. }
  111. else if (callbackType == AK_Duration)
  112. {
  113. auto durationInfo = static_cast<AkDurationCallbackInfo*>(callbackInfo);
  114. auto const eventData = static_cast<SATLEventData_wwise*>(callbackInfo->pCookie);
  115. if (durationInfo && eventData && eventData->m_owner)
  116. {
  117. AudioTriggerNotificationBus::QueueEvent(
  118. TriggerNotificationIdType{ eventData->m_owner }, &AudioTriggerNotificationBus::Events::ReportDurationInfo,
  119. eventData->m_triggerId,
  120. eventData->nATLID,
  121. durationInfo->fDuration,
  122. durationInfo->fEstimatedDuration);
  123. }
  124. }
  125. }
  126. ///////////////////////////////////////////////////////////////////////////////////////////////////
  127. void AudioDeviceCallback(
  128. [[maybe_unused]] AK::IAkGlobalPluginContext* context,
  129. [[maybe_unused]] AkUniqueID audioDeviceSharesetId,
  130. [[maybe_unused]] AkUInt32 deviceId,
  131. AK::AkAudioDeviceEvent deviceEvent,
  132. [[maybe_unused]] AKRESULT inAkResult
  133. )
  134. {
  135. if (deviceEvent == AK::AkAudioDeviceEvent_Initialization)
  136. {
  137. audioDeviceInitializationEvent = true;
  138. }
  139. }
  140. ///////////////////////////////////////////////////////////////////////////////////////////////////
  141. void PrepareEventCallback(
  142. AkUniqueID akEventId,
  143. [[maybe_unused]] const void* bankPtr,
  144. [[maybe_unused]] AKRESULT loadResult,
  145. [[maybe_unused]] AkMemPoolId memPoolId,
  146. void* cookie)
  147. {
  148. auto const eventData = static_cast<SATLEventData_wwise*>(cookie);
  149. if (eventData)
  150. {
  151. eventData->nAKID = akEventId;
  152. // TODO (PrepareTrigger/PrepareEvent functionality):
  153. // Audio::CallbackRequest::ReportFinishedEvent (eventData->nATLID, loadResult == AK_Success)
  154. }
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////////////////////////
  157. #if !defined(WWISE_RELEASE)
  158. static void ErrorMonitorCallback(
  159. AK::Monitor::ErrorCode in_eErrorCode, ///< Error code number value
  160. const AkOSChar* in_pszError, ///< Message or error string to be displayed
  161. AK::Monitor::ErrorLevel /*in_eErrorLevel*/, ///< Specifies whether it should be displayed as a message or an error
  162. AkPlayingID in_playingID, ///< Related Playing ID if applicable, AK_INVALID_PLAYING_ID otherwise
  163. AkGameObjectID in_gameObjID) ///< Related Game Object ID if applicable, AK_INVALID_GAME_OBJECT otherwise
  164. {
  165. char* errorStr = nullptr;
  166. CONVERT_OSCHAR_TO_CHAR(in_pszError, errorStr);
  167. AZLOG_NOTICE(
  168. "<Wwise> %s ErrorCode: %d PlayingID: %u GameObjID: %llu", errorStr, in_eErrorCode, in_playingID,
  169. static_cast<AZ::u64>(in_gameObjID));
  170. }
  171. #endif // WWISE_RELEASE
  172. ///////////////////////////////////////////////////////////////////////////////////////////////////
  173. static int GetAssetType(const SATLSourceData* sourceData)
  174. {
  175. if (!sourceData)
  176. {
  177. return eAAT_NONE;
  178. }
  179. return sourceData->m_sourceInfo.m_codecType == eACT_STREAM_PCM
  180. ? eAAT_STREAM
  181. : eAAT_SOURCE;
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////////////////////////
  184. static int GetAkCodecID(EAudioCodecType codecType)
  185. {
  186. switch (codecType)
  187. {
  188. // Wwise version 2022.x does not include AKCODECID_AAC
  189. #if defined(AKCODECID_AAC)
  190. case eACT_AAC:
  191. return AKCODECID_AAC;
  192. #endif // defined(AKCODECID_AAC)
  193. case eACT_ADPCM:
  194. return AKCODECID_ADPCM;
  195. case eACT_PCM:
  196. return AKCODECID_PCM;
  197. case eACT_VORBIS:
  198. return AKCODECID_VORBIS;
  199. case eACT_XMA:
  200. return AKCODECID_XMA;
  201. case eACT_XWMA:
  202. return AKCODECID_XWMA;
  203. case eACT_STREAM_PCM:
  204. default:
  205. AZ_Assert(codecType, "Codec not supported");
  206. return AKCODECID_VORBIS;
  207. }
  208. }
  209. ///////////////////////////////////////////////////////////////////////////////////////////////////
  210. CAudioSystemImpl_wwise::CAudioSystemImpl_wwise(const char* assetsPlatformName)
  211. : m_globalGameObjectID(static_cast<AkGameObjectID>(GLOBAL_AUDIO_OBJECT_ID))
  212. , m_defaultListenerGameObjectID(AK_INVALID_GAME_OBJECT)
  213. , m_initBankID(AK_INVALID_BANK_ID)
  214. #if !defined(WWISE_RELEASE)
  215. , m_isCommSystemInitialized(false)
  216. #endif // !WWISE_RELEASE
  217. {
  218. if (assetsPlatformName && assetsPlatformName[0] != '\0')
  219. {
  220. m_assetsPlatform = assetsPlatformName;
  221. }
  222. Platform::InitializeMemory();
  223. SetBankPaths();
  224. #if !defined(WWISE_RELEASE)
  225. m_fullImplString = AZStd::string::format("%s (%s)", WWISE_IMPL_VERSION_STRING, m_soundbankFolder.c_str());
  226. // Set up memory categories for debug tracking, do this early before initializing Wwise so they are available
  227. // before the any allocations through hooks occur.
  228. AZLOG_INFO("%s", "Memory Categories:");
  229. m_debugMemoryInfo.reserve(AkMemID_NUM + 1);
  230. for (AZ::u32 memId = 0; memId < AkMemID_NUM; ++memId)
  231. {
  232. AudioImplMemoryPoolInfo memInfo;
  233. azstrcpy(memInfo.m_poolName, sizeof(memInfo.m_poolName), Wwise::MemoryManagerCategories[memId]);
  234. memInfo.m_poolId = memId;
  235. m_debugMemoryInfo.push_back(memInfo);
  236. AZLOG_INFO("Memory category ID: %u - '%s'", memId, Wwise::MemoryManagerCategories[memId]);
  237. }
  238. // Add one more category for global stats.
  239. AudioImplMemoryPoolInfo memInfo;
  240. azstrcpy(memInfo.m_poolName, sizeof(memInfo.m_poolName), "Global");
  241. m_debugMemoryInfo.push_back(memInfo);
  242. #endif // !WWISE_RELEASE
  243. AudioSystemImplementationRequestBus::Handler::BusConnect();
  244. AudioSystemImplementationNotificationBus::Handler::BusConnect();
  245. }
  246. ///////////////////////////////////////////////////////////////////////////////////////////////////
  247. CAudioSystemImpl_wwise::~CAudioSystemImpl_wwise()
  248. {
  249. AudioSystemImplementationRequestBus::Handler::BusDisconnect();
  250. AudioSystemImplementationNotificationBus::Handler::BusDisconnect();
  251. }
  252. ///////////////////////////////////////////////////////////////////////////////////////////////////
  253. // AudioSystemImplementationNotificationBus
  254. ///////////////////////////////////////////////////////////////////////////////////////////////////
  255. ///////////////////////////////////////////////////////////////////////////////////////////////////
  256. void CAudioSystemImpl_wwise::OnAudioSystemLoseFocus()
  257. {
  258. #if AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND
  259. AKRESULT akResult = AK::SoundEngine::Suspend();
  260. if (!IS_WWISE_OK(akResult))
  261. {
  262. AZLOG_ERROR("Wwise failed to Suspend, AKRESULT %d", akResult);
  263. }
  264. #endif // AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND
  265. }
  266. ///////////////////////////////////////////////////////////////////////////////////////////////////
  267. void CAudioSystemImpl_wwise::OnAudioSystemGetFocus()
  268. {
  269. #if AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND
  270. AKRESULT akResult = AK::SoundEngine::WakeupFromSuspend();
  271. if (!IS_WWISE_OK(akResult))
  272. {
  273. AZLOG_ERROR("Wwise failed to WakeupFromSuspend, AKRESULT %d", akResult);
  274. }
  275. #endif // AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND
  276. }
  277. ///////////////////////////////////////////////////////////////////////////////////////////////////
  278. void CAudioSystemImpl_wwise::OnAudioSystemMuteAll()
  279. {
  280. // With Wwise we drive this via events.
  281. }
  282. ///////////////////////////////////////////////////////////////////////////////////////////////////
  283. void CAudioSystemImpl_wwise::OnAudioSystemUnmuteAll()
  284. {
  285. // With Wwise we drive this via events.
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////////////////////////
  288. void CAudioSystemImpl_wwise::OnAudioSystemRefresh()
  289. {
  290. AKRESULT akResult = AK_Fail;
  291. if (m_initBankID != AK_INVALID_BANK_ID)
  292. {
  293. akResult = AK::SoundEngine::UnloadBank(m_initBankID, nullptr);
  294. if (!IS_WWISE_OK(akResult))
  295. {
  296. AZLOG_ERROR("Wwise failed to unload %s, returned AKRESULT %d", Wwise::InitBank, akResult);
  297. }
  298. }
  299. AkOSChar* initBankName = nullptr;
  300. CONVERT_CHAR_TO_OSCHAR(Wwise::InitBank, initBankName);
  301. akResult = AK::SoundEngine::LoadBank(initBankName, m_initBankID);
  302. if (!IS_WWISE_OK(akResult))
  303. {
  304. AZLOG_ERROR("Wwise failed to load %s, returned AKRESULT %d", Wwise::InitBank, akResult);
  305. m_initBankID = AK_INVALID_BANK_ID;
  306. }
  307. }
  308. ///////////////////////////////////////////////////////////////////////////////////////////////////
  309. // AudioSystemImplementationRequestBus
  310. ///////////////////////////////////////////////////////////////////////////////////////////////////
  311. ///////////////////////////////////////////////////////////////////////////////////////////////////
  312. void CAudioSystemImpl_wwise::Update([[maybe_unused]] const float updateIntervalMS)
  313. {
  314. AZ_PROFILE_FUNCTION(Audio);
  315. if (AK::SoundEngine::IsInitialized())
  316. {
  317. #if !defined(WWISE_RELEASE)
  318. AKRESULT akResult = AK_Fail;
  319. static bool enableOutputCapture = false;
  320. if (Wwise::Cvars::s_EnableOutputCapture && !enableOutputCapture)
  321. {
  322. // This file ends up in the cache folder
  323. // Need to disable this on LTX, it produces garbage output. But there's no way to "IsLTX()" yet.
  324. akResult = AK::SoundEngine::StartOutputCapture(AKTEXT("../wwise_audio_capture.wav"));
  325. AZ_Assert(IS_WWISE_OK(akResult), "AK::SoundEngine::StartOutputCapture failed!");
  326. enableOutputCapture = Wwise::Cvars::s_EnableOutputCapture;
  327. }
  328. else if (!Wwise::Cvars::s_EnableOutputCapture && enableOutputCapture)
  329. {
  330. akResult = AK::SoundEngine::StopOutputCapture();
  331. AZ_Assert(IS_WWISE_OK(akResult), "AK::SoundEngine::StopOutputCapture failed!");
  332. enableOutputCapture = Wwise::Cvars::s_EnableOutputCapture;
  333. }
  334. if (audioDeviceInitializationEvent)
  335. {
  336. AkChannelConfig channelConfig = AK::SoundEngine::GetSpeakerConfiguration();
  337. int surroundSpeakers = channelConfig.uNumChannels;
  338. int lfeSpeakers = 0;
  339. if (AK::HasLFE(channelConfig.uChannelMask))
  340. {
  341. --surroundSpeakers;
  342. ++lfeSpeakers;
  343. }
  344. m_speakerConfigString = AZStd::string::format("Output: %d.%d", surroundSpeakers, lfeSpeakers);
  345. m_fullImplString = AZStd::string::format("%s (%s) %s", WWISE_IMPL_VERSION_STRING, m_soundbankFolder.c_str(), m_speakerConfigString.c_str());
  346. audioDeviceInitializationEvent = false;
  347. }
  348. #endif // !WWISE_RELEASE
  349. AK::SoundEngine::RenderAudio();
  350. }
  351. }
  352. ///////////////////////////////////////////////////////////////////////////////////////////////////
  353. EAudioRequestStatus CAudioSystemImpl_wwise::Initialize()
  354. {
  355. // If something fails so severely during initialization that we need to fall back to a 'Null' implementation
  356. // we will need to shut down what has been initialized so far. Therefore make sure to call Shutdown() before returning EAudioRequestStatus::Failure!
  357. AkMemSettings akMemSettings;
  358. AK::MemoryMgr::GetDefaultSettings(akMemSettings);
  359. akMemSettings.pfMalloc = Wwise::MemHooks::Malloc;
  360. akMemSettings.pfMalign = Wwise::MemHooks::Malign;
  361. akMemSettings.pfRealloc = Wwise::MemHooks::Realloc;
  362. akMemSettings.pfReallocAligned = Wwise::MemHooks::ReallocAligned;
  363. akMemSettings.pfFree = Wwise::MemHooks::Free;
  364. akMemSettings.pfTotalReservedMemorySize = Wwise::MemHooks::TotalReservedMemorySize;
  365. akMemSettings.pfSizeOfMemory = Wwise::MemHooks::SizeOfMemory;
  366. akMemSettings.uMemAllocationSizeLimit = Wwise::Cvars::s_PrimaryMemorySize << 10;
  367. AKRESULT akResult = AK::MemoryMgr::Init(&akMemSettings);
  368. if (!IS_WWISE_OK(akResult))
  369. {
  370. AZLOG_ERROR("AK::MemoryMgr::Init() returned AKRESULT %d", akResult);
  371. ShutDown();
  372. return EAudioRequestStatus::Failure;
  373. }
  374. akResult = AK::SoundEngine::RegisterAudioDeviceStatusCallback(AudioDeviceCallback);
  375. if (!IS_WWISE_OK(akResult))
  376. {
  377. AZLOG_ERROR("AK::SoundEngine::RegisterAudioDeviceStatusCallback returned AKRESULT %d", akResult);
  378. }
  379. AkStreamMgrSettings akStreamSettings;
  380. AK::StreamMgr::GetDefaultSettings(akStreamSettings);
  381. if (AK::StreamMgr::Create(akStreamSettings) == nullptr)
  382. {
  383. AZLOG_ERROR("%s", "AK::StreamMrg::Create() failed!");
  384. ShutDown();
  385. return EAudioRequestStatus::Failure;
  386. }
  387. akResult = m_fileIOHandler.Init(Wwise::Cvars::s_StreamDeviceMemorySize << 10);
  388. if (!IS_WWISE_OK(akResult))
  389. {
  390. AZLOG_ERROR("m_fileIOHandler.Init() returned AKRESULT %d", akResult);
  391. ShutDown();
  392. return EAudioRequestStatus::Failure;
  393. }
  394. m_fileIOHandler.SetBankPath(m_soundbankFolder.c_str());
  395. AkInitSettings akInitSettings;
  396. AK::SoundEngine::GetDefaultInitSettings(akInitSettings);
  397. akInitSettings.uCommandQueueSize = aznumeric_cast<AkUInt32>(Wwise::Cvars::s_CommandQueueMemorySize << 10);
  398. #if !defined(WWISE_RELEASE)
  399. akInitSettings.uMonitorQueuePoolSize = aznumeric_cast<AkUInt32>(Wwise::Cvars::s_MonitorQueueMemorySize << 10);
  400. #endif // !WWISE_RELEASE
  401. akInitSettings.bEnableGameSyncPreparation = false;
  402. #if AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION
  403. akInitSettings.settingsMainOutput.channelConfig.SetStandardOrAnonymous(
  404. AK::ChannelMaskToNumChannels(AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION),
  405. AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION);
  406. #endif
  407. AkPlatformInitSettings akPlatformInitSettings;
  408. AK::SoundEngine::GetDefaultPlatformInitSettings(akPlatformInitSettings);
  409. Platform::SetupAkSoundEngine(akPlatformInitSettings);
  410. akResult = AK::SoundEngine::Init(&akInitSettings, &akPlatformInitSettings);
  411. if (!IS_WWISE_OK(akResult))
  412. {
  413. AZLOG_ERROR("AK::SoundEngine::Init() returned AKRESULT %d", akResult);
  414. ShutDown();
  415. return EAudioRequestStatus::Failure;
  416. }
  417. AkMusicSettings akMusicSettings;
  418. AK::MusicEngine::GetDefaultInitSettings(akMusicSettings);
  419. akResult = AK::MusicEngine::Init(&akMusicSettings);
  420. if (!IS_WWISE_OK(akResult))
  421. {
  422. AZLOG_ERROR("AK::MusicEngine::Init() returned AKRESULT %d", akResult);
  423. ShutDown();
  424. return EAudioRequestStatus::Failure;
  425. }
  426. AkSpatialAudioInitSettings akSpatialAudioSettings;
  427. akResult = AK::SpatialAudio::Init(akSpatialAudioSettings);
  428. if (!IS_WWISE_OK(akResult))
  429. {
  430. AZLOG_ERROR("AK::SpatialAudio::Init() returned AKRESULT %d", akResult);
  431. ShutDown();
  432. return EAudioRequestStatus::Failure;
  433. }
  434. #if !defined(WWISE_RELEASE)
  435. if (Audio::Wwise::Cvars::s_EnableCommSystem)
  436. {
  437. m_isCommSystemInitialized = true;
  438. AkCommSettings akCommSettings;
  439. AK::Comm::GetDefaultInitSettings(akCommSettings);
  440. akResult = AK::Comm::Init(akCommSettings);
  441. if (!IS_WWISE_OK(akResult))
  442. {
  443. AZLOG_ERROR(
  444. "AK::Comm::Init() returned AKRESULT %d. Communication between the Wwise authoring application and the game will not "
  445. "be possible",
  446. akResult);
  447. m_isCommSystemInitialized = false;
  448. }
  449. akResult = AK::Monitor::SetLocalOutput(AK::Monitor::ErrorLevel_All, ErrorMonitorCallback);
  450. if (!IS_WWISE_OK(akResult))
  451. {
  452. AK::Comm::Term();
  453. AZLOG_ERROR("AK::Monitor::SetLocalOutput() returned AKRESULT %d", akResult);
  454. m_isCommSystemInitialized = false;
  455. }
  456. }
  457. #endif // !WWISE_RELEASE
  458. // Initialize the AudioSourceManager
  459. AudioSourceManager::Get().Initialize();
  460. // Register the Global Audio Object used for the events that don't need a location in the game world
  461. akResult = AK::SoundEngine::RegisterGameObj(m_globalGameObjectID, WwiseGlobalAudioObjectName);
  462. if (!IS_WWISE_OK(akResult))
  463. {
  464. AZLOG_ERROR("AK::SoundEngine::RegisterGameObject() failed for '%s' with AKRESULT %d", WwiseGlobalAudioObjectName, akResult);
  465. }
  466. // Load init.bnk before making the system available to the users
  467. AkOSChar* initBankName = nullptr;
  468. CONVERT_CHAR_TO_OSCHAR(Wwise::InitBank, initBankName);
  469. akResult = AK::SoundEngine::LoadBank(initBankName, m_initBankID);
  470. if (!IS_WWISE_OK(akResult))
  471. {
  472. // This does not qualify for a fallback to the 'Null' audio implementation!
  473. AZLOG_ERROR("Wwise failed to load %s, returned AKRESULT %d", Wwise::InitBank, akResult);
  474. m_initBankID = AK_INVALID_BANK_ID;
  475. }
  476. return EAudioRequestStatus::Success;
  477. }
  478. ///////////////////////////////////////////////////////////////////////////////////////////////////
  479. EAudioRequestStatus CAudioSystemImpl_wwise::ShutDown()
  480. {
  481. AKRESULT akResult = AK_Fail;
  482. #if !defined(WWISE_RELEASE)
  483. if (m_isCommSystemInitialized)
  484. {
  485. AK::Comm::Term();
  486. akResult = AK::Monitor::SetLocalOutput(0, nullptr);
  487. if (!IS_WWISE_OK(akResult))
  488. {
  489. AZLOG_WARN("AK::Monitor::SetLocalOutput() returned AKRESULT %d", akResult);
  490. }
  491. m_isCommSystemInitialized = false;
  492. }
  493. #endif // !WWISE_RELEASE
  494. akResult = AK::SoundEngine::UnregisterAudioDeviceStatusCallback();
  495. if (akResult != AK_Success)
  496. {
  497. AZLOG_WARN("AK::SoundEngine::UnregisterAudioDeviceStatusCallback() returned AKRESULT %d", akResult);
  498. }
  499. // Shutdown the AudioSourceManager
  500. AudioSourceManager::Get().Shutdown();
  501. AK::MusicEngine::Term();
  502. if (AK::SoundEngine::IsInitialized())
  503. {
  504. // UnRegister the DummyGameObject
  505. akResult = AK::SoundEngine::UnregisterGameObj(m_globalGameObjectID);
  506. if (!IS_WWISE_OK(akResult))
  507. {
  508. AZLOG_WARN(
  509. "AK::SoundEngine::UnregisterGameObject() failed for '%s' with AKRESULT %d", WwiseGlobalAudioObjectName, akResult);
  510. }
  511. akResult = AK::SoundEngine::ClearBanks();
  512. if (!IS_WWISE_OK(akResult))
  513. {
  514. AZLOG_ERROR("AK::SoundEngine::ClearBanks() returned AKRESULT %d", akResult);
  515. }
  516. AK::SoundEngine::Term();
  517. }
  518. // Terminate the streaming device and streaming manager
  519. // CAkFilePackageLowLevelIOBlocking::Term() destroys its associated streaming device
  520. // that lives in the Stream Manager, and unregisters itself as the File Location Resolver.
  521. if (AK::IAkStreamMgr::Get())
  522. {
  523. m_fileIOHandler.ShutDown();
  524. AK::IAkStreamMgr::Get()->Destroy();
  525. }
  526. // Terminate the Memory Manager
  527. if (AK::MemoryMgr::IsInitialized())
  528. {
  529. AK::MemoryMgr::Term();
  530. }
  531. return EAudioRequestStatus::Success;
  532. }
  533. ///////////////////////////////////////////////////////////////////////////////////////////////////
  534. EAudioRequestStatus CAudioSystemImpl_wwise::Release()
  535. {
  536. // Deleting this object and destroying the allocator has been moved to AudioEngineWwiseSystemComponent
  537. return EAudioRequestStatus::Success;
  538. }
  539. ///////////////////////////////////////////////////////////////////////////////////////////////////
  540. EAudioRequestStatus CAudioSystemImpl_wwise::StopAllSounds()
  541. {
  542. AK::SoundEngine::StopAll();
  543. return EAudioRequestStatus::Success;
  544. }
  545. ///////////////////////////////////////////////////////////////////////////////////////////////////
  546. EAudioRequestStatus CAudioSystemImpl_wwise::RegisterAudioObject(
  547. IATLAudioObjectData* const audioObjectData,
  548. const char* const objectName)
  549. {
  550. if (audioObjectData)
  551. {
  552. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  553. const AKRESULT akResult = AK::SoundEngine::RegisterGameObj(implObjectData->nAKID, objectName);
  554. const bool akSuccess = IS_WWISE_OK(akResult);
  555. if (!akSuccess)
  556. {
  557. AZLOG_WARN("AK::SoundEngine::RegisterGameObj() returned AKRESULT %d", akResult);
  558. }
  559. return BoolToARS(akSuccess);
  560. }
  561. else
  562. {
  563. AZLOG_WARN("%s", "RegisterAudioObject failed, audioObjectData was null");
  564. return EAudioRequestStatus::Failure;
  565. }
  566. }
  567. ///////////////////////////////////////////////////////////////////////////////////////////////////
  568. EAudioRequestStatus CAudioSystemImpl_wwise::UnregisterAudioObject(IATLAudioObjectData* const audioObjectData)
  569. {
  570. if (audioObjectData)
  571. {
  572. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  573. const AKRESULT akResult = AK::SoundEngine::UnregisterGameObj(implObjectData->nAKID);
  574. const bool akSuccess = IS_WWISE_OK(akResult);
  575. if (!akSuccess)
  576. {
  577. AZLOG_WARN("AK::SoundEngine::UnregisterGameObj() returned AKRESULT %d", akResult);
  578. }
  579. return BoolToARS(akSuccess);
  580. }
  581. else
  582. {
  583. AZLOG_WARN("%s", "UnregisterAudioObject failed, audioObjectData was null");
  584. return EAudioRequestStatus::Failure;
  585. }
  586. }
  587. ///////////////////////////////////////////////////////////////////////////////////////////////////
  588. EAudioRequestStatus CAudioSystemImpl_wwise::ResetAudioObject(IATLAudioObjectData* const audioObjectData)
  589. {
  590. if (audioObjectData)
  591. {
  592. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  593. implObjectData->cEnvironmentImplAmounts.clear();
  594. implObjectData->bNeedsToUpdateEnvironments = false;
  595. return EAudioRequestStatus::Success;
  596. }
  597. else
  598. {
  599. AZLOG_WARN("%s", "ResetAudioObject failed, audioObjectData was null");
  600. return EAudioRequestStatus::Failure;
  601. }
  602. }
  603. ///////////////////////////////////////////////////////////////////////////////////////////////////
  604. EAudioRequestStatus CAudioSystemImpl_wwise::UpdateAudioObject(IATLAudioObjectData* const audioObjectData)
  605. {
  606. AZ_PROFILE_FUNCTION(Audio);
  607. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  608. if (audioObjectData)
  609. {
  610. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  611. if (implObjectData->bNeedsToUpdateEnvironments)
  612. {
  613. result = PostEnvironmentAmounts(implObjectData);
  614. }
  615. }
  616. return result;
  617. }
  618. ///////////////////////////////////////////////////////////////////////////////////////////////////
  619. EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerSync(
  620. [[maybe_unused]] IATLAudioObjectData* const audioObjectData,
  621. const IATLTriggerImplData* const triggerData)
  622. {
  623. return PrepUnprepTriggerSync(triggerData, true);
  624. }
  625. ///////////////////////////////////////////////////////////////////////////////////////////////////
  626. EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerSync(
  627. [[maybe_unused]] IATLAudioObjectData* const audioObjectData,
  628. const IATLTriggerImplData* const triggerData)
  629. {
  630. return PrepUnprepTriggerSync(triggerData, false);
  631. }
  632. ///////////////////////////////////////////////////////////////////////////////////////////////////
  633. EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerAsync(
  634. [[maybe_unused]] IATLAudioObjectData* const audioObjectData,
  635. const IATLTriggerImplData* const triggerData,
  636. IATLEventData* const eventData)
  637. {
  638. return PrepUnprepTriggerAsync(triggerData, eventData, true);
  639. }
  640. ///////////////////////////////////////////////////////////////////////////////////////////////////
  641. EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerAsync(
  642. [[maybe_unused]] IATLAudioObjectData* const audioObjectData,
  643. const IATLTriggerImplData* const triggerData,
  644. IATLEventData* const eventData)
  645. {
  646. return PrepUnprepTriggerAsync(triggerData, eventData, false);
  647. }
  648. ///////////////////////////////////////////////////////////////////////////////////////////////////
  649. EAudioRequestStatus CAudioSystemImpl_wwise::ActivateTrigger(
  650. IATLAudioObjectData* const audioObjectData,
  651. const IATLTriggerImplData* const triggerData,
  652. IATLEventData* const eventData,
  653. const SATLSourceData* const sourceData)
  654. {
  655. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  656. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  657. auto const implTriggerData = static_cast<const SATLTriggerImplData_wwise*>(triggerData);
  658. auto const implEventData = static_cast<SATLEventData_wwise*>(eventData);
  659. if (implObjectData && implTriggerData && implEventData)
  660. {
  661. AkGameObjectID akObjectId = (implObjectData->bHasPosition ? implObjectData->nAKID : m_globalGameObjectID);
  662. if (implObjectData->bHasPosition)
  663. {
  664. PostEnvironmentAmounts(implObjectData);
  665. }
  666. AkPlayingID akPlayingId = AK_INVALID_PLAYING_ID;
  667. switch (GetAssetType(sourceData))
  668. {
  669. case eAAT_SOURCE:
  670. {
  671. AZ_Assert(sourceData, "SourceData not provided for source type!");
  672. // format: "external/{collection_id}/{language_id}/{file_id}.wem"
  673. auto filePath = AZStd::string::format("%s/%llu/%llu/%llu.wem",
  674. Audio::Wwise::ExternalSourcesPath,
  675. sourceData->m_sourceInfo.m_collectionId,
  676. sourceData->m_sourceInfo.m_languageId,
  677. sourceData->m_sourceInfo.m_fileId);
  678. AkOSChar* finalFilePath = nullptr;
  679. CONVERT_CHAR_TO_OSCHAR(filePath.c_str(), finalFilePath);
  680. AkExternalSourceInfo sources[1];
  681. sources[0].iExternalSrcCookie = static_cast<AkUInt32>(sourceData->m_sourceInfo.m_sourceId);
  682. sources[0].szFile = finalFilePath;
  683. sources[0].idCodec = GetAkCodecID(sourceData->m_sourceInfo.m_codecType);
  684. akPlayingId = AK::SoundEngine::PostEvent(
  685. implTriggerData->nAKID,
  686. akObjectId,
  687. AK_EndOfEvent,
  688. &WwiseEventCallback,
  689. implEventData,
  690. 1,
  691. sources);
  692. if (akPlayingId != AK_INVALID_PLAYING_ID)
  693. {
  694. implEventData->audioEventState = eAES_PLAYING;
  695. implEventData->nAKID = akPlayingId;
  696. result = EAudioRequestStatus::Success;
  697. }
  698. else
  699. {
  700. // if Posting an Event failed, try to prepare it, if it isn't prepared already
  701. AZLOG_WARN("Failed to post Wwise event %u with external source '%s'", implTriggerData->nAKID, filePath.c_str());
  702. }
  703. break;
  704. }
  705. case eAAT_STREAM:
  706. [[fallthrough]];
  707. case eAAT_NONE:
  708. [[fallthrough]];
  709. default:
  710. {
  711. akPlayingId = AK::SoundEngine::PostEvent(
  712. implTriggerData->nAKID,
  713. akObjectId,
  714. AK_EndOfEvent | AK_Duration,
  715. &WwiseEventCallback,
  716. implEventData);
  717. if (akPlayingId != AK_INVALID_PLAYING_ID)
  718. {
  719. if (sourceData)
  720. {
  721. TAudioSourceId sourceId = sourceData->m_sourceInfo.m_sourceId;
  722. if (sourceId != INVALID_AUDIO_SOURCE_ID)
  723. {
  724. // Activate the audio input source (associates sourceId w/ playingId)...
  725. AudioSourceManager::Get().ActivateSource(sourceId, akPlayingId);
  726. implEventData->nSourceId = sourceId;
  727. }
  728. }
  729. implEventData->audioEventState = eAES_PLAYING;
  730. implEventData->nAKID = akPlayingId;
  731. result = EAudioRequestStatus::Success;
  732. }
  733. else
  734. {
  735. // if Posting an Event failed, try to prepare it, if it isn't prepared already
  736. AZLOG_WARN("Failed to post Wwise event %u", implTriggerData->nAKID);
  737. }
  738. break;
  739. }
  740. }
  741. }
  742. else
  743. {
  744. AZLOG_ERROR("%s", "Invalid AudioObjectData, ATLTriggerData, or EventData passed to ActivateTrigger");
  745. }
  746. return result;
  747. }
  748. ///////////////////////////////////////////////////////////////////////////////////////////////////
  749. EAudioRequestStatus CAudioSystemImpl_wwise::StopEvent(
  750. [[maybe_unused]] IATLAudioObjectData* const audioObjectData,
  751. const IATLEventData* const eventData)
  752. {
  753. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  754. auto const implEventData = static_cast<const SATLEventData_wwise*>(eventData);
  755. if (implEventData)
  756. {
  757. switch (implEventData->audioEventState)
  758. {
  759. case eAES_PLAYING:
  760. {
  761. AK::SoundEngine::StopPlayingID(implEventData->nAKID, 10);
  762. result = EAudioRequestStatus::Success;
  763. break;
  764. }
  765. default:
  766. {
  767. AZLOG_ERROR("%s", "Stopping an event in this state is not supported yet");
  768. break;
  769. }
  770. }
  771. }
  772. else
  773. {
  774. AZLOG_ERROR("%s", "Invalid EventData passed to StopEvent");
  775. }
  776. return result;
  777. }
  778. ///////////////////////////////////////////////////////////////////////////////////////////////////
  779. EAudioRequestStatus CAudioSystemImpl_wwise::StopAllEvents(IATLAudioObjectData* const audioObjectData)
  780. {
  781. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  782. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  783. if (implObjectData)
  784. {
  785. const AkGameObjectID akObjectId = implObjectData->bHasPosition ? implObjectData->nAKID : m_globalGameObjectID;
  786. AK::SoundEngine::StopAll(akObjectId);
  787. result = EAudioRequestStatus::Success;
  788. }
  789. else
  790. {
  791. AZLOG_ERROR("%s", "Invalid AudioObjectData passed to StopAllEvents");
  792. }
  793. return result;
  794. }
  795. ///////////////////////////////////////////////////////////////////////////////////////////////////
  796. EAudioRequestStatus CAudioSystemImpl_wwise::SetPosition(
  797. IATLAudioObjectData* const audioObjectData,
  798. const SATLWorldPosition& worldPosition)
  799. {
  800. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  801. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  802. if (implObjectData)
  803. {
  804. AkSoundPosition akSoundPos;
  805. ATLTransformToAkTransform(worldPosition, akSoundPos);
  806. const AKRESULT akResult = AK::SoundEngine::SetPosition(implObjectData->nAKID, akSoundPos);
  807. if (IS_WWISE_OK(akResult))
  808. {
  809. result = EAudioRequestStatus::Success;
  810. }
  811. else
  812. {
  813. AZLOG_WARN("AK::SoundEngine::SetPosition() returned AKRESULT %d", akResult);
  814. }
  815. }
  816. else
  817. {
  818. AZLOG_ERROR("%s", "Invalid AudioObjectData passed to SetPosition");
  819. }
  820. return result;
  821. }
  822. ///////////////////////////////////////////////////////////////////////////////////////////////////
  823. EAudioRequestStatus CAudioSystemImpl_wwise::SetMultiplePositions(
  824. IATLAudioObjectData* const audioObjectData,
  825. const MultiPositionParams& multiPositionParams)
  826. {
  827. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  828. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  829. if (implObjectData)
  830. {
  831. AZStd::vector<AkSoundPosition> akPositions;
  832. AZStd::for_each(multiPositionParams.m_positions.begin(), multiPositionParams.m_positions.end(),
  833. [&akPositions](const auto& position)
  834. {
  835. akPositions.emplace_back(AZVec3ToAkTransform(position));
  836. }
  837. );
  838. AK::SoundEngine::MultiPositionType type = AK::SoundEngine::MultiPositionType_MultiDirections; // default 'Blended'
  839. if (multiPositionParams.m_type == MultiPositionBehaviorType::Separate)
  840. {
  841. type = AK::SoundEngine::MultiPositionType_MultiSources;
  842. }
  843. const AKRESULT akResult = AK::SoundEngine::SetMultiplePositions(implObjectData->nAKID, akPositions.data(), static_cast<AkUInt16>(akPositions.size()), type);
  844. if (IS_WWISE_OK(akResult))
  845. {
  846. result = EAudioRequestStatus::Success;
  847. }
  848. else
  849. {
  850. AZLOG_WARN("AK::SoundEngine::SetMultiplePositions returned AKRESULT %d", akResult);
  851. }
  852. }
  853. else
  854. {
  855. AZLOG_ERROR("%s", "Invalid AudioObjectData passed to SetMultiplePositions");
  856. }
  857. return result;
  858. }
  859. ///////////////////////////////////////////////////////////////////////////////////////////////////
  860. EAudioRequestStatus CAudioSystemImpl_wwise::SetEnvironment(
  861. IATLAudioObjectData* const audioObjectData,
  862. const IATLEnvironmentImplData* const environmentData,
  863. const float amount)
  864. {
  865. static const float s_envEpsilon = 0.0001f;
  866. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  867. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  868. auto const implEnvironmentData = static_cast<const SATLEnvironmentImplData_wwise*>(environmentData);
  869. if (implObjectData && implEnvironmentData)
  870. {
  871. switch (implEnvironmentData->eType)
  872. {
  873. case eWAET_AUX_BUS:
  874. {
  875. float currentAmount = -1.f;
  876. auto it = implObjectData->cEnvironmentImplAmounts.find(implEnvironmentData->nAKBusID);
  877. if (it != implObjectData->cEnvironmentImplAmounts.end())
  878. {
  879. currentAmount = it->second;
  880. }
  881. if (currentAmount == -1.f || !AZ::IsClose(currentAmount, amount, s_envEpsilon))
  882. {
  883. implObjectData->cEnvironmentImplAmounts[implEnvironmentData->nAKBusID] = amount;
  884. implObjectData->bNeedsToUpdateEnvironments = true;
  885. }
  886. result = EAudioRequestStatus::Success;
  887. break;
  888. }
  889. case eWAET_RTPC:
  890. {
  891. auto akRtpcValue = static_cast<AkRtpcValue>(implEnvironmentData->fMult * amount + implEnvironmentData->fShift);
  892. const AKRESULT akResult = AK::SoundEngine::SetRTPCValue(implEnvironmentData->nAKRtpcID, akRtpcValue, implObjectData->nAKID);
  893. if (IS_WWISE_OK(akResult))
  894. {
  895. result = EAudioRequestStatus::Success;
  896. }
  897. else
  898. {
  899. AZLOG_WARN("AK::SoundEngine::SetRTPCValue returned AKRESULT %d", akResult);
  900. }
  901. break;
  902. }
  903. default:
  904. {
  905. AZ_Assert(false, "<Wwise> Unknown AudioEnvironmentImplementation type!");
  906. }
  907. }
  908. }
  909. else
  910. {
  911. AZLOG_ERROR("%s", "Invalid AudioObjectData or EnvironmentData passed to SetEnvironment");
  912. }
  913. return result;
  914. }
  915. ///////////////////////////////////////////////////////////////////////////////////////////////////
  916. EAudioRequestStatus CAudioSystemImpl_wwise::SetRtpc(
  917. IATLAudioObjectData* const audioObjectData,
  918. const IATLRtpcImplData* const rtpcData,
  919. const float value)
  920. {
  921. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  922. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  923. auto const implRtpcData = static_cast<const SATLRtpcImplData_wwise*>(rtpcData);
  924. if (implObjectData && implRtpcData)
  925. {
  926. auto akRtpcValue = static_cast<AkRtpcValue>(implRtpcData->m_fMult * value + implRtpcData->m_fShift);
  927. const AKRESULT akResult = AK::SoundEngine::SetRTPCValue(implRtpcData->nAKID, akRtpcValue, implObjectData->nAKID);
  928. if (IS_WWISE_OK(akResult))
  929. {
  930. result = EAudioRequestStatus::Success;
  931. }
  932. else
  933. {
  934. AZLOG_WARN("AK::SoundEngine::SetRTPCValue returned AKRESULT %d", akResult);
  935. }
  936. }
  937. else
  938. {
  939. AZLOG_ERROR("%s", "Invalid AudioObjectData or RtpcData passed to SetRtpc");
  940. }
  941. return result;
  942. }
  943. ///////////////////////////////////////////////////////////////////////////////////////////////////
  944. EAudioRequestStatus CAudioSystemImpl_wwise::SetSwitchState(
  945. IATLAudioObjectData* const audioObjectData,
  946. const IATLSwitchStateImplData* const switchStateData)
  947. {
  948. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  949. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  950. auto const implSwitchStateData = static_cast<const SATLSwitchStateImplData_wwise*>(switchStateData);
  951. if (implObjectData && implSwitchStateData)
  952. {
  953. switch (implSwitchStateData->eType)
  954. {
  955. case eWST_SWITCH:
  956. {
  957. const AkGameObjectID akObjectId = (implObjectData->bHasPosition ? implObjectData->nAKID : m_globalGameObjectID);
  958. const AKRESULT akResult = AK::SoundEngine::SetSwitch(
  959. implSwitchStateData->nAKSwitchID,
  960. implSwitchStateData->nAKStateID,
  961. akObjectId);
  962. if (IS_WWISE_OK(akResult))
  963. {
  964. result = EAudioRequestStatus::Success;
  965. }
  966. else
  967. {
  968. AZLOG_WARN("AK::SoundEngine::SetSwitch() returned AKRESULT %d", akResult);
  969. }
  970. break;
  971. }
  972. case eWST_STATE:
  973. {
  974. const AKRESULT akResult = AK::SoundEngine::SetState(
  975. implSwitchStateData->nAKSwitchID,
  976. implSwitchStateData->nAKStateID);
  977. if (IS_WWISE_OK(akResult))
  978. {
  979. result = EAudioRequestStatus::Success;
  980. }
  981. else
  982. {
  983. AZLOG_WARN("AK::SoundEngine::SetState() returned AKRESULT %d", akResult);
  984. }
  985. break;
  986. }
  987. case eWST_RTPC:
  988. {
  989. const AkGameObjectID akObjectId = implObjectData->nAKID;
  990. const AKRESULT akResult = AK::SoundEngine::SetRTPCValue(
  991. implSwitchStateData->nAKSwitchID,
  992. static_cast<AkRtpcValue>(implSwitchStateData->fRtpcValue),
  993. akObjectId);
  994. if (IS_WWISE_OK(akResult))
  995. {
  996. result = EAudioRequestStatus::Success;
  997. }
  998. else
  999. {
  1000. AZLOG_WARN("AK::SoundEngine::SetRTPCValue() returned AKRESULT %d", akResult);
  1001. }
  1002. break;
  1003. }
  1004. case eWST_NONE:
  1005. {
  1006. break;
  1007. }
  1008. default:
  1009. {
  1010. AZ_Assert(false, "<Wwise> Unknown EWwiseSwitchType");
  1011. break;
  1012. }
  1013. }
  1014. }
  1015. else
  1016. {
  1017. AZLOG_ERROR("%s", "Invalid AudioObjectData or SwitchStateData passed to SetSwitchState");
  1018. }
  1019. return result;
  1020. }
  1021. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1022. EAudioRequestStatus CAudioSystemImpl_wwise::SetObstructionOcclusion(
  1023. IATLAudioObjectData* const audioObjectData,
  1024. const float obstruction,
  1025. const float occlusion)
  1026. {
  1027. if (obstruction < ObstructionOcclusionMin || obstruction > ObstructionOcclusionMax)
  1028. {
  1029. AZLOG_WARN(
  1030. "Obstruction value %f is out of range, Obstruction should be in range [%f, %f]", obstruction, ObstructionOcclusionMin,
  1031. ObstructionOcclusionMax);
  1032. }
  1033. if (occlusion < ObstructionOcclusionMin || occlusion > ObstructionOcclusionMax)
  1034. {
  1035. AZLOG_WARN(
  1036. "Occlusion value %f is out of range, Occlusion should be in range [%f, %f]", occlusion, ObstructionOcclusionMin,
  1037. ObstructionOcclusionMax);
  1038. }
  1039. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1040. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  1041. if (implObjectData)
  1042. {
  1043. const AKRESULT akResult = AK::SoundEngine::SetObjectObstructionAndOcclusion(
  1044. implObjectData->nAKID,
  1045. m_defaultListenerGameObjectID, // only set the obstruction/occlusion for the default listener for now
  1046. static_cast<AkReal32>(obstruction),
  1047. static_cast<AkReal32>(occlusion));
  1048. if (IS_WWISE_OK(akResult))
  1049. {
  1050. result = EAudioRequestStatus::Success;
  1051. }
  1052. else
  1053. {
  1054. AZLOG_WARN("AK::SoundEngine::SetObjectObstructionAndOcclusion() returned AKRESULT %d", akResult);
  1055. }
  1056. }
  1057. else
  1058. {
  1059. AZLOG_ERROR("%s", "Invalid AudioObjectData passed to SetObjectObstructionAndOcclusion");
  1060. }
  1061. return result;
  1062. }
  1063. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1064. EAudioRequestStatus CAudioSystemImpl_wwise::SetListenerPosition(
  1065. IATLListenerData* const listenerData,
  1066. const SATLWorldPosition& newPosition)
  1067. {
  1068. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1069. auto const implListenerData = static_cast<SATLListenerData_wwise*>(listenerData);
  1070. if (implListenerData)
  1071. {
  1072. AkListenerPosition akListenerPos;
  1073. ATLTransformToAkTransform(newPosition, akListenerPos);
  1074. const AKRESULT akResult = AK::SoundEngine::SetPosition(implListenerData->nAKListenerObjectId, akListenerPos);
  1075. if (IS_WWISE_OK(akResult))
  1076. {
  1077. result = EAudioRequestStatus::Success;
  1078. }
  1079. else
  1080. {
  1081. AZLOG_WARN("AK::SoundEngine::SetPosition() returned AKRESULT %d", akResult);
  1082. }
  1083. }
  1084. else
  1085. {
  1086. AZLOG_ERROR("%s", "Invalid ListenerData passed to SetListenerPosition");
  1087. }
  1088. return result;
  1089. }
  1090. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1091. EAudioRequestStatus CAudioSystemImpl_wwise::ResetRtpc(IATLAudioObjectData* const audioObjectData, const IATLRtpcImplData* const rtpcData)
  1092. {
  1093. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1094. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  1095. auto const implRtpcDat = static_cast<const SATLRtpcImplData_wwise*>(rtpcData);
  1096. if (implObjectData && implRtpcDat)
  1097. {
  1098. const AKRESULT akResult = AK::SoundEngine::ResetRTPCValue(implRtpcDat->nAKID, implObjectData->nAKID);
  1099. if (IS_WWISE_OK(akResult))
  1100. {
  1101. result = EAudioRequestStatus::Success;
  1102. }
  1103. else
  1104. {
  1105. AZLOG_WARN("AK::SoundEngine::ResetRTPCValue() returned AKRESULT %d", akResult);
  1106. }
  1107. }
  1108. else
  1109. {
  1110. AZLOG_ERROR("%s", "Invalid AudioObjectData or RtpcData passed to ResetRtpc");
  1111. }
  1112. return result;
  1113. }
  1114. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1115. EAudioRequestStatus CAudioSystemImpl_wwise::RegisterInMemoryFile(SATLAudioFileEntryInfo* const fileEntryInfo)
  1116. {
  1117. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1118. if (fileEntryInfo)
  1119. {
  1120. auto const implFileEntryData = static_cast<SATLAudioFileEntryData_wwise*>(fileEntryInfo->pImplData);
  1121. if (implFileEntryData)
  1122. {
  1123. AkBankID akBankId = AK_INVALID_BANK_ID;
  1124. const AKRESULT akResult = AK::SoundEngine::LoadBankMemoryView(
  1125. fileEntryInfo->pFileData,
  1126. aznumeric_cast<AkUInt32>(fileEntryInfo->nSize),
  1127. akBankId);
  1128. if (IS_WWISE_OK(akResult))
  1129. {
  1130. implFileEntryData->nAKBankID = akBankId;
  1131. result = EAudioRequestStatus::Success;
  1132. }
  1133. else
  1134. {
  1135. implFileEntryData->nAKBankID = AK_INVALID_BANK_ID;
  1136. AZLOG_WARN("AK::SoundEngine::LoadBankMemoryView() returned AKRESULT %d", akResult);
  1137. }
  1138. }
  1139. else
  1140. {
  1141. AZLOG_ERROR("%s", "Invalid AudioFileEntryData passed to RegisterInMemoryFile");
  1142. }
  1143. }
  1144. return result;
  1145. }
  1146. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1147. EAudioRequestStatus CAudioSystemImpl_wwise::UnregisterInMemoryFile(SATLAudioFileEntryInfo* const fileEntryInfo)
  1148. {
  1149. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1150. if (fileEntryInfo)
  1151. {
  1152. auto const implFileEntryData = static_cast<SATLAudioFileEntryData_wwise*>(fileEntryInfo->pImplData);
  1153. if (implFileEntryData)
  1154. {
  1155. const AKRESULT akResult = AK::SoundEngine::UnloadBank(implFileEntryData->nAKBankID, fileEntryInfo->pFileData);
  1156. if (IS_WWISE_OK(akResult))
  1157. {
  1158. result = EAudioRequestStatus::Success;
  1159. }
  1160. else
  1161. {
  1162. AZLOG_WARN("AK::SoundEngine::UnloadBank() returned AKRESULT %d", akResult);
  1163. }
  1164. }
  1165. else
  1166. {
  1167. AZLOG_ERROR("%s", "Invalid AudioFileEntryData passed to UnregisterInMemoryFile");
  1168. }
  1169. }
  1170. return result;
  1171. }
  1172. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1173. EAudioRequestStatus CAudioSystemImpl_wwise::ParseAudioFileEntry(const AZ::rapidxml::xml_node<char>* audioFileEntryNode, SATLAudioFileEntryInfo* const fileEntryInfo)
  1174. {
  1175. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1176. if (audioFileEntryNode && azstricmp(audioFileEntryNode->name(), WwiseXmlTags::WwiseFileTag) == 0 && fileEntryInfo)
  1177. {
  1178. const char* audioFileEntryName = nullptr;
  1179. auto fileEntryNameAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1180. if (fileEntryNameAttr)
  1181. {
  1182. audioFileEntryName = fileEntryNameAttr->value();
  1183. }
  1184. bool isLocalized = false;
  1185. auto localizedAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::WwiseLocalizedAttribute, 0, false);
  1186. // Legacy Preload support
  1187. if (!localizedAttr)
  1188. {
  1189. localizedAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::Legacy::WwiseLocalizedAttribute, 0, false);
  1190. }
  1191. if (localizedAttr)
  1192. {
  1193. if (azstricmp(localizedAttr->value(), "true") == 0)
  1194. {
  1195. isLocalized = true;
  1196. }
  1197. }
  1198. if (audioFileEntryName && audioFileEntryName[0] != '\0')
  1199. {
  1200. fileEntryInfo->bLocalized = isLocalized;
  1201. fileEntryInfo->sFileName = audioFileEntryName;
  1202. fileEntryInfo->nMemoryBlockAlignment = AK_BANK_PLATFORM_DATA_ALIGNMENT;
  1203. fileEntryInfo->pImplData = azcreate(SATLAudioFileEntryData_wwise, (), Audio::AudioImplAllocator);
  1204. result = EAudioRequestStatus::Success;
  1205. }
  1206. else
  1207. {
  1208. fileEntryInfo->sFileName = nullptr;
  1209. fileEntryInfo->nMemoryBlockAlignment = 0;
  1210. fileEntryInfo->pImplData = nullptr;
  1211. }
  1212. }
  1213. return result;
  1214. }
  1215. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1216. void CAudioSystemImpl_wwise::DeleteAudioFileEntryData(IATLAudioFileEntryData* const oldAudioFileEntry)
  1217. {
  1218. azdestroy(oldAudioFileEntry, Audio::AudioImplAllocator, SATLAudioFileEntryData_wwise);
  1219. }
  1220. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1221. const char* const CAudioSystemImpl_wwise::GetAudioFileLocation(SATLAudioFileEntryInfo* const fileEntryInfo)
  1222. {
  1223. const char* location = nullptr;
  1224. if (fileEntryInfo)
  1225. {
  1226. location = fileEntryInfo->bLocalized ? m_localizedSoundbankFolder.c_str() : m_soundbankFolder.c_str();
  1227. }
  1228. return location;
  1229. }
  1230. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1231. SATLAudioObjectData_wwise* CAudioSystemImpl_wwise::NewGlobalAudioObjectData(const TAudioObjectID objectId)
  1232. {
  1233. AZ_UNUSED(objectId);
  1234. auto newObjectData = azcreate(SATLAudioObjectData_wwise, (AK_INVALID_GAME_OBJECT, false), Audio::AudioImplAllocator);
  1235. return newObjectData;
  1236. }
  1237. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1238. SATLAudioObjectData_wwise* CAudioSystemImpl_wwise::NewAudioObjectData(const TAudioObjectID objectId)
  1239. {
  1240. auto newObjectData = azcreate(SATLAudioObjectData_wwise, (static_cast<AkGameObjectID>(objectId), true), Audio::AudioImplAllocator);
  1241. return newObjectData;
  1242. }
  1243. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1244. void CAudioSystemImpl_wwise::DeleteAudioObjectData(IATLAudioObjectData* const oldObjectData)
  1245. {
  1246. azdestroy(oldObjectData, Audio::AudioImplAllocator, SATLAudioObjectData_wwise);
  1247. }
  1248. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1249. SATLListenerData_wwise* CAudioSystemImpl_wwise::NewDefaultAudioListenerObjectData(const TATLIDType listenerId)
  1250. {
  1251. auto newObjectData = azcreate(SATLListenerData_wwise, (static_cast<AkGameObjectID>(listenerId)), Audio::AudioImplAllocator);
  1252. if (newObjectData)
  1253. {
  1254. auto listenerName = AZStd::string::format("DefaultAudioListener(%llu)", static_cast<AZ::u64>(newObjectData->nAKListenerObjectId));
  1255. AKRESULT akResult = AK::SoundEngine::RegisterGameObj(newObjectData->nAKListenerObjectId, listenerName.c_str());
  1256. if (IS_WWISE_OK(akResult))
  1257. {
  1258. akResult = AK::SoundEngine::SetDefaultListeners(&newObjectData->nAKListenerObjectId, 1);
  1259. if (IS_WWISE_OK(akResult))
  1260. {
  1261. m_defaultListenerGameObjectID = newObjectData->nAKListenerObjectId;
  1262. }
  1263. else
  1264. {
  1265. AZLOG_WARN("AK::SoundEngine::SetDefaultListeners() returned AKRESULT %d", akResult);
  1266. }
  1267. }
  1268. else
  1269. {
  1270. AZLOG_WARN("AK::SoundEngine::RegisterGameObj() returned AKRESULT %d", akResult);
  1271. }
  1272. }
  1273. return newObjectData;
  1274. }
  1275. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1276. SATLListenerData_wwise* CAudioSystemImpl_wwise::NewAudioListenerObjectData(const TATLIDType listenerId)
  1277. {
  1278. auto newObjectData = azcreate(SATLListenerData_wwise, (static_cast<AkGameObjectID>(listenerId)), Audio::AudioImplAllocator);
  1279. if (newObjectData)
  1280. {
  1281. auto listenerName = AZStd::string::format("AudioListener(%llu)", static_cast<AZ::u64>(newObjectData->nAKListenerObjectId));
  1282. AKRESULT akResult = AK::SoundEngine::RegisterGameObj(newObjectData->nAKListenerObjectId, listenerName.c_str());
  1283. if (!IS_WWISE_OK(akResult))
  1284. {
  1285. AZLOG_WARN("AK::SoundEngine::RegisterGameObj() returned AKRESULT %d", akResult);
  1286. }
  1287. }
  1288. return newObjectData;
  1289. }
  1290. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1291. void CAudioSystemImpl_wwise::DeleteAudioListenerObjectData(IATLListenerData* const oldListenerData)
  1292. {
  1293. auto listenerData = static_cast<SATLListenerData_wwise*>(oldListenerData);
  1294. if (listenerData)
  1295. {
  1296. AKRESULT akResult = AK::SoundEngine::UnregisterGameObj(listenerData->nAKListenerObjectId);
  1297. if (IS_WWISE_OK(akResult))
  1298. {
  1299. if (listenerData->nAKListenerObjectId == m_defaultListenerGameObjectID)
  1300. {
  1301. m_defaultListenerGameObjectID = AK_INVALID_GAME_OBJECT;
  1302. }
  1303. }
  1304. else
  1305. {
  1306. AZLOG_WARN("AK::SoundEngine::UnregisterGameObj() returned AKRESULT %d", akResult);
  1307. }
  1308. }
  1309. azdestroy(oldListenerData, Audio::AudioImplAllocator, SATLListenerData_wwise);
  1310. }
  1311. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1312. SATLEventData_wwise* CAudioSystemImpl_wwise::NewAudioEventData(const TAudioEventID eventId)
  1313. {
  1314. auto newObjectData = azcreate(SATLEventData_wwise, (eventId), Audio::AudioImplAllocator);
  1315. return newObjectData;
  1316. }
  1317. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1318. void CAudioSystemImpl_wwise::DeleteAudioEventData(IATLEventData* const oldEventData)
  1319. {
  1320. azdestroy(oldEventData, Audio::AudioImplAllocator, SATLEventData_wwise);
  1321. }
  1322. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1323. void CAudioSystemImpl_wwise::ResetAudioEventData(IATLEventData* const eventData)
  1324. {
  1325. auto const implEventData = static_cast<SATLEventData_wwise*>(eventData);
  1326. if (implEventData)
  1327. {
  1328. implEventData->audioEventState = eAES_NONE;
  1329. implEventData->nAKID = AK_INVALID_UNIQUE_ID;
  1330. implEventData->nSourceId = INVALID_AUDIO_SOURCE_ID;
  1331. }
  1332. }
  1333. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1334. IATLTriggerImplData* CAudioSystemImpl_wwise::NewAudioTriggerImplData(const AZ::rapidxml::xml_node<char>* audioTriggerNode)
  1335. {
  1336. SATLTriggerImplData_wwise* newTriggerImpl = nullptr;
  1337. if (audioTriggerNode && azstricmp(audioTriggerNode->name(), WwiseXmlTags::WwiseEventTag) == 0)
  1338. {
  1339. auto eventNameAttr = audioTriggerNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1340. if (eventNameAttr)
  1341. {
  1342. const char* eventName = eventNameAttr->value();
  1343. const AkUniqueID akId = AK::SoundEngine::GetIDFromString(eventName);
  1344. if (akId != AK_INVALID_UNIQUE_ID)
  1345. {
  1346. newTriggerImpl = azcreate(SATLTriggerImplData_wwise, (akId), Audio::AudioImplAllocator);
  1347. }
  1348. }
  1349. }
  1350. return newTriggerImpl;
  1351. }
  1352. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1353. void CAudioSystemImpl_wwise::DeleteAudioTriggerImplData(IATLTriggerImplData* const oldTriggerImplData)
  1354. {
  1355. azdestroy(oldTriggerImplData, Audio::AudioImplAllocator, SATLTriggerImplData_wwise);
  1356. }
  1357. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1358. IATLRtpcImplData* CAudioSystemImpl_wwise::NewAudioRtpcImplData(const AZ::rapidxml::xml_node<char>* audioRtpcNode)
  1359. {
  1360. SATLRtpcImplData_wwise* newRtpcImpl = nullptr;
  1361. AkRtpcID akRtpcId = AK_INVALID_RTPC_ID;
  1362. float mult = 1.f;
  1363. float shift = 0.f;
  1364. ParseRtpcImpl(audioRtpcNode, akRtpcId, mult, shift);
  1365. if (akRtpcId != AK_INVALID_RTPC_ID)
  1366. {
  1367. newRtpcImpl = azcreate(SATLRtpcImplData_wwise, (akRtpcId, mult, shift), Audio::AudioImplAllocator);
  1368. }
  1369. return newRtpcImpl;
  1370. }
  1371. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1372. void CAudioSystemImpl_wwise::DeleteAudioRtpcImplData(IATLRtpcImplData* const oldRtpcImplData)
  1373. {
  1374. azdestroy(oldRtpcImplData, Audio::AudioImplAllocator, SATLRtpcImplData_wwise);
  1375. }
  1376. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1377. IATLSwitchStateImplData* CAudioSystemImpl_wwise::NewAudioSwitchStateImplData(const AZ::rapidxml::xml_node<char>* audioSwitchNode)
  1378. {
  1379. SATLSwitchStateImplData_wwise* newSwitchImpl = nullptr;
  1380. const char* nodeName = audioSwitchNode->name();
  1381. if (azstricmp(nodeName, WwiseXmlTags::WwiseSwitchTag) == 0)
  1382. {
  1383. newSwitchImpl = ParseWwiseSwitchOrState(audioSwitchNode, eWST_SWITCH);
  1384. }
  1385. else if (azstricmp(nodeName, WwiseXmlTags::WwiseStateTag) == 0)
  1386. {
  1387. newSwitchImpl = ParseWwiseSwitchOrState(audioSwitchNode, eWST_STATE);
  1388. }
  1389. else if (azstricmp(nodeName, WwiseXmlTags::WwiseRtpcSwitchTag) == 0)
  1390. {
  1391. newSwitchImpl = ParseWwiseRtpcSwitch(audioSwitchNode);
  1392. }
  1393. return newSwitchImpl;
  1394. }
  1395. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1396. void CAudioSystemImpl_wwise::DeleteAudioSwitchStateImplData(IATLSwitchStateImplData* const oldSwitchStateImplData)
  1397. {
  1398. azdestroy(oldSwitchStateImplData, Audio::AudioImplAllocator, SATLSwitchStateImplData_wwise);
  1399. }
  1400. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1401. IATLEnvironmentImplData* CAudioSystemImpl_wwise::NewAudioEnvironmentImplData(const AZ::rapidxml::xml_node<char>* audioEnvironmentNode)
  1402. {
  1403. SATLEnvironmentImplData_wwise* newEnvironmentImpl = nullptr;
  1404. if (azstricmp(audioEnvironmentNode->name(), WwiseXmlTags::WwiseAuxBusTag) == 0)
  1405. {
  1406. auto auxBusNameAttr = audioEnvironmentNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1407. if (auxBusNameAttr)
  1408. {
  1409. const char* auxBusName = auxBusNameAttr->value();
  1410. const AkUniqueID akBusId = AK::SoundEngine::GetIDFromString(auxBusName);
  1411. if (akBusId != AK_INVALID_AUX_ID)
  1412. {
  1413. newEnvironmentImpl = azcreate(SATLEnvironmentImplData_wwise, (eWAET_AUX_BUS, static_cast<AkAuxBusID>(akBusId)), Audio::AudioImplAllocator);
  1414. }
  1415. }
  1416. }
  1417. else if (azstricmp(audioEnvironmentNode->name(), WwiseXmlTags::WwiseRtpcTag) == 0)
  1418. {
  1419. AkRtpcID akRtpcId = AK_INVALID_RTPC_ID;
  1420. float mult = 1.f;
  1421. float shift = 0.f;
  1422. ParseRtpcImpl(audioEnvironmentNode, akRtpcId, mult, shift);
  1423. if (akRtpcId != AK_INVALID_RTPC_ID)
  1424. {
  1425. newEnvironmentImpl = azcreate(SATLEnvironmentImplData_wwise, (eWAET_RTPC, akRtpcId, mult, shift), Audio::AudioImplAllocator);
  1426. }
  1427. }
  1428. return newEnvironmentImpl;
  1429. }
  1430. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1431. void CAudioSystemImpl_wwise::DeleteAudioEnvironmentImplData(IATLEnvironmentImplData* const oldEnvironmentImplData)
  1432. {
  1433. azdestroy(oldEnvironmentImplData, Audio::AudioImplAllocator, SATLEnvironmentImplData_wwise);
  1434. }
  1435. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1436. const char* const CAudioSystemImpl_wwise::GetImplementationNameString() const
  1437. {
  1438. #if !defined(WWISE_RELEASE)
  1439. return m_fullImplString.c_str();
  1440. #else
  1441. return nullptr;
  1442. #endif // !WWISE_RELEASE
  1443. }
  1444. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1445. void CAudioSystemImpl_wwise::GetMemoryInfo(SAudioImplMemoryInfo& memoryInfo) const
  1446. {
  1447. memoryInfo.nPrimaryPoolSize = AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().Capacity();
  1448. memoryInfo.nPrimaryPoolUsedSize = memoryInfo.nPrimaryPoolSize - AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().GetUnAllocatedMemory();
  1449. memoryInfo.nPrimaryPoolAllocations = 0;
  1450. memoryInfo.nSecondaryPoolSize = 0;
  1451. memoryInfo.nSecondaryPoolUsedSize = 0;
  1452. memoryInfo.nSecondaryPoolAllocations = 0;
  1453. }
  1454. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1455. AZStd::vector<AudioImplMemoryPoolInfo> CAudioSystemImpl_wwise::GetMemoryPoolInfo()
  1456. {
  1457. #if !defined(WWISE_RELEASE)
  1458. // Update memory category info...
  1459. for (auto& memInfo : m_debugMemoryInfo)
  1460. {
  1461. if (memInfo.m_poolId < 0)
  1462. {
  1463. break;
  1464. }
  1465. AK::MemoryMgr::CategoryStats categoryStats;
  1466. AK::MemoryMgr::GetCategoryStats(memInfo.m_poolId, categoryStats);
  1467. memInfo.m_memoryUsed = static_cast<AZ::u32>(categoryStats.uUsed);
  1468. memInfo.m_peakUsed = static_cast<AZ::u32>(categoryStats.uPeakUsed);
  1469. memInfo.m_numAllocs = categoryStats.uAllocs;
  1470. memInfo.m_numFrees = categoryStats.uFrees;
  1471. }
  1472. AK::MemoryMgr::GlobalStats globalStats;
  1473. AK::MemoryMgr::GetGlobalStats(globalStats);
  1474. auto& memInfo = m_debugMemoryInfo.back();
  1475. memInfo.m_memoryReserved = static_cast<AZ::u32>(globalStats.uReserved);
  1476. memInfo.m_memoryUsed = static_cast<AZ::u32>(globalStats.uUsed);
  1477. memInfo.m_peakUsed = static_cast<AZ::u32>(globalStats.uMax);
  1478. // return the memory infos...
  1479. return m_debugMemoryInfo;
  1480. #else
  1481. return AZStd::vector<AudioImplMemoryPoolInfo>();
  1482. #endif // !WWISE_RELEASE
  1483. }
  1484. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1485. bool CAudioSystemImpl_wwise::CreateAudioSource(const SAudioInputConfig& sourceConfig)
  1486. {
  1487. return AudioSourceManager::Get().CreateSource(sourceConfig);
  1488. }
  1489. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1490. void CAudioSystemImpl_wwise::DestroyAudioSource(TAudioSourceId sourceId)
  1491. {
  1492. AudioSourceManager::Get().DestroySource(sourceId);
  1493. }
  1494. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1495. void CAudioSystemImpl_wwise::SetPanningMode(PanningMode mode)
  1496. {
  1497. AkPanningRule panningRule;
  1498. switch (mode)
  1499. {
  1500. case PanningMode::Speakers:
  1501. panningRule = AkPanningRule_Speakers;
  1502. break;
  1503. case PanningMode::Headphones:
  1504. panningRule = AkPanningRule_Headphones;
  1505. break;
  1506. default:
  1507. return;
  1508. }
  1509. AKRESULT akResult = AK::SoundEngine::SetPanningRule(panningRule);
  1510. if (!IS_WWISE_OK(akResult))
  1511. {
  1512. AZLOG_WARN("AK::SoundEngine::SetPanningRule() returned AKRESULT %d", akResult);
  1513. }
  1514. }
  1515. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1516. SATLSwitchStateImplData_wwise* CAudioSystemImpl_wwise::ParseWwiseSwitchOrState(const AZ::rapidxml::xml_node<char>* node, EWwiseSwitchType type)
  1517. {
  1518. SATLSwitchStateImplData_wwise* switchStateImpl = nullptr;
  1519. auto switchNameAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1520. if (switchNameAttr)
  1521. {
  1522. const char* switchName = switchNameAttr->value();
  1523. auto valueNode = node->first_node(WwiseXmlTags::WwiseValueTag, 0, false);
  1524. if (valueNode)
  1525. {
  1526. auto valueNameAttr = valueNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1527. if (valueNameAttr)
  1528. {
  1529. const char* stateName = valueNameAttr->value();
  1530. const AkUniqueID akSGroupId = AK::SoundEngine::GetIDFromString(switchName);
  1531. const AkUniqueID akSNameId = AK::SoundEngine::GetIDFromString(stateName);
  1532. if (akSGroupId != AK_INVALID_UNIQUE_ID && akSNameId != AK_INVALID_UNIQUE_ID)
  1533. {
  1534. switchStateImpl = azcreate(SATLSwitchStateImplData_wwise, (type, akSGroupId, akSNameId), Audio::AudioImplAllocator);
  1535. }
  1536. }
  1537. }
  1538. }
  1539. return switchStateImpl;
  1540. }
  1541. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1542. SATLSwitchStateImplData_wwise* CAudioSystemImpl_wwise::ParseWwiseRtpcSwitch(const AZ::rapidxml::xml_node<char>* node)
  1543. {
  1544. SATLSwitchStateImplData_wwise* switchStateImpl = nullptr;
  1545. if (node && azstricmp(node->name(), WwiseXmlTags::WwiseRtpcSwitchTag) == 0)
  1546. {
  1547. auto rtpcNameAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1548. if (rtpcNameAttr)
  1549. {
  1550. const char* rtpcName = rtpcNameAttr->value();
  1551. float rtpcValue = 0.f;
  1552. auto rtpcValueAttr = node->first_attribute(WwiseXmlTags::WwiseValueAttribute, 0, false);
  1553. if (rtpcValueAttr)
  1554. {
  1555. rtpcValue = AZStd::stof(AZStd::string(rtpcValueAttr->value()));
  1556. const AkUniqueID akRtpcId = AK::SoundEngine::GetIDFromString(rtpcName);
  1557. if (akRtpcId != AK_INVALID_RTPC_ID)
  1558. {
  1559. switchStateImpl = azcreate(SATLSwitchStateImplData_wwise, (eWST_RTPC, akRtpcId, akRtpcId, rtpcValue), Audio::AudioImplAllocator);
  1560. }
  1561. }
  1562. }
  1563. }
  1564. return switchStateImpl;
  1565. }
  1566. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1567. void CAudioSystemImpl_wwise::ParseRtpcImpl(const AZ::rapidxml::xml_node<char>* node, AkRtpcID& akRtpcId, float& mult, float& shift)
  1568. {
  1569. if (node && azstricmp(node->name(), WwiseXmlTags::WwiseRtpcTag) == 0)
  1570. {
  1571. auto rtpcAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false);
  1572. if (rtpcAttr)
  1573. {
  1574. const char* rtpcName = rtpcAttr->value();
  1575. akRtpcId = static_cast<AkRtpcID>(AK::SoundEngine::GetIDFromString(rtpcName));
  1576. if (akRtpcId != AK_INVALID_RTPC_ID)
  1577. {
  1578. auto multAttr = node->first_attribute(WwiseXmlTags::WwiseMutiplierAttribute, 0, false);
  1579. if (multAttr)
  1580. {
  1581. mult = AZStd::stof(AZStd::string(multAttr->value()));
  1582. }
  1583. auto shiftAttr = node->first_attribute(WwiseXmlTags::WwiseShiftAttribute, 0, false);
  1584. if (shiftAttr)
  1585. {
  1586. shift = AZStd::stof(AZStd::string(shiftAttr->value()));
  1587. }
  1588. }
  1589. }
  1590. }
  1591. }
  1592. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1593. EAudioRequestStatus CAudioSystemImpl_wwise::PrepUnprepTriggerSync(
  1594. const IATLTriggerImplData* const triggerData,
  1595. bool prepare)
  1596. {
  1597. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1598. auto const implTriggerData = static_cast<const SATLTriggerImplData_wwise*>(triggerData);
  1599. if (implTriggerData)
  1600. {
  1601. AkUniqueID akUniqueId = implTriggerData->nAKID;
  1602. const AKRESULT akResult = AK::SoundEngine::PrepareEvent(
  1603. prepare ? AK::SoundEngine::Preparation_Load : AK::SoundEngine::Preparation_Unload,
  1604. &akUniqueId,
  1605. 1);
  1606. if (IS_WWISE_OK(akResult))
  1607. {
  1608. result = EAudioRequestStatus::Success;
  1609. }
  1610. else
  1611. {
  1612. AZLOG_WARN("AK::SoundEngine::PrepareEvent() returned AKRESULT %d", akResult);
  1613. }
  1614. }
  1615. else
  1616. {
  1617. AZLOG_ERROR("%s", "Invalid ATLTriggerData or EventData passed to PrepUnprepTriggerSync");
  1618. }
  1619. return result;
  1620. }
  1621. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1622. EAudioRequestStatus CAudioSystemImpl_wwise::PrepUnprepTriggerAsync(
  1623. [[maybe_unused]] const IATLTriggerImplData* const triggerData,
  1624. [[maybe_unused]] IATLEventData* const eventData,
  1625. [[maybe_unused]] bool prepare)
  1626. {
  1627. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1628. #if 0 // Turned off, PrepareEvent is not supported yet.
  1629. auto const implTriggerData = static_cast<const SATLTriggerImplData_wwise*>(triggerData);
  1630. auto const implEventData = static_cast<SATLEventData_wwise*>(eventData);
  1631. if (implTriggerData && implEventData)
  1632. {
  1633. AkUniqueID akUniqueId = implTriggerData->nAKID;
  1634. const AKRESULT akResult = AK::SoundEngine::PrepareEvent(
  1635. prepare ? AK::SoundEngine::Preparation_Load : AK::SoundEngine::Preparation_Unload,
  1636. &akUniqueId,
  1637. 1,
  1638. &PrepareEventCallback,
  1639. implEventData);
  1640. if (IS_WWISE_OK(akResult))
  1641. {
  1642. implEventData->nAKID = akUniqueId;
  1643. implEventData->audioEventState = eAES_UNLOADING;
  1644. result = EAudioRequestStatus::Success;
  1645. }
  1646. else
  1647. {
  1648. g_audioImplLogger_wwise.Log(
  1649. LogType::Warning,
  1650. "Wwise PrepareEvent with %s failed for Wwise event %u with AKRESULT: %u",
  1651. prepare ? "Preparation_Load" : "Preparation_Unload",
  1652. akUniqueId,
  1653. akResult);
  1654. }
  1655. }
  1656. else
  1657. {
  1658. g_audioImplLogger_wwise.Log(LogType::Error,
  1659. "Invalid ATLTriggerData or EventData passed to the Wwise implementation of %sTriggerAsync",
  1660. prepare ? "Prepare" : "Unprepare");
  1661. }
  1662. #endif
  1663. return result;
  1664. }
  1665. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1666. void CAudioSystemImpl_wwise::SetBankPaths()
  1667. {
  1668. // Default...
  1669. // "sounds/wwise/"
  1670. AZStd::string bankPath = Audio::Wwise::DefaultBanksPath;
  1671. // "sounds/wwise/wwise_config.json"
  1672. AZStd::string configFile = bankPath + Audio::Wwise::ConfigFile;
  1673. if (AZ::IO::FileIOBase::GetInstance()
  1674. && AZ::IO::FileIOBase::GetInstance()->Exists(configFile.c_str()))
  1675. {
  1676. Audio::Wwise::ConfigurationSettings configSettings;
  1677. if (configSettings.Load(configFile))
  1678. {
  1679. for (const auto& platformMap : configSettings.m_platformMappings)
  1680. {
  1681. // May need to do a series of checks compare the data in the config settings to what's actually in the file system.
  1682. // This is the most straightforward platform check.
  1683. if (azstricmp(platformMap.m_enginePlatform.c_str(), AZ_TRAIT_OS_PLATFORM_NAME) == 0)
  1684. {
  1685. AZStd::string platformPath;
  1686. // "sounds/wwise/windows"
  1687. AZ::StringFunc::AssetDatabasePath::Join(bankPath.c_str(), platformMap.m_bankSubPath.c_str(), platformPath);
  1688. AZStd::string initBankPath;
  1689. // "sounds/wwise/windows/init.bnk"
  1690. AZ::StringFunc::AssetDatabasePath::Join(platformPath.c_str(), Audio::Wwise::InitBank, initBankPath);
  1691. if (AZ::IO::FileIOBase::GetInstance()->Exists(initBankPath.c_str()))
  1692. {
  1693. if (!platformPath.ends_with(AZ_CORRECT_DATABASE_SEPARATOR))
  1694. {
  1695. platformPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
  1696. }
  1697. bankPath = AZStd::move(platformPath);
  1698. break;
  1699. }
  1700. }
  1701. }
  1702. }
  1703. }
  1704. m_soundbankFolder = bankPath;
  1705. m_localizedSoundbankFolder = bankPath;
  1706. Audio::Wwise::SetBanksRootPath(m_soundbankFolder);
  1707. }
  1708. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1709. bool CAudioSystemImpl_wwise::SEnvPairCompare::operator()(const AZStd::pair<const AkAuxBusID, float>& pair1, const AZStd::pair<const AkAuxBusID, float>& pair2) const
  1710. {
  1711. return (pair1.second > pair2.second);
  1712. }
  1713. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1714. EAudioRequestStatus CAudioSystemImpl_wwise::PostEnvironmentAmounts(IATLAudioObjectData* const audioObjectData)
  1715. {
  1716. EAudioRequestStatus result = EAudioRequestStatus::Failure;
  1717. auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
  1718. if (implObjectData)
  1719. {
  1720. AkAuxSendValue akAuxSendValues[LY_MAX_AUX_PER_OBJ];
  1721. AZ::u32 auxCount = 0;
  1722. SATLAudioObjectData_wwise::TEnvironmentImplMap::iterator envPair = implObjectData->cEnvironmentImplAmounts.begin();
  1723. const SATLAudioObjectData_wwise::TEnvironmentImplMap::const_iterator envBegin = implObjectData->cEnvironmentImplAmounts.begin();
  1724. const SATLAudioObjectData_wwise::TEnvironmentImplMap::const_iterator envEnd = implObjectData->cEnvironmentImplAmounts.end();
  1725. if (implObjectData->cEnvironmentImplAmounts.size() <= LY_MAX_AUX_PER_OBJ)
  1726. {
  1727. for (; envPair != envEnd; ++auxCount)
  1728. {
  1729. const float amount = envPair->second;
  1730. akAuxSendValues[auxCount].auxBusID = envPair->first;
  1731. akAuxSendValues[auxCount].fControlValue = amount;
  1732. akAuxSendValues[auxCount].listenerID = m_defaultListenerGameObjectID; // TODO: Expand api to allow specify listeners
  1733. // If an amount is zero, we still want to send it to the middleware, but we also want to remove it from the map.
  1734. if (amount == 0.0f)
  1735. {
  1736. envPair = implObjectData->cEnvironmentImplAmounts.erase(envPair);
  1737. }
  1738. else
  1739. {
  1740. ++envPair;
  1741. }
  1742. }
  1743. }
  1744. else
  1745. {
  1746. // sort the environments in order of decreasing amounts and take the first LY_MAX_AUX_PER_OBJ worth
  1747. using TEnvPairSet = AZStd::set<SATLAudioObjectData_wwise::TEnvironmentImplMap::value_type, SEnvPairCompare, Audio::AudioImplStdAllocator>;
  1748. TEnvPairSet envPairs(envBegin, envEnd);
  1749. TEnvPairSet::const_iterator sortedEnvPair = envPairs.begin();
  1750. const TEnvPairSet::const_iterator sortedEnvEnd = envPairs.end();
  1751. for (; (sortedEnvPair != sortedEnvEnd) && (auxCount < LY_MAX_AUX_PER_OBJ); ++sortedEnvPair, ++auxCount)
  1752. {
  1753. akAuxSendValues[auxCount].auxBusID = sortedEnvPair->first;
  1754. akAuxSendValues[auxCount].fControlValue = sortedEnvPair->second;
  1755. akAuxSendValues[auxCount].listenerID = m_defaultListenerGameObjectID; // TODO: Expand api to allow specify listeners
  1756. }
  1757. // remove all Environments with 0.0 amounts
  1758. while (envPair != envEnd)
  1759. {
  1760. if (envPair->second == 0.0f)
  1761. {
  1762. envPair = implObjectData->cEnvironmentImplAmounts.erase(envPair);
  1763. }
  1764. else
  1765. {
  1766. ++envPair;
  1767. }
  1768. }
  1769. }
  1770. AZ_Assert(auxCount <= LY_MAX_AUX_PER_OBJ, "WwiseImpl PostEnvironmentAmounts - Exceeded the allowed number of aux environments that can be set!");
  1771. const AKRESULT akResult = AK::SoundEngine::SetGameObjectAuxSendValues(implObjectData->nAKID, akAuxSendValues, auxCount);
  1772. if (IS_WWISE_OK(akResult))
  1773. {
  1774. result = EAudioRequestStatus::Success;
  1775. }
  1776. else
  1777. {
  1778. AZLOG_WARN(
  1779. "AK::SoundEngine::SetGameObjectAuxSendValues() on object %llu returned AKRESULT %u",
  1780. static_cast<AZ::u64>(implObjectData->nAKID), akResult);
  1781. }
  1782. implObjectData->bNeedsToUpdateEnvironments = false;
  1783. }
  1784. return result;
  1785. }
  1786. //////////////////////////////////////////////////////////////////////////
  1787. const char* const CAudioSystemImpl_wwise::GetImplSubPath() const
  1788. {
  1789. return WwiseImplSubPath;
  1790. }
  1791. //////////////////////////////////////////////////////////////////////////
  1792. void CAudioSystemImpl_wwise::SetLanguage(const char* const language)
  1793. {
  1794. if (language)
  1795. {
  1796. AZStd::string languageSubfolder(language);
  1797. languageSubfolder += "/";
  1798. m_localizedSoundbankFolder = m_soundbankFolder;
  1799. m_localizedSoundbankFolder.append(languageSubfolder);
  1800. m_fileIOHandler.SetLanguageFolder(languageSubfolder.c_str());
  1801. }
  1802. }
  1803. } // namespace Audio