AkSettings.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520
  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 "AkUnrealHelper.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 "AssetTools/Public/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 "SettingsEditor/Public/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. auto* SettingsClass = UClass::TryFindTypeSlow<UClass>(*SettingsClassName);
  166. #else
  167. auto* SettingsClass = FindObject<UClass>(ANY_PACKAGE, *SettingsClassName);
  168. #endif
  169. if (!SettingsClass)
  170. {
  171. return;
  172. }
  173. auto* MigrationFunction = SettingsClass->FindFunctionByName(TEXT("MigrateMultiCoreRendering"));
  174. auto* Settings = SettingsClass->GetDefaultObject();
  175. if (!MigrationFunction || !Settings)
  176. {
  177. return;
  178. }
  179. Settings->ProcessEvent(MigrationFunction, &EnableMultiCoreRendering);
  180. AkUnrealEditorHelper::SaveConfigFile(Settings);
  181. }
  182. #endif
  183. void MatchAcousticTextureNamesToPhysMaterialNames(
  184. const TArray<FAssetData>& PhysicalMaterials,
  185. const TArray<FAssetData>& AcousticTextures,
  186. TArray<int32>& assignments)
  187. {
  188. uint32 NumPhysMat = (uint32)PhysicalMaterials.Num();
  189. uint32 NumAcousticTex = (uint32)AcousticTextures.Num();
  190. // Create a scores matrix
  191. Array2D<float> scores(NumPhysMat, NumAcousticTex, 0);
  192. for (uint32 i = 0; i < NumPhysMat; ++i)
  193. {
  194. TArray<bool> perfectObjectMatches;
  195. perfectObjectMatches.Init(false, NumAcousticTex);
  196. if (PhysicalMaterials[i].GetAsset())
  197. {
  198. FString physMaterialName = PhysicalMaterials[i].GetAsset()->GetName();
  199. if (physMaterialName.Len() == 0)
  200. continue;
  201. for (uint32 j = 0; j < NumAcousticTex; ++j)
  202. {
  203. // Skip objects for which we already found a perfect match
  204. if (perfectObjectMatches[j] == true)
  205. continue;
  206. if (AcousticTextures[j].GetAsset())
  207. {
  208. FString acousticTextureName = AcousticTextures[j].GetAsset()->GetName();
  209. if (acousticTextureName.Len() == 0)
  210. continue;
  211. // Calculate longest common substring length
  212. float lcs = LCS::GetLCSScore(
  213. physMaterialName.ToLower(),
  214. acousticTextureName.ToLower());
  215. scores(i, j) = lcs;
  216. if (FMath::IsNearlyEqual(lcs, 1.f))
  217. {
  218. assignments[i] = j;
  219. perfectObjectMatches[j] = true;
  220. break;
  221. }
  222. }
  223. }
  224. }
  225. }
  226. for (uint32 i = 0; i < NumPhysMat; ++i)
  227. {
  228. if (assignments[i] == -1)
  229. {
  230. float bestScore = 0.f;
  231. int32 matchedIdx = -1;
  232. for (uint32 j = 0; j < NumAcousticTex; ++j)
  233. {
  234. if (scores(i, j) > bestScore)
  235. {
  236. bestScore = scores(i, j);
  237. matchedIdx = j;
  238. }
  239. }
  240. if (bestScore >= 0.2f)
  241. assignments[i] = matchedIdx;
  242. }
  243. }
  244. }
  245. }
  246. FString UAkSettings::DefaultSoundDataFolder = TEXT("WwiseAudio");
  247. #if WITH_EDITOR
  248. float UAkSettings::MinimumDecayKeyDistance = 0.01f;
  249. #endif
  250. UAkSettings::UAkSettings(const FObjectInitializer& ObjectInitializer)
  251. : Super(ObjectInitializer)
  252. {
  253. WwiseSoundDataFolder.Path = DefaultSoundDataFolder;
  254. GlobalDecayAbsorption = 0.5f;
  255. #if WITH_EDITOR
  256. AssetRegistryModule = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
  257. //register to asset modification delegates
  258. auto& AssetRegistry = AssetRegistryModule->Get();
  259. AssetRegistry.OnAssetAdded().AddUObject(this, &UAkSettings::OnAssetAdded);
  260. AssetRegistry.OnAssetRemoved().AddUObject(this, &UAkSettings::OnAssetRemoved);
  261. VisualizeRoomsAndPortals = false;
  262. bShowReverbInfo = true;
  263. #endif // WITH_EDITOR
  264. }
  265. UAkSettings::~UAkSettings()
  266. {
  267. #if WITH_EDITOR
  268. #if AK_SUPPORT_WAAPI
  269. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  270. if (waapiClient != nullptr)
  271. {
  272. if (WaapiProjectLoadedHandle.IsValid())
  273. {
  274. waapiClient->OnProjectLoaded.Remove(WaapiProjectLoadedHandle);
  275. WaapiProjectLoadedHandle.Reset();
  276. }
  277. if (WaapiConnectionLostHandle.IsValid())
  278. {
  279. waapiClient->OnConnectionLost.Remove(WaapiConnectionLostHandle);
  280. WaapiConnectionLostHandle.Reset();
  281. }
  282. ClearWaapiTextureCallbacks();
  283. }
  284. #endif
  285. #endif
  286. }
  287. ECollisionChannel UAkSettings::ConvertFitToGeomCollisionChannel(EAkCollisionChannel CollisionChannel)
  288. {
  289. if (CollisionChannel != EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault)
  290. return (ECollisionChannel)CollisionChannel;
  291. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  292. if (AkSettings)
  293. return AkSettings->DefaultFitToGeometryCollisionChannel;
  294. return ECollisionChannel::ECC_WorldStatic;
  295. }
  296. ECollisionChannel UAkSettings::ConvertOcclusionCollisionChannel(EAkCollisionChannel CollisionChannel)
  297. {
  298. if (CollisionChannel != EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault)
  299. return (ECollisionChannel)CollisionChannel;
  300. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  301. if (AkSettings)
  302. return AkSettings->DefaultOcclusionCollisionChannel;
  303. return ECollisionChannel::ECC_WorldStatic;
  304. }
  305. void UAkSettings::PostInitProperties()
  306. {
  307. Super::PostInitProperties();
  308. #if WITH_EDITOR
  309. UAkSettingsPerUser* AkSettingsPerUser = GetMutableDefault<UAkSettingsPerUser>();
  310. if (AkSettingsPerUser)
  311. {
  312. bool didChanges = false;
  313. if (!WwiseWindowsInstallationPath_DEPRECATED.Path.IsEmpty())
  314. {
  315. AkSettingsPerUser->WwiseWindowsInstallationPath = WwiseWindowsInstallationPath_DEPRECATED;
  316. WwiseWindowsInstallationPath_DEPRECATED.Path.Reset();
  317. didChanges = true;
  318. }
  319. if (!WwiseMacInstallationPath_DEPRECATED.FilePath.IsEmpty())
  320. {
  321. AkSettingsPerUser->WwiseMacInstallationPath = WwiseMacInstallationPath_DEPRECATED;
  322. WwiseMacInstallationPath_DEPRECATED.FilePath.Reset();
  323. didChanges = true;
  324. }
  325. if (bAutoConnectToWAAPI_DEPRECATED)
  326. {
  327. AkSettingsPerUser->bAutoConnectToWAAPI = true;
  328. bAutoConnectToWAAPI_DEPRECATED = false;
  329. didChanges = true;
  330. }
  331. if (didChanges)
  332. {
  333. AkUnrealEditorHelper::SaveConfigFile(this);
  334. AkSettingsPerUser->SaveConfig();
  335. }
  336. }
  337. if (!MigratedEnableMultiCoreRendering)
  338. {
  339. MigratedEnableMultiCoreRendering = true;
  340. for (const auto& PlatformName : AkUnrealPlatformHelper::GetAllSupportedWwisePlatforms())
  341. {
  342. AkSettings_Helper::MigrateMultiCoreRendering(bEnableMultiCoreRendering_DEPRECATED, *PlatformName);
  343. }
  344. }
  345. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  346. #endif // WITH_EDITOR
  347. }
  348. #if WITH_EDITOR
  349. void UAkSettings::PreEditChange(FProperty* PropertyAboutToChange)
  350. {
  351. PreviousWwiseProjectPath = WwiseProjectPath.FilePath;
  352. PreviousWwiseGeneratedSoundBankFolder = GeneratedSoundBanksFolder.Path;
  353. }
  354. bool UAkSettings::UpdateGeneratedSoundBanksPath(FString Path)
  355. {
  356. PreviousWwiseGeneratedSoundBankFolder = GeneratedSoundBanksFolder.Path;
  357. GeneratedSoundBanksFolder.Path = Path;
  358. return UpdateGeneratedSoundBanksPath();
  359. }
  360. bool UAkSettings::GeneratedSoundBanksPathExists() const
  361. {
  362. return FPaths::DirectoryExists(AkUnrealHelper::GetSoundBankDirectory());
  363. }
  364. bool UAkSettings::AreSoundBanksGenerated() const
  365. {
  366. return FPaths::FileExists(FPaths::Combine(AkUnrealHelper::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. GeneratedSoundBanksFolder.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, AkGeometryMap))
  413. {
  414. if (PropertyName == GET_MEMBER_NAME_CHECKED(FAkGeometrySurfacePropertiesToMap, AcousticTexture))
  415. {
  416. for (auto& elem : AkGeometryMap)
  417. {
  418. PhysicalMaterialAcousticTextureMap[elem.Key.LoadSynchronous()] = elem.Value.AcousticTexture.LoadSynchronous();
  419. }
  420. }
  421. else if (PropertyName == GET_MEMBER_NAME_CHECKED(FAkGeometrySurfacePropertiesToMap, OcclusionValue))
  422. {
  423. for (auto& elem : AkGeometryMap)
  424. {
  425. PhysicalMaterialOcclusionMap[elem.Key.LoadSynchronous()] = elem.Value.OcclusionValue;
  426. }
  427. }
  428. }
  429. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, VisualizeRoomsAndPortals))
  430. {
  431. OnShowRoomsPortalsChanged.Broadcast();
  432. }
  433. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, bShowReverbInfo))
  434. {
  435. OnShowReverbInfoChanged.Broadcast();
  436. }
  437. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, EnvironmentDecayAuxBusMap))
  438. {
  439. if (PropertyChangedEvent.ChangeType != EPropertyChangeType::Interactive)
  440. {
  441. DecayAuxBusMapChanged();
  442. OnAuxBusAssignmentMapChanged.Broadcast();
  443. }
  444. }
  445. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, GlobalDecayAbsorption))
  446. {
  447. OnAuxBusAssignmentMapChanged.Broadcast();
  448. }
  449. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DefaultReverbAuxBus))
  450. {
  451. OnAuxBusAssignmentMapChanged.Broadcast();
  452. }
  453. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, HFDampingName)
  454. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DecayEstimateName)
  455. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, TimeToFirstReflectionName)
  456. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, HFDampingRTPC)
  457. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, DecayEstimateRTPC)
  458. || MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, TimeToFirstReflectionRTPC))
  459. {
  460. OnReverbRTPCChanged.Broadcast();
  461. }
  462. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, WwiseStagingDirectory))
  463. {
  464. FAkAudioModule::AkAudioModuleInstance->UpdateWwiseResourceLoaderSettings();
  465. }
  466. else if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSettings, GeneratedSoundBanksFolder))
  467. {
  468. UpdateGeneratedSoundBanksPath();
  469. }
  470. Super::PostEditChangeProperty(PropertyChangedEvent);
  471. }
  472. void UAkSettings::ToggleVisualizeRoomsAndPortals()
  473. {
  474. VisualizeRoomsAndPortals = !VisualizeRoomsAndPortals;
  475. OnShowRoomsPortalsChanged.Broadcast();
  476. }
  477. void UAkSettings::ToggleShowReverbInfo()
  478. {
  479. bShowReverbInfo = !bShowReverbInfo;
  480. OnShowReverbInfoChanged.Broadcast();
  481. }
  482. void UAkSettings::FillAkGeometryMap(
  483. const TArray<FAssetData>& PhysicalMaterialAssets,
  484. const TArray<FAssetData>& AcousticTextureAssets)
  485. {
  486. TArray<int32> assignments;
  487. assignments.Init(-1, PhysicalMaterialAssets.Num());
  488. AkSettings_Helper::MatchAcousticTextureNamesToPhysMaterialNames(PhysicalMaterialAssets, AcousticTextureAssets, assignments);
  489. for (int i = 0; i < PhysicalMaterialAssets.Num(); i++)
  490. {
  491. auto physicalMaterial = Cast<UPhysicalMaterial>(PhysicalMaterialAssets[i].GetAsset());
  492. if (!PhysicalMaterialAcousticTextureMap.Contains(physicalMaterial))
  493. {
  494. if (assignments[i] != -1)
  495. {
  496. int32 acousticTextureIdx = assignments[i];
  497. auto acousticTexture = Cast<UAkAcousticTexture>(AcousticTextureAssets[acousticTextureIdx].GetAsset());
  498. PhysicalMaterialAcousticTextureMap.Add(physicalMaterial, acousticTexture);
  499. }
  500. else
  501. {
  502. PhysicalMaterialAcousticTextureMap.Add(physicalMaterial);
  503. }
  504. }
  505. else
  506. {
  507. if (assignments[i] != -1)
  508. {
  509. if (!PhysicalMaterialAcousticTextureMap[physicalMaterial])
  510. {
  511. int32 acousticTextureIdx = assignments[i];
  512. auto acousticTexture = Cast<UAkAcousticTexture>(AcousticTextureAssets[acousticTextureIdx].GetAsset());
  513. PhysicalMaterialAcousticTextureMap[physicalMaterial] = acousticTexture;
  514. }
  515. }
  516. }
  517. if (!PhysicalMaterialOcclusionMap.Contains(physicalMaterial))
  518. PhysicalMaterialOcclusionMap.Add(physicalMaterial, 1.f);
  519. }
  520. UpdateAkGeometryMap();
  521. }
  522. void UAkSettings::UpdateAkGeometryMap()
  523. {
  524. decltype(AkGeometryMap) UpdatedGeometryMap;
  525. for (const auto& AcousticTextureTuple : PhysicalMaterialAcousticTextureMap)
  526. {
  527. const auto* PhysicalMaterial(AcousticTextureTuple.Key);
  528. const auto* AcousticTexture(AcousticTextureTuple.Value);
  529. const auto* OcclusionPtr = PhysicalMaterialOcclusionMap.Find(PhysicalMaterial);
  530. if (UNLIKELY(!OcclusionPtr))
  531. {
  532. UE_LOG(LogAkAudio, Warning, TEXT("UpdateAkGeometryMap: Could not find Occlusion of Physical Material %s with Acoustic Texture %s"),
  533. PhysicalMaterial ? *PhysicalMaterial->GetFName().ToString() : TEXT("[nullptr]"),
  534. AcousticTexture ? *AcousticTexture->GetFName().ToString() : TEXT("[nullptr]"));
  535. continue;
  536. }
  537. FAkGeometrySurfacePropertiesToMap SurfaceProperties;
  538. SurfaceProperties.AcousticTexture = AcousticTexture;
  539. SurfaceProperties.OcclusionValue = *OcclusionPtr;
  540. UpdatedGeometryMap.Emplace(PhysicalMaterial, MoveTemp(SurfaceProperties));
  541. }
  542. UpdatedGeometryMap.KeySort([](const auto& Lhs, const auto& Rhs) {
  543. if (UNLIKELY(!Lhs.IsValid() || !Rhs.IsValid()))
  544. {
  545. return !Lhs.IsValid();
  546. }
  547. return Lhs->GetPathName().Compare(Rhs->GetPathName()) < 0;
  548. });
  549. if (!UpdatedGeometryMap.OrderIndependentCompareEqual(AkGeometryMap))
  550. {
  551. UE_LOG(LogAkAudio, Verbose, TEXT("UpdateAkGeometryMap: Updating changed AkGeometryMap"));
  552. AkGeometryMap = UpdatedGeometryMap;
  553. AkUnrealEditorHelper::SaveConfigFile(this);
  554. }
  555. else
  556. {
  557. UE_LOG(LogAkAudio, VeryVerbose, TEXT("UpdateAkGeometryMap: AkGeometryMap is unchanged. Skip updating."));
  558. }
  559. }
  560. void UAkSettings::InitAkGeometryMap()
  561. {
  562. PhysicalMaterialAcousticTextureMap.Empty();
  563. PhysicalMaterialOcclusionMap.Empty();
  564. // copy everything from the ini file
  565. for (auto& elem : AkGeometryMap)
  566. {
  567. auto physMat = elem.Key.LoadSynchronous();
  568. auto surfaceProps = elem.Value;
  569. PhysicalMaterialAcousticTextureMap.Add(physMat, surfaceProps.AcousticTexture.LoadSynchronous());
  570. PhysicalMaterialOcclusionMap.Add(physMat, surfaceProps.OcclusionValue);
  571. }
  572. bAkGeometryMapInitialized = true;
  573. // Obtain the 2 list of children we want to match
  574. TArray<FAssetData> PhysicalMaterials, AcousticTextures;
  575. #if UE_5_1_OR_LATER
  576. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetClassPathName(), PhysicalMaterials);
  577. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextures);
  578. #else
  579. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetFName(), PhysicalMaterials);
  580. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextures);
  581. #endif
  582. FillAkGeometryMap(PhysicalMaterials, AcousticTextures);
  583. }
  584. void UAkSettings::ClearAkRoomDecayAuxBusMap()
  585. {
  586. EnvironmentDecayAuxBusMap.Empty();
  587. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  588. }
  589. void UAkSettings::InsertDecayKeyValue(const float& decayKey)
  590. {
  591. if (decayKey < 0.0f)
  592. {
  593. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: Reverb Assignment Map: Decay key values must be positive."));
  594. return;
  595. }
  596. // Refuse key value if it is too close to an existing key value (within MinimumDecayKeyDistance).
  597. TArray<float> decayKeys;
  598. EnvironmentDecayAuxBusMap.GetKeys(decayKeys);
  599. for (int i = 0; i < decayKeys.Num(); ++i)
  600. {
  601. if (FMath::Abs(decayKeys[i] - decayKey) < MinimumDecayKeyDistance)
  602. {
  603. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: Reverb Assignment Map: New decay key too close to existing key. Must be +- %f from any existing key."), MinimumDecayKeyDistance);
  604. return;
  605. }
  606. // Keys are reverse sorted. If the new key value is larger enough than the current index, we have found a valid insert space.
  607. // (There will be no other keys larger than the current index to check against).
  608. if (decayKey - decayKeys[i] > MinimumDecayKeyDistance)
  609. break;
  610. }
  611. EnvironmentDecayAuxBusMap.Add(decayKey, nullptr);
  612. SortDecayKeys();
  613. }
  614. void UAkSettings::SetAcousticTextureParams(const FGuid& textureID, const FAkAcousticTextureParams& params)
  615. {
  616. if (AcousticTextureParamsMap.Contains(textureID))
  617. AcousticTextureParamsMap[textureID] = params;
  618. else
  619. AcousticTextureParamsMap.Add(textureID, params);
  620. #if AK_SUPPORT_WAAPI
  621. RegisterWaapiTextureCallback(textureID);
  622. #endif
  623. }
  624. void UAkSettings::ClearTextureParamsMap()
  625. {
  626. AcousticTextureParamsMap.Empty();
  627. #if AK_SUPPORT_WAAPI
  628. ClearWaapiTextureCallbacks();
  629. #endif
  630. }
  631. #if AK_SUPPORT_WAAPI
  632. void UAkSettings::WaapiProjectLoaded()
  633. {
  634. TArray<FGuid> keys;
  635. AcousticTextureParamsMap.GetKeys(keys);
  636. for (auto key : keys)
  637. {
  638. UpdateTextureParams(key);
  639. UpdateTextureColor(key);
  640. RegisterWaapiTextureCallback(key);
  641. }
  642. }
  643. void UAkSettings::WaapiDisconnected()
  644. {
  645. ClearWaapiTextureCallbacks();
  646. }
  647. void UAkSettings::RegisterWaapiTextureCallback(const FGuid& textureID)
  648. {
  649. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  650. if (waapiClient != nullptr && waapiClient->IsConnected())
  651. {
  652. auto absorptionCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  653. {
  654. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  655. if (itemObj != nullptr)
  656. {
  657. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  658. FGuid itemID = FGuid::NewGuid();
  659. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  660. if (AcousticTextureParamsMap.Find(itemID) != nullptr)
  661. {
  662. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  663. {
  664. UpdateTextureParams(itemID);
  665. });
  666. }
  667. }
  668. });
  669. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  670. options->SetStringField(WwiseWaapiHelper::OBJECT, textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces));
  671. TArray<FString> absorptionStrings{ "AbsorptionLow", "AbsorptionMidLow", "AbsorptionMidHigh", "AbsorptionHigh" };
  672. TSharedPtr<FJsonObject> jsonResult;
  673. TSharedPtr<FJsonObject> unsubscribeResult;
  674. bool unsubscribeNeeded = WaapiTextureSubscriptions.Find(textureID) != nullptr;
  675. TArray<uint64> subscriptionIDs{ 0,0,0,0 };
  676. for (int i = 0; i < absorptionStrings.Num(); ++i)
  677. {
  678. options->SetStringField(WwiseWaapiHelper::PROPERTY, absorptionStrings[i]);
  679. if (unsubscribeNeeded)
  680. {
  681. waapiClient->Unsubscribe(WaapiTextureSubscriptions[textureID][i], unsubscribeResult);
  682. }
  683. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, absorptionCallback, subscriptionIDs[i], jsonResult))
  684. {
  685. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture propertyChanged subscription failed."));
  686. }
  687. }
  688. WaapiTextureSubscriptions.Add(textureID, subscriptionIDs);
  689. auto colorCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  690. {
  691. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  692. if (itemObj != nullptr)
  693. {
  694. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  695. FGuid itemID = FGuid::NewGuid();
  696. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  697. if (AcousticTextureParamsMap.Find(itemID) != nullptr)
  698. {
  699. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  700. {
  701. UpdateTextureColor(itemID);
  702. });
  703. }
  704. }
  705. });
  706. options = MakeShareable(new FJsonObject());
  707. options->SetStringField(WwiseWaapiHelper::OBJECT, textureID.ToString(EGuidFormats::DigitsWithHyphensInBraces));
  708. unsubscribeNeeded = WaapiTextureColorSubscriptions.Find(textureID) != nullptr;
  709. uint64 subscriptionID = 0;
  710. options->SetStringField(WwiseWaapiHelper::PROPERTY, "Color");
  711. if (unsubscribeNeeded)
  712. {
  713. waapiClient->Unsubscribe(WaapiTextureColorSubscriptions[textureID], unsubscribeResult);
  714. }
  715. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, colorCallback, subscriptionID, jsonResult))
  716. {
  717. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture Color propertyChanged subscription failed."));
  718. }
  719. WaapiTextureColorSubscriptions.Add(textureID, subscriptionID);
  720. unsubscribeNeeded = WaapiTextureColorOverrideSubscriptions.Find(textureID) != nullptr;
  721. subscriptionID = 0;
  722. options->SetStringField(WwiseWaapiHelper::PROPERTY, "OverrideColor");
  723. if (unsubscribeNeeded)
  724. {
  725. waapiClient->Unsubscribe(WaapiTextureColorOverrideSubscriptions[textureID], unsubscribeResult);
  726. }
  727. if (!waapiClient->Subscribe(ak::wwise::core::object::propertyChanged, options, colorCallback, subscriptionID, jsonResult))
  728. {
  729. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture OverrideColor propertyChanged subscription failed."));
  730. }
  731. WaapiTextureColorOverrideSubscriptions.Add(textureID, subscriptionID);
  732. }
  733. }
  734. void UAkSettings::UnregisterWaapiTextureCallback(const FGuid& textureID)
  735. {
  736. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  737. if (waapiClient != nullptr && waapiClient->IsConnected())
  738. {
  739. if (WaapiTextureSubscriptions.Find(textureID) != nullptr)
  740. {
  741. TSharedPtr<FJsonObject> unsubscribeResult;
  742. for (int i = 0; i < WaapiTextureSubscriptions[textureID].Num(); ++i)
  743. waapiClient->Unsubscribe(WaapiTextureSubscriptions[textureID][i], unsubscribeResult);
  744. WaapiTextureSubscriptions.Remove(textureID);
  745. }
  746. if (WaapiTextureColorSubscriptions.Find(textureID) != nullptr)
  747. {
  748. TSharedPtr<FJsonObject> unsubscribeResult;
  749. waapiClient->Unsubscribe(WaapiTextureColorSubscriptions[textureID], unsubscribeResult);
  750. WaapiTextureColorSubscriptions.Remove(textureID);
  751. }
  752. if (WaapiTextureColorOverrideSubscriptions.Find(textureID) != nullptr)
  753. {
  754. TSharedPtr<FJsonObject> unsubscribeResult;
  755. waapiClient->Unsubscribe(WaapiTextureColorOverrideSubscriptions[textureID], unsubscribeResult);
  756. WaapiTextureColorOverrideSubscriptions.Remove(textureID);
  757. }
  758. }
  759. }
  760. void UAkSettings::ClearWaapiTextureCallbacks()
  761. {
  762. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  763. if (waapiClient != nullptr && waapiClient->IsConnected())
  764. {
  765. for (auto it = WaapiTextureSubscriptions.CreateIterator(); it; ++it)
  766. {
  767. TSharedPtr<FJsonObject> unsubscribeResult;
  768. for (int i = 0; i < it.Value().Num(); ++i)
  769. waapiClient->Unsubscribe(it.Value()[i], unsubscribeResult);
  770. }
  771. for (auto it = WaapiTextureColorSubscriptions.CreateIterator(); it; ++it)
  772. {
  773. TSharedPtr<FJsonObject> unsubscribeResult;
  774. waapiClient->Unsubscribe(it.Value(), unsubscribeResult);
  775. }
  776. for (auto it = WaapiTextureColorOverrideSubscriptions.CreateIterator(); it; ++it)
  777. {
  778. TSharedPtr<FJsonObject> unsubscribeResult;
  779. waapiClient->Unsubscribe(it.Value(), unsubscribeResult);
  780. }
  781. WaapiTextureSubscriptions.Empty();
  782. WaapiTextureColorSubscriptions.Empty();
  783. WaapiTextureColorOverrideSubscriptions.Empty();
  784. }
  785. }
  786. void UAkSettings::UpdateTextureParams(const FGuid& textureID)
  787. {
  788. WAAPIGetTextureParams(textureID, AcousticTextureParamsMap[textureID]);
  789. OnTextureParamsChanged.Broadcast(textureID);
  790. }
  791. void UAkSettings::UpdateTextureColor(const FGuid& textureID)
  792. {
  793. if (!WAAPIGetObjectOverrideColor(textureID))
  794. {
  795. SetTextureColor(textureID, -1);
  796. return;
  797. }
  798. int colorIndex = 0;
  799. if (WAAPIGetObjectColorIndex(textureID, colorIndex))
  800. {
  801. SetTextureColor(textureID, colorIndex);
  802. }
  803. }
  804. void UAkSettings::SetTextureColor(FGuid textureID, int colorIndex)
  805. {
  806. TArray<FAssetData> AcousticTextures;
  807. #if UE_5_1_OR_LATER
  808. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextures);
  809. #else
  810. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextures);
  811. #endif
  812. FLinearColor color = FAkAudioStyle::GetWwiseObjectColor(colorIndex);
  813. for (FAssetData& textureAsset : AcousticTextures)
  814. {
  815. if (UAkAcousticTexture* texture = Cast<UAkAcousticTexture>(textureAsset.GetAsset()))
  816. {
  817. if (texture->AcousticTextureInfo.WwiseGuid == textureID && texture->EditColor != color)
  818. {
  819. texture->Modify();
  820. texture->EditColor = color;
  821. break;
  822. }
  823. }
  824. }
  825. }
  826. #endif // AK_SUPPORT_WAAPI
  827. void UAkSettings::DecayAuxBusMapChanged()
  828. {
  829. // If a key has been moved beyond its neighbours, restrict it between neighbouring key values
  830. // Removal - nothing to restrict
  831. if (PreviousDecayAuxBusMap.Num() > EnvironmentDecayAuxBusMap.Num())
  832. {
  833. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  834. return;
  835. }
  836. // Addition - when the insert button is used, restrictions will already be handled.
  837. // If the stock Unreal '+' button is used, a 0-nullptr entry will be added at the end of the map. In this case,
  838. // remove it and insert it using the InsertDecayKeyValue so it can be properly restricted and placed.
  839. if (PreviousDecayAuxBusMap.Num() < EnvironmentDecayAuxBusMap.Num())
  840. {
  841. if (EnvironmentDecayAuxBusMap.Num() > 1)
  842. {
  843. TArray<float> keys;
  844. EnvironmentDecayAuxBusMap.GetKeys(keys);
  845. if (keys.Last() == 0.0f && EnvironmentDecayAuxBusMap[0.0f] == nullptr)
  846. {
  847. EnvironmentDecayAuxBusMap.Remove(0.0f);
  848. InsertDecayKeyValue(0.0f);
  849. }
  850. }
  851. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  852. return;
  853. }
  854. // Find key that has changed
  855. int changedKeyIndex = -1;
  856. const int numKeys = PreviousDecayAuxBusMap.Num();
  857. TArray<float> previousKeys;
  858. TArray<float> newKeys;
  859. PreviousDecayAuxBusMap.GetKeys(previousKeys);
  860. EnvironmentDecayAuxBusMap.GetKeys(newKeys);
  861. for (int i = 0; i < numKeys; ++i)
  862. {
  863. if (!FMath::IsNearlyEqual(previousKeys[i], newKeys[i], 1.0e-06F)) // Floating point property values have a tendancy to gradually wander in UE.
  864. {
  865. changedKeyIndex = i;
  866. break;
  867. }
  868. }
  869. // If no key values have changed, an aux bus has been changed. Nothing to restrict.
  870. if (changedKeyIndex == -1)
  871. return;
  872. // check key value
  873. float newKeyValue = newKeys[changedKeyIndex];
  874. float restrictedKeyValue = newKeyValue;
  875. FString restrictionInfoString;
  876. // Keys are sorted in reverse order such that they are ordered vertically from smallest to largest, in the UI.
  877. // So, check newKeyValue <= newKeys[changedKeyIndex + 1] and newKeyValue >= newKeys[changedKeyIndex - 1].
  878. const bool changedKeyIsSmallest = changedKeyIndex == numKeys - 1;
  879. float lowerLimit = changedKeyIsSmallest ? 0.0f : newKeys[changedKeyIndex + 1];
  880. if (newKeyValue <= lowerLimit)
  881. {
  882. restrictedKeyValue = changedKeyIsSmallest ? 0.0f : lowerLimit + MinimumDecayKeyDistance;
  883. restrictionInfoString = FString("Decay key value limited by next lowest value.");
  884. }
  885. else if (changedKeyIndex > 0 && newKeyValue >= newKeys[changedKeyIndex - 1])
  886. {
  887. restrictedKeyValue = newKeys[changedKeyIndex - 1] - MinimumDecayKeyDistance;
  888. restrictionInfoString = FString("Decay key value limited by next highest value.");
  889. }
  890. // If key value needs to be restricted, remove and replace the entry in the map.
  891. if (restrictedKeyValue != newKeyValue)
  892. {
  893. FAkAudioStyle::DisplayEditorMessage(FText::FromString(restrictionInfoString));
  894. TSoftObjectPtr<UAkAuxBus> auxBusToMove = EnvironmentDecayAuxBusMap[newKeyValue];
  895. EnvironmentDecayAuxBusMap.Remove(newKeyValue);
  896. EnvironmentDecayAuxBusMap.Add(restrictedKeyValue, auxBusToMove);
  897. SortDecayKeys();
  898. }
  899. else // No restriction to apply, but still keep track of the new key values.
  900. {
  901. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  902. }
  903. }
  904. void UAkSettings::SortDecayKeys()
  905. {
  906. // high to low decay ('large' to 'small' environment structure)
  907. EnvironmentDecayAuxBusMap.KeySort([](const float& left, const float& right) {return left > right; });
  908. PreviousDecayAuxBusMap = EnvironmentDecayAuxBusMap;
  909. }
  910. void UAkSettings::OnAssetAdded(const FAssetData& NewAssetData)
  911. {
  912. if (!bAkGeometryMapInitialized)
  913. return;
  914. #if UE_5_1_OR_LATER
  915. if (NewAssetData.AssetClassPath == UPhysicalMaterial::StaticClass()->GetClassPathName())
  916. #else
  917. if (NewAssetData.AssetClass == UPhysicalMaterial::StaticClass()->GetFName())
  918. #endif
  919. {
  920. if (auto physicalMaterial = Cast<UPhysicalMaterial>(NewAssetData.GetAsset()))
  921. {
  922. TArray<FAssetData> PhysicalMaterials, AcousticTextures;
  923. PhysicalMaterials.Add(NewAssetData);
  924. #if UE_5_1_OR_LATER
  925. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetClassPathName(), AcousticTextures);
  926. #else
  927. AssetRegistryModule->Get().GetAssetsByClass(UAkAcousticTexture::StaticClass()->GetFName(), AcousticTextures);
  928. #endif
  929. FillAkGeometryMap(PhysicalMaterials, AcousticTextures);
  930. }
  931. }
  932. #if UE_5_1_OR_LATER
  933. else if (NewAssetData.AssetClassPath == UAkAcousticTexture::StaticClass()->GetClassPathName())
  934. #else
  935. else if (NewAssetData.AssetClass == UAkAcousticTexture::StaticClass()->GetFName())
  936. #endif
  937. {
  938. if (auto acousticTexture = Cast<UAkAcousticTexture>(NewAssetData.GetAsset()))
  939. {
  940. TArray<FAssetData> PhysicalMaterials, AcousticTextures;
  941. #if UE_5_1_OR_LATER
  942. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetClassPathName(), PhysicalMaterials);
  943. #else
  944. AssetRegistryModule->Get().GetAssetsByClass(UPhysicalMaterial::StaticClass()->GetFName(), PhysicalMaterials);
  945. #endif
  946. AcousticTextures.Add(NewAssetData);
  947. FillAkGeometryMap(PhysicalMaterials, AcousticTextures);
  948. FAkAcousticTextureParams params;
  949. bool paramsExist = AcousticTextureParamsMap.Contains(acousticTexture->AcousticTextureInfo.WwiseGuid);
  950. if (paramsExist)
  951. {
  952. params = *AcousticTextureParamsMap.Find(acousticTexture->AcousticTextureInfo.WwiseGuid);
  953. params.shortID = acousticTexture->AcousticTextureInfo.WwiseShortId;
  954. }
  955. #if AK_SUPPORT_WAAPI
  956. bool paramsSet = WAAPIGetTextureParams(acousticTexture->AcousticTextureInfo.WwiseGuid, params);
  957. if (paramsSet && !paramsExist)
  958. AcousticTextureParamsMap.Add(acousticTexture->AcousticTextureInfo.WwiseGuid, params);
  959. RegisterWaapiTextureCallback(acousticTexture->AcousticTextureInfo.WwiseGuid);
  960. int colorIndex = -1;
  961. if (WAAPIGetObjectColorIndex(acousticTexture->AcousticTextureInfo.WwiseGuid, colorIndex))
  962. {
  963. acousticTexture->EditColor = FAkAudioStyle::GetWwiseObjectColor(colorIndex);
  964. }
  965. #endif
  966. }
  967. }
  968. }
  969. void UAkSettings::OnAssetRemoved(const struct FAssetData& AssetData)
  970. {
  971. #if UE_5_1_OR_LATER
  972. if (AssetData.AssetClassPath == UPhysicalMaterial::StaticClass()->GetClassPathName())
  973. #else
  974. if (AssetData.AssetClass == UPhysicalMaterial::StaticClass()->GetFName())
  975. #endif
  976. {
  977. if (auto physicalMaterial = Cast<UPhysicalMaterial>(AssetData.GetAsset()))
  978. {
  979. PhysicalMaterialAcousticTextureMap.Remove(physicalMaterial);
  980. PhysicalMaterialOcclusionMap.Remove(physicalMaterial);
  981. UpdateAkGeometryMap();
  982. }
  983. }
  984. #if UE_5_1_OR_LATER
  985. else if(AssetData.AssetClassPath == UAkAcousticTexture::StaticClass()->GetClassPathName())
  986. #else
  987. else if(AssetData.AssetClass == UAkAcousticTexture::StaticClass()->GetFName())
  988. #endif
  989. {
  990. if(auto acousticTexture = Cast<UAkAcousticTexture>(AssetData.GetAsset()))
  991. {
  992. AcousticTextureParamsMap.Remove(acousticTexture->AcousticTextureInfo.WwiseGuid);
  993. #if AK_SUPPORT_WAAPI
  994. UnregisterWaapiTextureCallback(acousticTexture->AcousticTextureInfo.WwiseGuid);
  995. #endif
  996. }
  997. }
  998. }
  999. #if AK_SUPPORT_WAAPI
  1000. void UAkSettings::InitWaapiSync()
  1001. {
  1002. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  1003. if (waapiClient != nullptr)
  1004. {
  1005. if (waapiClient->IsProjectLoaded())
  1006. WaapiProjectLoaded();
  1007. WaapiProjectLoadedHandle = waapiClient->OnProjectLoaded.AddLambda([this]()
  1008. {
  1009. WaapiProjectLoaded();
  1010. });
  1011. WaapiConnectionLostHandle = waapiClient->OnConnectionLost.AddLambda([this]()
  1012. {
  1013. WaapiDisconnected();
  1014. });
  1015. }
  1016. }
  1017. #endif
  1018. void UAkSettings::EnsurePluginContentIsInAlwaysCook() const
  1019. {
  1020. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  1021. bool packageSettingsNeedUpdate = false;
  1022. TArray<FString> PathsToCheck = { TEXT("/Wwise/WwiseTree"), TEXT("/Wwise/WwiseTypes") };
  1023. for (auto pathToCheck : PathsToCheck)
  1024. {
  1025. if (!PackagingSettings->DirectoriesToAlwaysCook.ContainsByPredicate([pathToCheck](FDirectoryPath PathInArray) { return PathInArray.Path == pathToCheck; }))
  1026. {
  1027. FDirectoryPath newPath;
  1028. newPath.Path = pathToCheck;
  1029. PackagingSettings->DirectoriesToAlwaysCook.Add(newPath);
  1030. packageSettingsNeedUpdate = true;
  1031. }
  1032. }
  1033. if (packageSettingsNeedUpdate)
  1034. {
  1035. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  1036. }
  1037. }
  1038. void UAkSettings::RemoveSoundDataFromAlwaysCook(const FString& SoundDataPath)
  1039. {
  1040. bool changed = false;
  1041. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  1042. for (int32 i = PackagingSettings->DirectoriesToAlwaysCook.Num() - 1; i >= 0; --i)
  1043. {
  1044. if (PackagingSettings->DirectoriesToAlwaysCook[i].Path == SoundDataPath)
  1045. {
  1046. PackagingSettings->DirectoriesToAlwaysCook.RemoveAt(i);
  1047. changed = true;
  1048. break;
  1049. }
  1050. }
  1051. if (changed)
  1052. {
  1053. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  1054. }
  1055. }
  1056. void UAkSettings::SanitizeProjectPath(FString& Path, const FString& PreviousPath, const FText& DialogMessage)
  1057. {
  1058. AkUnrealHelper::TrimPath(Path);
  1059. FString TempPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*Path);
  1060. FText FailReason;
  1061. if (!FPaths::ValidatePath(TempPath, &FailReason))
  1062. {
  1063. if (EAppReturnType::Ok == FMessageDialog::Open(EAppMsgType::Ok, FailReason))
  1064. {
  1065. Path = PreviousPath;
  1066. return;
  1067. }
  1068. }
  1069. auto ProjectDirectory = AkUnrealHelper::GetProjectDirectory();
  1070. if (!FPaths::FileExists(TempPath))
  1071. {
  1072. // Path might be a valid one (relative to game) entered manually. Check that.
  1073. TempPath = FPaths::ConvertRelativePathToFull(ProjectDirectory, Path);
  1074. if (!FPaths::FileExists(TempPath))
  1075. {
  1076. if (EAppReturnType::Ok == FMessageDialog::Open(EAppMsgType::Ok, DialogMessage))
  1077. {
  1078. Path = PreviousPath;
  1079. return;
  1080. }
  1081. }
  1082. }
  1083. // Make the path relative to the game dir
  1084. FPaths::MakePathRelativeTo(TempPath, *ProjectDirectory);
  1085. Path = TempPath;
  1086. if (Path != PreviousPath)
  1087. {
  1088. #if UE_4_26_OR_LATER
  1089. auto WwiseBrowserTab = FGlobalTabmanager::Get()->TryInvokeTab(FName("WwiseBrowser"));
  1090. #else
  1091. TSharedRef<SDockTab> WwiseBrowserTab = FGlobalTabmanager::Get()->InvokeTab(FName("WwiseBrowser"));
  1092. #endif
  1093. bRequestRefresh = true;
  1094. }
  1095. }
  1096. void UAkSettings::OnAudioRoutingUpdate()
  1097. {
  1098. // Calculate what is expected
  1099. bool bExpectedCustom = false;
  1100. bool bExpectedSeparate = false;
  1101. bool bExpectedUsingAudioMixer = false;
  1102. bool bExpectedAudioModuleOverride = true;
  1103. bool bExpectedWwiseSoundEngineEnabled = true;
  1104. bool bExpectedWwiseAudioLinkEnabled = false;
  1105. bool bExpectedAkAudioMixerEnabled = false;
  1106. FString ExpectedAudioDeviceModuleName;
  1107. FString ExpectedAudioMixerModuleName;
  1108. switch (AudioRouting)
  1109. {
  1110. case EAkUnrealAudioRouting::Custom:
  1111. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for Custom"));
  1112. bExpectedCustom = true;
  1113. break;
  1114. case EAkUnrealAudioRouting::Separate:
  1115. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for Separate"));
  1116. bExpectedSeparate = true;
  1117. bExpectedUsingAudioMixer = true;
  1118. bExpectedAudioModuleOverride = false;
  1119. break;
  1120. case EAkUnrealAudioRouting::EnableWwiseOnly:
  1121. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for DisableUnreal"));
  1122. bExpectedUsingAudioMixer = false;
  1123. ExpectedAudioDeviceModuleName = TEXT("");
  1124. ExpectedAudioMixerModuleName = TEXT("");
  1125. break;
  1126. case EAkUnrealAudioRouting::EnableUnrealOnly:
  1127. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for DisableWwise"));
  1128. bExpectedSeparate = true;
  1129. bExpectedUsingAudioMixer = true;
  1130. bExpectedAudioModuleOverride = false;
  1131. bExpectedWwiseSoundEngineEnabled = false;
  1132. break;
  1133. case EAkUnrealAudioRouting::AudioMixer:
  1134. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for AudioMixer"));
  1135. bExpectedUsingAudioMixer = true;
  1136. bExpectedAkAudioMixerEnabled = true;
  1137. ExpectedAudioDeviceModuleName = TEXT("AkAudioMixer");
  1138. ExpectedAudioMixerModuleName = TEXT("AkAudioMixer");
  1139. break;
  1140. case EAkUnrealAudioRouting::AudioLink:
  1141. UE_LOG(LogAkAudio, VeryVerbose, TEXT("OnAudioRoutingUpdate: Setting for AudioLink"));
  1142. bExpectedSeparate = true;
  1143. bExpectedUsingAudioMixer = true;
  1144. bExpectedWwiseAudioLinkEnabled = true;
  1145. bExpectedAudioModuleOverride = false;
  1146. break;
  1147. default:
  1148. UE_LOG(LogAkAudio, Warning, TEXT("OnAudioRoutingUpdate: Unknown AudioRouting"));
  1149. return;
  1150. }
  1151. //
  1152. // Actually update the files
  1153. //
  1154. UE_LOG(LogAkAudio, Verbose, TEXT("OnAudioRoutingUpdate: Updating system settings."));
  1155. {
  1156. bWwiseSoundEngineEnabled = bExpectedWwiseSoundEngineEnabled;
  1157. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise SoundEngine Enabled: %s"), bExpectedWwiseSoundEngineEnabled ? TEXT("true") : TEXT("false"));
  1158. bWwiseAudioLinkEnabled = bExpectedWwiseAudioLinkEnabled;
  1159. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise AudioLink Enabled: %s"), bExpectedWwiseAudioLinkEnabled ? TEXT("true") : TEXT("false"));
  1160. bAkAudioMixerEnabled = bExpectedAkAudioMixerEnabled;
  1161. UE_LOG(LogAkAudio, Log, TEXT("OnAudioRoutingUpdate: Wwise AudioMixer Enabled: %s"), bExpectedAkAudioMixerEnabled ? TEXT("true") : TEXT("false"));
  1162. #if UE_5_0_OR_LATER
  1163. TryUpdateDefaultConfigFile();
  1164. #else
  1165. UpdateDefaultConfigFile();
  1166. #endif
  1167. }
  1168. TArray<FString> IniPlatformNames;
  1169. #if UE_5_0_OR_LATER
  1170. for (const auto& PlatformInfo : FDataDrivenPlatformInfoRegistry::GetAllPlatformInfos())
  1171. {
  1172. if (!PlatformInfo.Value.bIsFakePlatform)
  1173. {
  1174. IniPlatformNames.Add(PlatformInfo.Value.IniPlatformName.ToString());
  1175. }
  1176. }
  1177. #else
  1178. for (const auto& Platform : GetTargetPlatformManagerRef().GetTargetPlatforms())
  1179. {
  1180. IniPlatformNames.Add(Platform->IniPlatformName());
  1181. }
  1182. #endif
  1183. for (const auto& IniPlatformName : IniPlatformNames)
  1184. {
  1185. const auto RelativePlatformEnginePath = FString::Printf(TEXT("%s/%sEngine.ini"), *IniPlatformName, *IniPlatformName);
  1186. auto PlatformEnginePath = FString::Printf(TEXT("%s%s"), *FPaths::SourceConfigDir(), *RelativePlatformEnginePath);
  1187. #if UE_5_1_OR_LATER
  1188. PlatformEnginePath = FConfigCacheIni::NormalizeConfigIniPath(PlatformEnginePath);
  1189. #else
  1190. FPaths::RemoveDuplicateSlashes(PlatformEnginePath);
  1191. PlatformEnginePath = FPaths::CreateStandardFilename(PlatformEnginePath);
  1192. #endif
  1193. const FString FullPlatformEnginePath = FPaths::ConvertRelativePathToFull(PlatformEnginePath);
  1194. if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*FullPlatformEnginePath))
  1195. {
  1196. FText ErrorMessage;
  1197. if (ISourceControlModule::Get().IsEnabled())
  1198. {
  1199. if (SourceControlHelpers::CheckoutOrMarkForAdd(FullPlatformEnginePath, FText::FromString(FullPlatformEnginePath), NULL, ErrorMessage))
  1200. {
  1201. ErrorMessage = FText();
  1202. }
  1203. }
  1204. else if (!FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*FullPlatformEnginePath, false))
  1205. {
  1206. ErrorMessage = FText::Format(LOCTEXT("FailedToMakeWritable", "Could not make {0} writable."), FText::FromString(FullPlatformEnginePath));
  1207. }
  1208. if (!ErrorMessage.IsEmpty())
  1209. {
  1210. FNotificationInfo Info(ErrorMessage);
  1211. Info.ExpireDuration = 3.0;
  1212. FSlateNotificationManager::Get().AddNotification(Info);
  1213. continue;
  1214. }
  1215. }
  1216. if (bExpectedUsingAudioMixer)
  1217. {
  1218. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing UseAudioMixer override"), *RelativePlatformEnginePath);
  1219. GConfig->RemoveKey(TEXT("Audio"), TEXT("UseAudioMixer"), PlatformEnginePath);
  1220. }
  1221. else
  1222. {
  1223. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating UseAudioMixer to: %s"), *RelativePlatformEnginePath, bExpectedUsingAudioMixer ? TEXT("true") : TEXT("false"));
  1224. GConfig->SetBool(TEXT("Audio"), TEXT("UseAudioMixer"), bExpectedUsingAudioMixer, PlatformEnginePath);
  1225. }
  1226. if (bExpectedAudioModuleOverride)
  1227. {
  1228. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating AudioDeviceModuleName: %s"), *RelativePlatformEnginePath, ExpectedAudioDeviceModuleName.IsEmpty() ? TEXT("[empty]") : *ExpectedAudioDeviceModuleName);
  1229. UE_LOG(LogAkAudio, Log, TEXT("%s: Updating AudioMixerModuleName: %s"), *RelativePlatformEnginePath, ExpectedAudioMixerModuleName.IsEmpty() ? TEXT("[empty]") : *ExpectedAudioMixerModuleName);
  1230. GConfig->SetString(TEXT("Audio"), TEXT("AudioDeviceModuleName"), *ExpectedAudioDeviceModuleName, PlatformEnginePath);
  1231. GConfig->SetString(TEXT("Audio"), TEXT("AudioMixerModuleName"), *ExpectedAudioMixerModuleName, PlatformEnginePath);
  1232. }
  1233. else
  1234. {
  1235. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing AudioDeviceModuleName override"), *RelativePlatformEnginePath);
  1236. UE_LOG(LogAkAudio, Log, TEXT("%s: Removing AudioMixerModuleName override"), *RelativePlatformEnginePath);
  1237. GConfig->RemoveKey(TEXT("Audio"), TEXT("AudioDeviceModuleName"), PlatformEnginePath);
  1238. GConfig->RemoveKey(TEXT("Audio"), TEXT("AudioMixerModuleName"), PlatformEnginePath);
  1239. }
  1240. GConfig->Flush(false, PlatformEnginePath);
  1241. }
  1242. }
  1243. void UAkSettings::RemoveSoundDataFromAlwaysStageAsUFS(const FString& SoundDataPath)
  1244. {
  1245. bool changed = false;
  1246. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  1247. for (int32 i = PackagingSettings->DirectoriesToAlwaysStageAsUFS.Num() - 1; i >= 0; --i)
  1248. {
  1249. if (PackagingSettings->DirectoriesToAlwaysStageAsUFS[i].Path == SoundDataPath)
  1250. {
  1251. PackagingSettings->DirectoriesToAlwaysStageAsUFS.RemoveAt(i);
  1252. changed = true;
  1253. break;
  1254. }
  1255. }
  1256. if (changed)
  1257. {
  1258. AkUnrealEditorHelper::SaveConfigFile(PackagingSettings);
  1259. }
  1260. }
  1261. #endif // WITH_EDITOR
  1262. const FAkAcousticTextureParams* UAkSettings::GetTextureParams(const uint32& shortID) const
  1263. {
  1264. for (auto it = AcousticTextureParamsMap.CreateConstIterator(); it; ++it)
  1265. {
  1266. if (it.Value().shortID == shortID)
  1267. return AcousticTextureParamsMap.Find(it.Key());
  1268. }
  1269. return nullptr;
  1270. }
  1271. bool UAkSettings::ReverbRTPCsInUse() const
  1272. {
  1273. return DecayRTPCInUse() || DampingRTPCInUse() || PredelayRTPCInUse();
  1274. }
  1275. bool UAkSettings::DecayRTPCInUse() const
  1276. {
  1277. const bool validPath = !DecayEstimateRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1278. return validPath || !DecayEstimateName.IsEmpty();
  1279. }
  1280. bool UAkSettings::DampingRTPCInUse() const
  1281. {
  1282. const bool validPath = !HFDampingRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1283. return validPath || !HFDampingName.IsEmpty();
  1284. }
  1285. bool UAkSettings::PredelayRTPCInUse() const
  1286. {
  1287. const bool validPath = !TimeToFirstReflectionRTPC.ToSoftObjectPath().ToString().IsEmpty();
  1288. return validPath || !TimeToFirstReflectionName.IsEmpty();
  1289. }
  1290. bool UAkSettings::GetAssociatedAcousticTexture(const UPhysicalMaterial* physMaterial, UAkAcousticTexture*& acousticTexture) const
  1291. {
  1292. TSoftObjectPtr<class UPhysicalMaterial> physMatPtr(physMaterial);
  1293. auto props = AkGeometryMap.Find(physMatPtr);
  1294. if (!props)
  1295. return false;
  1296. TSoftObjectPtr<class UAkAcousticTexture> texturePtr = props->AcousticTexture;
  1297. acousticTexture = texturePtr.LoadSynchronous();
  1298. return true;
  1299. }
  1300. bool UAkSettings::GetAssociatedOcclusionValue(const UPhysicalMaterial* physMaterial, float& occlusionValue) const
  1301. {
  1302. TSoftObjectPtr<class UPhysicalMaterial> physMatPtr(physMaterial);
  1303. auto props = AkGeometryMap.Find(physMatPtr);
  1304. if (!props)
  1305. return false;
  1306. occlusionValue = props->OcclusionValue;
  1307. return true;
  1308. }
  1309. void UAkSettings::GetAuxBusForDecayValue(float decay, UAkAuxBus*& auxBus)
  1310. {
  1311. TArray<float> decayKeys;
  1312. EnvironmentDecayAuxBusMap.GetKeys(decayKeys);
  1313. decayKeys.Sort();
  1314. int numKeys = decayKeys.Num();
  1315. if (numKeys > 0)
  1316. {
  1317. int i = numKeys - 1;
  1318. if (decay > decayKeys[i])
  1319. {
  1320. auxBus = DefaultReverbAuxBus.LoadSynchronous();
  1321. return;
  1322. }
  1323. while (i > 0 && decay <= decayKeys[i - 1])
  1324. {
  1325. --i;
  1326. }
  1327. TSoftObjectPtr<UAkAuxBus> auxBusPtr = EnvironmentDecayAuxBusMap[decayKeys[i]];
  1328. auxBus = auxBusPtr.LoadSynchronous();
  1329. }
  1330. else
  1331. {
  1332. auxBus = DefaultReverbAuxBus.LoadSynchronous();
  1333. }
  1334. }
  1335. void UAkSettings::GetAudioInputEvent(UAkAudioEvent*& OutInputEvent)
  1336. {
  1337. OutInputEvent = AudioInputEvent.LoadSynchronous();
  1338. }
  1339. #undef LOCTEXT_NAMESPACE