AkSettings.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535
  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 "AkSettings.h"
  16. #include "AkAcousticTexture.h"
  17. #include "AkAuxBus.h"
  18. #include "AkAudioDevice.h"
  19. #include "AkAudioEvent.h"
  20. #include "AkAudioModule.h"
  21. #include "AkSettingsPerUser.h"
  22. #include "WwiseUnrealDefines.h"
  23. #include "AssetRegistry/AssetRegistryModule.h"
  24. #include "AssetRegistry/AssetData.h"
  25. #include "Framework/Docking/TabManager.h"
  26. #include "Framework/Notifications/NotificationManager.h"
  27. #include "StringMatchAlgos/Array2D.h"
  28. #include "StringMatchAlgos/StringMatching.h"
  29. #include "UObject/UnrealType.h"
  30. #include "Widgets/Notifications/SNotificationList.h"
  31. #if WITH_EDITOR
  32. #include "AkAudioStyle.h"
  33. #include "AssetToolsModule.h"
  34. #if UE_5_0_OR_LATER
  35. #include "HAL/PlatformFileManager.h"
  36. #else
  37. #include "HAL/PlatformFilemanager.h"
  38. #endif
  39. #include "Misc/ConfigCacheIni.h"
  40. #include "Misc/FileHelper.h"
  41. #include "Misc/MessageDialog.h"
  42. #include "Platforms/AkUEPlatform.h"
  43. #include "Settings/ProjectPackagingSettings.h"
  44. #include "ISettingsEditorModule.h"
  45. #include "ISourceControlModule.h"
  46. #include "SourceControlHelpers.h"
  47. #include "AkUnrealEditorHelper.h"
  48. #if AK_SUPPORT_WAAPI
  49. #include "AkWaapiClient.h"
  50. #include "AkWaapiUtils.h"
  51. #include "Async/Async.h"
  52. bool WAAPIGetTextureParams(FGuid textureID, FAkAcousticTextureParams& params)
  53. {
  54. auto waapiClient = FAkWaapiClient::Get();
  55. if (waapiClient != nullptr)
  56. {
  57. /* Construct the relevant WAAPI json fields. */
  58. TArray<TSharedPtr<FJsonValue>> fromID;
  59. fromID.Add(MakeShareable(new FJsonValueString(textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces))));
  60. TSharedRef<FJsonObject> getArgsJson = FAkWaapiClient::CreateWAAPIGetArgumentJson(FAkWaapiClient::WAAPIGetFromOption::ID, fromID);
  61. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  62. TArray<TSharedPtr<FJsonValue>> StructJsonArray;
  63. StructJsonArray.Add(MakeShareable(new FJsonValueString("id")));
  64. TArray<FString> absorptionStrings{ "@AbsorptionLow", "@AbsorptionMidLow", "@AbsorptionMidHigh", "@AbsorptionHigh" };
  65. for (int i = 0; i < absorptionStrings.Num(); ++i)
  66. StructJsonArray.Add(MakeShareable(new FJsonValueString(absorptionStrings[i])));
  67. options->SetArrayField(FAkWaapiClient::WAAPIStrings::RETURN, StructJsonArray);
  68. TSharedPtr<FJsonObject> outJsonResult;
  69. if (waapiClient->Call(ak::wwise::core::object::get, getArgsJson, options, outJsonResult, 500, false))
  70. {
  71. /* Get absorption values from WAAPI return json. */
  72. TArray<TSharedPtr<FJsonValue>> returnJson = outJsonResult->GetArrayField(FAkWaapiClient::WAAPIStrings::RETURN);
  73. if (returnJson.Num() > 0)
  74. {
  75. auto jsonObj = returnJson[0]->AsObject();
  76. if (jsonObj != nullptr)
  77. {
  78. TSharedPtr<FJsonObject> absorptionObject = nullptr;
  79. for (int i = 0; i < absorptionStrings.Num(); ++i)
  80. {
  81. params.AbsorptionValues[i] = (float)(jsonObj->GetNumberField(absorptionStrings[i])) / 100.0f;
  82. }
  83. return true;
  84. }
  85. }
  86. }
  87. }
  88. return false;
  89. }
  90. bool WAAPIGetObjectColorIndex(FGuid textureID, int& index)
  91. {
  92. auto waapiClient = FAkWaapiClient::Get();
  93. if (waapiClient != nullptr)
  94. {
  95. /* Construct the relevant WAAPI json fields. */
  96. TArray<TSharedPtr<FJsonValue>> fromID;
  97. fromID.Add(MakeShareable(new FJsonValueString(textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces))));
  98. TSharedRef<FJsonObject> getArgsJson = FAkWaapiClient::CreateWAAPIGetArgumentJson(FAkWaapiClient::WAAPIGetFromOption::ID, fromID);
  99. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  100. TArray<TSharedPtr<FJsonValue>> StructJsonArray;
  101. StructJsonArray.Add(MakeShareable(new FJsonValueString("id")));
  102. StructJsonArray.Add(MakeShareable(new FJsonValueString("@Color")));
  103. options->SetArrayField(FAkWaapiClient::WAAPIStrings::RETURN, StructJsonArray);
  104. TSharedPtr<FJsonObject> outJsonResult;
  105. if (waapiClient->Call(ak::wwise::core::object::get, getArgsJson, options, outJsonResult, 500, false))
  106. {
  107. /* Get absorption values from WAAPI return json. */
  108. TArray<TSharedPtr<FJsonValue>> returnJson = outJsonResult->GetArrayField(FAkWaapiClient::WAAPIStrings::RETURN);
  109. if (returnJson.Num() > 0)
  110. {
  111. auto jsonObj = returnJson[0]->AsObject();
  112. if (jsonObj != nullptr)
  113. {
  114. index = (int)(jsonObj->GetNumberField("@Color"));
  115. return true;
  116. }
  117. }
  118. }
  119. }
  120. return false;
  121. }
  122. bool WAAPIGetObjectOverrideColor(FGuid textureID)
  123. {
  124. auto waapiClient = FAkWaapiClient::Get();
  125. if (waapiClient != nullptr)
  126. {
  127. /* Construct the relevant WAAPI json fields. */
  128. TArray<TSharedPtr<FJsonValue>> fromID;
  129. fromID.Add(MakeShareable(new FJsonValueString(textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces))));
  130. TSharedRef<FJsonObject> getArgsJson = FAkWaapiClient::CreateWAAPIGetArgumentJson(FAkWaapiClient::WAAPIGetFromOption::ID, fromID);
  131. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  132. TArray<TSharedPtr<FJsonValue>> StructJsonArray;
  133. StructJsonArray.Add(MakeShareable(new FJsonValueString("id")));
  134. StructJsonArray.Add(MakeShareable(new FJsonValueString("@OverrideColor")));
  135. options->SetArrayField(FAkWaapiClient::WAAPIStrings::RETURN, StructJsonArray);
  136. TSharedPtr<FJsonObject> outJsonResult;
  137. if (waapiClient->Call(ak::wwise::core::object::get, getArgsJson, options, outJsonResult, 500, false))
  138. {
  139. /* Get absorption values from WAAPI return json. */
  140. TArray<TSharedPtr<FJsonValue>> returnJson = outJsonResult->GetArrayField(FAkWaapiClient::WAAPIStrings::RETURN);
  141. if (returnJson.Num() > 0)
  142. {
  143. auto jsonObj = returnJson[0]->AsObject();
  144. if (jsonObj != nullptr)
  145. {
  146. return jsonObj->GetBoolField("@OverrideColor");
  147. }
  148. }
  149. }
  150. }
  151. return false;
  152. }
  153. #endif // AK_SUPPORT_WAAPI
  154. #endif // WITH_EDITOR
  155. #define LOCTEXT_NAMESPACE "AkSettings"
  156. //////////////////////////////////////////////////////////////////////////
  157. // UAkSettings
  158. namespace AkSettings_Helper
  159. {
  160. #if WITH_EDITOR
  161. void MigrateMultiCoreRendering(bool EnableMultiCoreRendering, const FString& PlatformName)
  162. {
  163. FString SettingsClassName = FString::Format(TEXT("Ak{0}InitializationSettings"), { *PlatformName });
  164. #if UE_5_1_OR_LATER
  165. SettingsClassName = "/Script/AkAudio." + SettingsClassName;
  166. auto* SettingsClass = UClass::TryFindTypeSlow<UClass>(*SettingsClassName);
  167. #else
  168. auto* SettingsClass = FindObject<UClass>(ANY_PACKAGE, *SettingsClassName);
  169. #endif
  170. if (!SettingsClass)
  171. {
  172. return;
  173. }
  174. auto* MigrationFunction = SettingsClass->FindFunctionByName(TEXT("MigrateMultiCoreRendering"));
  175. auto* Settings = SettingsClass->GetDefaultObject();
  176. if (!MigrationFunction || !Settings)
  177. {
  178. return;
  179. }
  180. Settings->ProcessEvent(MigrationFunction, &EnableMultiCoreRendering);
  181. AkUnrealEditorHelper::SaveConfigFile(Settings);
  182. }
  183. #endif
  184. void MatchAcousticTextureNamesToPhysMaterialNames(
  185. const TArray<FAssetData>& PhysicalMaterials,
  186. const TArray<FAssetData>& AcousticTextures,
  187. TArray<int32>& assignments)
  188. {
  189. uint32 NumPhysMat = (uint32)PhysicalMaterials.Num();
  190. uint32 NumAcousticTex = (uint32)AcousticTextures.Num();
  191. // Create a scores matrix
  192. Array2D<float> scores(NumPhysMat, NumAcousticTex, 0);
  193. for (uint32 i = 0; i < NumPhysMat; ++i)
  194. {
  195. TArray<bool> perfectObjectMatches;
  196. perfectObjectMatches.Init(false, NumAcousticTex);
  197. if (PhysicalMaterials[i].GetAsset())
  198. {
  199. FString physMaterialName = PhysicalMaterials[i].GetAsset()->GetName();
  200. if (physMaterialName.Len() == 0)
  201. continue;
  202. for (uint32 j = 0; j < NumAcousticTex; ++j)
  203. {
  204. // Skip objects for which we already found a perfect match
  205. if (perfectObjectMatches[j] == true)
  206. continue;
  207. if (AcousticTextures[j].GetAsset())
  208. {
  209. FString acousticTextureName = AcousticTextures[j].GetAsset()->GetName();
  210. if (acousticTextureName.Len() == 0)
  211. continue;
  212. // Calculate longest common substring length
  213. float lcs = LCS::GetLCSScore(
  214. physMaterialName.ToLower(),
  215. acousticTextureName.ToLower());
  216. scores(i, j) = lcs;
  217. if (FMath::IsNearlyEqual(lcs, 1.f))
  218. {
  219. assignments[i] = j;
  220. perfectObjectMatches[j] = true;
  221. break;
  222. }
  223. }
  224. }
  225. }
  226. }
  227. for (uint32 i = 0; i < NumPhysMat; ++i)
  228. {
  229. if (assignments[i] == -1)
  230. {
  231. float bestScore = 0.f;
  232. int32 matchedIdx = -1;
  233. for (uint32 j = 0; j < NumAcousticTex; ++j)
  234. {
  235. if (scores(i, j) > bestScore)
  236. {
  237. bestScore = scores(i, j);
  238. matchedIdx = j;
  239. }
  240. }
  241. if (bestScore >= 0.2f)
  242. assignments[i] = matchedIdx;
  243. }
  244. }
  245. }
  246. }
  247. FString UAkSettings::DefaultSoundDataFolder = TEXT("WwiseAudio");
  248. UAkSettings::UAkSettings(const FObjectInitializer& ObjectInitializer)
  249. : Super(ObjectInitializer)
  250. {
  251. WwiseSoundDataFolder.Path = DefaultSoundDataFolder;
  252. GlobalDecayAbsorption = 0.5f;
  253. #if WITH_EDITOR
  254. AssetRegistryModule = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
  255. //register to asset modification delegates
  256. auto& AssetRegistry = AssetRegistryModule->Get();
  257. AssetRegistry.OnAssetAdded().AddUObject(this, &UAkSettings::OnAssetAdded);
  258. AssetRegistry.OnAssetRemoved().AddUObject(this, &UAkSettings::OnAssetRemoved);
  259. #endif // WITH_EDITOR
  260. }
  261. UAkSettings::~UAkSettings()
  262. {
  263. #if WITH_EDITOR
  264. #if AK_SUPPORT_WAAPI
  265. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  266. if (waapiClient != nullptr)
  267. {
  268. if (WaapiProjectLoadedHandle.IsValid())
  269. {
  270. waapiClient->OnProjectLoaded.Remove(WaapiProjectLoadedHandle);
  271. WaapiProjectLoadedHandle.Reset();
  272. }
  273. if (WaapiConnectionLostHandle.IsValid())
  274. {
  275. waapiClient->OnConnectionLost.Remove(WaapiConnectionLostHandle);
  276. WaapiConnectionLostHandle.Reset();
  277. }
  278. ClearWaapiTextureCallbacks();
  279. }
  280. #endif
  281. #endif
  282. }
  283. ECollisionChannel UAkSettings::ConvertFitToGeomCollisionChannel(EAkCollisionChannel CollisionChannel)
  284. {
  285. if (CollisionChannel != EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault)
  286. return (ECollisionChannel)CollisionChannel;
  287. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  288. if (AkSettings)
  289. return AkSettings->DefaultFitToGeometryCollisionChannel;
  290. return ECollisionChannel::ECC_WorldStatic;
  291. }
  292. ECollisionChannel UAkSettings::ConvertOcclusionCollisionChannel(EAkCollisionChannel CollisionChannel)
  293. {
  294. if (CollisionChannel != EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault)
  295. return (ECollisionChannel)CollisionChannel;
  296. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  297. if (AkSettings)
  298. return AkSettings->DefaultOcclusionCollisionChannel;
  299. return ECollisionChannel::ECC_WorldStatic;
  300. }
  301. void UAkSettings::PostInitProperties()
  302. {
  303. Super::PostInitProperties();
  304. #if WITH_EDITOR
  305. UAkSettingsPerUser* AkSettingsPerUser = GetMutableDefault<UAkSettingsPerUser>();
  306. if (AkSettingsPerUser)
  307. {
  308. bool didChanges = false;
  309. if (!WwiseWindowsInstallationPath_DEPRECATED.Path.IsEmpty())
  310. {
  311. AkSettingsPerUser->WwiseWindowsInstallationPath = WwiseWindowsInstallationPath_DEPRECATED;
  312. WwiseWindowsInstallationPath_DEPRECATED.Path.Reset();
  313. didChanges = true;
  314. }
  315. if (!WwiseMacInstallationPath_DEPRECATED.FilePath.IsEmpty())
  316. {
  317. AkSettingsPerUser->WwiseMacInstallationPath = WwiseMacInstallationPath_DEPRECATED;
  318. WwiseMacInstallationPath_DEPRECATED.FilePath.Reset();
  319. didChanges = true;
  320. }
  321. if (bAutoConnectToWAAPI_DEPRECATED)
  322. {
  323. AkSettingsPerUser->bAutoConnectToWAAPI = true;
  324. bAutoConnectToWAAPI_DEPRECATED = false;
  325. didChanges = true;
  326. }
  327. if (didChanges)
  328. {
  329. AkUnrealEditorHelper::SaveConfigFile(this);
  330. AkSettingsPerUser->SaveConfig();
  331. }
  332. }
  333. if (!MigratedEnableMultiCoreRendering)
  334. {
  335. MigratedEnableMultiCoreRendering = true;
  336. for (const auto& PlatformName : AkUnrealPlatformHelper::GetAllSupportedWwisePlatforms())
  337. {
  338. AkSettings_Helper::MigrateMultiCoreRendering(bEnableMultiCoreRendering_DEPRECATED, *PlatformName);
  339. }
  340. }
  341. if(RootOutputPath.Path.IsEmpty())
  342. {
  343. RootOutputPath = GeneratedSoundBanksFolder_DEPRECATED;
  344. AkUnrealEditorHelper::SaveConfigFile(this);
  345. }
  346. #endif // WITH_EDITOR
  347. }
  348. #if WITH_EDITOR
  349. void UAkSettings::PreEditChange(FProperty* PropertyAboutToChange)
  350. {
  351. PreviousWwiseProjectPath = WwiseProjectPath.FilePath;
  352. PreviousWwiseGeneratedSoundBankFolder = RootOutputPath.Path;
  353. }
  354. bool UAkSettings::UpdateGeneratedSoundBanksPath(FString Path)
  355. {
  356. PreviousWwiseGeneratedSoundBankFolder = RootOutputPath.Path;
  357. RootOutputPath.Path = Path;
  358. return UpdateGeneratedSoundBanksPath();
  359. }
  360. bool UAkSettings::GeneratedSoundBanksPathExists() const
  361. {
  362. return FPaths::DirectoryExists(WwiseUnrealHelper::GetSoundBankDirectory());
  363. }
  364. bool UAkSettings::AreSoundBanksGenerated() const
  365. {
  366. return FPaths::FileExists(FPaths::Combine(WwiseUnrealHelper::GetSoundBankDirectory(), TEXT("ProjectInfo.json")));
  367. }
  368. void UAkSettings::RefreshAcousticTextureParams() const
  369. {
  370. for (auto const& texture : AcousticTextureParamsMap)
  371. {
  372. OnTextureParamsChanged.Broadcast(texture.Key);
  373. }
  374. }
  375. bool UAkSettings::UpdateGeneratedSoundBanksPath()
  376. {
  377. bool bPathChanged = AkUnrealEditorHelper::SanitizeFolderPathAndMakeRelativeToContentDir(
  378. RootOutputPath.Path, PreviousWwiseGeneratedSoundBankFolder,
  379. FText::FromString("Please enter a valid directory path"));
  380. if (bPathChanged)
  381. {
  382. OnGeneratedSoundBanksPathChanged.Broadcast();
  383. }
  384. else
  385. {
  386. UE_LOG(LogAkAudio, Log, TEXT("AkSettings: The given GeneratedSoundBanks folder was the same as the previous one."));
  387. }
  388. return bPathChanged;
  389. }
  390. void UAkSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
  391. {
  392. const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
  393. const FName MemberPropertyName = (PropertyChangedEvent.MemberProperty != nullptr) ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;
  394. ISettingsEditorModule& SettingsEditorModule = FModuleManager::GetModuleChecked<ISettingsEditorModule>("SettingsEditor");
  395. if ( PropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, MaxSimultaneousReverbVolumes))
  396. {
  397. MaxSimultaneousReverbVolumes = FMath::Clamp<uint8>( MaxSimultaneousReverbVolumes, 0, AK_MAX_AUX_PER_OBJ );
  398. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  399. if( AkAudioDevice )
  400. {
  401. AkAudioDevice->SetMaxAuxBus(MaxSimultaneousReverbVolumes);
  402. }
  403. }
  404. else if (PropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, AudioRouting))
  405. {
  406. OnAudioRoutingUpdate();
  407. }
  408. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, WwiseProjectPath))
  409. {
  410. SanitizeProjectPath(WwiseProjectPath.FilePath, PreviousWwiseProjectPath, FText::FromString("Please enter a valid Wwise project"));
  411. }
  412. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, GeometrySurfacePropertiesTable))
  413. {
  414. InitGeometrySurfacePropertiesTable();
  415. }
  416. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, ReverbAssignmentTable))
  417. {
  418. InitReverbAssignmentTable();
  419. if (ReverbAssignmentTable.IsValid() && !ReverbAssignmentTableChangedHandle.IsValid())
  420. {
  421. ReverbAssignmentTableChangedHandle = ReverbAssignmentTable->OnDataTableChanged().AddUObject(this, &UAkSettings::OnReverbAssignmentTableChanged);
  422. }
  423. }
  424. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, GlobalDecayAbsorption))
  425. {
  426. OnGlobalDecayAbsorptionChanged.Broadcast();
  427. }
  428. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DefaultReverbAuxBus))
  429. {
  430. OnReverbAssignmentChanged.Broadcast();
  431. }
  432. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, HFDampingName)
  433. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DecayEstimateName)
  434. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, TimeToFirstReflectionName)
  435. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, HFDampingRTPC)
  436. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DecayEstimateRTPC)
  437. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, TimeToFirstReflectionRTPC))
  438. {
  439. OnReverbRTPCChanged.Broadcast();
  440. }
  441. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, WwiseStagingDirectory))
  442. {
  443. FAkAudioModule::AkAudioModuleInstance->UpdateWwiseResourceLoaderSettings();
  444. }
  445. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, RootOutputPath))
  446. {
  447. UpdateGeneratedSoundBanksPath();
  448. }
  449. Super::PostEditChangeProperty(PropertyChangedEvent);
  450. }
  451. void UAkSettings::UpdateGeometrySurfacePropertiesTable(
  452. const TArray<FAssetData>& PhysicalMaterialAssets,
  453. const TArray<FAssetData>& AcousticTextureAssets)
  454. {
  455. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  456. if (GeometryTable == nullptr)
  457. {
  458. return;
  459. }
  460. TArray<int32> assignments;
  461. assignments.Init(-1, PhysicalMaterialAssets.Num());
  462. AkSettings_Helper::MatchAcousticTextureNamesToPhysMaterialNames(PhysicalMaterialAssets, AcousticTextureAssets, assignments);
  463. for (int i = 0; i < PhysicalMaterialAssets.Num(); i++)
  464. {
  465. auto physicalMaterial = Cast<UPhysicalMaterial>(PhysicalMaterialAssets[i].GetAsset());
  466. FWwiseGeometrySurfacePropertiesRow GeometrySurfaceProperties;
  467. FName Key = FName(physicalMaterial->GetPathName());
  468. auto GeometrySurfacePropertiesFound = GeometryTable->FindRow<FWwiseGeometrySurfacePropertiesRow>(Key, TEXT("Find Physical Material"), false);
  469. if (!GeometrySurfacePropertiesFound)
  470. {
  471. if (assignments[i] != -1)
  472. {
  473. int32 acousticTextureIdx = assignments[i];
  474. GeometrySurfaceProperties.AcousticTexture = Cast<UAkAcousticTexture>(AcousticTextureAssets[acousticTextureIdx].GetAsset());
  475. GeometryTable->AddRow(Key, GeometrySurfaceProperties);
  476. }
  477. else
  478. {
  479. GeometryTable->AddRow(Key, GeometrySurfaceProperties);
  480. }
  481. }
  482. else
  483. {
  484. if (assignments[i] != -1)
  485. {
  486. if (GeometrySurfacePropertiesFound->AcousticTexture == nullptr)
  487. {
  488. int32 acousticTextureIdx = assignments[i];
  489. GeometrySurfaceProperties.AcousticTexture = Cast<UAkAcousticTexture>(AcousticTextureAssets[acousticTextureIdx].GetAsset());
  490. GeometryTable->AddRow(Key, GeometrySurfaceProperties);
  491. }
  492. }
  493. }
  494. }
  495. }
  496. void UAkSettings::InitGeometrySurfacePropertiesTable()
  497. {
  498. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  499. if (GeometryTable != nullptr)
  500. {
  501. if (GeometryTable->RowStruct->GetStructCPPName() != "FWwiseGeometrySurfacePropertiesRow")
  502. {
  503. UE_LOG(LogAkAudio, Log, TEXT("GeometrySurfacePropertiesTable cannot be assigned to %s. It must be assigned to a Data Table with FWwiseGeometrySurfacePropertiesRow type rows."), *GeometryTable->GetPathName());
  504. GeometryTable = nullptr;
  505. GeometrySurfacePropertiesTable = nullptr;
  506. }
  507. }
  508. if (GeometryTable == nullptr)
  509. {
  510. // find a valid GeometrySurfacePropertiesTable
  511. TArray<FAssetData> TableAssets;
  512. #if UE_5_1_OR_LATER
  513. AssetRegistryModule->Get().GetAssetsByClass(UDataTable::StaticClass()->GetClassPathName(), TableAssets);
  514. #else
  515. AssetRegistryModule->Get().GetAssetsByClass(UDataTable::StaticClass()->GetFName(), TableAssets);
  516. #endif
  517. for (const auto& TableAsset : TableAssets)
  518. {
  519. auto Table = Cast<UDataTable>(TableAsset.GetAsset());
  520. // verify it has the correct structure
  521. if (Table && Table->RowStruct && Table->RowStruct->GetStructCPPName() == "FWwiseGeometrySurfacePropertiesRow")
  522. {
  523. UE_LOG(LogAkAudio, Log, TEXT("No GeometrySurfacePropertiesTable is assigned in the Integration Settings. Assigning %s."), *Table->GetPathName());
  524. GeometryTable = Table;
  525. GeometrySurfacePropertiesTable = TSoftObjectPtr<UDataTable>(Table);
  526. AkUnrealEditorHelper::SaveConfigFile(this);
  527. break;
  528. }
  529. }
  530. }
  531. if (GeometryTable == nullptr)
  532. {
  533. // create a new asset
  534. auto& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
  535. auto NewTable = Cast<UDataTable>(AssetToolsModule.CreateAsset(TEXT("DefaultGeometrySurfacePropertiesTable"), DefaultAssetCreationPath, UDataTable::StaticClass(), nullptr));
  536. NewTable->RowStruct = FWwiseGeometrySurfacePropertiesRow::StaticStruct();
  537. GeometryTable = NewTable;
  538. GeometrySurfacePropertiesTable = TSoftObjectPtr<UDataTable>(NewTable);
  539. AkUnrealEditorHelper::SaveConfigFile(this);
  540. }
  541. if (GeometryTable == nullptr)
  542. {
  543. UE_LOG(LogAkAudio, Log, TEXT("No GeometrySurfacePropertiesTable is assigned in the Integration Settings. Couldn't find a corresponding asset or create a new one."));
  544. return;
  545. }
  546. // Migrate the old AkGeometryMap if it exists
  547. if (AkGeometryMap.Num() != 0)
  548. {
  549. UE_LOG(LogAkAudio, Log, TEXT("AkGeometryMap is deprecated. Its contents will be moved to the asset assigned to the GeometrySurfacePropertiesTable Integration Setting."));
  550. for (const auto& MapElement : AkGeometryMap)
  551. {
  552. auto PhysicalMaterial = MapElement.Key.LoadSynchronous();
  553. auto GeometrySurfacePropeties = MapElement.Value;
  554. GeometryTable->AddRow(FName(PhysicalMaterial->GetPathName()), FWwiseGeometrySurfacePropertiesRow(GeometrySurfacePropeties.AcousticTexture, GeometrySurfacePropeties.OcclusionValue));
  555. }
  556. VerifyAndUpdateGeometrySurfacePropertiesTable();
  557. AkGeometryMap.Empty();
  558. AkUnrealEditorHelper::SaveConfigFile(this);
  559. }
  560. FillGeometrySurfacePropertiesTable();
  561. bGeometrySurfacePropertiesTableInitialized = true;
  562. }
  563. void UAkSettings::FillGeometrySurfacePropertiesTable()
  564. {
  565. // Fill the table with existing physical materials and acoustic textures
  566. TArray<FAssetData> PhysicalMaterialAssets, AcousticTextureAssets;
  567. #if UE_5_1_OR_LATER
  568. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetClassPathName(), PhysicalMaterialAssets);
  569. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextureAssets);
  570. #else
  571. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetFName(), PhysicalMaterialAssets);
  572. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextureAssets);
  573. #endif
  574. UpdateGeometrySurfacePropertiesTable(PhysicalMaterialAssets, AcousticTextureAssets);
  575. }
  576. void UAkSettings::VerifyAndUpdateGeometrySurfacePropertiesTable()
  577. {
  578. // do not allow rows with invalid physical materials
  579. TSet<FName> ToRemove;
  580. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  581. if (GeometryTable == nullptr)
  582. {
  583. return;
  584. }
  585. GeometryTable->ForeachRow<FWwiseGeometrySurfacePropertiesRow>("Verify GeometrySurfacePropertiesTable contents",
  586. [this, &ToRemove](const FName& Key, const FWwiseGeometrySurfacePropertiesRow& Value)
  587. {
  588. #if UE_5_1_OR_LATER
  589. auto PhysicalMaterialAsset = AssetRegistryModule->Get().GetAssetByObjectPath(FSoftObjectPath(Key.ToString()));
  590. #else
  591. auto PhysicalMaterialAsset = AssetRegistryModule->Get().GetAssetByObjectPath(Key);
  592. #endif
  593. if (PhysicalMaterialAsset == nullptr)
  594. {
  595. ToRemove.Add(Key);
  596. }
  597. }
  598. );
  599. for (const auto& Key : ToRemove)
  600. {
  601. UE_LOG(LogAkAudio, Log, TEXT("GeometrySurfacePropertiesTable: Invalid row '%s' will be removed."), *Key.ToString());
  602. GeometryTable->RemoveRow(Key);
  603. }
  604. FillGeometrySurfacePropertiesTable();
  605. }
  606. void UAkSettings::SetAcousticTextureParams(const FGuid& textureID, const FAkAcousticTextureParams& params)
  607. {
  608. if (AcousticTextureParamsMap.Contains(textureID))
  609. AcousticTextureParamsMap[textureID] = params;
  610. else
  611. AcousticTextureParamsMap.Add(textureID, params);
  612. #if AK_SUPPORT_WAAPI
  613. RegisterWaapiTextureCallback(textureID);
  614. #endif
  615. }
  616. void UAkSettings::ClearTextureParamsMap()
  617. {
  618. AcousticTextureParamsMap.Empty();
  619. #if AK_SUPPORT_WAAPI
  620. ClearWaapiTextureCallbacks();
  621. #endif
  622. }
  623. #if AK_SUPPORT_WAAPI
  624. void UAkSettings::WaapiProjectLoaded()
  625. {
  626. TArray<FGuid> keys;
  627. AcousticTextureParamsMap.GetKeys(keys);
  628. for (auto key : keys)
  629. {
  630. UpdateTextureParams(key);
  631. UpdateTextureColor(key);
  632. RegisterWaapiTextureCallback(key);
  633. }
  634. }
  635. void UAkSettings::WaapiDisconnected()
  636. {
  637. ClearWaapiTextureCallbacks();
  638. }
  639. void UAkSettings::RegisterWaapiTextureCallback(const FGuid& textureID)
  640. {
  641. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  642. if (waapiClient != nullptr && waapiClient->IsConnected())
  643. {
  644. auto absorptionCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  645. {
  646. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  647. if (itemObj != nullptr)
  648. {
  649. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  650. FGuid itemID = FGuid::NewGuid();
  651. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  652. if (AcousticTextureParamsMap.Find(itemID) != nullptr)
  653. {
  654. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  655. {
  656. UpdateTextureParams(itemID);
  657. });
  658. }
  659. }
  660. });
  661. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  662. options->SetStringField(WwiseWaapiHelper::OBJECT, textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces));
  663. TArray<FString> absorptionStrings{ "AbsorptionLow", "AbsorptionMidLow", "AbsorptionMidHigh", "AbsorptionHigh" };
  664. TSharedPtr<FJsonObject> jsonResult;
  665. TSharedPtr<FJsonObject> unsubscribeResult;
  666. bool unsubscribeNeeded = WaapiTextureSubscriptions.Find(textureID) != nullptr;
  667. TArray<uint64> subscriptionIDs{ 0,0,0,0 };
  668. for (int i = 0; i < absorptionStrings.Num(); ++i)
  669. {
  670. options->SetStringField(WwiseWaapiHelper::PROPERTY, absorptionStrings[i]);
  671. if (unsubscribeNeeded)
  672. {
  673. waapiClient->Unsubscribe(WaapiTextureSubscriptions[textureID][i], unsubscribeResult);
  674. }
  675. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, absorptionCallback, subscriptionIDs[i], jsonResult))
  676. {
  677. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture propertyChanged subscription failed."));
  678. }
  679. }
  680. WaapiTextureSubscriptions.Add(textureID, subscriptionIDs);
  681. auto colorCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  682. {
  683. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  684. if (itemObj != nullptr)
  685. {
  686. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  687. FGuid itemID = FGuid::NewGuid();
  688. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  689. if (AcousticTextureParamsMap.Find(itemID) != nullptr)
  690. {
  691. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  692. {
  693. UpdateTextureColor(itemID);
  694. });
  695. }
  696. }
  697. });
  698. options = MakeShareable(new FJsonObject());
  699. options->SetStringField(WwiseWaapiHelper::OBJECT, textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces));
  700. unsubscribeNeeded = WaapiTextureColorSubscriptions.Find(textureID) != nullptr;
  701. uint64 subscriptionID = 0;
  702. options->SetStringField(WwiseWaapiHelper::PROPERTY, "Color");
  703. if (unsubscribeNeeded)
  704. {
  705. waapiClient->Unsubscribe(WaapiTextureColorSubscriptions[textureID], unsubscribeResult);
  706. }
  707. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, colorCallback, subscriptionID, jsonResult))
  708. {
  709. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture Color propertyChanged subscription failed."));
  710. }
  711. WaapiTextureColorSubscriptions.Add(textureID, subscriptionID);
  712. unsubscribeNeeded = WaapiTextureColorOverrideSubscriptions.Find(textureID) != nullptr;
  713. subscriptionID = 0;
  714. options->SetStringField(WwiseWaapiHelper::PROPERTY, "OverrideColor");
  715. if (unsubscribeNeeded)
  716. {
  717. waapiClient->Unsubscribe(WaapiTextureColorOverrideSubscriptions[textureID], unsubscribeResult);
  718. }
  719. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, colorCallback, subscriptionID, jsonResult))
  720. {
  721. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture OverrideColor propertyChanged subscription failed."));
  722. }
  723. WaapiTextureColorOverrideSubscriptions.Add(textureID, subscriptionID);
  724. }
  725. }
  726. void UAkSettings::UnregisterWaapiTextureCallback(const FGuid& textureID)
  727. {
  728. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  729. if (waapiClient != nullptr && waapiClient->IsConnected())
  730. {
  731. if (WaapiTextureSubscriptions.Find(textureID) != nullptr)
  732. {
  733. TSharedPtr<FJsonObject> unsubscribeResult;
  734. for (int i = 0; i < WaapiTextureSubscriptions[textureID].Num(); ++i)
  735. waapiClient->Unsubscribe(WaapiTextureSubscriptions[textureID][i], unsubscribeResult);
  736. WaapiTextureSubscriptions.Remove(textureID);
  737. }
  738. if (WaapiTextureColorSubscriptions.Find(textureID) != nullptr)
  739. {
  740. TSharedPtr<FJsonObject> unsubscribeResult;
  741. waapiClient->Unsubscribe(WaapiTextureColorSubscriptions[textureID], unsubscribeResult);
  742. WaapiTextureColorSubscriptions.Remove(textureID);
  743. }
  744. if (WaapiTextureColorOverrideSubscriptions.Find(textureID) != nullptr)
  745. {
  746. TSharedPtr<FJsonObject> unsubscribeResult;
  747. waapiClient->Unsubscribe(WaapiTextureColorOverrideSubscriptions[textureID], unsubscribeResult);
  748. WaapiTextureColorOverrideSubscriptions.Remove(textureID);
  749. }
  750. }
  751. }
  752. void UAkSettings::ClearWaapiTextureCallbacks()
  753. {
  754. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  755. if (waapiClient != nullptr && waapiClient->IsConnected())
  756. {
  757. for (auto it = WaapiTextureSubscriptions.CreateIterator(); it; ++it)
  758. {
  759. TSharedPtr<FJsonObject> unsubscribeResult;
  760. for (int i = 0; i < it.Value().Num(); ++i)
  761. waapiClient->Unsubscribe(it.Value()[i], unsubscribeResult);
  762. }
  763. for (auto it = WaapiTextureColorSubscriptions.CreateIterator(); it; ++it)
  764. {
  765. TSharedPtr<FJsonObject> unsubscribeResult;
  766. waapiClient->Unsubscribe(it.Value(), unsubscribeResult);
  767. }
  768. for (auto it = WaapiTextureColorOverrideSubscriptions.CreateIterator(); it; ++it)
  769. {
  770. TSharedPtr<FJsonObject> unsubscribeResult;
  771. waapiClient->Unsubscribe(it.Value(), unsubscribeResult);
  772. }
  773. WaapiTextureSubscriptions.Empty();
  774. WaapiTextureColorSubscriptions.Empty();
  775. WaapiTextureColorOverrideSubscriptions.Empty();
  776. }
  777. }
  778. void UAkSettings::UpdateTextureParams(const FGuid& textureID)
  779. {
  780. WAAPIGetTextureParams(textureID, AcousticTextureParamsMap[textureID]);
  781. OnTextureParamsChanged.Broadcast(textureID);
  782. }
  783. void UAkSettings::UpdateTextureColor(const FGuid& textureID)
  784. {
  785. if (!WAAPIGetObjectOverrideColor(textureID))
  786. {
  787. SetTextureColor(textureID, -1);
  788. return;
  789. }
  790. int colorIndex = 0;
  791. if (WAAPIGetObjectColorIndex(textureID, colorIndex))
  792. {
  793. SetTextureColor(textureID, colorIndex);
  794. }
  795. }
  796. void UAkSettings::SetTextureColor(FGuid textureID, int colorIndex)
  797. {
  798. TArray<FAssetData> AcousticTextures;
  799. #if UE_5_1_OR_LATER
  800. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextures);
  801. #else
  802. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextures);
  803. #endif
  804. FLinearColor color = FAkAudioStyle::GetWwiseObjectColor(colorIndex);
  805. for (FAssetData& textureAsset : AcousticTextures)
  806. {
  807. if (UAkAcousticTexture* texture = Cast<UAkAcousticTexture>(textureAsset.GetAsset()))
  808. {
  809. if (texture->AcousticTextureInfo.WwiseGuid == textureID && texture->EditColor != color)
  810. {
  811. texture->Modify();
  812. texture->EditColor = color;
  813. break;
  814. }
  815. }
  816. }
  817. }
  818. #endif // AK_SUPPORT_WAAPI
  819. void UAkSettings::OnAssetAdded(const FAssetData& NewAssetData)
  820. {
  821. if (!bGeometrySurfacePropertiesTableInitialized)
  822. {
  823. return;
  824. }
  825. #if UE_5_1_OR_LATER
  826. if (NewAssetData.AssetClassPath == UPhysicalMaterial::StaticClass()->GetClassPathName())
  827. #else
  828. if (NewAssetData.AssetClass == UPhysicalMaterial::StaticClass()->GetFName())
  829. #endif
  830. {
  831. if (auto physicalMaterial = Cast<UPhysicalMaterial>(NewAssetData.GetAsset()))
  832. {
  833. TArray<FAssetData> PhysicalMaterials, AcousticTextures;
  834. PhysicalMaterials.Add(NewAssetData);
  835. #if UE_5_1_OR_LATER
  836. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextures);
  837. #else
  838. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextures);
  839. #endif
  840. UpdateGeometrySurfacePropertiesTable(PhysicalMaterials, AcousticTextures);
  841. }
  842. }
  843. #if UE_5_1_OR_LATER
  844. else if (NewAssetData.AssetClassPath == UAkAcousticTexture::StaticClass()->GetClassPathName())
  845. #else
  846. else if (NewAssetData.AssetClass == UAkAcousticTexture::StaticClass()->GetFName())
  847. #endif
  848. {
  849. if (auto acousticTexture = Cast<UAkAcousticTexture>(NewAssetData.GetAsset()))
  850. {
  851. TArray<FAssetData> PhysicalMaterials, AcousticTextures;
  852. #if UE_5_1_OR_LATER
  853. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetClassPathName(), PhysicalMaterials);
  854. #else
  855. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetFName(), PhysicalMaterials);
  856. #endif
  857. AcousticTextures.Add(NewAssetData);
  858. UpdateGeometrySurfacePropertiesTable(PhysicalMaterials, AcousticTextures);
  859. FAkAcousticTextureParams params;
  860. bool paramsExist = AcousticTextureParamsMap.Contains(acousticTexture->AcousticTextureInfo.WwiseGuid);
  861. if (paramsExist)
  862. {
  863. params = *AcousticTextureParamsMap.Find(acousticTexture->AcousticTextureInfo.WwiseGuid);
  864. params.shortID = acousticTexture->AcousticTextureInfo.WwiseShortId;
  865. }
  866. #if AK_SUPPORT_WAAPI
  867. bool paramsSet = WAAPIGetTextureParams(acousticTexture->AcousticTextureInfo.WwiseGuid, params);
  868. if (paramsSet && !paramsExist)
  869. AcousticTextureParamsMap.Add(acousticTexture->AcousticTextureInfo.WwiseGuid, params);
  870. RegisterWaapiTextureCallback(acousticTexture->AcousticTextureInfo.WwiseGuid);
  871. int colorIndex = -1;
  872. if (WAAPIGetObjectColorIndex(acousticTexture->AcousticTextureInfo.WwiseGuid, colorIndex))
  873. {
  874. acousticTexture->EditColor = FAkAudioStyle::GetWwiseObjectColor(colorIndex);
  875. }
  876. #endif
  877. }
  878. }
  879. }
  880. void UAkSettings::OnAssetRemoved(const struct FAssetData& AssetData)
  881. {
  882. #if UE_5_1_OR_LATER
  883. if (AssetData.AssetClassPath == UPhysicalMaterial::StaticClass()->GetClassPathName())
  884. #else
  885. if (AssetData.AssetClass == UPhysicalMaterial::StaticClass()->GetFName())
  886. #endif
  887. {
  888. if (auto physicalMaterial = Cast<UPhysicalMaterial>(AssetData.GetAsset()))
  889. {
  890. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  891. if (GeometryTable != nullptr)
  892. {
  893. GeometryTable->RemoveRow(FName(physicalMaterial->GetPathName()));
  894. }
  895. }
  896. }
  897. #if UE_5_1_OR_LATER
  898. else if(AssetData.AssetClassPath == UAkAcousticTexture::StaticClass()->GetClassPathName())
  899. #else
  900. else if(AssetData.AssetClass == UAkAcousticTexture::StaticClass()->GetFName())
  901. #endif
  902. {
  903. if(auto acousticTexture = Cast<UAkAcousticTexture>(AssetData.GetAsset()))
  904. {
  905. AcousticTextureParamsMap.Remove(acousticTexture->AcousticTextureInfo.WwiseGuid);
  906. #if AK_SUPPORT_WAAPI
  907. UnregisterWaapiTextureCallback(acousticTexture->AcousticTextureInfo.WwiseGuid);
  908. #endif
  909. }
  910. }
  911. }
  912. #if AK_SUPPORT_WAAPI
  913. void UAkSettings::InitWaapiSync()
  914. {
  915. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  916. if (waapiClient != nullptr)
  917. {
  918. if (waapiClient->IsProjectLoaded())
  919. WaapiProjectLoaded();
  920. WaapiProjectLoadedHandle = waapiClient->OnProjectLoaded.AddLambda([this]()
  921. {
  922. WaapiProjectLoaded();
  923. });
  924. WaapiConnectionLostHandle = waapiClient->OnConnectionLost.AddLambda([this]()
  925. {
  926. WaapiDisconnected();
  927. });
  928. }
  929. }
  930. #endif
  931. void UAkSettings::EnsurePluginContentIsInAlwaysCook() const
  932. {
  933. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  934. bool packageSettingsNeedUpdate = false;
  935. TArray<FString> PathsToCheck = { TEXT("/Wwise/WwiseTree"), TEXT("/Wwise/WwiseTypes") };
  936. for (auto pathToCheck : PathsToCheck)
  937. {
  938. if (!PackagingSettings->DirectoriesToAlwaysCook.ContainsByPredicate([pathToCheck](FDirectoryPath PathInArray) { return PathInArray.Path == pathToCheck; }))
  939. {
  940. FDirectoryPath newPath;
  941. newPath.Path = pathToCheck;
  942. PackagingSettings->DirectoriesToAlwaysCook.Add(newPath);
  943. packageSettingsNeedUpdate = true;
  944. }
  945. }
  946. if (packageSettingsNeedUpdate)
  947. {
  948. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  949. }
  950. }
  951. void UAkSettings::RemoveSoundDataFromAlwaysCook(const FString& SoundDataPath)
  952. {
  953. bool changed = false;
  954. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  955. for (int32 i = PackagingSettings->DirectoriesToAlwaysCook.Num() - 1; i >= 0; --i)
  956. {
  957. if (PackagingSettings->DirectoriesToAlwaysCook[i].Path == SoundDataPath)
  958. {
  959. PackagingSettings->DirectoriesToAlwaysCook.RemoveAt(i);
  960. changed = true;
  961. break;
  962. }
  963. }
  964. if (changed)
  965. {
  966. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  967. }
  968. }
  969. void UAkSettings::SanitizeProjectPath(FString& Path, const FString& PreviousPath, const FText& DialogMessage)
  970. {
  971. WwiseUnrealHelper::TrimPath(Path);
  972. FString TempPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*Path);
  973. FText FailReason;
  974. if (!FPaths::ValidatePath(TempPath, &FailReason))
  975. {
  976. if (EAppReturnType::Ok == FMessageDialog::Open(EAppMsgType::Ok, FailReason))
  977. {
  978. Path = PreviousPath;
  979. return;
  980. }
  981. }
  982. auto ProjectDirectory = WwiseUnrealHelper::GetProjectDirectory();
  983. if (!FPaths::FileExists(TempPath))
  984. {
  985. // Path might be a valid one (relative to game) entered manually. Check that.
  986. TempPath = FPaths::ConvertRelativePathToFull(ProjectDirectory, Path);
  987. if (!FPaths::FileExists(TempPath))
  988. {
  989. if (EAppReturnType::Ok == FMessageDialog::Open(EAppMsgType::Ok, DialogMessage))
  990. {
  991. Path = PreviousPath;
  992. return;
  993. }
  994. }
  995. }
  996. // Make the path relative to the game dir
  997. FPaths::MakePathRelativeTo(TempPath, *ProjectDirectory);
  998. Path = TempPath;
  999. if (Path != PreviousPath)
  1000. {
  1001. #if UE_4_26_OR_LATER
  1002. auto WwiseBrowserTab = FGlobalTabmanager::Get()->TryInvokeTab(FName("WwiseBrowser"));
  1003. #else
  1004. TSharedRef<SDockTab> WwiseBrowserTab = FGlobalTabmanager::Get()->InvokeTab(FName("WwiseBrowser"));
  1005. #endif
  1006. bRequestRefresh = true;
  1007. }
  1008. }
  1009. void UAkSettings::OnAudioRoutingUpdate()
  1010. {
  1011. // Calculate what is expected
  1012. bool bExpectedCustom = false;
  1013. bool bExpectedSeparate = false;
  1014. bool bExpectedUsingAudioMixer = false;
  1015. bool bExpectedAudioModuleOverride = true;
  1016. bool bExpectedWwiseSoundEngineEnabled = true;
  1017. bool bExpectedWwiseAudioLinkEnabled = false;
  1018. bool bExpectedAkAudioMixerEnabled = false;
  1019. FString ExpectedAudioDeviceModuleName;
  1020. FString ExpectedAudioMixerModuleName;
  1021. switch (AudioRouting)
  1022. {
  1023. case EAkUnrealAudioRouting::Custom:
  1024. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for Custom"));
  1025. bExpectedCustom = true;
  1026. break;
  1027. case EAkUnrealAudioRouting::Separate:
  1028. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for Separate"));
  1029. bExpectedSeparate = true;
  1030. bExpectedUsingAudioMixer = true;
  1031. bExpectedAudioModuleOverride = false;
  1032. break;
  1033. case EAkUnrealAudioRouting::EnableWwiseOnly:
  1034. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for DisableUnreal"));
  1035. bExpectedUsingAudioMixer = false;
  1036. ExpectedAudioDeviceModuleName = TEXT("");
  1037. ExpectedAudioMixerModuleName = TEXT("");
  1038. break;
  1039. case EAkUnrealAudioRouting::EnableUnrealOnly:
  1040. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for DisableWwise"));
  1041. bExpectedSeparate = true;
  1042. bExpectedUsingAudioMixer = true;
  1043. bExpectedAudioModuleOverride = false;
  1044. bExpectedWwiseSoundEngineEnabled = false;
  1045. break;
  1046. case EAkUnrealAudioRouting::AudioMixer:
  1047. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for AudioMixer"));
  1048. bExpectedUsingAudioMixer = true;
  1049. bExpectedAkAudioMixerEnabled = true;
  1050. ExpectedAudioDeviceModuleName = TEXT("AkAudioMixer");
  1051. ExpectedAudioMixerModuleName = TEXT("AkAudioMixer");
  1052. break;
  1053. case EAkUnrealAudioRouting::AudioLink:
  1054. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for AudioLink"));
  1055. bExpectedSeparate = true;
  1056. bExpectedUsingAudioMixer = true;
  1057. bExpectedWwiseAudioLinkEnabled = true;
  1058. bExpectedAudioModuleOverride = false;
  1059. break;
  1060. default:
  1061. UE_LOG(LogAkAudio, Warning, TEXT("OnAudioRoutingUpdate: Unknown AudioRouting"));
  1062. return;
  1063. }
  1064. //
  1065. // Actually update the files
  1066. //
  1067. UE_LOG(LogAkAudio, Verbose, TEXT("OnAudioRoutingUpdate: Updating system settings."));
  1068. {
  1069. bWwiseSoundEngineEnabled = bExpectedWwiseSoundEngineEnabled;
  1070. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise SoundEngine Enabled: %s"), bExpectedWwiseSoundEngineEnabled ? TEXT("true") : TEXT("false"));
  1071. bWwiseAudioLinkEnabled = bExpectedWwiseAudioLinkEnabled;
  1072. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise AudioLink Enabled: %s"), bExpectedWwiseAudioLinkEnabled ? TEXT("true") : TEXT("false"));
  1073. bAkAudioMixerEnabled = bExpectedAkAudioMixerEnabled;
  1074. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise AudioMixer Enabled: %s"), bExpectedAkAudioMixerEnabled ? TEXT("true") : TEXT("false"));
  1075. #if UE_5_0_OR_LATER
  1076. TryUpdateDefaultConfigFile();
  1077. #else
  1078. UpdateDefaultConfigFile();
  1079. #endif
  1080. }
  1081. TArray<FString> IniPlatformNames;
  1082. #if UE_5_0_OR_LATER
  1083. for (const auto& PlatformInfo : FDataDrivenPlatformInfoRegistry::GetAllPlatformInfos())
  1084. {
  1085. if (!PlatformInfo.Value.bIsFakePlatform)
  1086. {
  1087. IniPlatformNames.Add(PlatformInfo.Value.IniPlatformName.ToString());
  1088. }
  1089. }
  1090. #else
  1091. for (const auto& Platform : GetTargetPlatformManagerRef().GetTargetPlatforms())
  1092. {
  1093. IniPlatformNames.Add(Platform->IniPlatformName());
  1094. }
  1095. #endif
  1096. for (const auto& IniPlatformName : IniPlatformNames)
  1097. {
  1098. const auto RelativePlatformEnginePath = FString::Printf(TEXT("%s/%sEngine.ini"), *IniPlatformName, *IniPlatformName);
  1099. auto PlatformEnginePath = FString::Printf(TEXT("%s%s"), *FPaths::SourceConfigDir(), *RelativePlatformEnginePath);
  1100. #if UE_5_1_OR_LATER
  1101. PlatformEnginePath = FConfigCacheIni::NormalizeConfigIniPath(PlatformEnginePath);
  1102. #else
  1103. FPaths::RemoveDuplicateSlashes(PlatformEnginePath);
  1104. PlatformEnginePath = FPaths::CreateStandardFilename(PlatformEnginePath);
  1105. #endif
  1106. const FString FullPlatformEnginePath = FPaths::ConvertRelativePathToFull(PlatformEnginePath);
  1107. if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*FullPlatformEnginePath))
  1108. {
  1109. FText ErrorMessage;
  1110. if (ISourceControlModule::Get().IsEnabled())
  1111. {
  1112. if (SourceControlHelpers::CheckoutOrMarkForAdd(FullPlatformEnginePath, FText::FromString(FullPlatformEnginePath), NULL, ErrorMessage))
  1113. {
  1114. ErrorMessage = FText();
  1115. }
  1116. }
  1117. else if (!FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*FullPlatformEnginePath, false))
  1118. {
  1119. ErrorMessage = FText::Format(LOCTEXT("FailedToMakeWritable", "Could not make {0} writable."), FText::FromString(FullPlatformEnginePath));
  1120. }
  1121. if (!ErrorMessage.IsEmpty())
  1122. {
  1123. FNotificationInfo Info(ErrorMessage);
  1124. Info.ExpireDuration = 3.0;
  1125. FSlateNotificationManager::Get().AddNotification(Info);
  1126. continue;
  1127. }
  1128. }
  1129. if (bExpectedUsingAudioMixer)
  1130. {
  1131. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing UseAudioMixer override"), *RelativePlatformEnginePath);
  1132. GConfig->RemoveKey(TEXT("Audio"), TEXT("UseAudioMixer"), PlatformEnginePath);
  1133. }
  1134. else
  1135. {
  1136. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating UseAudioMixer to: %s"), *RelativePlatformEnginePath, bExpectedUsingAudioMixer ? TEXT("true") : TEXT("false"));
  1137. GConfig->SetBool(TEXT("Audio"), TEXT("UseAudioMixer"), bExpectedUsingAudioMixer, PlatformEnginePath);
  1138. }
  1139. if (bExpectedAudioModuleOverride)
  1140. {
  1141. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating AudioDeviceModuleName: %s"), *RelativePlatformEnginePath, ExpectedAudioDeviceModuleName.IsEmpty() ? TEXT("[empty]") : *ExpectedAudioDeviceModuleName);
  1142. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating AudioMixerModuleName: %s"), *RelativePlatformEnginePath, ExpectedAudioMixerModuleName.IsEmpty() ? TEXT("[empty]") : *ExpectedAudioMixerModuleName);
  1143. GConfig->SetString(TEXT("Audio"), TEXT("AudioDeviceModuleName"), *ExpectedAudioDeviceModuleName, PlatformEnginePath);
  1144. GConfig->SetString(TEXT("Audio"), TEXT("AudioMixerModuleName"), *ExpectedAudioMixerModuleName, PlatformEnginePath);
  1145. }
  1146. else
  1147. {
  1148. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing AudioDeviceModuleName override"), *RelativePlatformEnginePath);
  1149. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing AudioMixerModuleName override"), *RelativePlatformEnginePath);
  1150. GConfig->RemoveKey(TEXT("Audio"), TEXT("AudioDeviceModuleName"), PlatformEnginePath);
  1151. GConfig->RemoveKey(TEXT("Audio"), TEXT("AudioMixerModuleName"), PlatformEnginePath);
  1152. }
  1153. GConfig->Flush(false, PlatformEnginePath);
  1154. }
  1155. }
  1156. void UAkSettings::RemoveSoundDataFromAlwaysStageAsUFS(const FString& SoundDataPath)
  1157. {
  1158. bool changed = false;
  1159. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  1160. for (int32 i = PackagingSettings->DirectoriesToAlwaysStageAsUFS.Num() - 1; i >= 0; --i)
  1161. {
  1162. if (PackagingSettings->DirectoriesToAlwaysStageAsUFS[i].Path == SoundDataPath)
  1163. {
  1164. PackagingSettings->DirectoriesToAlwaysStageAsUFS.RemoveAt(i);
  1165. changed = true;
  1166. break;
  1167. }
  1168. }
  1169. if (changed)
  1170. {
  1171. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  1172. }
  1173. }
  1174. void UAkSettings::InitReverbAssignmentTable()
  1175. {
  1176. auto DecayTable = ReverbAssignmentTable.LoadSynchronous();
  1177. if (DecayTable && DecayTable->RowStruct)
  1178. {
  1179. if (DecayTable->RowStruct->GetStructCPPName() != "FWwiseDecayAuxBusRow")
  1180. {
  1181. UE_LOG(LogAkAudio, Log, TEXT("ReverbAssignmentTable cannot be assigned to %s. It must be assigned to a Data Table with FWwiseDecayAuxBusRow type rows."), *DecayTable->GetPathName());
  1182. DecayTable = nullptr;
  1183. ReverbAssignmentTable = nullptr;
  1184. }
  1185. }
  1186. if (DecayTable == nullptr)
  1187. {
  1188. // find a valid ReverbAssignmentTable
  1189. TArray<FAssetData> TableAssets;
  1190. #if UE_5_1_OR_LATER
  1191. AssetRegistryModule->Get().GetAssetsByClass(UDataTable::StaticClass()->GetClassPathName(), TableAssets);
  1192. #else
  1193. AssetRegistryModule->Get().GetAssetsByClass(UDataTable::StaticClass()->GetFName(), TableAssets);
  1194. #endif
  1195. for (const auto& TableAsset : TableAssets)
  1196. {
  1197. auto Table = Cast<UDataTable>(TableAsset.GetAsset());
  1198. // verify it has the correct structure
  1199. if (Table && Table->RowStruct && Table->RowStruct->GetStructCPPName() == "FWwiseDecayAuxBusRow")
  1200. {
  1201. UE_LOG(LogAkAudio, Log, TEXT("No ReverbAssignmentTable is assigned in the Integration Settings. Assigning %s."), *Table->GetPathName());
  1202. DecayTable = Table;
  1203. ReverbAssignmentTable = TSoftObjectPtr<UDataTable>(Table);
  1204. AkUnrealEditorHelper::SaveConfigFile(this);
  1205. break;
  1206. }
  1207. }
  1208. }
  1209. if (DecayTable == nullptr)
  1210. {
  1211. // create a new asset
  1212. auto& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
  1213. auto NewTable = Cast<UDataTable>(AssetToolsModule.CreateAsset(TEXT("DefaultReverbAssignmentTable"), DefaultAssetCreationPath, UDataTable::StaticClass(), nullptr));
  1214. NewTable->RowStruct = FWwiseDecayAuxBusRow::StaticStruct();
  1215. DecayTable = NewTable;
  1216. ReverbAssignmentTable = TSoftObjectPtr<UDataTable>(NewTable);
  1217. AkUnrealEditorHelper::SaveConfigFile(this);
  1218. }
  1219. if (DecayTable == nullptr)
  1220. {
  1221. UE_LOG(LogAkAudio, Log, TEXT("No ReverbAssignmentTable is assigned in the Integration Settings. Couldn't find a corresponding asset or create a new one."));
  1222. return;
  1223. }
  1224. ReverbAssignmentTableChangedHandle = ReverbAssignmentTable->OnDataTableChanged().AddUObject(this, &UAkSettings::OnReverbAssignmentTableChanged);
  1225. // Migrate the old EnvironmentDecayAuxBusMap if it exists
  1226. if (EnvironmentDecayAuxBusMap.Num() != 0)
  1227. {
  1228. UE_LOG(LogAkAudio, Log, TEXT("EnvironmentDecayAuxBusMap is deprecated. Its contents will be moved to the asset assigned to the ReverbAssignmentTable Integration Setting."));
  1229. for (const auto& MapElement : EnvironmentDecayAuxBusMap)
  1230. {
  1231. DecayTable->AddRow(FName(FString::SanitizeFloat(MapElement.Key)), FWwiseDecayAuxBusRow(MapElement.Key, MapElement.Value));
  1232. }
  1233. EnvironmentDecayAuxBusMap.Empty();
  1234. AkUnrealEditorHelper::SaveConfigFile(this);
  1235. }
  1236. }
  1237. void UAkSettings::OnReverbAssignmentTableChanged()
  1238. {
  1239. OnReverbAssignmentChanged.Broadcast();
  1240. }
  1241. const FAkAcousticTextureParams* UAkSettings::GetTextureParams(const uint32& shortID) const
  1242. {
  1243. for (auto it = AcousticTextureParamsMap.CreateConstIterator(); it; ++it)
  1244. {
  1245. if (it.Value().shortID == shortID)
  1246. return AcousticTextureParamsMap.Find(it.Key());
  1247. }
  1248. return nullptr;
  1249. }
  1250. #endif // WITH_EDITOR
  1251. bool UAkSettings::ReverbRTPCsInUse() const
  1252. {
  1253. return DecayRTPCInUse() || DampingRTPCInUse() || PredelayRTPCInUse();
  1254. }
  1255. bool UAkSettings::DecayRTPCInUse() const
  1256. {
  1257. const bool validPath = !DecayEstimateRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1258. return validPath || !DecayEstimateName.IsEmpty();
  1259. }
  1260. bool UAkSettings::DampingRTPCInUse() const
  1261. {
  1262. const bool validPath = !HFDampingRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1263. return validPath || !HFDampingName.IsEmpty();
  1264. }
  1265. bool UAkSettings::PredelayRTPCInUse() const
  1266. {
  1267. const bool validPath = !TimeToFirstReflectionRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1268. return validPath || !TimeToFirstReflectionName.IsEmpty();
  1269. }
  1270. bool UAkSettings::GetAssociatedAcousticTexture(const UPhysicalMaterial* physMaterial, UAkAcousticTexture*& acousticTexture) const
  1271. {
  1272. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  1273. if (GeometryTable == nullptr)
  1274. {
  1275. return false;
  1276. }
  1277. FName Key = FName(physMaterial->GetPathName());
  1278. auto GeometrySurfacePropertiesFound = GeometryTable->FindRow<FWwiseGeometrySurfacePropertiesRow>(Key, TEXT("Find Physical Material"), false);
  1279. if (!GeometrySurfacePropertiesFound)
  1280. {
  1281. return false;
  1282. }
  1283. acousticTexture = GeometrySurfacePropertiesFound->AcousticTexture.LoadSynchronous();
  1284. return true;
  1285. }
  1286. bool UAkSettings::GetAssociatedOcclusionValue(const UPhysicalMaterial* physMaterial, float& occlusionValue) const
  1287. {
  1288. auto GeometryTable = GeometrySurfacePropertiesTable.LoadSynchronous();
  1289. if (GeometryTable == nullptr)
  1290. {
  1291. return false;
  1292. }
  1293. FName Key = FName(physMaterial->GetPathName());
  1294. auto GeometrySurfacePropertiesFound = GeometryTable->FindRow<FWwiseGeometrySurfacePropertiesRow>(Key, TEXT("Find Physical Material"), false);
  1295. if (!GeometrySurfacePropertiesFound)
  1296. {
  1297. return false;
  1298. }
  1299. occlusionValue = GeometrySurfacePropertiesFound->TransmissionLoss;
  1300. return true;
  1301. }
  1302. UAkAuxBus* UAkSettings::GetAuxBusForDecayValue(float Decay)
  1303. {
  1304. auto DecayTable = ReverbAssignmentTable.LoadSynchronous();
  1305. if (!DecayTable)
  1306. {
  1307. return DefaultReverbAuxBus.LoadSynchronous();
  1308. }
  1309. float MinKey = FLT_MAX;
  1310. TSoftObjectPtr<UAkAuxBus> AuxBus;
  1311. DecayTable->ForeachRow<FWwiseDecayAuxBusRow>("Get decay values",
  1312. [Decay, &MinKey, &AuxBus](const FName& Key, const FWwiseDecayAuxBusRow& Value)
  1313. {
  1314. if (Decay <= Value.Decay && Value.Decay < MinKey)
  1315. {
  1316. MinKey = Value.Decay;
  1317. AuxBus = Value.AuxBus;
  1318. }
  1319. }
  1320. );
  1321. if (MinKey == FLT_MAX)
  1322. {
  1323. return DefaultReverbAuxBus.LoadSynchronous();
  1324. }
  1325. else if (!AuxBus.IsNull())
  1326. {
  1327. auto* Result = AuxBus.LoadSynchronous();
  1328. UE_CLOG(UNLIKELY(!Result), LogAkAudio, Warning, TEXT("UAkSettings::GetAuxBusForDecayValue: Could not load AuxBus for Decay Value (%f)"), MinKey);
  1329. return Result;
  1330. }
  1331. else
  1332. {
  1333. return nullptr;
  1334. }
  1335. }
  1336. void UAkSettings::GetAudioInputEvent(UAkAudioEvent*& OutInputEvent)
  1337. {
  1338. OutInputEvent = AudioInputEvent.LoadSynchronous();
  1339. }
  1340. #undef LOCTEXT_NAMESPACE