You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp

2190 lines
88 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/PlatformIncl.h>
#include <AudioSystemImpl_wwise.h>
#include <platform.h>
#include <AzCore/AzCore_Traits_Platform.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <IAudioSystem.h>
#include <AudioAllocators.h>
#include <AudioLogger.h>
#include <AudioSourceManager.h>
#include <AudioSystemImplCVars.h>
#include <Common_wwise.h>
#include <Config_wwise.h>
#include <FileIOHandler_wwise.h>
#include <AK/SoundEngine/Common/AkMemoryMgr.h> // Memory Manager
#include <AK/SoundEngine/Common/AkModule.h> // Memory and Stream Manager interfaces
#include <AK/SoundEngine/Common/AkSoundEngine.h> // Sound Engine
#include <AK/SpatialAudio/Common/AkSpatialAudio.h> // Spatial Audio
#include <AK/MusicEngine/Common/AkMusicEngine.h> // Music Engine
#include <PluginRegistration_wwise.h> // Registration of default set of plugins, customize this header to your needs.
#include <inttypes.h>
#if !defined(WWISE_RELEASE)
#include <AK/Comm/AkCommunication.h> // Communication between Wwise and the game (excluded in release build)
#include <AK/Tools/Common/AkMonitorError.h>
#include <AkPlatformFuncs_Platform.h>
#endif // WWISE_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
namespace Audio
{
namespace Platform
{
void InitializeMemory(CAudioLogger& audioLogger);
void SetupAkSoundEngine(AkPlatformInitSettings& platformInitSettings);
}
/////////////////////////////////////////////////////////////////////////////////
// AK MEMORY HOOKS SETUP
namespace Wwise::MemHooks
{
void* Malloc(AkMemPoolId memId, size_t size)
{
size_t memCategory = memId & AkMemID_MASK;
AZ_Assert(memCategory < AkMemID_NUM, "Wwise::MemHooks::Malloc - Bad AkMemPoolId passed: %zu", memCategory);
return AZ::AllocatorInstance<AudioImplAllocator>::Get().Allocate(size, 0, 0,
(memCategory < AkMemID_NUM) ? MemoryManagerCategories[memCategory] : nullptr);
}
void* Malign(AkMemPoolId memId, size_t size, AkUInt32 alignment)
{
size_t memCategory = memId & AkMemID_MASK;
AZ_Assert(memCategory < AkMemID_NUM, "WWise::MemHooks::Malign - Bad AkMemPoolId passed: %zu", memCategory);
return AZ::AllocatorInstance<AudioImplAllocator>::Get().Allocate(size, alignment, 0,
(memCategory < AkMemID_NUM) ? MemoryManagerCategories[memCategory] : nullptr);
}
void* Realloc([[maybe_unused]] AkMemPoolId memId, void* address, size_t size)
{
return AZ::AllocatorInstance<AudioImplAllocator>::Get().ReAllocate(address, size, 0);
}
void* ReallocAligned([[maybe_unused]] AkMemPoolId memId, void* address, size_t size, AkUInt32 alignment)
{
return AZ::AllocatorInstance<AudioImplAllocator>::Get().ReAllocate(address, size, alignment);
}
void Free([[maybe_unused]] AkMemPoolId memId, void* address)
{
AZ::AllocatorInstance<AudioImplAllocator>::Get().DeAllocate(address);
}
size_t TotalReservedMemorySize()
{
return AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().Capacity();
}
size_t SizeOfMemory([[maybe_unused]] AkMemPoolId memId, void* address)
{
return AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().AllocationSize(address);
}
} // namespace Wwise::MemHooks
extern CAudioLogger g_audioImplLogger_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;
static bool audioDeviceInitializationEvent = false;
///////////////////////////////////////////////////////////////////////////////////////////////////
// AK callbacks
void WwiseEventCallback(AkCallbackType callbackType, AkCallbackInfo* callbackInfo)
{
if (callbackType == AK_EndOfEvent)
{
auto const eventData = static_cast<SATLEventData_wwise*>(callbackInfo->pCookie);
if (eventData)
{
SAudioRequest request;
SAudioCallbackManagerRequestData<eACMRT_REPORT_FINISHED_EVENT> 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<AkDurationCallbackInfo*>(callbackInfo);
auto const eventData = static_cast<SATLEventData_wwise*>(callbackInfo->pCookie);
if (durationInfo && eventData)
{
AudioTriggerNotificationBus::QueueEvent(eventData->m_triggerId, &AudioTriggerNotificationBus::Events::ReportDurationInfo,
eventData->nATLID, durationInfo->fDuration, durationInfo->fEstimatedDuration);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void AudioDeviceCallback(
[[maybe_unused]] AK::IAkGlobalPluginContext* context,
[[maybe_unused]] AkUniqueID audioDeviceSharesetId,
[[maybe_unused]] AkUInt32 deviceId,
AK::AkAudioDeviceEvent deviceEvent,
[[maybe_unused]] AKRESULT inAkResult
)
{
if (deviceEvent == AK::AkAudioDeviceEvent_Initialization)
{
audioDeviceInitializationEvent = true;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void PrepareEventCallback(
AkUniqueID akEventId,
[[maybe_unused]] const void* bankPtr,
AKRESULT loadResult,
[[maybe_unused]] AkMemPoolId memPoolId,
void* cookie)
{
auto const eventData = static_cast<SATLEventData_wwise*>(cookie);
if (eventData)
{
eventData->nAKID = akEventId;
SAudioRequest request;
SAudioCallbackManagerRequestData<eACMRT_REPORT_FINISHED_EVENT> requestData(eventData->nATLID, loadResult == AK_Success);
request.nFlags = eARF_THREAD_SAFE_PUSH;
request.pData = &requestData;
AudioSystemThreadSafeRequestBus::Broadcast(&AudioSystemThreadSafeRequestBus::Events::PushRequestThreadSafe, request);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#if !defined(WWISE_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,
"<Wwise> %s ErrorCode: %d PlayingID: %u GameObjID: %llu", errorStr, in_eErrorCode, in_playingID, in_gameObjID);
}
#endif // WWISE_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<AkGameObjectID>(GLOBAL_AUDIO_OBJECT_ID))
, m_defaultListenerGameObjectID(AK_INVALID_GAME_OBJECT)
, m_initBankID(AK_INVALID_BANK_ID)
#if !defined(WWISE_RELEASE)
, m_isCommSystemInitialized(false)
#endif // !WWISE_RELEASE
{
if (assetsPlatformName && assetsPlatformName[0] != '\0')
{
m_assetsPlatform = assetsPlatformName;
}
Platform::InitializeMemory(g_audioImplLogger_wwise);
SetBankPaths();
#if !defined(WWISE_RELEASE)
m_fullImplString = AZStd::string::format("%s (%s)", WWISE_IMPL_VERSION_STRING, m_soundbankFolder.c_str());
// Set up memory categories for debug tracking, do this early before initializing Wwise so they are available
// before the any allocations through hooks occur.
g_audioImplLogger_wwise.Log(eALT_COMMENT, "Memory Categories:\n");
m_debugMemoryInfo.reserve(AkMemID_NUM + 1);
for (AZ::u32 memId = 0; memId < AkMemID_NUM; ++memId)
{
AudioImplMemoryPoolInfo memInfo;
azstrcpy(memInfo.m_poolName, sizeof(memInfo.m_poolName), Wwise::MemoryManagerCategories[memId]);
memInfo.m_poolId = memId;
m_debugMemoryInfo.push_back(memInfo);
g_audioImplLogger_wwise.Log(eALT_COMMENT, "Memory category ID: %u - '%s'\n", memId, Wwise::MemoryManagerCategories[memId]);
}
// Add one more category for global stats.
AudioImplMemoryPoolInfo memInfo;
azstrcpy(memInfo.m_poolName, sizeof(memInfo.m_poolName), "Global");
m_debugMemoryInfo.push_back(memInfo);
#endif // !WWISE_RELEASE
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, "<Wwise> Failed to unload %s!", Wwise::InitBank);
}
}
AkOSChar* initBankName = nullptr;
CONVERT_CHAR_TO_OSCHAR(Wwise::InitBank, initBankName);
akResult = AK::SoundEngine::LoadBank(initBankName, 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, "<Wwise> Failed to load %s!", Wwise::InitBank);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// AudioSystemImplementationRequestBus
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
void CAudioSystemImpl_wwise::Update([[maybe_unused]] const float updateIntervalMS)
{
AZ_PROFILE_FUNCTION(Audio);
if (AK::SoundEngine::IsInitialized())
{
#if !defined(WWISE_RELEASE)
AKRESULT akResult = AK_Fail;
static bool enableOutputCapture = false;
if (Wwise::Cvars::s_EnableOutputCapture && !enableOutputCapture)
{
// 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 = Wwise::Cvars::s_EnableOutputCapture;
}
else if (!Wwise::Cvars::s_EnableOutputCapture && enableOutputCapture)
{
akResult = AK::SoundEngine::StopOutputCapture();
AZ_Assert(IS_WWISE_OK(akResult), "AK::SoundEngine::StopOutputCapture failed!");
enableOutputCapture = Wwise::Cvars::s_EnableOutputCapture;
}
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 // !WWISE_RELEASE
AK::SoundEngine::RenderAudio();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::Initialize()
{
// If something fails so severely during initialization that we need to fall back to a '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;
AK::MemoryMgr::GetDefaultSettings(akMemSettings);
akMemSettings.pfMalloc = Wwise::MemHooks::Malloc;
akMemSettings.pfMalign = Wwise::MemHooks::Malign;
akMemSettings.pfRealloc = Wwise::MemHooks::Realloc;
akMemSettings.pfReallocAligned = Wwise::MemHooks::ReallocAligned;
akMemSettings.pfFree = Wwise::MemHooks::Free;
akMemSettings.pfTotalReservedMemorySize = Wwise::MemHooks::TotalReservedMemorySize;
akMemSettings.pfSizeOfMemory = Wwise::MemHooks::SizeOfMemory;
akMemSettings.uMemAllocationSizeLimit = Wwise::Cvars::s_PrimaryMemorySize << 10;
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;
}
akResult = AK::SoundEngine::RegisterAudioDeviceStatusCallback(AudioDeviceCallback);
if (!IS_WWISE_OK(akResult))
{
g_audioImplLogger_wwise.Log(eALT_WARNING, "AK::SoundEngine::RegisterAudioDeviceStatusCallback failed!\n");
}
AkStreamMgrSettings akStreamSettings;
AK::StreamMgr::GetDefaultSettings(akStreamSettings);
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(Wwise::Cvars::s_StreamDeviceMemorySize << 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.uCommandQueueSize = aznumeric_cast<AkUInt32>(Wwise::Cvars::s_CommandQueueMemorySize << 10);
#if !defined(WWISE_RELEASE)
akInitSettings.uMonitorQueuePoolSize = aznumeric_cast<AkUInt32>(Wwise::Cvars::s_MonitorQueueMemorySize << 10);
#endif // !WWISE_RELEASE
akInitSettings.bEnableGameSyncPreparation = false;
#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);
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;
}
AkSpatialAudioInitSettings akSpatialAudioSettings;
akResult = AK::SpatialAudio::Init(akSpatialAudioSettings);
if (!IS_WWISE_OK(akResult))
{
g_audioImplLogger_wwise.Log(eALT_ERROR, "AK::SpatialAudio::Init() returned AKRESULT %d", akResult);
ShutDown();
return eARS_FAILURE;
}
#if !defined(WWISE_RELEASE)
if (Audio::Wwise::Cvars::s_EnableCommSystem)
{
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 // !WWISE_RELEASE
// Initialize the AudioSourceManager
AudioSourceManager::Get().Initialize();
// Register the Global Audio Object 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, m_initBankID);
if (!IS_WWISE_OK(akResult))
{
// This does not qualify for a fallback to the 'Null' audio implementation!
g_audioImplLogger_wwise.Log(eALT_ERROR, "Wwise failed to load %s, returned AKRESULT %d", Wwise::InitBank, akResult);
m_initBankID = AK_INVALID_BANK_ID;
}
return eARS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::ShutDown()
{
AKRESULT akResult = AK_Fail;
#if !defined(WWISE_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_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())
{
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<SATLAudioObjectData_wwise*>(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<SATLAudioObjectData_wwise*>(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<SATLAudioObjectData_wwise*>(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(Audio);
EAudioRequestStatus result = eARS_FAILURE;
if (audioObjectData)
{
auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(audioObjectData);
if (implObjectData->bNeedsToUpdateEnvironments)
{
result = PostEnvironmentAmounts(implObjectData);
}
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerSync(
[[maybe_unused]] IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData)
{
return PrepUnprepTriggerSync(triggerData, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerSync(
[[maybe_unused]] IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData)
{
return PrepUnprepTriggerSync(triggerData, false);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::PrepareTriggerAsync(
[[maybe_unused]] IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData,
IATLEventData* const eventData)
{
return PrepUnprepTriggerAsync(triggerData, eventData, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::UnprepareTriggerAsync(
[[maybe_unused]] 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<SATLAudioObjectData_wwise*>(audioObjectData);
auto const implTriggerData = static_cast<const SATLTriggerImplData_wwise*>(triggerData);
auto const implEventData = static_cast<SATLEventData_wwise*>(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 filePath = 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* finalFilePath = nullptr;
CONVERT_CHAR_TO_OSCHAR(filePath.c_str(), finalFilePath);
AkExternalSourceInfo sources[1];
sources[0].iExternalSrcCookie = static_cast<AkUInt32>(sourceData->m_sourceInfo.m_sourceId);
sources[0].szFile = finalFilePath;
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, filePath.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(
[[maybe_unused]] IATLAudioObjectData* const audioObjectData,
const IATLEventData* const eventData)
{
EAudioRequestStatus result = eARS_FAILURE;
auto const implEventData = static_cast<const SATLEventData_wwise*>(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<SATLAudioObjectData_wwise*>(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<SATLAudioObjectData_wwise*>(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<SATLAudioObjectData_wwise*>(audioObjectData);
if (implObjectData)
{
AZStd::vector<AkSoundPosition> 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<AkUInt16>(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<SATLAudioObjectData_wwise*>(audioObjectData);
auto const implEnvironmentData = static_cast<const SATLEnvironmentImplData_wwise*>(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<AkRtpcValue>(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, "<Wwise> 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<SATLAudioObjectData_wwise*>(audioObjectData);
auto const implRtpcData = static_cast<const SATLRtpcImplData_wwise*>(rtpcData);
if (implObjectData && implRtpcData)
{
auto akRtpcValue = static_cast<AkRtpcValue>(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<AkRtpcValue>(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<SATLAudioObjectData_wwise*>(audioObjectData);
auto const implSwitchStateData = static_cast<const SATLSwitchStateImplData_wwise*>(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<AkRtpcValue>(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<AkRtpcValue>(implSwitchStateData->fRtpcValue),
akObjectId);
}
break;
}
case eWST_NONE:
{
break;
}
default:
{
g_audioImplLogger_wwise.Log(eALT_WARNING, "Unknown EWwiseSwitchType: %u", implSwitchStateData->eType);
AZ_Assert(false, "<Wwise> 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<SATLAudioObjectData_wwise*>(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<AkReal32>(obstruction),
static_cast<AkReal32>(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<SATLListenerData_wwise*>(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<SATLAudioObjectData_wwise*>(audioObjectData);
auto const implRtpcDat = static_cast<const SATLRtpcImplData_wwise*>(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<SATLAudioFileEntryData_wwise*>(fileEntryInfo->pImplData);
if (implFileEntryData)
{
AkBankID akBankId = AK_INVALID_BANK_ID;
const AKRESULT akResult = AK::SoundEngine::LoadBankMemoryView(
fileEntryInfo->pFileData,
aznumeric_cast<AkUInt32>(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, "Wwise failed to load bank '%s'\n", fileEntryInfo->sFileName);
}
}
else
{
g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioFileEntryData passed to RegisterInMemoryFile");
}
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::UnregisterInMemoryFile(SATLAudioFileEntryInfo* const fileEntryInfo)
{
EAudioRequestStatus result = eARS_FAILURE;
if (fileEntryInfo)
{
auto const implFileEntryData = static_cast<SATLAudioFileEntryData_wwise*>(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 unload bank '%s'\n", fileEntryInfo->sFileName);
}
}
else
{
g_audioImplLogger_wwise.Log(eALT_ERROR, "Invalid AudioFileEntryData passed to UnregisterInMemoryFile");
}
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::ParseAudioFileEntry(const AZ::rapidxml::xml_node<char>* 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<AkGameObjectID>(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<AkGameObjectID>(listenerId)), Audio::AudioImplAllocator, "ATLListenerData_wwise-Default");
if (newObjectData)
{
auto listenerName = AZStd::string::format("DefaultAudioListener(%" PRIu64 ")", static_cast<AZ::u64>(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<AkGameObjectID>(listenerId)), Audio::AudioImplAllocator, "ATLListenerData_wwise");
if (newObjectData)
{
auto listenerName = AZStd::string::format("AudioListener(%" PRIu64 ")", static_cast<AZ::u64>(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<SATLListenerData_wwise*>(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<SATLEventData_wwise*>(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<char>* 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<char>* 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<char>* 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<char>* 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<AkAuxBusID>(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(WWISE_RELEASE)
return m_fullImplString.c_str();
#else
return nullptr;
#endif // !WWISE_RELEASE
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void CAudioSystemImpl_wwise::GetMemoryInfo(SAudioImplMemoryInfo& memoryInfo) const
{
memoryInfo.nPrimaryPoolSize = AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().Capacity();
memoryInfo.nPrimaryPoolUsedSize = memoryInfo.nPrimaryPoolSize - AZ::AllocatorInstance<Audio::AudioImplAllocator>::Get().GetUnAllocatedMemory();
memoryInfo.nPrimaryPoolAllocations = 0;
memoryInfo.nSecondaryPoolSize = 0;
memoryInfo.nSecondaryPoolUsedSize = 0;
memoryInfo.nSecondaryPoolAllocations = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
AZStd::vector<AudioImplMemoryPoolInfo> CAudioSystemImpl_wwise::GetMemoryPoolInfo()
{
#if !defined(WWISE_RELEASE)
// Update memory category info...
for (auto& memInfo : m_debugMemoryInfo)
{
if (memInfo.m_poolId < 0)
{
break;
}
AK::MemoryMgr::CategoryStats categoryStats;
AK::MemoryMgr::GetCategoryStats(memInfo.m_poolId, categoryStats);
memInfo.m_memoryUsed = static_cast<AZ::u32>(categoryStats.uUsed);
memInfo.m_peakUsed = static_cast<AZ::u32>(categoryStats.uPeakUsed);
memInfo.m_numAllocs = categoryStats.uAllocs;
memInfo.m_numFrees = categoryStats.uFrees;
}
AK::MemoryMgr::GlobalStats globalStats;
AK::MemoryMgr::GetGlobalStats(globalStats);
auto& memInfo = m_debugMemoryInfo.back();
memInfo.m_memoryReserved = static_cast<AZ::u32>(globalStats.uReserved);
memInfo.m_memoryUsed = static_cast<AZ::u32>(globalStats.uUsed);
memInfo.m_peakUsed = static_cast<AZ::u32>(globalStats.uMax);
// return the memory infos...
return m_debugMemoryInfo;
#else
return AZStd::vector<AudioImplMemoryPoolInfo>();
#endif // !WWISE_RELEASE
}
///////////////////////////////////////////////////////////////////////////////////////////////////
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<char>* 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<char>* 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<char>* node, AkRtpcID& akRtpcId, float& mult, float& shift)
{
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<AkRtpcID>(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<const SATLTriggerImplData_wwise*>(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(
[[maybe_unused]] const IATLTriggerImplData* const triggerData,
[[maybe_unused]] IATLEventData* const eventData,
[[maybe_unused]] bool prepare)
{
EAudioRequestStatus result = eARS_FAILURE;
#if 0 // Turned off, PrepareEvent is not supported yet.
auto const implTriggerData = static_cast<const SATLTriggerImplData_wwise*>(triggerData);
auto const implEventData = static_cast<SATLEventData_wwise*>(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");
}
#endif
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()))
{
if (!platformPath.ends_with(AZ_CORRECT_DATABASE_SEPARATOR))
{
platformPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
}
bankPath = AZStd::move(platformPath);
break;
}
}
}
}
}
m_soundbankFolder = bankPath;
m_localizedSoundbankFolder = bankPath;
Audio::Wwise::SetBanksRootPath(m_soundbankFolder);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
bool CAudioSystemImpl_wwise::SEnvPairCompare::operator()(const AZStd::pair<const AkAuxBusID, float>& pair1, const AZStd::pair<const AkAuxBusID, float>& pair2) const
{
return (pair1.second > pair2.second);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
EAudioRequestStatus CAudioSystemImpl_wwise::PostEnvironmentAmounts(IATLAudioObjectData* const audioObjectData)
{
EAudioRequestStatus result = eARS_FAILURE;
auto const implObjectData = static_cast<SATLAudioObjectData_wwise*>(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<SATLAudioObjectData_wwise::TEnvironmentImplMap::value_type, SEnvPairCompare, Audio::AudioImplStdAllocator>;
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(language);
languageSubfolder += "/";
m_localizedSoundbankFolder = m_soundbankFolder;
m_localizedSoundbankFolder.append(languageSubfolder);
m_fileIOHandler.SetLanguageFolder(languageSubfolder.c_str());
}
}
} // namespace Audio