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/AudioSystem/Code/Source/Engine/SoundCVars.cpp

916 lines
42 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 <SoundCVars.h>
#include <AudioLogger.h>
#include <AudioInternalInterfaces.h>
#include <AudioSystem_Traits_Platform.h>
#include <AzCore/Console/ConsoleTypeHelpers.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <MicrophoneBus.h>
namespace Audio::CVars
{
// CVar: s_EnableRaycasts
// Usage: s_EnableRaycasts=true (false)
AZ_CVAR(bool, s_EnableRaycasts, true,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Set to true/false to globally enable/disable raycasting for audio occlusion & obstruction.");
// CVar: s_RaycastMinDistance
// Usage: s_RaycastMinDistance=0.5
// Note: This callback defines an "absolute" minimum constant that the value of the CVar should not go below.
// We clamp the value to this minimum if it goes below this.
AZ_CVAR(float, s_RaycastMinDistance, 0.5f,
[](const float& minDist) -> void
{
if (minDist >= s_RaycastMaxDistance)
{
AZ_Warning("SoundCVars", false,
"CVar 's_RaycastMinDistance' (%f) needs to be less than 's_RaycastMaxDistance' (%f).\n"
"Audio raycasts won't run until the distance range is fixed.\n",
static_cast<float>(s_RaycastMinDistance), static_cast<float>(s_RaycastMaxDistance));
}
static constexpr float s_absoluteMinRaycastDistance = 0.1f;
s_RaycastMinDistance = AZ::GetMax(minDist, s_absoluteMinRaycastDistance);
AZ_Warning("SoundCVars", s_RaycastMinDistance == minDist,
"CVar 's_RaycastMinDistance' will be clamped to an absolute minimum value of %f.\n", s_absoluteMinRaycastDistance);
},
AZ::ConsoleFunctorFlags::Null,
"Raycasts for obstruction/occlusion are not sent for sounds whose distance to the listener is less than this value.");
// CVar: s_RaycastMaxDistance
// Usage: s_RaycastMaxDistance=100.0
// Note: This callback defines an "absolute" maximum constant that the value of the CVar should not go above.
// We clamp the value to this maximum if it goes above this.
AZ_CVAR(float, s_RaycastMaxDistance, 100.f,
[](const float& maxDist) -> void
{
if (maxDist <= s_RaycastMinDistance)
{
AZ_Warning("SoundCVars", false,
"CVar 's_RaycastMaxDistance' (%f) needs to be greater than 's_RaycastMinDistance' (%f).\n"
"Audio raycasts won't run until the distance range is fixed.\n",
static_cast<float>(s_RaycastMaxDistance), static_cast<float>(s_RaycastMinDistance));
}
static constexpr float s_absoluteMaxRaycastDistance = 1000.f;
s_RaycastMaxDistance = AZ::GetMin(maxDist, s_absoluteMaxRaycastDistance);
AZ_Warning("SoundCVars", s_RaycastMaxDistance == maxDist,
"CVar 's_RaycastMaxDistance' will be clamped to an absolute maximum value of %f.\n", s_absoluteMaxRaycastDistance);
},
AZ::ConsoleFunctorFlags::Null,
"Raycasts for obstruction/occlusion are not sent for sounds whose distance to the listener is greater than this value.");
// CVar: s_RaycastCacheTimeMs
// Usage: s_RaycastCacheTimeMs=250.0
// Note: This callback defines an "absolute" minimum constant that the value of the CVar should not go below.
// We clamp the value to this minimum if it goes below this.
AZ_CVAR(float, s_RaycastCacheTimeMs, 250.f,
[](const float& cacheTimeMs) -> void
{
static constexpr float s_absoluteMinRaycastCacheTimeMs = 1 / 60.f;
s_RaycastCacheTimeMs = AZ::GetMax(cacheTimeMs, s_absoluteMinRaycastCacheTimeMs);
AZ_Warning("SoundCVars", cacheTimeMs == s_RaycastCacheTimeMs,
"CVar 's_RaycastCacheTimeMs' will be clamped to an absolute minimum of %f.\n", s_absoluteMinRaycastCacheTimeMs);
},
AZ::ConsoleFunctorFlags::Null,
"Physics raycast results are given this amount of time before they are considered dirty and need to be recast.");
// CVar: s_RaycastSmoothFactor
// Usage: s_RaycastSmoothFactor=5.0
AZ_CVAR(float, s_RaycastSmoothFactor, 7.f,
[](const float& smoothFactor) -> void
{
static constexpr float s_absoluteMinRaycastSmoothFactor = 0.f;
static constexpr float s_absoluteMaxRaycastSmoothFactor = 10.f;
s_RaycastSmoothFactor = AZ::GetClamp(smoothFactor, s_absoluteMinRaycastSmoothFactor, s_absoluteMaxRaycastSmoothFactor);
AZ_Warning("SoundCVars", s_RaycastSmoothFactor == smoothFactor,
"CVar 's_RaycastSmoothFactor' was be clamped to an absolute range of [%f, %f].\n",
s_absoluteMinRaycastSmoothFactor, s_absoluteMaxRaycastSmoothFactor);
},
AZ::ConsoleFunctorFlags::Null,
"How slowly the smoothing of obstruction/occlusion values should smooth to target: delta / (smoothFactor^2 + 1). "
"Low values will smooth faster, high values will smooth slower.");
AZ_CVAR(AZ::u64, s_ATLMemorySize, AZ_TRAIT_AUDIOSYSTEM_ATL_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of memory to be used by the ATL/Audio System.\n"
"Usage: s_ATLMemorySize=" AZ_TRAIT_AUDIOSYSTEM_ATL_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_FileCacheManagerMemorySize, AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB the File Cache Manager will use for banks.\n"
"Usage: s_FileCacheManagerMemorySize=" AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_AudioEventPoolSize, AZ_TRAIT_AUDIOSYSTEM_AUDIO_EVENT_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The number of audio events to preallocate in a pool.\n"
"Usage: s_AudioEventPoolSize=" AZ_TRAIT_AUDIOSYSTEM_AUDIO_EVENT_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_AudioObjectPoolSize, AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The number of audio objects to preallocate in a pool.\n"
"Usage: s_AudioObjectPoolSize=" AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(float, s_PositionUpdateThreshold, 0.1f,
nullptr, AZ::ConsoleFunctorFlags::Null,
"An audio object needs to move by this distance in order to issue a position update to the audio system.\n"
"Usage: s_PositionUpdateThreshold=5.0\n");
AZ_CVAR(float, s_VelocityTrackingThreshold, 0.1f,
nullptr, AZ::ConsoleFunctorFlags::Null,
"An audio object needs to have its velocity changed by this amount in order to issue an 'object_speed' Rtpc update to the audio system.\n"
"Usage: s_VelocityTrackingThreshold=0.5\n");
AZ_CVAR(AZ::u32, s_AudioProxiesInitType, 0,
[](const AZ::u32& initType) -> void
{
static constexpr AZ::u32 s_numAudioProxyInitTypes = 3;
if (initType < s_numAudioProxyInitTypes)
{
s_AudioProxiesInitType = initType;
}
},
AZ::ConsoleFunctorFlags::Null,
"Overrides the initialization mode of audio proxies globally.\n"
"0: AudioProxy-specific initiaization (Default).\n"
"1: All AudioProxy's initialize synchronously.\n"
"2: All AudioProxy's initialize asynchronously.\n"
"Usage: s_AudioProxiesInitType=2\n");
auto OnChangeAudioLanguage = []([[maybe_unused]] const AZ::CVarFixedString& language) -> void
{
SAudioRequest languageRequest;
SAudioManagerRequestData<eAMRT_CHANGE_LANGUAGE> languageRequestData;
languageRequest.pData = &languageRequestData;
languageRequest.nFlags = Audio::eARF_PRIORITY_HIGH;
AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, languageRequest);
};
AZ_CVAR(AZ::CVarFixedString, g_languageAudio, "", OnChangeAudioLanguage, AZ::ConsoleFunctorFlags::Null, "");
#if !defined(AUDIO_RELEASE)
AZ_CVAR(bool, s_IgnoreWindowFocus, false,
nullptr, AZ::ConsoleFunctorFlags::Null,
"Determines whether application focus should issue events to the audio system or not.\n"
"false: Window focus event should be issued (Default).\n"
"true: Ignore window focus events.\n"
"Usage: s_IgnoreWindowFocus=true\n");
AZ_CVAR(bool, s_ShowActiveAudioObjectsOnly, false,
nullptr, AZ::ConsoleFunctorFlags::Null,
"Determines whether active or all audio objects should be drawn when debug drawing is enabled.\n"
"false: Draws all audio objects (Default).\n"
"true: Draws only active audio objects.\n"
"Usage: s_ShowActiveAudioObjectsOnly=true\n");
AZ_CVAR(AZ::CVarFixedString, s_AudioTriggersDebugFilter, "",
nullptr, AZ::ConsoleFunctorFlags::Null,
"Filters debug drawing to only audio triggers that match this filter as sub-string.\n"
"Usage: s_AudioTriggersDebugFilter=impact_hit\n");
AZ_CVAR(AZ::CVarFixedString, s_AudioObjectsDebugFilter, "",
nullptr, AZ::ConsoleFunctorFlags::Null,
"Filters debug drawing to only audio objects whose name matches this filter as a sub-string.\n"
"Usage: s_AudioObjectsDebugFilter=weapon_axe\n");
auto OnChangeLogOptions = [](const AZ::CVarFixedString& options) -> void
{
if (options == "0")
{
Audio::Log::s_audioLogOptions = Log::Options::None;
return;
}
Audio::Flags<AZ::u32> flags;
flags.SetFlags(Log::Options::Errors, options.contains("a"));
flags.SetFlags(Log::Options::Warnings, options.contains("b"));
flags.SetFlags(Log::Options::Comments, options.contains("c"));
Audio::Log::s_audioLogOptions = flags.GetRawFlags();
};
AZ_CVAR(AZ::CVarFixedString, s_AudioLoggingOptions, "ab",
OnChangeLogOptions,
AZ::ConsoleFunctorFlags::Null,
"Toggles the log level of audio related messages.\n"
"Usage: s_AudioLoggingOptions=abc (flags can be combined)\n"
"Default: ab (Errors & Warnings)\n"
"a: Errors\n"
"b: Warnings\n"
"c: Comments\n");
auto OnChangeDebugDrawOptions = [](const AZ::CVarFixedString& options) -> void
{
s_debugDrawOptions.ClearAllFlags();
if (options == "0")
{
return;
}
s_debugDrawOptions.SetFlags(DebugDraw::Options::DrawObjects, options.contains("a"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ObjectLabels, options.contains("b"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ObjectTriggers, options.contains("c"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ObjectStates, options.contains("d"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ObjectRtpcs, options.contains("e"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ObjectEnvironments, options.contains("f"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::DrawRays, options.contains("g"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::RayLabels, options.contains("h"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::DrawListener, options.contains("i"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ActiveEvents, options.contains("v"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::ActiveObjects, options.contains("w"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::FileCacheInfo, options.contains("x"));
s_debugDrawOptions.SetFlags(DebugDraw::Options::MemoryInfo, options.contains("y"));
};
AZ_CVAR(AZ::CVarFixedString, s_DrawAudioDebug, "",
OnChangeDebugDrawOptions,
AZ::ConsoleFunctorFlags::IsCheat,
"Draws AudioTranslationLayer related debug data to the screen.\n"
"Usage: s_DrawAudioDebug=abcde (flags can be combined)\n"
"0: Turn off.\n"
"a: Draw spheres around active audio objects.\n"
"b: Show text labels for active audio objects.\n"
"c: Show trigger names for active audio objects.\n"
"d: Show current states for active audio objects.\n"
"e: Show RTPC values for active audio objects.\n"
"f: Show Environment amounts for active audio objects.\n"
"g: Draw occlusion rays.\n"
"h: Show occlusion ray labels.\n"
"i: Draw sphere around active audio listener.\n"
"v: List active Events.\n"
"w: List active Audio Objects.\n"
"x: Show FileCache Manager debug info.\n"
"y: Show memory usage info for the audio engine.\n");
auto OnChangeFileCacheManagerFilterOptions = [](const AZ::CVarFixedString& options) -> void
{
s_fcmDrawOptions.ClearAllFlags();
if (options == "0")
{
return;
}
s_fcmDrawOptions.SetFlags(FileCacheManagerDebugDraw::Options::Global, options.contains("a"));
s_fcmDrawOptions.SetFlags(FileCacheManagerDebugDraw::Options::LevelSpecific, options.contains("b"));
s_fcmDrawOptions.SetFlags(FileCacheManagerDebugDraw::Options::UseCounted, options.contains("c"));
s_fcmDrawOptions.SetFlags(FileCacheManagerDebugDraw::Options::Loaded, options.contains("d"));
};
AZ_CVAR(AZ::CVarFixedString, s_FileCacheManagerDebugFilter, "",
OnChangeFileCacheManagerFilterOptions,
AZ::ConsoleFunctorFlags::IsCheat,
"Allows for filtered display of the file cache entries such as Globals, Level Specifics, Use Counted and so on.\n"
"Usage: s_FileCacheManagerDebugFilter [0ab...] (flags can be combined)\n"
"Default: 0 (all)\n"
"a: Globals\n"
"b: Level Specifics\n"
"c: Use Counted\n"
"d: Currently Loaded\n");
static void s_ExecuteTrigger(const AZ::ConsoleCommandContainer& args);
static void s_StopTrigger(const AZ::ConsoleCommandContainer& args);
static void s_SetRtpc(const AZ::ConsoleCommandContainer& args);
static void s_SetSwitchState(const AZ::ConsoleCommandContainer& args);
static void s_LoadPreload(const AZ::ConsoleCommandContainer& args);
static void s_UnloadPreload(const AZ::ConsoleCommandContainer& args);
static void s_PlayFile(const AZ::ConsoleCommandContainer& args);
static void s_Microphone(const AZ::ConsoleCommandContainer& args);
static void s_PlayExternalSource(const AZ::ConsoleCommandContainer& args);
static void s_SetPanningMode(const AZ::ConsoleCommandContainer& args);
AZ_CONSOLEFREEFUNC(s_ExecuteTrigger, AZ::ConsoleFunctorFlags::IsCheat,
"Execute an Audio Trigger.\n"
"The first argument is the name of the AudioTrigger to be executed, the second argument is an optional AudioObject ID.\n"
"If the second argument is provided, the AudioTrigger is executed on the AudioObject with the given ID,\n"
"otherwise, the AudioTrigger is executed on the GlobalAudioObject\n"
"Usage: s_ExecuteTrigger Play_chicken_idle 605 or s_ExecuteTrigger MuteDialog\n");
AZ_CONSOLEFREEFUNC(s_StopTrigger, AZ::ConsoleFunctorFlags::IsCheat,
"Stops an Audio Trigger.\n"
"The first argument is the name of the AudioTrigger to be stopped, the second argument is an optional AudioObject ID.\n"
"If the second argument is provided, the AudioTrigger is stopped on the AudioObject with the given ID,\n"
"otherwise, the AudioTrigger is stopped on the GlobalAudioObject\n"
"Usage: s_StopTrigger Play_chicken_idle 605 or s_StopTrigger MuteDialog\n");
AZ_CONSOLEFREEFUNC(s_SetRtpc, AZ::ConsoleFunctorFlags::IsCheat,
"Set an Audio RTPC value.\n"
"The first argument is the name of the AudioRtpc to be set, the second argument is the float value to be set,"
"the third argument is an optional AudioObject ID.\n"
"If the third argument is provided, the AudioRtpc is set on the AudioObject with the given ID,\n"
"otherwise, the AudioRtpc is set on the GlobalAudioObject\n"
"Usage: s_SetRtpc character_speed 0.0 601 or s_SetRtpc volume_music 1.0\n");
AZ_CONSOLEFREEFUNC(s_SetSwitchState, AZ::ConsoleFunctorFlags::IsCheat,
"Set an Audio Switch to a provided State.\n"
"The first argument is the name of the AudioSwitch to, the second argument is the name of the SwitchState to be set,"
"the third argument is an optional AudioObject ID.\n"
"If the third argument is provided, the AudioSwitch is set on the AudioObject with the given ID,\n"
"otherwise, the AudioSwitch is set on the GlobalAudioObject\n"
"Usage: s_SetSwitchState SurfaceType concrete 601 or s_SetSwitchState weather rain\n");
AZ_CONSOLEFREEFUNC(s_LoadPreload, AZ::ConsoleFunctorFlags::IsCheat,
"Load an Audio Preload to the FileCacheManager.\n"
"The first argument is the name of the ATL preload.\n"
"Usage: s_LoadPreload GlobalBank\n");
AZ_CONSOLEFREEFUNC(s_UnloadPreload, AZ::ConsoleFunctorFlags::IsCheat,
"Unload an Audio Preload from the FileCacheManager.\n"
"The first argument is the name of the ATL Prelaod.\n"
"Usage: s_UnloadPreload GlobalBank\n");
AZ_CONSOLEFREEFUNC(s_PlayFile, AZ::ConsoleFunctorFlags::IsCheat,
"Play an audio file directly.\n"
"First argument is the name of the file to play. Only .wav and .pcm (raw) files are supported right now.\n"
"Second argument is the name of the audio trigger to use."
"Usage: s_PlayFile \"sounds\\wwise\\external_sources\\sfx\\my_file.wav\" Play_audio_input_2D\n");
AZ_CONSOLEFREEFUNC(s_Microphone, AZ::ConsoleFunctorFlags::IsCheat,
"Turn on/off microphone input.\n"
"First argument is 0 or 1 to turn off or on the Microphone, respectively.\n"
"Second argument is the name of the ATL trigger to use (when turning microphone on) for Audio Input.\n"
"Usage: s_Microphone 1 Play_audio_input_2D\n"
"Usage: s_Microphone 0\n");
AZ_CONSOLEFREEFUNC(s_PlayExternalSource, AZ::ConsoleFunctorFlags::IsCheat,
"Execute an 'External Source' audio trigger.\n"
"The first argument is the name of the audio trigger to execute.\n"
"The second argument is the collection Id.\n"
"The third argument is the language Id.\n"
"The fourth argument is the file Id.\n"
"Usage: s_PlayExternalSource Play_external_VO 0 0 1\n");
AZ_CONSOLEFREEFUNC(s_SetPanningMode, AZ::ConsoleFunctorFlags::IsCheat,
"Set the Panning mode to either 'speakers' or 'headphones'.\n"
"Speakers will have a 60 degree angle from the listener to the L/R speakers.\n"
"Headphones will have a 180 degree angle from the listener to the L/R speakers.\n"
"Usage: s_SetPanningMode speakers (default)\n"
"Usage: s_SetPanningMode headphones\n");
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_ExecuteTrigger(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 1 || args.size() == 2)
{
AZStd::string triggerName(args[0]);
TAudioControlID triggerId = INVALID_AUDIO_CONTROL_ID;
AudioSystemRequestBus::BroadcastResult(triggerId, &AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName.c_str());
if (triggerId != INVALID_AUDIO_CONTROL_ID)
{
TAudioObjectID objectId = INVALID_AUDIO_OBJECT_ID;
if (args.size() == 2)
{
if (!AZ::ConsoleTypeHelpers::StringToValue<TAudioObjectID>(objectId, args[1]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid Object ID: %.*s", AZ_STRING_ARG(args[1]));
return;
}
}
SAudioRequest request;
SAudioObjectRequestData<eAORT_EXECUTE_TRIGGER> requestData(triggerId, 0.0f);
request.nAudioObjectID = objectId;
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Unknown trigger name: %.*s", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_ExecuteTrigger TriggerName [Optional Object ID]");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_StopTrigger(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 1 || args.size() == 2)
{
AZStd::string triggerName(args[0]);
TAudioControlID triggerId = INVALID_AUDIO_CONTROL_ID;
AudioSystemRequestBus::BroadcastResult(triggerId, &AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName.c_str());
if (triggerId != INVALID_AUDIO_CONTROL_ID)
{
TAudioObjectID objectId = INVALID_AUDIO_OBJECT_ID;
if (args.size() == 2)
{
if (!AZ::ConsoleTypeHelpers::StringToValue<TAudioObjectID>(objectId, args[1]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid Object ID: %.*s", AZ_STRING_ARG(args[1]));
return;
}
}
SAudioRequest request;
SAudioObjectRequestData<eAORT_STOP_TRIGGER> requestData(triggerId);
request.nAudioObjectID = objectId;
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Unknown trigger name: %.*s", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_StopTrigger TriggerName [Optional Object ID]");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_SetRtpc(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 2 || args.size() == 3)
{
AZStd::string rtpcName(args[0]);
TAudioControlID rtpcId = INVALID_AUDIO_CONTROL_ID;
AudioSystemRequestBus::BroadcastResult(rtpcId, &AudioSystemRequestBus::Events::GetAudioRtpcID, rtpcName.c_str());
if (rtpcId != INVALID_AUDIO_CONTROL_ID)
{
float value = 0.f;
if (!AZ::ConsoleTypeHelpers::StringToValue<float>(value, args[1]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid float number: %.*s", AZ_STRING_ARG(args[1]));
return;
}
TAudioObjectID objectId = INVALID_AUDIO_OBJECT_ID;
if (args.size() == 3)
{
if (!AZ::ConsoleTypeHelpers::StringToValue<TAudioObjectID>(objectId, args[2]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid Object ID: %.*s", AZ_STRING_ARG(args[2]));
return;
}
}
SAudioRequest request;
SAudioObjectRequestData<eAORT_SET_RTPC_VALUE> requestData(rtpcId, value);
request.nAudioObjectID = objectId;
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Unknown Rtpc name: %.*s", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_SetRtpc RtpcName RtpcValue [Optional Object ID]");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_SetSwitchState(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 2 || args.size() == 3)
{
AZStd::string switchName(args[0]);
TAudioControlID switchId = INVALID_AUDIO_CONTROL_ID;
AudioSystemRequestBus::BroadcastResult(switchId, &AudioSystemRequestBus::Events::GetAudioSwitchID, switchName.c_str());
if (switchId != INVALID_AUDIO_CONTROL_ID)
{
AZStd::string stateName(args[1]);
TAudioSwitchStateID stateId = INVALID_AUDIO_SWITCH_STATE_ID;
AudioSystemRequestBus::BroadcastResult(
stateId, &AudioSystemRequestBus::Events::GetAudioSwitchStateID, switchId, stateName.c_str());
if (stateId != INVALID_AUDIO_SWITCH_STATE_ID)
{
TAudioObjectID objectId = INVALID_AUDIO_OBJECT_ID;
if (args.size() == 3)
{
if (!AZ::ConsoleTypeHelpers::StringToValue<TAudioObjectID>(objectId, args[2]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid Object ID: %.*s", AZ_STRING_ARG(args[2]));
return;
}
}
SAudioRequest request;
SAudioObjectRequestData<eAORT_SET_SWITCH_STATE> requestData(switchId, stateId);
request.nAudioObjectID = objectId;
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Invalid Switch State name: %.*s", AZ_STRING_ARG(args[1]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Unknown Switch name: %.*s", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_SetSwitchState SwitchName SwitchStateName [Optional Object ID]");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_LoadPreload(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 1)
{
AZStd::string preloadName(args[0]);
TAudioPreloadRequestID preloadId = INVALID_AUDIO_PRELOAD_REQUEST_ID;
AudioSystemRequestBus::BroadcastResult(preloadId, &AudioSystemRequestBus::Events::GetAudioPreloadRequestID, preloadName.c_str());
if (preloadId != INVALID_AUDIO_PRELOAD_REQUEST_ID)
{
SAudioRequest request;
SAudioManagerRequestData<eAMRT_PRELOAD_SINGLE_REQUEST> requestData(preloadId);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Preload named %.*s not found", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_LoadPreload PreloadName");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_UnloadPreload(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 1)
{
AZStd::string preloadName(args[0]);
TAudioPreloadRequestID preloadId = INVALID_AUDIO_PRELOAD_REQUEST_ID;
AudioSystemRequestBus::BroadcastResult(preloadId, &AudioSystemRequestBus::Events::GetAudioPreloadRequestID, preloadName.c_str());
if (preloadId != INVALID_AUDIO_PRELOAD_REQUEST_ID)
{
SAudioRequest request;
SAudioManagerRequestData<eAMRT_UNLOAD_SINGLE_REQUEST> requestData(preloadId);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Preload named %.*s not found", AZ_STRING_ARG(args[0]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_UnloadPreload PreloadName");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_PlayFile(const AZ::ConsoleCommandContainer& args)
{
if (args.size() >= 2)
{
AZStd::string filename(args[0]);
AZStd::string fileext;
AZStd::to_lower(fileext.begin(), fileext.end());
AZ::StringFunc::Path::GetExtension(filename.c_str(), fileext, false);
AudioInputSourceType audioInputType = AudioInputSourceType::Unsupported;
// Use file extension to guess the file type
if (fileext.compare("wav") == 0)
{
audioInputType = AudioInputSourceType::WavFile;
}
else if (fileext.compare("pcm") == 0)
{
audioInputType = AudioInputSourceType::PcmFile;
}
if (audioInputType != AudioInputSourceType::Unsupported)
{
// Setup the configuration...
SAudioInputConfig audioInputConfig(audioInputType, filename.c_str());
if (audioInputType == AudioInputSourceType::PcmFile)
{
if (args.size() == 4)
{
audioInputConfig.m_bitsPerSample = 16;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u32>(audioInputConfig.m_numChannels, args[2]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid number of channels '%.*s'", AZ_STRING_ARG(args[2]));
return;
}
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u32>(audioInputConfig.m_sampleRate, args[3]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid sample rate '%.*s'", AZ_STRING_ARG(args[3]));
return;
}
audioInputConfig.m_sampleType = AudioInputSampleType::Int;
}
else
{
g_audioLogger.Log(
eALT_ERROR, "Using PCM file, additional parameters needed: [NumChannels] [SampleRate] (e.g. 2 16000)");
return;
}
}
TAudioSourceId sourceId = INVALID_AUDIO_SOURCE_ID;
AudioSystemRequestBus::BroadcastResult(sourceId, &AudioSystemRequestBus::Events::CreateAudioSource, audioInputConfig);
if (sourceId != INVALID_AUDIO_SOURCE_ID)
{
TAudioControlID triggerId = INVALID_AUDIO_CONTROL_ID;
AudioSystemRequestBus::BroadcastResult(
triggerId, &AudioSystemRequestBus::Events::GetAudioTriggerID, args[1].data());
if (triggerId != INVALID_AUDIO_CONTROL_ID)
{
SAudioRequest request;
SAudioObjectRequestData<eAORT_EXECUTE_SOURCE_TRIGGER> requestData(triggerId, sourceId);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::DestroyAudioSource, sourceId);
g_audioLogger.Log(eALT_ERROR, "Failed to find the trigger named %.*s", AZ_STRING_ARG(args[1]));
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Unable to create a new audio source");
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Audio files with extension '.%s' are unsupported", fileext.c_str());
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_PlayFile \"path\\to\\myfile.wav\" Play_audio_input_2D");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_Microphone(const AZ::ConsoleCommandContainer& args)
{
static bool micState = false; // mic is off initially
static TAudioSourceId micSourceId = INVALID_AUDIO_SOURCE_ID;
static TAudioControlID triggerId = INVALID_AUDIO_CONTROL_ID;
if (args.size() == 2)
{
AZ::u32 state;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u32>(state, args[0]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid number passed '%.*s', should be 0 or 1", AZ_STRING_ARG(args[0]));
return;
}
AZStd::string triggerName(args[1]);
if (state == 1 && !micState && micSourceId == INVALID_AUDIO_SOURCE_ID && triggerId == INVALID_AUDIO_CONTROL_ID)
{
g_audioLogger.Log(eALT_ALWAYS, "Turning on Microhpone with %s\n", triggerName.c_str());
bool success = true;
AudioSystemRequestBus::BroadcastResult(triggerId, &AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName.c_str());
if (triggerId != INVALID_AUDIO_CONTROL_ID)
{
// Start the mic session
bool startedMic = false;
MicrophoneRequestBus::BroadcastResult(startedMic, &MicrophoneRequestBus::Events::StartSession);
if (startedMic)
{
SAudioInputConfig micConfig;
MicrophoneRequestBus::BroadcastResult(micConfig, &MicrophoneRequestBus::Events::GetFormatConfig);
// If you want to test resampling, set the values here before you create an Audio Source.
// In this case, we would be specifying 16kHz, 16-bit integers.
// micConfig.m_sampleRate = 16000;
// micConfig.m_bitsPerSample = 16;
// micConfig.m_sampleType = AudioInputSampleType::Int;
AudioSystemRequestBus::BroadcastResult(micSourceId, &AudioSystemRequestBus::Events::CreateAudioSource, micConfig);
if (micSourceId != INVALID_AUDIO_SOURCE_ID)
{
SAudioRequest request;
SAudioObjectRequestData<eAORT_EXECUTE_SOURCE_TRIGGER> requestData(triggerId, micSourceId);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
success = false;
g_audioLogger.Log(eALT_ERROR, "Failed to create a new audio source for the microphone");
}
}
else
{
success = false;
g_audioLogger.Log(eALT_ERROR, "Failed to start the microphone session");
}
}
else
{
success = false;
g_audioLogger.Log(eALT_ERROR, "Failed to find the trigger named %s", triggerName.c_str());
}
if (success)
{
micState = true;
}
else
{
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::DestroyAudioSource, micSourceId);
MicrophoneRequestBus::Broadcast(&MicrophoneRequestBus::Events::EndSession);
micSourceId = INVALID_AUDIO_SOURCE_ID;
triggerId = INVALID_AUDIO_CONTROL_ID;
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Error encountered while turning on/off microphone");
}
}
else if (args.size() == 1)
{
AZ::u32 state;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u32>(state, args[0]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid number passed '%.*s', should be 0 or 1", AZ_STRING_ARG(args[0]));
return;
}
if (state == 0 && micState && micSourceId != INVALID_AUDIO_SOURCE_ID && triggerId != INVALID_AUDIO_CONTROL_ID)
{
g_audioLogger.Log(eALT_ALWAYS, "Turning off Microphone\n");
// Stop the trigger (may not be necessary)
SAudioRequest request;
SAudioObjectRequestData<eAORT_STOP_TRIGGER> requestData(triggerId);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
// Destroy the audio source, end the mic session, and reset state...
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::DestroyAudioSource, micSourceId);
MicrophoneRequestBus::Broadcast(&MicrophoneRequestBus::Events::EndSession);
micSourceId = INVALID_AUDIO_SOURCE_ID;
triggerId = INVALID_AUDIO_CONTROL_ID;
micState = false;
}
else
{
g_audioLogger.Log(eALT_ERROR, "Error encountered while turning on/off microphone");
}
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_Microphone 1 Play_audio_input_2D\nUsage: s_Microphone 0");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_PlayExternalSource(const AZ::ConsoleCommandContainer& args)
{
// This cookie value is a hash on the name of the External Source.
// By default when you add an External Source to a sound, it gives the name 'External_Source' and has this hash.
// Apparently it can be changed in the Wwise project, so it's unfortunately content-dependent. But there's no easy
// way to extract that info in this context.
static constexpr AZ::u64 externalSourceCookieValue = 618371124ull;
TAudioControlID triggerId = INVALID_AUDIO_CONTROL_ID;
if (args.size() == 4)
{
AZStd::string triggerName(args[0]);
AudioSystemRequestBus::BroadcastResult(triggerId, &AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName.c_str());
if (triggerId == INVALID_AUDIO_CONTROL_ID)
{
g_audioLogger.Log(eALT_ERROR, "Failed to find the trigger named '%s'\n", triggerName.c_str());
return;
}
AZ::u64 collection;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u64>(collection, args[1]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid collection number passed '%.*s'", AZ_STRING_ARG(args[1]));
return;
}
AZ::u64 language;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u64>(language, args[2]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid language number passed '%.*s'", AZ_STRING_ARG(args[2]));
return;
}
AZ::u64 file;
if (!AZ::ConsoleTypeHelpers::StringToValue<AZ::u64>(file, args[3]))
{
g_audioLogger.Log(eALT_ERROR, "Invalid file number passed '%.*s'", AZ_STRING_ARG(args[3]));
return;
}
SAudioSourceInfo sourceInfo(externalSourceCookieValue, file, language, collection, eACT_PCM);
SAudioRequest request;
SAudioObjectRequestData<eAORT_EXECUTE_SOURCE_TRIGGER> requestData(triggerId, sourceInfo);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_PlayExternalSource Play_ext_vo 0 0 1");
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void s_SetPanningMode(const AZ::ConsoleCommandContainer& args)
{
if (args.size() == 1)
{
PanningMode panningMode;
AZStd::string mode(args[0]);
AZStd::to_lower(mode.begin(), mode.end());
if (mode == "speakers")
{
panningMode = PanningMode::Speakers;
g_audioLogger.Log(eALT_COMMENT, "Setting Panning Mode to 'Speakers'\n");
}
else if (mode == "headphones")
{
panningMode = PanningMode::Headphones;
g_audioLogger.Log(eALT_COMMENT, "Setting Panning Mode to 'Headphones'\n");
}
else
{
g_audioLogger.Log(eALT_ERROR,
"Panning mode '%.*s' is invalid. Please specify either 'speakers' or 'headphones'\n",
AZ_STRING_ARG(args[0]));
return;
}
SAudioRequest request;
SAudioManagerRequestData<eAMRT_SET_AUDIO_PANNING_MODE> requestData(panningMode);
request.nFlags = eARF_PRIORITY_NORMAL;
request.pData = &requestData;
AudioSystemRequestBus::Broadcast(&AudioSystemRequestBus::Events::PushRequest, request);
}
else
{
g_audioLogger.Log(eALT_ERROR, "Usage: s_SetPanningMode (speakers|headphones)\n");
}
}
#endif // !AUDIO_RELEASE
} // namespace Audio::CVars