AkUnrealHelper.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "AkUnrealHelper.h"
  16. #include "Wwise/Stats/SoundEngine.h"
  17. #include "AkUEFeatures.h"
  18. #if UE_5_1_OR_LATER
  19. #include "Engine/HitResult.h"
  20. #endif
  21. #include "Misc/Paths.h"
  22. namespace AkUnrealHelper
  23. {
  24. const TCHAR* MediaFolderName = TEXT("Media");
  25. const TCHAR* ExternalSourceFolderName = TEXT("ExternalSources");
  26. constexpr auto SoundBankNamePrefix = TEXT("SB_");
  27. const FGuid InitBankID(0x701ECBBD, 0x9C7B4030, 0x8CDB749E, 0xE5D1C7B9);
  28. FString(*GetWwisePluginDirectoryPtr)();
  29. FString(*GetWwiseProjectPathPtr)();
  30. FString(*GetSoundBankDirectoryPtr)();
  31. FString(*GetStagePathPtr)();
  32. void SetHelperFunctions(FString(* GetWwisePluginDirectoryImpl)(), FString(* GetWwiseProjectPathImpl)(),
  33. FString(* GetSoundBankDirectoryImpl)(), FString(* GetStagePathImpl)())
  34. {
  35. GetWwisePluginDirectoryPtr = GetWwisePluginDirectoryImpl;
  36. GetWwiseProjectPathPtr = GetWwiseProjectPathImpl;
  37. GetSoundBankDirectoryPtr = GetSoundBankDirectoryImpl;
  38. GetStagePathPtr = GetStagePathImpl;
  39. }
  40. FString GetWwisePluginDirectory()
  41. {
  42. if (!GetWwisePluginDirectoryPtr)
  43. {
  44. UE_LOG(LogWwiseSoundEngine, Error, TEXT("AkUnrealHelper::GetWwisePluginDirectory implementation not set."));
  45. return {};
  46. }
  47. return GetWwisePluginDirectoryPtr();
  48. }
  49. FString GetWwiseProjectPath()
  50. {
  51. if (!GetWwiseProjectPathPtr)
  52. {
  53. UE_LOG(LogWwiseSoundEngine, Error, TEXT("AkUnrealHelper::GetWwiseProjectPath implementation not set."));
  54. return {};
  55. }
  56. return GetWwiseProjectPathPtr();
  57. }
  58. FString GetSoundBankDirectory()
  59. {
  60. if (!GetSoundBankDirectoryPtr)
  61. {
  62. UE_LOG(LogWwiseSoundEngine, Error, TEXT("AkUnrealHelper::GetSoundBankDirectory implementation not set."));
  63. return {};
  64. }
  65. return GetSoundBankDirectoryPtr();
  66. }
  67. FString GetStagePath()
  68. {
  69. if (!GetStagePathPtr)
  70. {
  71. UE_LOG(LogWwiseSoundEngine, Error, TEXT("AkUnrealHelper::GetStagePath implementation not set."));
  72. return {};
  73. }
  74. return GetStagePathPtr();
  75. }
  76. void TrimPath(FString& Path)
  77. {
  78. Path.TrimStartAndEndInline();
  79. }
  80. FString GetProjectDirectory()
  81. {
  82. return FPaths::ConvertRelativePathToFull(FPaths::ProjectDir());
  83. }
  84. FString GetContentDirectory()
  85. {
  86. return FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir());
  87. }
  88. FString GetThirdPartyDirectory()
  89. {
  90. return FPaths::Combine(GetWwisePluginDirectory(), TEXT("ThirdParty"));
  91. }
  92. FString GetExternalSourceDirectory()
  93. {
  94. return FPaths::Combine(GetSoundBankDirectory(), ExternalSourceFolderName);
  95. }
  96. FString GetWwiseProjectDirectoryPath()
  97. {
  98. return FPaths::GetPath(GetWwiseProjectPath()) + TEXT("/");
  99. }
  100. bool MakePathRelativeToWwiseProject(FString& AbsolutePath)
  101. {
  102. auto wwiseProjectRoot = AkUnrealHelper::GetWwiseProjectDirectoryPath();
  103. #if PLATFORM_WINDOWS
  104. AbsolutePath.ReplaceInline(TEXT("/"), TEXT("\\"));
  105. wwiseProjectRoot.ReplaceInline(TEXT("/"), TEXT("\\"));
  106. #endif
  107. bool success = FPaths::MakePathRelativeTo(AbsolutePath, *wwiseProjectRoot);
  108. #if PLATFORM_WINDOWS
  109. AbsolutePath.ReplaceInline(TEXT("/"), TEXT("\\"));
  110. #endif
  111. return success;
  112. }
  113. FString GetWwiseSoundBankInfoCachePath()
  114. {
  115. return FPaths::Combine(FPaths::GetPath(GetWwiseProjectPath()), TEXT(".cache"), TEXT("SoundBankInfoCache.dat"));
  116. }
  117. const TCHAR* GetResultString(AKRESULT InResult)
  118. {
  119. switch (InResult)
  120. {
  121. case AK_NotImplemented: return TEXT("This feature is not implemented.");
  122. case AK_Success: return TEXT("The operation was successful.");
  123. case AK_Fail: return TEXT("The operation failed.");
  124. case AK_PartialSuccess: return TEXT("The operation succeeded partially.");
  125. case AK_NotCompatible: return TEXT("Incompatible formats");
  126. case AK_AlreadyConnected: return TEXT("The stream is already connected to another node.");
  127. case AK_InvalidFile: return TEXT("The provided file is the wrong format or unexpected values causes the file to be invalid.");
  128. case AK_AudioFileHeaderTooLarge: return TEXT("The file header is too large.");
  129. case AK_MaxReached: return TEXT("The maximum was reached.");
  130. case AK_InvalidID: return TEXT("The ID is invalid.");
  131. case AK_IDNotFound: return TEXT("The ID was not found.");
  132. case AK_InvalidInstanceID: return TEXT("The InstanceID is invalid.");
  133. case AK_NoMoreData: return TEXT("No more data is available from the source.");
  134. case AK_InvalidStateGroup: return TEXT("The StateGroup is not a valid channel.");
  135. case AK_ChildAlreadyHasAParent: return TEXT("The child already has a parent.");
  136. case AK_InvalidLanguage: return TEXT("The language is invalid (applies to the Low-Level I/O).");
  137. case AK_CannotAddItseflAsAChild: return TEXT("It is not possible to add itself as its own child.");
  138. case AK_InvalidParameter: return TEXT("Something is not within bounds, check the documentation of the function returning this code.");
  139. case AK_ElementAlreadyInList: return TEXT("The item could not be added because it was already in the list.");
  140. case AK_PathNotFound: return TEXT("This path is not known.");
  141. case AK_PathNoVertices: return TEXT("Stuff in vertices before trying to start it");
  142. case AK_PathNotRunning: return TEXT("Only a running path can be paused.");
  143. case AK_PathNotPaused: return TEXT("Only a paused path can be resumed.");
  144. case AK_PathNodeAlreadyInList: return TEXT("This path is already there.");
  145. case AK_PathNodeNotInList: return TEXT("This path is not there.");
  146. case AK_DataNeeded: return TEXT("The consumer needs more.");
  147. case AK_NoDataNeeded: return TEXT("The consumer does not need more.");
  148. case AK_DataReady: return TEXT("The provider has available data.");
  149. case AK_NoDataReady: return TEXT("The provider does not have available data.");
  150. case AK_InsufficientMemory: return TEXT("Memory error.");
  151. case AK_Cancelled: return TEXT("The requested action was cancelled (not an error).");
  152. case AK_UnknownBankID: return TEXT("Trying to load a bank using an ID which is not defined.");
  153. case AK_BankReadError: return TEXT("Error while reading a bank.");
  154. case AK_InvalidSwitchType: return TEXT("Invalid switch type (used with the switch container)");
  155. case AK_FormatNotReady: return TEXT("Source format not known yet.");
  156. case AK_WrongBankVersion: return TEXT("The bank version is not compatible with the current bank reader.");
  157. case AK_FileNotFound: return TEXT("File not found.");
  158. case AK_DeviceNotReady: return TEXT("Specified ID doesn't match a valid hardware device: either the device doesn't exist or is disabled.");
  159. case AK_BankAlreadyLoaded: return TEXT("The bank load failed because the bank is already loaded.");
  160. case AK_RenderedFX: return TEXT("The effect on the node is rendered.");
  161. case AK_ProcessNeeded: return TEXT("A routine needs to be executed on some CPU.");
  162. case AK_ProcessDone: return TEXT("The executed routine has finished its execution.");
  163. case AK_MemManagerNotInitialized: return TEXT("The memory manager should have been initialized at this point.");
  164. case AK_StreamMgrNotInitialized: return TEXT("The stream manager should have been initialized at this point.");
  165. case AK_SSEInstructionsNotSupported: return TEXT("The machine does not support SSE instructions (required on PC).");
  166. case AK_Busy: return TEXT("The system is busy and could not process the request.");
  167. case AK_UnsupportedChannelConfig: return TEXT("Channel configuration is not supported in the current execution context.");
  168. case AK_PluginMediaNotAvailable: return TEXT("Plugin media is not available for effect.");
  169. case AK_MustBeVirtualized: return TEXT("Sound was Not Allowed to play.");
  170. case AK_CommandTooLarge: return TEXT("SDK command is too large to fit in the command queue.");
  171. case AK_RejectedByFilter: return TEXT("A play request was rejected due to the MIDI filter parameters.");
  172. case AK_InvalidCustomPlatformName: return TEXT("Detecting incompatibility between Custom platform of banks and custom platform of connected application");
  173. case AK_DLLCannotLoad: return TEXT("Plugin DLL could not be loaded, either because it is not found or one dependency is missing.");
  174. case AK_DLLPathNotFound: return TEXT("Plugin DLL search path could not be found.");
  175. case AK_NoJavaVM: return TEXT("No Java VM provided in AkInitSettings.");
  176. case AK_OpenSLError: return TEXT("OpenSL returned an error. Check error log for more details.");
  177. case AK_PluginNotRegistered: return TEXT("Plugin is not registered. Make sure to implement a AK::PluginRegistration class for it and use AK_STATIC_LINK_PLUGIN in the game binary.");
  178. case AK_DataAlignmentError: return TEXT("A pointer to audio data was not aligned to the platform's required alignment (check AkTypes.h in the platform-specific folder)");
  179. case AK_DeviceNotCompatible: return TEXT("Incompatible Audio device.");
  180. case AK_DuplicateUniqueID: return TEXT("Two Wwise objects share the same ID.");
  181. case AK_InitBankNotLoaded: return TEXT("The Init bank was not loaded yet, the sound engine isn't completely ready yet.");
  182. case AK_DeviceNotFound: return TEXT("The specified device ID does not match with any of the output devices that the sound engine is currently using.");
  183. case AK_PlayingIDNotFound: return TEXT("Calling a function with a playing ID that is not known.");
  184. case AK_InvalidFloatValue: return TEXT("One parameter has a invalid float value such as NaN, INF or FLT_MAX.");
  185. case AK_FileFormatMismatch: return TEXT("Media file format unexpected");
  186. case AK_NoDistinctListener: return TEXT("No distinct listener provided for AddOutput");
  187. case AK_ACP_Error: return TEXT("Generic XMA decoder error.");
  188. case AK_ResourceInUse: return TEXT("Resource is in use and cannot be released.");
  189. case AK_InvalidBankType: return TEXT("Invalid bank type. The bank type was either supplied through a function call (e.g. LoadBank) or obtained from a bank loaded from memory.");
  190. case AK_AlreadyInitialized: return TEXT("Init() was called but that element was already initialized.");
  191. case AK_NotInitialized: return TEXT("The component being used is not initialized. Most likely AK::SoundEngine::Init() was not called yet, or AK::SoundEngine::Term was called too early.");
  192. case AK_FilePermissionError: return TEXT("The file access permissions prevent opening a file.");
  193. case AK_UnknownFileError: return TEXT("Rare file error occured, as opposed to AK_FileNotFound or AK_FilePermissionError. This lumps all unrecognized OS file system errors.");
  194. default: return TEXT("Unknown Error.");
  195. }
  196. }
  197. #if WITH_EDITOR
  198. FString GuidToBankName(const FGuid& Guid)
  199. {
  200. if (Guid == InitBankID)
  201. {
  202. return TEXT("Init");
  203. }
  204. return FString(SoundBankNamePrefix) + Guid.ToString(EGuidFormats::Digits);
  205. }
  206. FGuid BankNameToGuid(const FString& BankName)
  207. {
  208. FString copy = BankName;
  209. copy.RemoveFromStart(SoundBankNamePrefix);
  210. FGuid result;
  211. FGuid::ParseExact(copy, EGuidFormats::Digits, result);
  212. return result;
  213. }
  214. FString FormatFolderPath(const FString folderPath)
  215. {
  216. auto path = folderPath.Replace(TEXT("\\"), TEXT("/"));
  217. if (path[0] == '/') {
  218. path.RemoveAt(0);
  219. }
  220. return path;
  221. }
  222. #endif
  223. }