/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Sound engine #include // Music Engine #include // Memory Manager #include // Default memory and stream managers #include // Registration of default set of plugins, customize this header to your needs. #if !defined(WWISE_FOR_RELEASE) #include // Communication between Wwise and the game (excluded in release build) #include #include #endif // WWISE_FOR_RELEASE #if defined(AK_MAX_AUX_PER_OBJ) #define LY_MAX_AUX_PER_OBJ AK_MAX_AUX_PER_OBJ #else #define LY_MAX_AUX_PER_OBJ (4) #endif ///////////////////////////////////////////////////////////////////////////////// // AK MEMORY HOOKS SETUP // // ##### REQUIRED ###### // // AK declares these hooks as "extern" functions in AkTypes.h. // Client code is required to give them definitions. // ///////////////////////////////////////////////////////////////////////////////// namespace AK { void* AllocHook(size_t in_size) { return azmalloc(in_size, AUDIO_MEMORY_ALIGNMENT, Audio::AudioImplAllocator, "AudioWwise"); } void FreeHook(void* in_ptr) { azfree(in_ptr, Audio::AudioImplAllocator); } void* VirtualAllocHook(void* in_pMemAddress, size_t in_size, DWORD in_dwAllocationType, DWORD in_dwProtect) { //return VirtualAlloc(in_pMemAddress, in_size, in_dwAllocationType, in_dwProtect); return azmalloc(in_size, AUDIO_MEMORY_ALIGNMENT, Audio::AudioImplAllocator, "AudioWwise"); } void VirtualFreeHook(void* in_pMemAddress, size_t in_size, DWORD in_dwFreeType) { //VirtualFree(in_pMemAddress, in_size, in_dwFreeType); azfree(in_pMemAddress, Audio::AudioImplAllocator); } } namespace Audio { namespace Platform { void SetupAkSoundEngine(AkPlatformInitSettings& platformInitSettings); } extern CAudioLogger g_audioImplLogger_wwise; extern CAudioWwiseImplCVars g_audioImplCVars_wwise; const char* const CAudioSystemImpl_wwise::WwiseImplSubPath = "wwise/"; const char* const CAudioSystemImpl_wwise::WwiseGlobalAudioObjectName = "LY-GlobalAudioObject"; const float CAudioSystemImpl_wwise::ObstructionOcclusionMin = 0.0f; const float CAudioSystemImpl_wwise::ObstructionOcclusionMax = 1.0f; /////////////////////////////////////////////////////////////////////////////////////////////////// // AK callbacks void WwiseEventCallback(AkCallbackType callbackType, AkCallbackInfo* callbackInfo) { if (callbackType == AK_EndOfEvent) { auto const eventData = static_cast(callbackInfo->pCookie); if (eventData) { SAudioRequest request; SAudioCallbackManagerRequestData requestData(eventData->nATLID, true); request.nFlags = eARF_THREAD_SAFE_PUSH; request.pData = &requestData; AudioSystemThreadSafeRequestBus::Broadcast(&AudioSystemThreadSafeRequestBus::Events::PushRequestThreadSafe, request); if (eventData->nSourceId != INVALID_AUDIO_SOURCE_ID) { AkPlayingID playingId = AudioSourceManager::Get().FindPlayingSource(eventData->nSourceId); AudioSourceManager::Get().DeactivateSource(playingId); } } } else if (callbackType == AK_Duration) { auto durationInfo = static_cast(callbackInfo); auto const eventData = static_cast(callbackInfo->pCookie); if (durationInfo && eventData) { AudioTriggerNotificationBus::QueueEvent(eventData->m_triggerId, &AudioTriggerNotificationBus::Events::ReportDurationInfo, eventData->nATLID, durationInfo->fDuration, durationInfo->fEstimatedDuration); } } } static bool audioDeviceInitializationEvent = false; void AudioDeviceCallback( AK::IAkGlobalPluginContext* context, AkUniqueID audioDeviceSharesetId, AkUInt32 deviceId, AK::AkAudioDeviceEvent deviceEvent, AKRESULT inAkResult ) { if (deviceEvent == AK::AkAudioDeviceEvent_Initialization) { audioDeviceInitializationEvent = true; } } /////////////////////////////////////////////////////////////////////////////////////////////////// void PrepareEventCallback( AkUniqueID akEventId, const void* bankPtr, AKRESULT loadResult, AkMemPoolId memPoolId, void* cookie) { auto const eventData = static_cast(cookie); if (eventData) { eventData->nAKID = akEventId; SAudioRequest request; SAudioCallbackManagerRequestData requestData(eventData->nATLID, loadResult == AK_Success); request.nFlags = eARF_THREAD_SAFE_PUSH; request.pData = &requestData; AudioSystemThreadSafeRequestBus::Broadcast(&AudioSystemThreadSafeRequestBus::Events::PushRequestThreadSafe, request); } } /////////////////////////////////////////////////////////////////////////////////////////////////// #if !defined(WWISE_FOR_RELEASE) static void ErrorMonitorCallback( AK::Monitor::ErrorCode in_eErrorCode, ///< Error code number value const AkOSChar* in_pszError, ///< Message or error string to be displayed AK::Monitor::ErrorLevel in_eErrorLevel, ///< Specifies whether it should be displayed as a message or an error AkPlayingID in_playingID, ///< Related Playing ID if applicable, AK_INVALID_PLAYING_ID otherwise AkGameObjectID in_gameObjID ///< Related Game Object ID if applicable, AK_INVALID_GAME_OBJECT otherwise ) { char* errorStr = nullptr; CONVERT_OSCHAR_TO_CHAR(in_pszError, errorStr); g_audioImplLogger_wwise.Log( ((in_eErrorLevel & AK::Monitor::ErrorLevel_Error) != 0) ? eALT_ERROR : eALT_COMMENT, " %s ErrorCode: %d PlayingID: %u GameObjID: %llu", errorStr, in_eErrorCode, in_playingID, in_gameObjID); } #endif // WWISE_FOR_RELEASE /////////////////////////////////////////////////////////////////////////////////////////////////// static int GetAssetType(const SATLSourceData* sourceData) { if (!sourceData) { return eAAT_NONE; } return sourceData->m_sourceInfo.m_codecType == eACT_STREAM_PCM ? eAAT_STREAM : eAAT_SOURCE; } /////////////////////////////////////////////////////////////////////////////////////////////////// static int GetAkCodecID(EAudioCodecType codecType) { switch (codecType) { case eACT_AAC: return AKCODECID_AAC; case eACT_ADPCM: return AKCODECID_ADPCM; case eACT_PCM: return AKCODECID_PCM; case eACT_VORBIS: return AKCODECID_VORBIS; case eACT_XMA: return AKCODECID_XMA; case eACT_XWMA: return AKCODECID_XWMA; case eACT_STREAM_PCM: default: AZ_Assert(codecType, "Codec not supported"); return AKCODECID_VORBIS; } } /////////////////////////////////////////////////////////////////////////////////////////////////// CAudioSystemImpl_wwise::CAudioSystemImpl_wwise(const char* assetsPlatformName) : m_globalGameObjectID(static_cast(GLOBAL_AUDIO_OBJECT_ID)) , m_defaultListenerGameObjectID(AK_INVALID_GAME_OBJECT) , m_initBankID(AK_INVALID_BANK_ID) #if !defined(WWISE_FOR_RELEASE) , m_isCommSystemInitialized(false) #endif // !WWISE_FOR_RELEASE { if (assetsPlatformName && assetsPlatformName[0] != '\0') { m_assetsPlatform = assetsPlatformName; } SetBankPaths(); #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) m_fullImplString = AZStd::string::format("%s (%s)", WWISE_IMPL_VERSION_STRING, m_soundbankFolder.c_str()); #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE AudioSystemImplementationRequestBus::Handler::BusConnect(); AudioSystemImplementationNotificationBus::Handler::BusConnect(); } /////////////////////////////////////////////////////////////////////////////////////////////////// CAudioSystemImpl_wwise::~CAudioSystemImpl_wwise() { AudioSystemImplementationRequestBus::Handler::BusDisconnect(); AudioSystemImplementationNotificationBus::Handler::BusDisconnect(); } /////////////////////////////////////////////////////////////////////////////////////////////////// // AudioSystemImplementationNotificationBus /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::OnAudioSystemLoseFocus() { #if AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND AKRESULT akResult = AK::SoundEngine::Suspend(); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to Suspend, AKRESULT = %d\n", akResult); } #endif // AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::OnAudioSystemGetFocus() { #if AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND AKRESULT akResult = AK::SoundEngine::WakeupFromSuspend(); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to WakeupFromSuspend, AKRESULT = %d\n", akResult); } #endif // AZ_TRAIT_AUDIOENGINEWWISE_AUDIOSYSTEMIMPL_USE_SUSPEND } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::OnAudioSystemMuteAll() { // With Wwise we drive this via events. } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::OnAudioSystemUnmuteAll() { // With Wwise we drive this via events. } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::OnAudioSystemRefresh() { AKRESULT akResult = AK_Fail; if (m_initBankID != AK_INVALID_BANK_ID) { akResult = AK::SoundEngine::UnloadBank(m_initBankID, nullptr); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to unload %s, returned the AKRESULT: %d", Wwise::InitBank, akResult); AZ_Assert(false, " Failed to unload %s!", Wwise::InitBank); } } AkOSChar* initBankName = nullptr; CONVERT_CHAR_TO_OSCHAR(Wwise::InitBank, initBankName); akResult = AK::SoundEngine::LoadBank(initBankName, AK_DEFAULT_POOL_ID, m_initBankID); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to load %s, returned the AKRESULT: %d", Wwise::InitBank, akResult); m_initBankID = AK_INVALID_BANK_ID; AZ_Assert(false, " Failed to load %s!", Wwise::InitBank); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // AudioSystemImplementationRequestBus /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::Update(const float updateIntervalMS) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); if (AK::SoundEngine::IsInitialized()) { #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) AKRESULT akResult = AK_Fail; static int enableOutputCapture = 0; if (g_audioImplCVars_wwise.m_nEnableOutputCapture == 1 && enableOutputCapture == 0) { // This file ends up in the cache folder // Need to disable this on LTX, it produces garbage output. But there's no way to "IsLTX()" yet. akResult = AK::SoundEngine::StartOutputCapture(AKTEXT("../wwise_audio_capture.wav")); AZ_Assert(IS_WWISE_OK(akResult), "AK::SoundEngine::StartOutputCapture failed!"); enableOutputCapture = g_audioImplCVars_wwise.m_nEnableOutputCapture; } else if (g_audioImplCVars_wwise.m_nEnableOutputCapture == 0 && enableOutputCapture == 1) { akResult = AK::SoundEngine::StopOutputCapture(); AZ_Assert(IS_WWISE_OK(akResult), "AK::SoundEngine::StopOutputCapture failed!"); enableOutputCapture = g_audioImplCVars_wwise.m_nEnableOutputCapture; } if (audioDeviceInitializationEvent) { AkChannelConfig channelConfig = AK::SoundEngine::GetSpeakerConfiguration(); int surroundSpeakers = channelConfig.uNumChannels; int lfeSpeakers = 0; if (AK::HasLFE(channelConfig.uChannelMask)) { --surroundSpeakers; ++lfeSpeakers; } m_speakerConfigString = AZStd::string::format("Output: %d.%d", surroundSpeakers, lfeSpeakers); m_fullImplString = AZStd::string::format("%s (%s) %s", WWISE_IMPL_VERSION_STRING, m_soundbankFolder.c_str(), m_speakerConfigString.c_str()); audioDeviceInitializationEvent = false; } #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE AK::SoundEngine::RenderAudio(); } } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::Initialize() { // If something fails so severely during initialization that we need to fall back to the NULL implementation // we will need to shut down what has been initialized so far. Therefore make sure to call Shutdown() before returning eARS_FAILURE! AkMemSettings akMemSettings; akMemSettings.uMaxNumPools = 20; AKRESULT akResult = AK::MemoryMgr::Init(&akMemSettings); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::MemoryMgr::Init() returned AKRESULT %d", akResult); ShutDown(); return eARS_FAILURE; } const AkMemPoolId prepareMemPoolId = AK::MemoryMgr::CreatePool(nullptr, g_audioImplCVars_wwise.m_nPrepareEventMemoryPoolSize << 10, 16, AkMalloc, 16); if (prepareMemPoolId == AK_INVALID_POOL_ID) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::MemoryMgr::CreatePool() PrepareEventMemoryPool failed!\n"); ShutDown(); return eARS_FAILURE; } akResult = AK::MemoryMgr::SetPoolName(prepareMemPoolId, "PrepareEventMemoryPool"); if (akResult != AK_Success) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::MemoryMgr::SetPoolName() could not set name of event prepare memory pool!\n"); ShutDown(); return eARS_FAILURE; } akResult = AK::SoundEngine::RegisterAudioDeviceStatusCallback(AudioDeviceCallback); if (akResult != AK_Success) { g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::SoundEngine::RegisterAudioDeviceStatusCallback failed!\n"); } AkStreamMgrSettings akStreamSettings; AK::StreamMgr::GetDefaultSettings(akStreamSettings); akStreamSettings.uMemorySize = g_audioImplCVars_wwise.m_nStreamManagerMemoryPoolSize << 10; if (AK::StreamMgr::Create(akStreamSettings) == nullptr) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::StreamMgr::Create() failed!\n"); ShutDown(); return eARS_FAILURE; } akResult = m_fileIOHandler.Init(g_audioImplCVars_wwise.m_nStreamDeviceMemoryPoolSize << 10); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "m_fileIOHandler.Init() returned AKRESULT %d", akResult); ShutDown(); return eARS_FAILURE; } m_fileIOHandler.SetBankPath(m_soundbankFolder.c_str()); AkInitSettings akInitSettings; AK::SoundEngine::GetDefaultInitSettings(akInitSettings); akInitSettings.uDefaultPoolSize = g_audioImplCVars_wwise.m_nSoundEngineDefaultMemoryPoolSize << 10; akInitSettings.uCommandQueueSize = g_audioImplCVars_wwise.m_nCommandQueueMemoryPoolSize << 10; #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) akInitSettings.uMonitorPoolSize = g_audioImplCVars_wwise.m_nMonitorMemoryPoolSize << 10; akInitSettings.uMonitorQueuePoolSize = g_audioImplCVars_wwise.m_nMonitorQueueMemoryPoolSize << 10; #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE akInitSettings.uPrepareEventMemoryPoolID = prepareMemPoolId; akInitSettings.bEnableGameSyncPreparation = false;//TODO: ??? #if AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION akInitSettings.settingsMainOutput.channelConfig.SetStandardOrAnonymous( AK::ChannelMaskToNumChannels(AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION), AZ_TRAIT_AUDIOENGINEWWISE_DEFAULT_SPEAKER_CONFIGURATION); #endif AkPlatformInitSettings akPlatformInitSettings; AK::SoundEngine::GetDefaultPlatformInitSettings(akPlatformInitSettings); akPlatformInitSettings.uLEngineDefaultPoolSize = g_audioImplCVars_wwise.m_nLowerEngineDefaultPoolSize << 10; Platform::SetupAkSoundEngine(akPlatformInitSettings); akResult = AK::SoundEngine::Init(&akInitSettings, &akPlatformInitSettings); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::SoundEngine::Init() returned AKRESULT %d", akResult); ShutDown(); return eARS_FAILURE; } AkMusicSettings akMusicSettings; AK::MusicEngine::GetDefaultInitSettings(akMusicSettings); akResult = AK::MusicEngine::Init(&akMusicSettings); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::MusicEngine::Init() returned AKRESULT %d", akResult); ShutDown(); return eARS_FAILURE; } #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) if (g_audioImplCVars_wwise.m_nEnableCommSystem == 1) { m_isCommSystemInitialized = true; AkCommSettings akCommSettings; AK::Comm::GetDefaultInitSettings(akCommSettings); akResult = AK::Comm::Init(akCommSettings); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::Comm::Init() returned AKRESULT %d. Communication between the Wwise authoring application and the game will not be possible\n", akResult); m_isCommSystemInitialized = false; } akResult = AK::Monitor::SetLocalOutput(AK::Monitor::ErrorLevel_All, ErrorMonitorCallback); if (!IS_WWISE_OK(akResult)) { AK::Comm::Term(); g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::Monitor::SetLocalOutput() returned AKRESULT %d", akResult); m_isCommSystemInitialized = false; } } #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE // Initialize the AudioSourceManager AudioSourceManager::Get().Initialize(); // Register the DummyGameObject used for the events that don't need a location in the game world akResult = AK::SoundEngine::RegisterGameObj(m_globalGameObjectID, WwiseGlobalAudioObjectName); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::SoundEngine::RegisterGameObject() failed for '%s' with AKRESULT %d", WwiseGlobalAudioObjectName, akResult); } // Load init.bnk before making the system available to the users AkOSChar* initBankName = nullptr; CONVERT_CHAR_TO_OSCHAR(Wwise::InitBank, initBankName); akResult = AK::SoundEngine::LoadBank(initBankName, AK_DEFAULT_POOL_ID, m_initBankID); if (!IS_WWISE_OK(akResult)) { // This does not qualify for a fallback to the NULL implementation! // Still notify the user about this failure! g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to load %s, returned the AKRESULT: %d", Wwise::InitBank, akResult); m_initBankID = AK_INVALID_BANK_ID; } #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) // Set up memory pool information... AkInt32 numPools = AK::MemoryMgr::GetNumPools(); m_debugMemoryPoolInfo.reserve(numPools); g_audioImplLogger_wwise.Log(eALT_COMMENT, "Number of AK Memory Pools: %d", numPools); for (AkInt32 poolId = 0; poolId < numPools; ++poolId) { akResult = AK::MemoryMgr::CheckPoolId(poolId); if (IS_WWISE_OK(akResult)) { AudioImplMemoryPoolInfo poolInfo; AkOSChar* poolName = AK::MemoryMgr::GetPoolName(poolId); char* nameTemp = nullptr; CONVERT_OSCHAR_TO_CHAR(poolName, nameTemp); AKPLATFORM::SafeStrCpy(poolInfo.m_poolName, nameTemp, AZ_ARRAY_SIZE(poolInfo.m_poolName)); poolInfo.m_poolId = poolId; g_audioImplLogger_wwise.Log(eALT_COMMENT, "Found Wwise Memory Pool: %d - '%s'", poolId, poolInfo.m_poolName); m_debugMemoryPoolInfo.push_back(poolInfo); } } #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE return eARS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::ShutDown() { AKRESULT akResult = AK_Fail; #if !defined(WWISE_FOR_RELEASE) if (m_isCommSystemInitialized) { AK::Comm::Term(); akResult = AK::Monitor::SetLocalOutput(0, nullptr); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::Monitor::SetLocalOutput() returned AKRESULT %d", akResult); } m_isCommSystemInitialized = false; } #endif // !WWISE_FOR_RELEASE akResult = AK::SoundEngine::UnregisterAudioDeviceStatusCallback(); if (akResult != AK_Success) { g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::SoundEngine::UnregisterAudioDeviceStatusCallback failed!\n"); } // Shutdown the AudioSourceManager AudioSourceManager::Get().Shutdown(); AK::MusicEngine::Term(); if (AK::SoundEngine::IsInitialized()) { // UnRegister the DummyGameObject akResult = AK::SoundEngine::UnregisterGameObj(m_globalGameObjectID); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::SoundEngine::UnregisterGameObject() failed for '%s' with AKRESULT %d", WwiseGlobalAudioObjectName, akResult); } akResult = AK::SoundEngine::ClearBanks(); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Failed to clear sound banks!"); } AK::SoundEngine::Term(); } // Terminate the streaming device and streaming manager // CAkFilePackageLowLevelIOBlocking::Term() destroys its associated streaming device // that lives in the Stream Manager, and unregisters itself as the File Location Resolver. if (AK::IAkStreamMgr::Get()) { m_fileIOHandler.ShutDown(); AK::IAkStreamMgr::Get()->Destroy(); } // Terminate the Memory Manager if (AK::MemoryMgr::IsInitialized()) { akResult = AK::MemoryMgr::DestroyPool(0); AK::MemoryMgr::Term(); } return eARS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::Release() { // Deleting this object and destroying the allocator has been moved to AudioEngineWwiseSystemComponent return eARS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::StopAllSounds() { AK::SoundEngine::StopAll(); return eARS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::RegisterAudioObject( IATLAudioObjectData* const audioObjectData, const char* const objectName) { if (audioObjectData) { auto const implObjectData = static_cast(audioObjectData); const AKRESULT akResult = AK::SoundEngine::RegisterGameObj(implObjectData->nAKID, objectName); const bool akSuccess = IS_WWISE_OK(akResult); if (!akSuccess) { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise RegisterGameObj failed with AKRESULT: %d", akResult); } return BoolToARS(akSuccess); } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise RegisterGameObj failed, audioObjectData was null"); return eARS_FAILURE; } } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::UnregisterAudioObject(IATLAudioObjectData* const audioObjectData) { if (audioObjectData) { auto const implObjectData = static_cast(audioObjectData); const AKRESULT akResult = AK::SoundEngine::UnregisterGameObj(implObjectData->nAKID); const bool akSuccess = IS_WWISE_OK(akResult); if (!akSuccess) { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise UnregisterGameObj failed with AKRESULT: %d", akResult); } return BoolToARS(akSuccess); } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise UnregisterGameObj failed, audioObjectData was null"); return eARS_FAILURE; } } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::ResetAudioObject(IATLAudioObjectData* const audioObjectData) { if (audioObjectData) { auto const implObjectData = static_cast(audioObjectData); implObjectData->cEnvironmentImplAmounts.clear(); implObjectData->bNeedsToUpdateEnvironments = false; return eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Resetting Audio object failed, audioObjectData was null"); return eARS_FAILURE; } } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::UpdateAudioObject(IATLAudioObjectData* const audioObjectData) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); EAudioRequestStatus result = eARS_FAILURE; if (audioObjectData) { auto const implObjectData = static_cast(audioObjectData); if (implObjectData->bNeedsToUpdateEnvironments) { result = PostEnvironmentAmounts(implObjectData); } } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerSync( IATLAudioObjectData* const audioObjectData, const IATLTriggerImplData* const triggerData) { return PrepUnprepTriggerSync(triggerData, true); } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerSync( IATLAudioObjectData* const audioObjectData, const IATLTriggerImplData* const triggerData) { return PrepUnprepTriggerSync(triggerData, false); } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerAsync( IATLAudioObjectData* const audioObjectData, const IATLTriggerImplData* const triggerData, IATLEventData* const eventData) { return PrepUnprepTriggerAsync(triggerData, eventData, true); } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerAsync( IATLAudioObjectData* const audioObjectData, const IATLTriggerImplData* const triggerData, IATLEventData* const eventData) { return PrepUnprepTriggerAsync(triggerData, eventData, false); } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::ActivateTrigger( IATLAudioObjectData* const audioObjectData, const IATLTriggerImplData* const triggerData, IATLEventData* const eventData, const SATLSourceData* const sourceData) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); auto const implTriggerData = static_cast(triggerData); auto const implEventData = static_cast(eventData); if (implObjectData && implTriggerData && implEventData) { AkGameObjectID akObjectId = AK_INVALID_GAME_OBJECT; if (implObjectData->bHasPosition) { akObjectId = implObjectData->nAKID; PostEnvironmentAmounts(implObjectData); } else { akObjectId = m_globalGameObjectID; } AkPlayingID akPlayingId = AK_INVALID_PLAYING_ID; switch (GetAssetType(sourceData)) { case eAAT_SOURCE: { AZ_Assert(sourceData, "SourceData not provided for source type!"); // format: "external/{collection_id}/{language_id}/{file_id}.wem" auto sTemp = AZStd::string::format("%s" "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 ".wem", Audio::Wwise::ExternalSourcesPath, sourceData->m_sourceInfo.m_collectionId, sourceData->m_sourceInfo.m_languageId, sourceData->m_sourceInfo.m_fileId); AkOSChar* tempName = nullptr; CONVERT_CHAR_TO_OSCHAR(sTemp.c_str(), tempName); AkExternalSourceInfo sources[1]; sources[0].iExternalSrcCookie = static_cast(sourceData->m_sourceInfo.m_sourceId); sources[0].szFile = tempName; sources[0].idCodec = GetAkCodecID(sourceData->m_sourceInfo.m_codecType); akPlayingId = AK::SoundEngine::PostEvent( implTriggerData->nAKID, akObjectId, AK_EndOfEvent | AK_Duration, &WwiseEventCallback, implEventData, 1, sources); if (akPlayingId != AK_INVALID_PLAYING_ID) { implEventData->audioEventState = eAES_PLAYING; implEventData->nAKID = akPlayingId; result = eARS_SUCCESS; } else { // if Posting an Event failed, try to prepare it, if it isn't prepared already g_audioImplLogger_wwise.Log(eALT_WARNING, "Failed to Post Wwise event %u with external source '%s'", implTriggerData->nAKID, sTemp.c_str()); } break; } case eAAT_STREAM: [[fallthrough]]; case eAAT_NONE: [[fallthrough]]; default: { akPlayingId = AK::SoundEngine::PostEvent( implTriggerData->nAKID, akObjectId, AK_EndOfEvent | AK_Duration, &WwiseEventCallback, implEventData); if (akPlayingId != AK_INVALID_PLAYING_ID) { if (sourceData) { TAudioSourceId sourceId = sourceData->m_sourceInfo.m_sourceId; if (sourceId != INVALID_AUDIO_SOURCE_ID) { // Activate the audio input source (associates sourceId w/ playingId)... AudioSourceManager::Get().ActivateSource(sourceId, akPlayingId); implEventData->nSourceId = sourceId; } } implEventData->audioEventState = eAES_PLAYING; implEventData->nAKID = akPlayingId; result = eARS_SUCCESS; } else { // if Posting an Event failed, try to prepare it, if it isn't prepared already g_audioImplLogger_wwise.Log(eALT_WARNING, "Failed to Post Wwise event %u", implTriggerData->nAKID); } break; } } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData, ATLTriggerData or EventData passed to the Wwise implementation of ActivateTrigger."); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::StopEvent( IATLAudioObjectData* const audioObjectData, const IATLEventData* const eventData) { EAudioRequestStatus result = eARS_FAILURE; auto const implEventData = static_cast(eventData); if (implEventData) { switch (implEventData->audioEventState) { case eAES_PLAYING: { AK::SoundEngine::StopPlayingID(implEventData->nAKID, 10); result = eARS_SUCCESS; break; } default: { g_audioImplLogger_wwise.Log(eALT_ERROR, "Stopping an event of this type is not supported yet"); break; } } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid EventData passed to the Wwise implementation of StopEvent."); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::StopAllEvents(IATLAudioObjectData* const audioObjectData) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); if (implObjectData) { const AkGameObjectID akObjectId = implObjectData->bHasPosition ? implObjectData->nAKID : m_globalGameObjectID; AK::SoundEngine::StopAll(akObjectId); result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData passed to the Wwise implementation of StopAllEvents."); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetPosition( IATLAudioObjectData* const audioObjectData, const SATLWorldPosition& worldPosition) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); if (implObjectData) { AkSoundPosition akSoundPos; ATLTransformToAkTransform(worldPosition, akSoundPos); const AKRESULT akResult = AK::SoundEngine::SetPosition(implObjectData->nAKID, akSoundPos); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise SetPosition failed with AKRESULT: %d", akResult); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData passed to the Wwise implementation of SetPosition."); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetMultiplePositions( IATLAudioObjectData* const audioObjectData, const MultiPositionParams& multiPositionParams) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); if (implObjectData) { AZStd::vector akPositions; AZStd::for_each(multiPositionParams.m_positions.begin(), multiPositionParams.m_positions.end(), [&akPositions](const auto& position) { akPositions.emplace_back(AZVec3ToAkTransform(position)); } ); AK::SoundEngine::MultiPositionType type = AK::SoundEngine::MultiPositionType_MultiDirections; // default 'Blended' if (multiPositionParams.m_type == MultiPositionBehaviorType::Separate) { type = AK::SoundEngine::MultiPositionType_MultiSources; } const AKRESULT akResult = AK::SoundEngine::SetMultiplePositions(implObjectData->nAKID, akPositions.data(), static_cast(akPositions.size()), type); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise SetMultiplePositions failed with AKRESULT: %d\n", akResult); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData passed to the Wwise implementation of SetMultiplePositions."); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetEnvironment( IATLAudioObjectData* const audioObjectData, const IATLEnvironmentImplData* const environmentData, const float amount) { static const float s_envEpsilon = 0.0001f; EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); auto const implEnvironmentData = static_cast(environmentData); if (implObjectData && implEnvironmentData) { switch (implEnvironmentData->eType) { case eWAET_AUX_BUS: { float currentAmount = -1.f; auto it = implObjectData->cEnvironmentImplAmounts.find(implEnvironmentData->nAKBusID); if (it != implObjectData->cEnvironmentImplAmounts.end()) { currentAmount = it->second; } if (currentAmount == -1.f || !AZ::IsClose(currentAmount, amount, s_envEpsilon)) { implObjectData->cEnvironmentImplAmounts[implEnvironmentData->nAKBusID] = amount; implObjectData->bNeedsToUpdateEnvironments = true; } result = eARS_SUCCESS; break; } case eWAET_RTPC: { auto akRtpcValue = static_cast(implEnvironmentData->fMult * amount + implEnvironmentData->fShift); const AKRESULT akResult = AK::SoundEngine::SetRTPCValue(implEnvironmentData->nAKRtpcID, akRtpcValue, implObjectData->nAKID); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set the Rtpc %u to value %f on object %u in SetEnvironement()", implEnvironmentData->nAKRtpcID, akRtpcValue, implObjectData->nAKID); } break; } default: { AZ_Assert(false, " Unknown AudioEnvironmentImplementation type!"); } } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData or EnvironmentData passed to the Wwise implementation of SetEnvironment"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetRtpc( IATLAudioObjectData* const audioObjectData, const IATLRtpcImplData* const rtpcData, const float value) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); auto const implRtpcData = static_cast(rtpcData); if (implObjectData && implRtpcData) { auto akRtpcValue = static_cast(implRtpcData->m_fMult * value + implRtpcData->m_fShift); const AKRESULT akResult = AK::SoundEngine::SetRTPCValue(implRtpcData->nAKID, akRtpcValue, implObjectData->nAKID); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set the Rtpc %llu to value %f on object %llu", implRtpcData->nAKID, static_cast(value), implObjectData->nAKID); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData or RtpcData passed to the Wwise implementation of SetRtpc"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetSwitchState( IATLAudioObjectData* const audioObjectData, const IATLSwitchStateImplData* const switchStateData) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); auto const implSwitchStateData = static_cast(switchStateData); if (implObjectData && implSwitchStateData) { switch (implSwitchStateData->eType) { case eWST_SWITCH: { const AkGameObjectID akObjectId = implObjectData->bHasPosition ? implObjectData->nAKID : m_globalGameObjectID; const AKRESULT akResult = AK::SoundEngine::SetSwitch( implSwitchStateData->nAKSwitchID, implSwitchStateData->nAKStateID, akObjectId); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set the switch group %u to state %u on object %llu", implSwitchStateData->nAKSwitchID, implSwitchStateData->nAKStateID, akObjectId); } break; } case eWST_STATE: { const AKRESULT akResult = AK::SoundEngine::SetState( implSwitchStateData->nAKSwitchID, implSwitchStateData->nAKStateID); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set the state group %u to state %u", implSwitchStateData->nAKSwitchID, implSwitchStateData->nAKStateID); } break; } case eWST_RTPC: { const AkGameObjectID akObjectId = implObjectData->nAKID; const AKRESULT akResult = AK::SoundEngine::SetRTPCValue( implSwitchStateData->nAKSwitchID, static_cast(implSwitchStateData->fRtpcValue), akObjectId); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set the Rtpc %u to value %f on object %llu", implSwitchStateData->nAKSwitchID, static_cast(implSwitchStateData->fRtpcValue), akObjectId); } break; } case eWST_NONE: { break; } default: { g_audioImplLogger_wwise.Log(eALT_WARNING, "Unknown EWwiseSwitchType: %u", implSwitchStateData->eType); AZ_Assert(false, " Unknown EWwiseSwitchType"); break; } } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData or RtpcData passed to the Wwise implementation of SetRtpc"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetObstructionOcclusion( IATLAudioObjectData* const audioObjectData, const float obstruction, const float occlusion) { if (obstruction < ObstructionOcclusionMin || obstruction > ObstructionOcclusionMax) { g_audioImplLogger_wwise.Log( eALT_WARNING, "Obstruction value %f is out of range, Obstruction should be between %f and %f.", obstruction, ObstructionOcclusionMin, ObstructionOcclusionMax); } if (occlusion < ObstructionOcclusionMin || occlusion > ObstructionOcclusionMax) { g_audioImplLogger_wwise.Log( eALT_WARNING, "Occlusion value %f is out of range, Occlusion should be between %f and %f.", occlusion, ObstructionOcclusionMin, ObstructionOcclusionMax); } EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); if (implObjectData) { const AKRESULT akResult = AK::SoundEngine::SetObjectObstructionAndOcclusion( implObjectData->nAKID, m_defaultListenerGameObjectID, // only set the obstruction/occlusion for the default listener for now static_cast(obstruction), static_cast(occlusion)); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to set Obstruction %f and Occlusion %f on object %llu", obstruction, occlusion, implObjectData->nAKID); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData passed to the Wwise implementation of SetObjectObstructionAndOcclusion"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::SetListenerPosition( IATLListenerData* const listenerData, const SATLWorldPosition& newPosition) { EAudioRequestStatus result = eARS_FAILURE; auto const implListenerData = static_cast(listenerData); if (implListenerData) { AkListenerPosition akListenerPos; ATLTransformToAkTransform(newPosition, akListenerPos); const AKRESULT akResult = AK::SoundEngine::SetPosition(implListenerData->nAKListenerObjectId, akListenerPos); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise SetListenerPosition failed with AKRESULT: %u", akResult); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid ATLListenerData passed to the Wwise implementation of SetListenerPosition"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::ResetRtpc(IATLAudioObjectData* const audioObjectData, const IATLRtpcImplData* const rtpcData) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); auto const implRtpcDat = static_cast(rtpcData); if (implObjectData && implRtpcDat) { const AKRESULT akResult = AK::SoundEngine::ResetRTPCValue(implRtpcDat->nAKID, implObjectData->nAKID); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise failed to reset the Rtpc %u on object %llu", implRtpcDat->nAKID, implObjectData->nAKID); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioObjectData or RtpcData passed to the Wwise implementation of ResetRtpc"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::RegisterInMemoryFile(SATLAudioFileEntryInfo* const fileEntryInfo) { EAudioRequestStatus result = eARS_FAILURE; if (fileEntryInfo) { auto const implFileEntryData = static_cast(fileEntryInfo->pImplData); if (implFileEntryData) { AkBankID akBankId = AK_INVALID_BANK_ID; const AKRESULT akResult = AK::SoundEngine::LoadBank( fileEntryInfo->pFileData, static_cast(fileEntryInfo->nSize), akBankId); if (IS_WWISE_OK(akResult)) { implFileEntryData->nAKBankID = akBankId; result = eARS_SUCCESS; } else { implFileEntryData->nAKBankID = AK_INVALID_BANK_ID; g_audioImplLogger_wwise.Log(eALT_ERROR, "Failed to load file %s\n", fileEntryInfo->sFileName); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioFileEntryData passed to the Wwise implementation of RegisterInMemoryFile"); } } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::UnregisterInMemoryFile(SATLAudioFileEntryInfo* const fileEntryInfo) { EAudioRequestStatus result = eARS_FAILURE; if (fileEntryInfo) { auto const implFileEntryData = static_cast(fileEntryInfo->pImplData); if (implFileEntryData) { const AKRESULT akResult = AK::SoundEngine::UnloadBank(implFileEntryData->nAKBankID, fileEntryInfo->pFileData); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise Failed to unregister in memory file %s\n", fileEntryInfo->sFileName); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioFileEntryData passed to the Wwise implementation of UnregisterInMemoryFile"); } } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::ParseAudioFileEntry(const AZ::rapidxml::xml_node* audioFileEntryNode, SATLAudioFileEntryInfo* const fileEntryInfo) { EAudioRequestStatus result = eARS_FAILURE; if (audioFileEntryNode && azstricmp(audioFileEntryNode->name(), WwiseXmlTags::WwiseFileTag) == 0 && fileEntryInfo) { const char* audioFileEntryName = nullptr; auto fileEntryNameAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (fileEntryNameAttr) { audioFileEntryName = fileEntryNameAttr->value(); } bool isLocalized = false; auto localizedAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::WwiseLocalizedAttribute, 0, false); // Legacy Preload support if (!localizedAttr) { localizedAttr = audioFileEntryNode->first_attribute(WwiseXmlTags::Legacy::WwiseLocalizedAttribute, 0, false); } if (localizedAttr) { if (azstricmp(localizedAttr->value(), "true") == 0) { isLocalized = true; } } if (audioFileEntryName && audioFileEntryName[0] != '\0') { fileEntryInfo->bLocalized = isLocalized; fileEntryInfo->sFileName = audioFileEntryName; fileEntryInfo->nMemoryBlockAlignment = AK_BANK_PLATFORM_DATA_ALIGNMENT; fileEntryInfo->pImplData = azcreate(SATLAudioFileEntryData_wwise, (), Audio::AudioImplAllocator, "ATLAudioFileEntryData_wwise"); result = eARS_SUCCESS; } else { fileEntryInfo->sFileName = nullptr; fileEntryInfo->nMemoryBlockAlignment = 0; fileEntryInfo->pImplData = nullptr; } } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioFileEntryData(IATLAudioFileEntryData* const oldAudioFileEntry) { azdestroy(oldAudioFileEntry, Audio::AudioImplAllocator, SATLAudioFileEntryData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// const char* const CAudioSystemImpl_wwise::GetAudioFileLocation(SATLAudioFileEntryInfo* const fileEntryInfo) { const char* location = nullptr; if (fileEntryInfo) { location = fileEntryInfo->bLocalized ? m_localizedSoundbankFolder.c_str() : m_soundbankFolder.c_str(); } return location; } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLAudioObjectData_wwise* CAudioSystemImpl_wwise::NewGlobalAudioObjectData(const TAudioObjectID objectId) { AZ_UNUSED(objectId); auto newObjectData = azcreate(SATLAudioObjectData_wwise, (AK_INVALID_GAME_OBJECT, false), Audio::AudioImplAllocator, "ATLAudioObjectData_wwise-Global"); return newObjectData; } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLAudioObjectData_wwise* CAudioSystemImpl_wwise::NewAudioObjectData(const TAudioObjectID objectId) { auto newObjectData = azcreate(SATLAudioObjectData_wwise, (static_cast(objectId), true), Audio::AudioImplAllocator, "ATLAudioObjectData_wwise"); return newObjectData; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioObjectData(IATLAudioObjectData* const oldObjectData) { azdestroy(oldObjectData, Audio::AudioImplAllocator, SATLAudioObjectData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLListenerData_wwise* CAudioSystemImpl_wwise::NewDefaultAudioListenerObjectData(const TATLIDType listenerId) { auto newObjectData = azcreate(SATLListenerData_wwise, (static_cast(listenerId)), Audio::AudioImplAllocator, "ATLListenerData_wwise-Default"); if (newObjectData) { auto listenerName = AZStd::string::format("DefaultAudioListener(%" PRIu64 ")", static_cast(newObjectData->nAKListenerObjectId)); AKRESULT akResult = AK::SoundEngine::RegisterGameObj(newObjectData->nAKListenerObjectId, listenerName.c_str()); if (IS_WWISE_OK(akResult)) { akResult = AK::SoundEngine::SetDefaultListeners(&newObjectData->nAKListenerObjectId, 1); if (IS_WWISE_OK(akResult)) { m_defaultListenerGameObjectID = newObjectData->nAKListenerObjectId; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise failed in SetDefaultListeners to set AkGameObjectID %llu as default with AKRESULT: %u", newObjectData->nAKListenerObjectId, akResult); } } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise failed in RegisterGameObj registering a DefaultAudioListener with AKRESULT: %u", akResult); } } return newObjectData; } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLListenerData_wwise* CAudioSystemImpl_wwise::NewAudioListenerObjectData(const TATLIDType listenerId) { auto newObjectData = azcreate(SATLListenerData_wwise, (static_cast(listenerId)), Audio::AudioImplAllocator, "ATLListenerData_wwise"); if (newObjectData) { auto listenerName = AZStd::string::format("AudioListener(%" PRIu64 ")", static_cast(newObjectData->nAKListenerObjectId)); AKRESULT akResult = AK::SoundEngine::RegisterGameObj(newObjectData->nAKListenerObjectId, listenerName.c_str()); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise failed in RegisterGameObj registering an AudioListener with AKRESULT: %u", akResult); } } return newObjectData; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioListenerObjectData(IATLListenerData* const oldListenerData) { auto listenerData = static_cast(oldListenerData); if (listenerData) { AKRESULT akResult = AK::SoundEngine::UnregisterGameObj(listenerData->nAKListenerObjectId); if (IS_WWISE_OK(akResult)) { if (listenerData->nAKListenerObjectId == m_defaultListenerGameObjectID) { m_defaultListenerGameObjectID = AK_INVALID_GAME_OBJECT; } } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise failed in UnregisterGameObj unregistering an AudioListener(%llu) with AKRESULT: %u", listenerData->nAKListenerObjectId, akResult); } } azdestroy(oldListenerData, Audio::AudioImplAllocator, SATLListenerData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLEventData_wwise* CAudioSystemImpl_wwise::NewAudioEventData(const TAudioEventID eventId) { auto newObjectData = azcreate(SATLEventData_wwise, (eventId), Audio::AudioImplAllocator, "ATLEventData_wwise"); return newObjectData; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioEventData(IATLEventData* const oldEventData) { azdestroy(oldEventData, Audio::AudioImplAllocator, SATLEventData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::ResetAudioEventData(IATLEventData* const eventData) { auto const implEventData = static_cast(eventData); if (implEventData) { implEventData->audioEventState = eAES_NONE; implEventData->nAKID = AK_INVALID_UNIQUE_ID; implEventData->nSourceId = INVALID_AUDIO_SOURCE_ID; } } /////////////////////////////////////////////////////////////////////////////////////////////////// IATLTriggerImplData* CAudioSystemImpl_wwise::NewAudioTriggerImplData(const AZ::rapidxml::xml_node* audioTriggerNode) { SATLTriggerImplData_wwise* newTriggerImpl = nullptr; if (audioTriggerNode && azstricmp(audioTriggerNode->name(), WwiseXmlTags::WwiseEventTag) == 0) { auto eventNameAttr = audioTriggerNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (eventNameAttr) { const char* eventName = eventNameAttr->value(); const AkUniqueID akId = AK::SoundEngine::GetIDFromString(eventName); if (akId != AK_INVALID_UNIQUE_ID) { newTriggerImpl = azcreate(SATLTriggerImplData_wwise, (akId), Audio::AudioImplAllocator, "ATLTriggerImplData_wwise"); } } } return newTriggerImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioTriggerImplData(IATLTriggerImplData* const oldTriggerImplData) { azdestroy(oldTriggerImplData, Audio::AudioImplAllocator, SATLTriggerImplData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// IATLRtpcImplData* CAudioSystemImpl_wwise::NewAudioRtpcImplData(const AZ::rapidxml::xml_node* audioRtpcNode) { SATLRtpcImplData_wwise* newRtpcImpl = nullptr; AkRtpcID akRtpcId = AK_INVALID_RTPC_ID; float mult = 1.f; float shift = 0.f; ParseRtpcImpl(audioRtpcNode, akRtpcId, mult, shift); if (akRtpcId != AK_INVALID_RTPC_ID) { newRtpcImpl = azcreate(SATLRtpcImplData_wwise, (akRtpcId, mult, shift), Audio::AudioImplAllocator, "ATLRtpcImplData_wwise"); } return newRtpcImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioRtpcImplData(IATLRtpcImplData* const oldRtpcImplData) { azdestroy(oldRtpcImplData, Audio::AudioImplAllocator, SATLRtpcImplData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// IATLSwitchStateImplData* CAudioSystemImpl_wwise::NewAudioSwitchStateImplData(const AZ::rapidxml::xml_node* audioSwitchNode) { SATLSwitchStateImplData_wwise* newSwitchImpl = nullptr; const char* nodeName = audioSwitchNode->name(); if (azstricmp(nodeName, WwiseXmlTags::WwiseSwitchTag) == 0) { newSwitchImpl = ParseWwiseSwitchOrState(audioSwitchNode, eWST_SWITCH); } else if (azstricmp(nodeName, WwiseXmlTags::WwiseStateTag) == 0) { newSwitchImpl = ParseWwiseSwitchOrState(audioSwitchNode, eWST_STATE); } else if (azstricmp(nodeName, WwiseXmlTags::WwiseRtpcSwitchTag) == 0) { newSwitchImpl = ParseWwiseRtpcSwitch(audioSwitchNode); } return newSwitchImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioSwitchStateImplData(IATLSwitchStateImplData* const oldSwitchStateImplData) { azdestroy(oldSwitchStateImplData, Audio::AudioImplAllocator, SATLSwitchStateImplData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// IATLEnvironmentImplData* CAudioSystemImpl_wwise::NewAudioEnvironmentImplData(const AZ::rapidxml::xml_node* audioEnvironmentNode) { SATLEnvironmentImplData_wwise* newEnvironmentImpl = nullptr; if (azstricmp(audioEnvironmentNode->name(), WwiseXmlTags::WwiseAuxBusTag) == 0) { auto auxBusNameAttr = audioEnvironmentNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (auxBusNameAttr) { const char* auxBusName = auxBusNameAttr->value(); const AkUniqueID akBusId = AK::SoundEngine::GetIDFromString(auxBusName); if (akBusId != AK_INVALID_AUX_ID) { newEnvironmentImpl = azcreate(SATLEnvironmentImplData_wwise, (eWAET_AUX_BUS, static_cast(akBusId)), Audio::AudioImplAllocator, "ATLEnvironmentImplData_wwise"); } } } else if (azstricmp(audioEnvironmentNode->name(), WwiseXmlTags::WwiseRtpcTag) == 0) { AkRtpcID akRtpcId = AK_INVALID_RTPC_ID; float mult = 1.f; float shift = 0.f; ParseRtpcImpl(audioEnvironmentNode, akRtpcId, mult, shift); if (akRtpcId != AK_INVALID_RTPC_ID) { newEnvironmentImpl = azcreate(SATLEnvironmentImplData_wwise, (eWAET_RTPC, akRtpcId, mult, shift), Audio::AudioImplAllocator, "ATLEnvironmentImplData_wwise"); } } return newEnvironmentImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DeleteAudioEnvironmentImplData(IATLEnvironmentImplData* const oldEnvironmentImplData) { azdestroy(oldEnvironmentImplData, Audio::AudioImplAllocator, SATLEnvironmentImplData_wwise); } /////////////////////////////////////////////////////////////////////////////////////////////////// const char* const CAudioSystemImpl_wwise::GetImplementationNameString() const { #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) return m_fullImplString.c_str(); #else return nullptr; #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::GetMemoryInfo(SAudioImplMemoryInfo& memoryInfo) const { memoryInfo.nPrimaryPoolSize = AZ::AllocatorInstance::Get().Capacity(); memoryInfo.nPrimaryPoolUsedSize = memoryInfo.nPrimaryPoolSize - AZ::AllocatorInstance::Get().GetUnAllocatedMemory(); memoryInfo.nPrimaryPoolAllocations = 0; #if AZ_TRAIT_AUDIOENGINEWWISE_PROVIDE_IMPL_SECONDARY_POOL memoryInfo.nSecondaryPoolSize = g_audioImplMemoryPoolSecondary_wwise.MemSize(); memoryInfo.nSecondaryPoolUsedSize = memoryInfo.nSecondaryPoolSize - g_audioImplMemoryPoolSecondary_wwise.MemFree(); memoryInfo.nSecondaryPoolAllocations = g_audioImplMemoryPoolSecondary_wwise.FragmentCount(); #else memoryInfo.nSecondaryPoolSize = 0; memoryInfo.nSecondaryPoolUsedSize = 0; memoryInfo.nSecondaryPoolAllocations = 0; #endif // AZ_TRAIT_AUDIOENGINEWWISE_PROVIDE_IMPL_SECONDARY_POOL } /////////////////////////////////////////////////////////////////////////////////////////////////// AZStd::vector CAudioSystemImpl_wwise::GetMemoryPoolInfo() { #if defined(INCLUDE_WWISE_IMPL_PRODUCTION_CODE) // Update pools... for (auto& poolInfo : m_debugMemoryPoolInfo) { AKRESULT akResult = AK::MemoryMgr::CheckPoolId(poolInfo.m_poolId); if (IS_WWISE_OK(akResult)) { AK::MemoryMgr::PoolStats poolStats; akResult = AK::MemoryMgr::GetPoolStats(poolInfo.m_poolId, poolStats); if (IS_WWISE_OK(akResult)) { poolInfo.m_memoryReserved = poolStats.uReserved; poolInfo.m_memoryUsed = poolStats.uUsed; poolInfo.m_peakUsed = poolStats.uPeakUsed; poolInfo.m_numAllocs = poolStats.uAllocs; poolInfo.m_numFrees = poolStats.uFrees; } } } // return the pool infos... return m_debugMemoryPoolInfo; #else return AZStd::vector(); #endif // INCLUDE_WWISE_IMPL_PRODUCTION_CODE } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystemImpl_wwise::CreateAudioSource(const SAudioInputConfig& sourceConfig) { return AudioSourceManager::Get().CreateSource(sourceConfig); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::DestroyAudioSource(TAudioSourceId sourceId) { AudioSourceManager::Get().DestroySource(sourceId); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::SetPanningMode(PanningMode mode) { AkPanningRule panningRule; switch (mode) { case PanningMode::Speakers: panningRule = AkPanningRule_Speakers; break; case PanningMode::Headphones: panningRule = AkPanningRule_Headphones; break; default: return; } AKRESULT akResult = AK::SoundEngine::SetPanningRule(panningRule); if (!IS_WWISE_OK(akResult)) { g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to set Panning Rule to [%s]\n", panningRule == AkPanningRule_Speakers ? "Speakers" : "Headphones"); } } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLSwitchStateImplData_wwise* CAudioSystemImpl_wwise::ParseWwiseSwitchOrState(const AZ::rapidxml::xml_node* node, EWwiseSwitchType type) { SATLSwitchStateImplData_wwise* switchStateImpl = nullptr; auto switchNameAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (switchNameAttr) { const char* switchName = switchNameAttr->value(); auto valueNode = node->first_node(WwiseXmlTags::WwiseValueTag, 0, false); if (valueNode) { auto valueNameAttr = valueNode->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (valueNameAttr) { const char* stateName = valueNameAttr->value(); const AkUniqueID akSGroupId = AK::SoundEngine::GetIDFromString(switchName); const AkUniqueID akSNameId = AK::SoundEngine::GetIDFromString(stateName); if (akSGroupId != AK_INVALID_UNIQUE_ID && akSNameId != AK_INVALID_UNIQUE_ID) { switchStateImpl = azcreate(SATLSwitchStateImplData_wwise, (type, akSGroupId, akSNameId), Audio::AudioImplAllocator, "ATLSwitchStateImplData_wwise"); } } } } return switchStateImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// SATLSwitchStateImplData_wwise* CAudioSystemImpl_wwise::ParseWwiseRtpcSwitch(const AZ::rapidxml::xml_node* node) { SATLSwitchStateImplData_wwise* switchStateImpl = nullptr; if (node && azstricmp(node->name(), WwiseXmlTags::WwiseRtpcSwitchTag) == 0) { auto rtpcNameAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (rtpcNameAttr) { const char* rtpcName = rtpcNameAttr->value(); float rtpcValue = 0.f; auto rtpcValueAttr = node->first_attribute(WwiseXmlTags::WwiseValueAttribute, 0, false); if (rtpcValueAttr) { rtpcValue = AZStd::stof(AZStd::string(rtpcValueAttr->value())); const AkUniqueID akRtpcId = AK::SoundEngine::GetIDFromString(rtpcName); if (akRtpcId != AK_INVALID_RTPC_ID) { switchStateImpl = azcreate(SATLSwitchStateImplData_wwise, (eWST_RTPC, akRtpcId, akRtpcId, rtpcValue), Audio::AudioImplAllocator, "ATLSwitchStateImplData_wwise"); } } } } return switchStateImpl; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::ParseRtpcImpl(const AZ::rapidxml::xml_node* node, AkRtpcID& akRtpcId, float& mult, float& shift) { SATLRtpcImplData_wwise* newRtpcImpl = nullptr; if (node && azstricmp(node->name(), WwiseXmlTags::WwiseRtpcTag) == 0) { auto rtpcAttr = node->first_attribute(WwiseXmlTags::WwiseNameAttribute, 0, false); if (rtpcAttr) { const char* rtpcName = rtpcAttr->value(); akRtpcId = static_cast(AK::SoundEngine::GetIDFromString(rtpcName)); if (akRtpcId != AK_INVALID_RTPC_ID) { auto multAttr = node->first_attribute(WwiseXmlTags::WwiseMutiplierAttribute, 0, false); if (multAttr) { mult = AZStd::stof(AZStd::string(multAttr->value())); } auto shiftAttr = node->first_attribute(WwiseXmlTags::WwiseShiftAttribute, 0, false); if (shiftAttr) { shift = AZStd::stof(AZStd::string(shiftAttr->value())); } } } } } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::PrepUnprepTriggerSync( const IATLTriggerImplData* const triggerData, bool prepare) { EAudioRequestStatus result = eARS_FAILURE; auto const implTriggerData = static_cast(triggerData); if (implTriggerData) { AkUniqueID akUniqueId = implTriggerData->nAKID; const AKRESULT akResult = AK::SoundEngine::PrepareEvent( prepare ? AK::SoundEngine::Preparation_Load : AK::SoundEngine::Preparation_Unload, &akUniqueId, 1); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise PrepareEvent with %s failed for Wwise event %u with AKRESULT: %u", prepare ? "Preparation_Load" : "Preparation_Unload", akUniqueId, akResult); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid ATLTriggerData or EventData passed to the Wwise implementation of %sTriggerSync", prepare ? "Prepare" : "Unprepare"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::PrepUnprepTriggerAsync( const IATLTriggerImplData* const triggerData, IATLEventData* const eventData, bool prepare) { EAudioRequestStatus result = eARS_FAILURE; auto const implTriggerData = static_cast(triggerData); auto const implEventData = static_cast(eventData); if (implTriggerData && implEventData) { AkUniqueID akUniqueId = implTriggerData->nAKID; const AKRESULT akResult = AK::SoundEngine::PrepareEvent( prepare ? AK::SoundEngine::Preparation_Load : AK::SoundEngine::Preparation_Unload, &akUniqueId, 1, &PrepareEventCallback, implEventData); if (IS_WWISE_OK(akResult)) { implEventData->nAKID = akUniqueId; implEventData->audioEventState = eAES_UNLOADING; result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log( eALT_WARNING, "Wwise PrepareEvent with %s failed for Wwise event %u with AKRESULT: %u", prepare ? "Preparation_Load" : "Preparation_Unload", akUniqueId, akResult); } } else { g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid ATLTriggerData or EventData passed to the Wwise implementation of %sTriggerAsync", prepare ? "Prepare" : "Unprepare"); } return result; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::SetBankPaths() { // Default... // "sounds/wwise/" AZStd::string bankPath = Audio::Wwise::DefaultBanksPath; // "sounds/wwise/wwise_config.json" AZStd::string configFile = bankPath + Audio::Wwise::ConfigFile; if (AZ::IO::FileIOBase::GetInstance() && AZ::IO::FileIOBase::GetInstance()->Exists(configFile.c_str())) { Audio::Wwise::ConfigurationSettings configSettings; if (configSettings.Load(configFile)) { for (const auto& platformMap : configSettings.m_platformMappings) { // May need to do a series of checks compare the data in the config settings to what's actually in the file system. // This is the most straightforward platform check. if (azstricmp(platformMap.m_enginePlatform.c_str(), AZ_TRAIT_OS_PLATFORM_NAME) == 0) { AZStd::string platformPath; // "sounds/wwise/windows" AZ::StringFunc::AssetDatabasePath::Join(bankPath.c_str(), platformMap.m_bankSubPath.c_str(), platformPath); AZStd::string initBankPath; // "sounds/wwise/windows/init.bnk" AZ::StringFunc::AssetDatabasePath::Join(platformPath.c_str(), Audio::Wwise::InitBank, initBankPath); if (AZ::IO::FileIOBase::GetInstance()->Exists(initBankPath.c_str())) { bankPath = AZ::StringFunc::AssetDatabasePath::AppendSeparator(platformPath); break; } } } } } m_soundbankFolder = bankPath; m_localizedSoundbankFolder = bankPath; Audio::Wwise::SetBanksRootPath(m_soundbankFolder); } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystemImpl_wwise::SEnvPairCompare::operator()(const AZStd::pair& pair1, const AZStd::pair& pair2) const { return (pair1.second > pair2.second); } /////////////////////////////////////////////////////////////////////////////////////////////////// EAudioRequestStatus CAudioSystemImpl_wwise::PostEnvironmentAmounts(IATLAudioObjectData* const audioObjectData) { EAudioRequestStatus result = eARS_FAILURE; auto const implObjectData = static_cast(audioObjectData); if (implObjectData) { AkAuxSendValue akAuxSendValues[LY_MAX_AUX_PER_OBJ]; AZ::u32 auxCount = 0; SATLAudioObjectData_wwise::TEnvironmentImplMap::iterator envPair = implObjectData->cEnvironmentImplAmounts.begin(); const SATLAudioObjectData_wwise::TEnvironmentImplMap::const_iterator envBegin = implObjectData->cEnvironmentImplAmounts.begin(); const SATLAudioObjectData_wwise::TEnvironmentImplMap::const_iterator envEnd = implObjectData->cEnvironmentImplAmounts.end(); if (implObjectData->cEnvironmentImplAmounts.size() <= LY_MAX_AUX_PER_OBJ) { for (; envPair != envEnd; ++auxCount) { const float amount = envPair->second; akAuxSendValues[auxCount].auxBusID = envPair->first; akAuxSendValues[auxCount].fControlValue = amount; akAuxSendValues[auxCount].listenerID = m_defaultListenerGameObjectID; // TODO: Expand api to allow specify listeners // If an amount is zero, we still want to send it to the middleware, but we also want to remove it from the map. if (amount == 0.0f) { envPair = implObjectData->cEnvironmentImplAmounts.erase(envPair); } else { ++envPair; } } } else { // sort the environments in order of decreasing amounts and take the first LY_MAX_AUX_PER_OBJ worth using TEnvPairSet = AZStd::set; TEnvPairSet envPairs(envBegin, envEnd); TEnvPairSet::const_iterator sortedEnvPair = envPairs.begin(); const TEnvPairSet::const_iterator sortedEnvEnd = envPairs.end(); for (; (sortedEnvPair != sortedEnvEnd) && (auxCount < LY_MAX_AUX_PER_OBJ); ++sortedEnvPair, ++auxCount) { akAuxSendValues[auxCount].auxBusID = sortedEnvPair->first; akAuxSendValues[auxCount].fControlValue = sortedEnvPair->second; akAuxSendValues[auxCount].listenerID = m_defaultListenerGameObjectID; // TODO: Expand api to allow specify listeners } // remove all Environments with 0.0 amounts while (envPair != envEnd) { if (envPair->second == 0.0f) { envPair = implObjectData->cEnvironmentImplAmounts.erase(envPair); } else { ++envPair; } } } AZ_Assert(auxCount <= LY_MAX_AUX_PER_OBJ, "WwiseImpl PostEnvironmentAmounts - Exceeded the allowed number of aux environments that can be set!"); const AKRESULT akResult = AK::SoundEngine::SetGameObjectAuxSendValues(implObjectData->nAKID, akAuxSendValues, auxCount); if (IS_WWISE_OK(akResult)) { result = eARS_SUCCESS; } else { g_audioImplLogger_wwise.Log(eALT_WARNING, "Wwise SetGameObjectAuxSendValues failed on object %llu with AKRESULT: %u", implObjectData->nAKID, akResult); } implObjectData->bNeedsToUpdateEnvironments = false; } return result; } ////////////////////////////////////////////////////////////////////////// const char* const CAudioSystemImpl_wwise::GetImplSubPath() const { return WwiseImplSubPath; } ////////////////////////////////////////////////////////////////////////// void CAudioSystemImpl_wwise::SetLanguage(const char* const language) { if (language) { AZStd::string languageSubfolder; if (azstricmp(language, "english") == 0) { languageSubfolder = "english(us)"; } else { languageSubfolder = language; } languageSubfolder += "/"; m_localizedSoundbankFolder = m_soundbankFolder; m_localizedSoundbankFolder.append(languageSubfolder); m_fileIOHandler.SetLanguageFolder(languageSubfolder.c_str()); } } } // namespace Audio