AkComponent.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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. /*=============================================================================
  16. AkComponent.cpp:
  17. =============================================================================*/
  18. #include "AkComponent.h"
  19. #include "AkAudioDevice.h"
  20. #include "AkAudioEvent.h"
  21. #include "AkAuxBus.h"
  22. #include "AkLateReverbComponent.h"
  23. #include "AkRoomComponent.h"
  24. #include "AkGameplayTypes.h"
  25. #include "AkSettings.h"
  26. #include "AkSpotReflector.h"
  27. #include "AkSwitchValue.h"
  28. #include "AkTrigger.h"
  29. #include "Components/BillboardComponent.h"
  30. #include "DrawDebugHelpers.h"
  31. #include "Engine/Texture2D.h"
  32. #include "Engine/World.h"
  33. #include "GameFramework/PlayerController.h"
  34. #include "UObject/UObjectIterator.h"
  35. #include "Wwise/WwiseExternalSourceManager.h"
  36. #include "Wwise/API/WwiseSoundEngineAPI.h"
  37. #include "Wwise/API/WwiseSpatialAudioAPI.h"
  38. #if WITH_EDITOR
  39. #include "LevelEditorViewport.h"
  40. #include "Editor.h"
  41. #endif
  42. /*------------------------------------------------------------------------------------
  43. Component Helpers
  44. ------------------------------------------------------------------------------------*/
  45. namespace UAkComponentUtils
  46. {
  47. APlayerController* GetAPlayerController(const UActorComponent* Component)
  48. {
  49. const APlayerCameraManager* AsPlayerCameraManager = Cast<APlayerCameraManager>(Component->GetOwner());
  50. return AsPlayerCameraManager ? AsPlayerCameraManager->GetOwningPlayerController() : nullptr;
  51. }
  52. void GetListenerPosition(const UAkComponent* Component, FVector& Location, FVector& Front, FVector& Up)
  53. {
  54. APlayerController* pPlayerController = GetAPlayerController(Component);
  55. if (pPlayerController != nullptr)
  56. {
  57. FVector Right;
  58. pPlayerController->GetAudioListenerPosition(Location, Front, Right);
  59. Up = FVector::CrossProduct(Front, Right);
  60. return;
  61. }
  62. #if WITH_EDITORONLY_DATA
  63. auto& Clients = GEditor->GetAllViewportClients();
  64. static FTransform LastKnownEditorTransform;
  65. for (int i = 0; i < Clients.Num(); i++)
  66. {
  67. FEditorViewportClient* ViewportClient = Clients[i];
  68. UWorld* World = ViewportClient->GetWorld();
  69. if (ViewportClient->Viewport && ViewportClient->Viewport->HasFocus() && World->AllowAudioPlayback())
  70. {
  71. EWorldType::Type WorldType = World->WorldType;
  72. if (WorldType == EWorldType::Editor || WorldType == EWorldType::PIE)
  73. {
  74. LastKnownEditorTransform = FAkAudioDevice::Get()->GetEditorListenerPosition(i);
  75. Location = LastKnownEditorTransform.GetLocation();
  76. Front = LastKnownEditorTransform.GetRotation().GetForwardVector();
  77. Up = LastKnownEditorTransform.GetRotation().GetUpVector();
  78. return;
  79. }
  80. else if (WorldType != EWorldType::Game && WorldType != EWorldType::GamePreview)
  81. {
  82. Location = ViewportClient->GetViewLocation();
  83. Front = ViewportClient->GetViewRotation().Quaternion().GetForwardVector();
  84. Up = ViewportClient->GetViewRotation().Quaternion().GetUpVector();
  85. LastKnownEditorTransform.SetLocation(Location);
  86. LastKnownEditorTransform.SetRotation(ViewportClient->GetViewRotation().Quaternion());
  87. return;
  88. }
  89. }
  90. }
  91. Location = LastKnownEditorTransform.GetLocation();
  92. Front = LastKnownEditorTransform.GetRotation().GetForwardVector();
  93. Up = LastKnownEditorTransform.GetRotation().GetUpVector();
  94. #endif
  95. }
  96. void GetLocationFrontUp(const UAkComponent* Component, FVector& Location, FVector& Front, FVector& Up)
  97. {
  98. if (Component->IsDefaultListener)
  99. {
  100. GetListenerPosition(Component, Location, Front, Up);
  101. }
  102. else
  103. {
  104. auto& Transform = Component->GetComponentTransform();
  105. Location = Transform.GetTranslation();
  106. Front = Transform.GetUnitAxis(EAxis::X);
  107. Up = Transform.GetUnitAxis(EAxis::Z);
  108. }
  109. }
  110. }
  111. AkReverbFadeControl::AkReverbFadeControl(const UAkLateReverbComponent& LateReverbComponent)
  112. : AuxBusId(LateReverbComponent.GetAuxBusId())
  113. , bIsFadingOut(false)
  114. , FadeControlUniqueId((void*)&LateReverbComponent)
  115. , CurrentControlValue(0.f)
  116. , TargetControlValue(LateReverbComponent.SendLevel)
  117. , FadeRate(LateReverbComponent.FadeRate)
  118. , Priority(LateReverbComponent.Priority)
  119. {}
  120. void AkReverbFadeControl::UpdateValues(const UAkLateReverbComponent& LateReverbComponent)
  121. {
  122. AuxBusId = LateReverbComponent.GetAuxBusId();
  123. TargetControlValue = LateReverbComponent.SendLevel;
  124. FadeRate = LateReverbComponent.FadeRate;
  125. Priority = LateReverbComponent.Priority;
  126. }
  127. bool AkReverbFadeControl::Update(float DeltaTime)
  128. {
  129. if (CurrentControlValue != TargetControlValue || bIsFadingOut)
  130. {
  131. // Rate (%/s) * Delta (s) = % for given delta, apply to target.
  132. const float Increment = DeltaTime * FadeRate * TargetControlValue;
  133. if (bIsFadingOut)
  134. {
  135. CurrentControlValue -= Increment;
  136. if (CurrentControlValue <= 0.f)
  137. return false;
  138. }
  139. else
  140. CurrentControlValue = FMath::Min(CurrentControlValue + Increment, TargetControlValue);
  141. }
  142. return true;
  143. }
  144. AkAuxSendValue AkReverbFadeControl::ToAkAuxSendValue() const
  145. {
  146. AkAuxSendValue ret;
  147. ret.listenerID = AK_INVALID_GAME_OBJECT;
  148. ret.auxBusID = AuxBusId;
  149. ret.fControlValue = CurrentControlValue;
  150. return ret;
  151. }
  152. bool AkReverbFadeControl::Prioritize(const AkReverbFadeControl& A, const AkReverbFadeControl& B)
  153. {
  154. if (A.bIsFadingOut == B.bIsFadingOut)
  155. {
  156. if (A.Priority == B.Priority)
  157. {
  158. // Sort by bus id if priority and fade are equal, to ensure comparisons in UAkComponent::NeedToUpdateAuxSends dont lead to continuous aux sends updates, when there are overlapping reverbs.
  159. return A.AuxBusId < B.AuxBusId;
  160. }
  161. return A.Priority > B.Priority;
  162. }
  163. // Ensure the fading out buffers are sent to the end of the array.
  164. return A.bIsFadingOut < B.bIsFadingOut;
  165. }
  166. /*------------------------------------------------------------------------------------
  167. UAkComponent
  168. ------------------------------------------------------------------------------------*/
  169. UAkComponent::UAkComponent(const class FObjectInitializer& ObjectInitializer) :
  170. Super(ObjectInitializer)
  171. {
  172. // Property initialization
  173. DrawFirstOrderReflections = false;
  174. DrawSecondOrderReflections = false;
  175. DrawHigherOrderReflections = false;
  176. DrawDiffraction = false;
  177. EarlyReflectionBusSendGain = 1.f;
  178. StopWhenOwnerDestroyed = true;
  179. bUseReverbVolumes = true;
  180. OcclusionRefreshInterval = 0.2f;
  181. PrimaryComponentTick.bCanEverTick = true;
  182. PrimaryComponentTick.TickGroup = TG_DuringPhysics;
  183. PrimaryComponentTick.bAllowTickOnDedicatedServer = false;
  184. bTickInEditor = true;
  185. bAutoActivate = true;
  186. bNeverNeedsRenderUpdate = true;
  187. bWantsOnUpdateTransform = true;
  188. #if WITH_EDITORONLY_DATA
  189. bVisualizeComponent = true;
  190. #endif
  191. AttenuationScalingFactor = 1.0f;
  192. bAutoDestroy = false;
  193. bUseDefaultListeners = true;
  194. OcclusionCollisionChannel = EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault;
  195. outerRadius = 0.0f;
  196. innerRadius = 0.0f;
  197. }
  198. ECollisionChannel UAkComponent::GetOcclusionCollisionChannel()
  199. {
  200. return UAkSettings::ConvertOcclusionCollisionChannel(OcclusionCollisionChannel.GetValue());
  201. }
  202. int32 UAkComponent::PostAssociatedAkEventAndWaitForEnd(FLatentActionInfo LatentInfo)
  203. {
  204. return PostAkEventAndWaitForEnd(AkAudioEvent, LatentInfo);
  205. }
  206. int32 UAkComponent::PostAkEventAndWaitForEnd(class UAkAudioEvent * AkEvent, FLatentActionInfo LatentInfo)
  207. {
  208. if (LIKELY(IsValid(AkEvent)))
  209. {
  210. return AkEvent->PostOnComponentAndWait(this, StopWhenOwnerDestroyed, LatentInfo);
  211. }
  212. UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid latent AkAudioEvent on component '%s'"), *GetName());
  213. return AK_INVALID_PLAYING_ID;
  214. }
  215. int32 UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, int32 CallbackMask,
  216. const FOnAkPostEventCallback& PostEventCallback)
  217. {
  218. if (LIKELY(IsValid(AkEvent)))
  219. {
  220. return AkEvent->PostOnComponent(this, PostEventCallback, CallbackMask, StopWhenOwnerDestroyed);
  221. }
  222. UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on component '%s'"), *GetName());
  223. return AK_INVALID_PLAYING_ID;
  224. }
  225. AkPlayingID UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, AkUInt32 Flags, AkCallbackFunc UserCallback,
  226. void* UserCookie)
  227. {
  228. if (LIKELY(IsValid(AkEvent)))
  229. {
  230. return AkEvent->PostOnComponent(this, nullptr, UserCallback, UserCookie, static_cast<AkCallbackType>(Flags), nullptr, StopWhenOwnerDestroyed);
  231. }
  232. UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on component '%s'"), *GetName());
  233. return AK_INVALID_PLAYING_ID;
  234. }
  235. AkRoomID UAkComponent::GetSpatialAudioRoomID() const
  236. {
  237. AkRoomID RoomID;
  238. if (CurrentRoom)
  239. {
  240. RoomID = CurrentRoom->GetRoomID();
  241. }
  242. return RoomID;
  243. }
  244. void UAkComponent::UpdateObstructionAndOcclusion()
  245. {
  246. SCOPED_AKAUDIO_EVENT_2(TEXT("UAkComponent::UpdateObstructionAndOcclusion"));
  247. auto World = GetWorld();
  248. auto AudioDevice = FAkAudioDevice::Get();
  249. if (World && AudioDevice && AudioDevice->ShouldNotifySoundEngine(World->WorldType))
  250. {
  251. FScopeLock Lock(&ListenerCriticalSection);
  252. AkObstructionAndOcclusionService::ListenerMap ObsOccListenerMap;
  253. for (auto& Listener : Listeners)
  254. {
  255. AkObstructionAndOcclusionService::FListenerInfo ListenerInfo(Listener->GetPosition(), Listener->GetSpatialAudioRoomID());
  256. ObsOccListenerMap.Add(Listener->GetAkGameObjectID(), ListenerInfo);
  257. }
  258. AkObstructionAndOcclusionService::PortalMap ObsOccPortalMap;
  259. AudioDevice->GetObsOccServicePortalMap(GetSpatialAudioRoom(), GetWorld(), ObsOccPortalMap);
  260. ObstructionService.UpdateObstructionAndOcclusion(ObsOccListenerMap, ObsOccPortalMap, GetPosition(), GetOwner(), GetSpatialAudioRoomID(), GetOcclusionCollisionChannel(), OcclusionRefreshInterval);
  261. }
  262. }
  263. void UAkComponent::PostTrigger(const UAkTrigger* TriggerValue, FString Trigger)
  264. {
  265. if (FAkAudioDevice::Get())
  266. {
  267. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  268. if (UNLIKELY(!SoundEngine)) return;
  269. if (TriggerValue)
  270. {
  271. SoundEngine->PostTrigger(TriggerValue->TriggerCookedData.TriggerId, GetAkGameObjectID());
  272. }
  273. else
  274. {
  275. SoundEngine->PostTrigger(TCHAR_TO_AK(*Trigger), GetAkGameObjectID());
  276. }
  277. }
  278. }
  279. void UAkComponent::SetSwitch(const UAkSwitchValue* SwitchValue, FString SwitchGroup, FString SwitchState)
  280. {
  281. if (FAkAudioDevice::Get())
  282. {
  283. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  284. if (UNLIKELY(!SoundEngine)) return;
  285. if (SwitchValue)
  286. {
  287. SoundEngine->SetSwitch(SwitchValue->GroupValueCookedData.GroupId, SwitchValue->GroupValueCookedData.Id, GetAkGameObjectID());
  288. }
  289. else
  290. {
  291. uint32 SwitchGroupID = SoundEngine->GetIDFromString(TCHAR_TO_AK(*SwitchGroup));
  292. uint32 SwitchStateID = SoundEngine->GetIDFromString(TCHAR_TO_AK(*SwitchState));
  293. SoundEngine->SetSwitch(SwitchGroupID, SwitchStateID, GetAkGameObjectID());
  294. }
  295. }
  296. }
  297. void UAkComponent::SetStopWhenOwnerDestroyed(bool bStopWhenOwnerDestroyed)
  298. {
  299. StopWhenOwnerDestroyed = bStopWhenOwnerDestroyed;
  300. }
  301. void UAkComponent::SetListeners(const TArray<UAkComponent*>& NewListeners)
  302. {
  303. auto AudioDevice = FAkAudioDevice::Get();
  304. if (AudioDevice)
  305. {
  306. FScopeLock Lock(&ListenerCriticalSection);
  307. bUseDefaultListeners = false;
  308. for(auto& Listener : Listeners)
  309. {
  310. Listener->IsListener = false;
  311. }
  312. Listeners.Reset();
  313. Listeners.Append(NewListeners);
  314. for(auto& Listener : Listeners)
  315. {
  316. Listener->IsListener = true;
  317. }
  318. AudioDevice->SetListeners(this, Listeners.Array());
  319. }
  320. }
  321. void UAkComponent::SetEarlyReflectionsAuxBus(const FString& AuxBusName)
  322. {
  323. FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
  324. if (AudioDevice)
  325. {
  326. AudioDevice->SetEarlyReflectionsAuxBus(this, FAkAudioDevice::GetShortID(nullptr, AuxBusName));
  327. }
  328. }
  329. void UAkComponent::SetEarlyReflectionsVolume(float SendVolume)
  330. {
  331. FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
  332. if (AudioDevice)
  333. {
  334. AudioDevice->SetEarlyReflectionsVolume(this, SendVolume);
  335. }
  336. }
  337. float UAkComponent::GetAttenuationRadius() const
  338. {
  339. return AkAudioEvent ? AttenuationScalingFactor * AkAudioEvent->MaxAttenuationRadius : 0.f;
  340. }
  341. void UAkComponent::SetOutputBusVolume(float BusVolume)
  342. {
  343. FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
  344. if (AudioDevice)
  345. {
  346. FScopeLock Lock(&ListenerCriticalSection);
  347. for (auto It = Listeners.CreateIterator(); It; ++It)
  348. {
  349. AudioDevice->SetGameObjectOutputBusVolume(this, *It, BusVolume);
  350. }
  351. }
  352. }
  353. void UAkComponent::OnRegister()
  354. {
  355. UWorld* CurrentWorld = GetWorld();
  356. if(!IsRegisteredWithWwise && CurrentWorld->WorldType != EWorldType::Inactive && CurrentWorld->WorldType != EWorldType::None)
  357. RegisterGameObject(); // Done before parent so that OnUpdateTransform follows registration and updates position correctly.
  358. FAkAudioDevice* AudioDevice = FAkAudioDevice::Get();
  359. if (AudioDevice)
  360. {
  361. ObstructionService.Init(GetAkGameObjectID(), CurrentWorld, OcclusionRefreshInterval, AudioDevice->UsingSpatialAudioRooms(CurrentWorld));
  362. }
  363. // It's possible for OnRegister to be called while the WorldType is inactive.
  364. // The game object will be registered again later when the WorldType is active.
  365. if (AudioDevice && IsRegisteredWithWwise)
  366. {
  367. if (EarlyReflectionAuxBus || !EarlyReflectionAuxBusName.IsEmpty())
  368. {
  369. AkUInt32 AuxBusID = FAkAudioDevice::GetShortID(EarlyReflectionAuxBus, EarlyReflectionAuxBusName);
  370. if (AuxBusID != AK_INVALID_UNIQUE_ID)
  371. AudioDevice->SetEarlyReflectionsAuxBus(this, AuxBusID);
  372. }
  373. if (EarlyReflectionBusSendGain != 1.0)
  374. AudioDevice->SetEarlyReflectionsVolume(this, EarlyReflectionBusSendGain);
  375. }
  376. Super::OnRegister();
  377. #if WITH_EDITORONLY_DATA
  378. if (bVisualizeComponent)
  379. {
  380. UpdateSpriteTexture();
  381. }
  382. #endif
  383. }
  384. #if WITH_EDITORONLY_DATA
  385. void UAkComponent::UpdateSpriteTexture()
  386. {
  387. if (SpriteComponent)
  388. {
  389. SpriteComponent->SetSprite(LoadObject<UTexture2D>(NULL, TEXT("/Wwise/S_AkComponent.S_AkComponent")));
  390. }
  391. }
  392. #endif
  393. void UAkComponent::OnUnregister()
  394. {
  395. // Route OnUnregister event.
  396. Super::OnUnregister();
  397. // Don't stop audio and clean up component if owner has been destroyed (default behaviour). This function gets
  398. // called from AActor::ClearComponents when an actor gets destroyed which is not usually what we want for one-
  399. // shot sounds.
  400. AActor* Owner = GetOwner();
  401. UWorld* CurrentWorld = GetWorld();
  402. if( !Owner || !CurrentWorld || StopWhenOwnerDestroyed || CurrentWorld->bIsTearingDown || (Owner->GetClass() == APlayerController::StaticClass() && CurrentWorld->WorldType == EWorldType::PIE))
  403. {
  404. Stop();
  405. }
  406. }
  407. void UAkComponent::OnComponentDestroyed( bool bDestroyingHierarchy )
  408. {
  409. UnregisterGameObject();
  410. Super::OnComponentDestroyed(bDestroyingHierarchy);
  411. }
  412. void UAkComponent::ShutdownAfterError( void )
  413. {
  414. UnregisterGameObject();
  415. Super::ShutdownAfterError();
  416. }
  417. bool UAkComponent::NeedToUpdateAuxSends(const TArray<AkAuxSendValue>& NewValues)
  418. {
  419. if (NewValues.Num() != CurrentAuxSendValues.Num())
  420. return true;
  421. for (int32 i = 0; i < NewValues.Num(); i++)
  422. {
  423. if (NewValues[i].listenerID != CurrentAuxSendValues[i].listenerID ||
  424. NewValues[i].auxBusID != CurrentAuxSendValues[i].auxBusID ||
  425. NewValues[i].fControlValue != CurrentAuxSendValues[i].fControlValue)
  426. {
  427. return true;
  428. }
  429. }
  430. return false;
  431. }
  432. void UAkComponent::ApplyAkReverbVolumeList(float DeltaTime)
  433. {
  434. for (int32 Idx = 0; Idx < ReverbFadeControls.Num(); )
  435. {
  436. if (!ReverbFadeControls[Idx].Update(DeltaTime))
  437. ReverbFadeControls.RemoveAt(Idx);
  438. else
  439. ++Idx;
  440. }
  441. if (ReverbFadeControls.Num() > 1)
  442. ReverbFadeControls.Sort(AkReverbFadeControl::Prioritize);
  443. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  444. if (AkAudioDevice)
  445. {
  446. TArray<AkAuxSendValue> NewAuxSendValues;
  447. for (int32 Idx = 0; Idx < ReverbFadeControls.Num() && Idx < AkAudioDevice->GetMaxAuxBus(); Idx++)
  448. {
  449. AkAuxSendValue* FoundAuxSend = NewAuxSendValues.FindByPredicate([this, Idx](const AkAuxSendValue& ItemInArray) { return ItemInArray.auxBusID == ReverbFadeControls[Idx].AuxBusId; });
  450. if (FoundAuxSend)
  451. {
  452. FoundAuxSend->fControlValue += ReverbFadeControls[Idx].ToAkAuxSendValue().fControlValue;
  453. }
  454. else
  455. {
  456. NewAuxSendValues.Add(ReverbFadeControls[Idx].ToAkAuxSendValue());
  457. }
  458. }
  459. if (NeedToUpdateAuxSends(NewAuxSendValues))
  460. {
  461. AkAudioDevice->SetAuxSends(this, NewAuxSendValues);
  462. CurrentAuxSendValues = NewAuxSendValues;
  463. }
  464. }
  465. }
  466. void UAkComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  467. {
  468. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  469. if (UNLIKELY(!SoundEngine)) return;
  470. if (SoundEngine->IsInitialized())
  471. {
  472. Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  473. auto World = GetWorld();
  474. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  475. // If we're a listener, update our position here instead of in OnUpdateTransform.
  476. // This is because PlayerController->GetAudioListenerPosition caches its value, and it can be out of sync
  477. if (IsDefaultListener && HasMoved())
  478. UpdateGameObjectPosition();
  479. if (AkAudioDevice && AkAudioDevice->WorldSpatialAudioVolumesUpdated(World))
  480. {
  481. UpdateSpatialAudioRoom(GetComponentLocation());
  482. // Find and apply all AkReverbVolumes at this location
  483. if (bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
  484. {
  485. UpdateAkLateReverbComponentList(GetComponentLocation());
  486. }
  487. }
  488. if (AkAudioDevice && bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
  489. ApplyAkReverbVolumeList(DeltaTime);
  490. if (World && AkAudioDevice && AkAudioDevice->ShouldNotifySoundEngine(World->WorldType))
  491. {
  492. FScopeLock Lock(&ListenerCriticalSection);
  493. AkObstructionAndOcclusionService::ListenerMap ObsOccListenerMap;
  494. for (auto& Listener : Listeners)
  495. {
  496. AkObstructionAndOcclusionService::FListenerInfo ListenerInfo(Listener->GetPosition(), Listener->GetSpatialAudioRoomID());
  497. ObsOccListenerMap.Add(Listener->GetAkGameObjectID(), ListenerInfo);
  498. }
  499. AkObstructionAndOcclusionService::PortalMap ObsOccPortalMap;
  500. if (AkAudioDevice)
  501. {
  502. AkAudioDevice->GetObsOccServicePortalMap(GetSpatialAudioRoom(), GetWorld(), ObsOccPortalMap);
  503. }
  504. ObstructionService.Tick(ObsOccListenerMap, ObsOccPortalMap, GetPosition(), GetOwner(), GetSpatialAudioRoomID(), GetOcclusionCollisionChannel(), DeltaTime, OcclusionRefreshInterval);
  505. }
  506. if (bAutoDestroy && bEventPosted && !HasActiveEvents())
  507. {
  508. DestroyComponent();
  509. }
  510. #if !UE_BUILD_SHIPPING
  511. if (DrawFirstOrderReflections || DrawSecondOrderReflections || DrawHigherOrderReflections)
  512. {
  513. DebugDrawReflections();
  514. }
  515. if (DrawDiffraction)
  516. {
  517. DebugDrawDiffraction();
  518. }
  519. #endif
  520. }
  521. }
  522. void UAkComponent::BeginPlay()
  523. {
  524. Super::BeginPlay();
  525. UpdateGameObjectPosition();
  526. // If spawned inside AkReverbVolume(s), we do not want the fade in effect to kick in.
  527. UpdateAkLateReverbComponentList(GetComponentLocation());
  528. for (auto& ReverbFadeControl : ReverbFadeControls)
  529. ReverbFadeControl.ForceCurrentToTargetValue();
  530. SetAttenuationScalingFactor(AttenuationScalingFactor);
  531. if (EnableSpotReflectors)
  532. AAkSpotReflector::UpdateSpotReflectors(this);
  533. }
  534. void UAkComponent::SetAttenuationScalingFactor(float Value)
  535. {
  536. AttenuationScalingFactor = Value;
  537. FAkAudioDevice* AudioDevice = FAkAudioDevice::Get();
  538. if (AudioDevice)
  539. AudioDevice->SetAttenuationScalingFactor(this, AttenuationScalingFactor);
  540. }
  541. void UAkComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport)
  542. {
  543. Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
  544. // If we're a listener, our position will be updated from Tick instead of here.
  545. // This is because PlayerController->GetAudioListenerPosition caches its value, and it can be out of sync
  546. if(!IsDefaultListener)
  547. UpdateGameObjectPosition();
  548. }
  549. UAkComponent* UAkComponent::GetAkComponent(AkGameObjectID GameObjectID)
  550. {
  551. return GameObjectID == DUMMY_GAMEOBJ ? nullptr : (UAkComponent*)GameObjectID;
  552. }
  553. void UAkComponent::GetAkGameObjectName(FString& Name) const
  554. {
  555. AActor* parentActor = GetOwner();
  556. if (parentActor)
  557. {
  558. #if WITH_EDITOR
  559. Name = parentActor->GetActorLabel() + ".";
  560. #else
  561. Name = parentActor->GetName() + ".";
  562. #endif
  563. }
  564. Name += GetName();
  565. UWorld* CurrentWorld = GetWorld();
  566. switch (CurrentWorld->WorldType)
  567. {
  568. case EWorldType::Editor:
  569. Name += "(Editor)";
  570. break;
  571. case EWorldType::EditorPreview:
  572. Name += "(EditorPreview)";
  573. break;
  574. case EWorldType::GamePreview:
  575. Name += "(GamePreview)";
  576. break;
  577. case EWorldType::Inactive:
  578. Name += "(Inactive)";
  579. break;
  580. }
  581. }
  582. void UAkComponent::PostRegisterGameObject() {}
  583. void UAkComponent::PostUnregisterGameObject() {}
  584. void UAkComponent::RegisterGameObject()
  585. {
  586. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  587. if ( AkAudioDevice )
  588. {
  589. if ( bUseDefaultListeners )
  590. {
  591. FScopeLock Lock(&ListenerCriticalSection);
  592. const auto& DefaultListeners = AkAudioDevice->GetDefaultListeners();
  593. Listeners.Empty(DefaultListeners.Num());
  594. for (auto Listener : DefaultListeners)
  595. {
  596. Listeners.Add(Listener);
  597. }
  598. }
  599. AkAudioDevice->RegisterComponent(this);
  600. IsRegisteredWithWwise = true;
  601. AkAudioDevice->SetGameObjectRadius(this, outerRadius, innerRadius);
  602. }
  603. PostRegisterGameObject();
  604. }
  605. void UAkComponent::UnregisterGameObject()
  606. {
  607. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  608. if (AkAudioDevice)
  609. {
  610. AkAudioDevice->UnregisterComponent(this);
  611. IsRegisteredWithWwise = false;
  612. }
  613. if(IsListener)
  614. {
  615. for (TObjectIterator<UAkComponent> Emitter; Emitter; ++Emitter)
  616. {
  617. Emitter->OnListenerUnregistered(this);
  618. }
  619. }
  620. PostUnregisterGameObject();
  621. }
  622. void UAkComponent::UpdateAkLateReverbComponentList( FVector Loc )
  623. {
  624. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  625. if (!AkAudioDevice)
  626. return;
  627. TArray<UAkLateReverbComponent*> FoundComponents = AkAudioDevice->FindLateReverbComponentsAtLocation(Loc, GetWorld());
  628. // Add the new volumes to the current list
  629. for (const auto& LateReverbComponent : FoundComponents)
  630. {
  631. const auto AuxBusId = LateReverbComponent->GetAuxBusId();
  632. const int32 FoundIdx = ReverbFadeControls.IndexOfByPredicate([&LateReverbComponent](const AkReverbFadeControl& Candidate)
  633. {
  634. return Candidate.FadeControlUniqueId == (void*)LateReverbComponent;
  635. });
  636. if (FoundIdx == INDEX_NONE)
  637. {
  638. // The volume was not found, add it to the list
  639. ReverbFadeControls.Add(AkReverbFadeControl(*LateReverbComponent));
  640. }
  641. else
  642. {
  643. // The volume was found. We still have to check if it is currently fading out, in case we are
  644. // getting back in a volume we just exited.
  645. ReverbFadeControls[FoundIdx].bIsFadingOut = false;
  646. // We need to update the late reverb values in case they have changed on the reverb component.
  647. ReverbFadeControls[FoundIdx].UpdateValues(*LateReverbComponent);
  648. }
  649. }
  650. // Fade out the current volumes not found in the new list
  651. for (auto& ReverbFadeControl : ReverbFadeControls)
  652. {
  653. const int32 FoundIdx = FoundComponents.IndexOfByPredicate([&ReverbFadeControl](const UAkLateReverbComponent* const Candidate)
  654. {
  655. return ReverbFadeControl.FadeControlUniqueId == (void*)Candidate;
  656. });
  657. if (FoundIdx == INDEX_NONE)
  658. ReverbFadeControl.bIsFadingOut = true;
  659. }
  660. }
  661. FVector UAkComponent::GetPosition() const
  662. {
  663. return FAkAudioDevice::AKVector64ToFVector(CurrentSoundPosition.Position());
  664. }
  665. bool UAkComponent::HasMoved()
  666. {
  667. AkSoundPosition soundpos;
  668. FVector Location, Front, Up;
  669. UAkComponentUtils::GetLocationFrontUp(this, Location, Front, Up);
  670. FAkAudioDevice::FVectorsToAKWorldTransform(Location, Front, Up, soundpos);
  671. return CurrentSoundPosition.Position().X != soundpos.Position().X || CurrentSoundPosition.Position().Y != soundpos.Position().Y || CurrentSoundPosition.Position().Z != soundpos.Position().Z ||
  672. CurrentSoundPosition.OrientationTop().X != soundpos.OrientationTop().X || CurrentSoundPosition.OrientationTop().Y != soundpos.OrientationTop().Y || CurrentSoundPosition.OrientationTop().Z != soundpos.OrientationTop().Z ||
  673. CurrentSoundPosition.OrientationFront().X != soundpos.OrientationFront().X || CurrentSoundPosition.OrientationFront().Y != soundpos.OrientationFront().Y || CurrentSoundPosition.OrientationFront().Z != soundpos.OrientationFront().Z;
  674. }
  675. void UAkComponent::UpdateGameObjectPosition()
  676. {
  677. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  678. if (IsActive() && AkAudioDevice)
  679. {
  680. if (AllowAudioPlayback())
  681. {
  682. AkSoundPosition soundpos;
  683. FVector Location, Front, Up;
  684. UAkComponentUtils::GetLocationFrontUp(this, Location, Front, Up);
  685. FAkAudioDevice::FVectorsToAKWorldTransform(Location, Front, Up, soundpos);
  686. UpdateSpatialAudioRoom(Location);
  687. AkAudioDevice->SetPosition(this, soundpos);
  688. CurrentSoundPosition = soundpos;
  689. }
  690. // Find and apply all AkReverbVolumes at this location
  691. if (bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
  692. {
  693. UpdateAkLateReverbComponentList(GetComponentLocation());
  694. }
  695. }
  696. }
  697. void UAkComponent::UpdateSpatialAudioRoom(FVector Location)
  698. {
  699. if (IsRegisteredWithWwise)
  700. {
  701. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  702. if (AkAudioDevice)
  703. {
  704. AKRESULT result = AK_Fail;
  705. TArray<UAkRoomComponent*> RoomComponents = AkAudioDevice->FindRoomComponentsAtLocation(Location, GetWorld());
  706. if (RoomComponents.Num() == 0)
  707. {
  708. if (AkAudioDevice->WorldHasActiveRooms(GetWorld()) && CurrentRoom != nullptr)
  709. {
  710. CurrentRoom = nullptr;
  711. result = AkAudioDevice->SetInSpatialAudioRoom(GetAkGameObjectID(), GetSpatialAudioRoomID());
  712. }
  713. }
  714. else if (CurrentRoom != RoomComponents[0])
  715. {
  716. CurrentRoom = RoomComponents[0];
  717. result = AkAudioDevice->SetInSpatialAudioRoom(GetAkGameObjectID(), GetSpatialAudioRoomID());
  718. }
  719. if (EnableSpotReflectors && result == AK_Success)
  720. AAkSpotReflector::UpdateSpotReflectors(this);
  721. }
  722. }
  723. }
  724. void UAkComponent::_DebugDrawReflections( const AkVector64& akEmitterPos, const AkVector64& akListenerPos, const AkReflectionPathInfo* paths, AkUInt32 uNumPaths) const
  725. {
  726. ::FlushDebugStrings(GWorld);
  727. for (AkInt32 idxPath = uNumPaths-1; idxPath >= 0; --idxPath)
  728. {
  729. const AkReflectionPathInfo& path = paths[idxPath];
  730. unsigned int order = path.numReflections;
  731. if ((DrawFirstOrderReflections && order == 1) ||
  732. (DrawSecondOrderReflections && order == 2) ||
  733. (DrawHigherOrderReflections && order > 2))
  734. {
  735. FColor colorLight;
  736. FColor colorMed;
  737. FColor colorDark;
  738. switch ((order - 1))
  739. {
  740. case 0:
  741. colorLight = FColor(0x9DEBF3);
  742. colorMed = FColor(0x318087);
  743. colorDark = FColor(0x186067);
  744. break;
  745. case 1:
  746. colorLight = FColor(0xFCDBA2);
  747. colorMed = FColor(0xDEAB4E);
  748. colorDark = FColor(0xA97B27);
  749. break;
  750. case 2:
  751. default:
  752. colorLight = FColor(0xFCB1A2);
  753. colorMed = FColor(0xDE674E);
  754. colorDark = FColor(0xA93E27);
  755. break;
  756. }
  757. FColor colorLightGrey(75, 75, 75);
  758. FColor colorMedGrey(50, 50, 50);
  759. FColor colorDarkGrey(35, 35, 35);
  760. const int kPathThickness = 5.f;
  761. const float kRadiusSphere = 25.f;
  762. const int kNumSphereSegments = 8;
  763. const FVector emitterPos = FAkAudioDevice::AKVector64ToFVector(akEmitterPos);
  764. FVector listenerPt = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
  765. for (int idxSeg = path.numPathPoints-1; idxSeg >= 0; --idxSeg)
  766. {
  767. const FVector reflectionPt = FAkAudioDevice::AKVector64ToFVector(path.pathPoint[idxSeg]);
  768. if (idxSeg != path.numPathPoints - 1)
  769. {
  770. // Note: Not drawing the first leg of the path from the listener. Often hard to see because it is typically the camera position.
  771. ::DrawDebugLine(GWorld, listenerPt, reflectionPt, path.isOccluded ? colorLightGrey : colorLight, false, -1.f, (uint8)'\000', kPathThickness / order);
  772. ::DrawDebugSphere(GWorld, reflectionPt, (kRadiusSphere/2) / order, kNumSphereSegments, path.isOccluded ? colorLightGrey : colorLight);
  773. }
  774. else
  775. {
  776. ::DrawDebugSphere(GWorld, reflectionPt, kRadiusSphere / order, kNumSphereSegments, path.isOccluded ? colorMedGrey : colorMed);
  777. }
  778. // Draw image source point. Not as useful as I had hoped.
  779. //const FVector imageSrc = FAkAudioDevice::AKVectorToFVector(path.imageSource);
  780. //::DrawDebugSphere(GWorld, imageSrc, kRadiusSphere/order, kNumSphereSegments, colorDark);
  781. listenerPt = reflectionPt;
  782. }
  783. if (!path.isOccluded)
  784. {
  785. // Finally the last path segment towards the emitter.
  786. ::DrawDebugLine(GWorld, listenerPt, emitterPos, path.isOccluded ? colorLightGrey : colorLight, false, -1.f, (uint8)'\000', kPathThickness / order);
  787. }
  788. }
  789. }
  790. }
  791. void UAkComponent::_DebugDrawDiffraction(const AkVector64& akEmitterPos, const AkVector64& akListenerPos, const AkDiffractionPathInfo* paths, AkUInt32 uNumPaths) const
  792. {
  793. ::FlushDebugStrings(GWorld);
  794. for (AkInt32 idxPath = uNumPaths - 1; idxPath >= 0; --idxPath)
  795. {
  796. const AkDiffractionPathInfo& path = paths[idxPath];
  797. FColor purple(0x492E74);
  798. FColor green(0x267158);
  799. if (path.nodeCount > 0)
  800. {
  801. const int kPathThickness = 5.f;
  802. const float kRadiusSphereMax = 35.f;
  803. const float kRadiusSphereMin = 2.f;
  804. const FVector emitterPos = FAkAudioDevice::AKVector64ToFVector(akEmitterPos);
  805. const FVector listenerPos = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
  806. FVector prevPt = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
  807. for (int idxSeg = 0; idxSeg < (int)path.nodeCount; ++idxSeg)
  808. {
  809. const FVector pt = FAkAudioDevice::AKVector64ToFVector(path.nodes[idxSeg]);
  810. if (idxSeg != 0)
  811. {
  812. ::DrawDebugLine(GWorld, prevPt, pt, green, false, -1.f, (uint8)'\000', kPathThickness);
  813. }
  814. float rad = kRadiusSphereMin + (1.f - path.angles[idxSeg] / PI) * (kRadiusSphereMax - kRadiusSphereMin);
  815. ::DrawDebugSphere(GWorld, pt, rad, 8, path.portals[idxSeg].IsValid() ? green : purple );
  816. prevPt = pt;
  817. }
  818. // Finally the last path segment towards the emitter.
  819. ::DrawDebugLine(GWorld, prevPt, emitterPos, green, false, -1.f, (uint8)'\000', kPathThickness);
  820. }
  821. }
  822. }
  823. void UAkComponent::DebugDrawReflections() const
  824. {
  825. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  826. if (UNLIKELY(!SpatialAudio)) return;
  827. enum { kMaxPaths = 64 };
  828. AkReflectionPathInfo paths[kMaxPaths];
  829. AkUInt32 uNumPaths = kMaxPaths;
  830. AkVector64 listenerPos, emitterPos;
  831. if (SpatialAudio->QueryReflectionPaths(GetAkGameObjectID(), 0, listenerPos, emitterPos, paths, uNumPaths) == AK_Success && uNumPaths > 0)
  832. _DebugDrawReflections(emitterPos, listenerPos, paths, uNumPaths);
  833. }
  834. void UAkComponent::DebugDrawDiffraction() const
  835. {
  836. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  837. if (UNLIKELY(!SpatialAudio)) return;
  838. enum { kMaxPaths = 16 };
  839. AkDiffractionPathInfo paths[kMaxPaths];
  840. AkUInt32 uNumPaths = kMaxPaths;
  841. AkVector64 listenerPos, emitterPos;
  842. if (SpatialAudio->QueryDiffractionPaths(GetAkGameObjectID(), 0, listenerPos, emitterPos, paths, uNumPaths) == AK_Success)
  843. {
  844. if (uNumPaths > 0)
  845. _DebugDrawDiffraction(emitterPos, listenerPos, paths, uNumPaths);
  846. }
  847. }
  848. void UAkComponent::SetGameObjectRadius(float in_outerRadius, float in_innerRadius)
  849. {
  850. outerRadius = in_outerRadius;
  851. innerRadius = in_innerRadius;
  852. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  853. if (AkAudioDevice && IsRegisteredWithWwise)
  854. {
  855. AkAudioDevice->SetGameObjectRadius(this, outerRadius, innerRadius);
  856. }
  857. }
  858. void UAkComponent::SetEnableSpotReflectors(bool in_enable)
  859. {
  860. if (EnableSpotReflectors != in_enable)
  861. {
  862. EnableSpotReflectors = in_enable;
  863. AAkSpotReflector::UpdateSpotReflectors(this);
  864. }
  865. }
  866. #if WITH_EDITOR
  867. void UAkComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
  868. {
  869. Super::PostEditChangeProperty(PropertyChangedEvent);
  870. if (PropertyChangedEvent.Property)
  871. {
  872. if ((PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, outerRadius) ||
  873. PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, innerRadius)) &&
  874. PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
  875. {
  876. if (innerRadius > outerRadius)
  877. innerRadius = outerRadius;
  878. SetGameObjectRadius(outerRadius, innerRadius);
  879. }
  880. if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, EnableSpotReflectors) &&
  881. PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
  882. {
  883. AAkSpotReflector::UpdateSpotReflectors(this);
  884. }
  885. }
  886. }
  887. #endif