12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- /*******************************************************************************
- The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
- Technology released in source code form as part of the game integration package.
- The content of this file may not be used without valid licenses to the
- AUDIOKINETIC Wwise Technology.
- Note that the use of the game engine is subject to the Unreal(R) Engine End User
- License Agreement at https://www.unrealengine.com/en-US/eula/unreal
-
- License Usage
-
- Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
- this file in accordance with the end user license agreement provided with the
- software or, alternatively, in accordance with the terms contained
- in a written agreement between you and Audiokinetic Inc.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- /*=============================================================================
- AkComponent.cpp:
- =============================================================================*/
- #include "AkComponent.h"
- #include "AkAudioDevice.h"
- #include "AkAudioEvent.h"
- #include "AkAuxBus.h"
- #include "AkLateReverbComponent.h"
- #include "AkRoomComponent.h"
- #include "AkGameplayTypes.h"
- #include "AkSettings.h"
- #include "AkSpotReflector.h"
- #include "AkSwitchValue.h"
- #include "AkTrigger.h"
- #include "Components/BillboardComponent.h"
- #include "DrawDebugHelpers.h"
- #include "Engine/Texture2D.h"
- #include "Engine/World.h"
- #include "GameFramework/PlayerController.h"
- #include "UObject/UObjectIterator.h"
- #include "Wwise/WwiseExternalSourceManager.h"
- #include "Wwise/API/WwiseSoundEngineAPI.h"
- #include "Wwise/API/WwiseSpatialAudioAPI.h"
- #if WITH_EDITOR
- #include "LevelEditorViewport.h"
- #include "Editor.h"
- #endif
- /*------------------------------------------------------------------------------------
- Component Helpers
- ------------------------------------------------------------------------------------*/
- namespace UAkComponentUtils
- {
- APlayerController* GetAPlayerController(const UActorComponent* Component)
- {
- const APlayerCameraManager* AsPlayerCameraManager = Cast<APlayerCameraManager>(Component->GetOwner());
- return AsPlayerCameraManager ? AsPlayerCameraManager->GetOwningPlayerController() : nullptr;
- }
- void GetListenerPosition(const UAkComponent* Component, FVector& Location, FVector& Front, FVector& Up)
- {
- APlayerController* pPlayerController = GetAPlayerController(Component);
- if (pPlayerController != nullptr)
- {
- FVector Right;
- pPlayerController->GetAudioListenerPosition(Location, Front, Right);
- Up = FVector::CrossProduct(Front, Right);
- return;
- }
- #if WITH_EDITORONLY_DATA
- auto& Clients = GEditor->GetAllViewportClients();
- static FTransform LastKnownEditorTransform;
- for (int i = 0; i < Clients.Num(); i++)
- {
- FEditorViewportClient* ViewportClient = Clients[i];
- UWorld* World = ViewportClient->GetWorld();
- if (ViewportClient->Viewport && ViewportClient->Viewport->HasFocus() && World->AllowAudioPlayback())
- {
- EWorldType::Type WorldType = World->WorldType;
- if (WorldType == EWorldType::Editor || WorldType == EWorldType::PIE)
- {
- LastKnownEditorTransform = FAkAudioDevice::Get()->GetEditorListenerPosition(i);
- Location = LastKnownEditorTransform.GetLocation();
- Front = LastKnownEditorTransform.GetRotation().GetForwardVector();
- Up = LastKnownEditorTransform.GetRotation().GetUpVector();
- return;
- }
- else if (WorldType != EWorldType::Game && WorldType != EWorldType::GamePreview)
- {
- Location = ViewportClient->GetViewLocation();
- Front = ViewportClient->GetViewRotation().Quaternion().GetForwardVector();
- Up = ViewportClient->GetViewRotation().Quaternion().GetUpVector();
- LastKnownEditorTransform.SetLocation(Location);
- LastKnownEditorTransform.SetRotation(ViewportClient->GetViewRotation().Quaternion());
- return;
- }
- }
- }
- Location = LastKnownEditorTransform.GetLocation();
- Front = LastKnownEditorTransform.GetRotation().GetForwardVector();
- Up = LastKnownEditorTransform.GetRotation().GetUpVector();
- #endif
- }
- void GetLocationFrontUp(const UAkComponent* Component, FVector& Location, FVector& Front, FVector& Up)
- {
- if (Component->IsDefaultListener)
- {
- GetListenerPosition(Component, Location, Front, Up);
- }
- else
- {
- auto& Transform = Component->GetComponentTransform();
- Location = Transform.GetTranslation();
- Front = Transform.GetUnitAxis(EAxis::X);
- Up = Transform.GetUnitAxis(EAxis::Z);
- }
- }
- }
- AkReverbFadeControl::AkReverbFadeControl(const UAkLateReverbComponent& LateReverbComponent)
- : AuxBusId(LateReverbComponent.GetAuxBusId())
- , bIsFadingOut(false)
- , FadeControlUniqueId((void*)&LateReverbComponent)
- , CurrentControlValue(0.f)
- , TargetControlValue(LateReverbComponent.SendLevel)
- , FadeRate(LateReverbComponent.FadeRate)
- , Priority(LateReverbComponent.Priority)
- {}
- void AkReverbFadeControl::UpdateValues(const UAkLateReverbComponent& LateReverbComponent)
- {
- AuxBusId = LateReverbComponent.GetAuxBusId();
- TargetControlValue = LateReverbComponent.SendLevel;
- FadeRate = LateReverbComponent.FadeRate;
- Priority = LateReverbComponent.Priority;
- }
- bool AkReverbFadeControl::Update(float DeltaTime)
- {
- if (CurrentControlValue != TargetControlValue || bIsFadingOut)
- {
- // Rate (%/s) * Delta (s) = % for given delta, apply to target.
- const float Increment = DeltaTime * FadeRate * TargetControlValue;
- if (bIsFadingOut)
- {
- CurrentControlValue -= Increment;
- if (CurrentControlValue <= 0.f)
- return false;
- }
- else
- CurrentControlValue = FMath::Min(CurrentControlValue + Increment, TargetControlValue);
- }
- return true;
- }
- AkAuxSendValue AkReverbFadeControl::ToAkAuxSendValue() const
- {
- AkAuxSendValue ret;
- ret.listenerID = AK_INVALID_GAME_OBJECT;
- ret.auxBusID = AuxBusId;
- ret.fControlValue = CurrentControlValue;
- return ret;
- }
- bool AkReverbFadeControl::Prioritize(const AkReverbFadeControl& A, const AkReverbFadeControl& B)
- {
- if (A.bIsFadingOut == B.bIsFadingOut)
- {
- if (A.Priority == B.Priority)
- {
- // 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.
- return A.AuxBusId < B.AuxBusId;
- }
- return A.Priority > B.Priority;
- }
- // Ensure the fading out buffers are sent to the end of the array.
- return A.bIsFadingOut < B.bIsFadingOut;
- }
- /*------------------------------------------------------------------------------------
- UAkComponent
- ------------------------------------------------------------------------------------*/
- UAkComponent::UAkComponent(const class FObjectInitializer& ObjectInitializer) :
- Super(ObjectInitializer)
- {
- // Property initialization
- DrawFirstOrderReflections = false;
- DrawSecondOrderReflections = false;
- DrawHigherOrderReflections = false;
- DrawDiffraction = false;
- EarlyReflectionBusSendGain = 1.f;
- StopWhenOwnerDestroyed = true;
- bUseReverbVolumes = true;
- OcclusionRefreshInterval = 0.2f;
- PrimaryComponentTick.bCanEverTick = true;
- PrimaryComponentTick.TickGroup = TG_DuringPhysics;
- PrimaryComponentTick.bAllowTickOnDedicatedServer = false;
- bTickInEditor = true;
- bAutoActivate = true;
- bNeverNeedsRenderUpdate = true;
- bWantsOnUpdateTransform = true;
- #if WITH_EDITORONLY_DATA
- bVisualizeComponent = true;
- #endif
- AttenuationScalingFactor = 1.0f;
- bAutoDestroy = false;
- bUseDefaultListeners = true;
- OcclusionCollisionChannel = EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault;
- outerRadius = 0.0f;
- innerRadius = 0.0f;
- }
- ECollisionChannel UAkComponent::GetOcclusionCollisionChannel()
- {
- return UAkSettings::ConvertOcclusionCollisionChannel(OcclusionCollisionChannel.GetValue());
- }
- int32 UAkComponent::PostAssociatedAkEventAndWaitForEnd(FLatentActionInfo LatentInfo)
- {
- return PostAkEventAndWaitForEnd(AkAudioEvent, LatentInfo);
- }
- int32 UAkComponent::PostAkEventAndWaitForEnd(class UAkAudioEvent * AkEvent, FLatentActionInfo LatentInfo)
- {
- if (LIKELY(IsValid(AkEvent)))
- {
- return AkEvent->PostOnComponentAndWait(this, StopWhenOwnerDestroyed, LatentInfo);
- }
- UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid latent AkAudioEvent on component '%s'"), *GetName());
- return AK_INVALID_PLAYING_ID;
- }
- int32 UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, int32 CallbackMask,
- const FOnAkPostEventCallback& PostEventCallback)
- {
- if (LIKELY(IsValid(AkEvent)))
- {
- return AkEvent->PostOnComponent(this, PostEventCallback, CallbackMask, StopWhenOwnerDestroyed);
- }
- UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on component '%s'"), *GetName());
- return AK_INVALID_PLAYING_ID;
- }
- AkPlayingID UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, AkUInt32 Flags, AkCallbackFunc UserCallback,
- void* UserCookie)
- {
- if (LIKELY(IsValid(AkEvent)))
- {
- return AkEvent->PostOnComponent(this, nullptr, UserCallback, UserCookie, static_cast<AkCallbackType>(Flags), nullptr, StopWhenOwnerDestroyed);
- }
- UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on component '%s'"), *GetName());
- return AK_INVALID_PLAYING_ID;
- }
- AkRoomID UAkComponent::GetSpatialAudioRoomID() const
- {
- AkRoomID RoomID;
- if (CurrentRoom)
- {
- RoomID = CurrentRoom->GetRoomID();
- }
- return RoomID;
- }
- void UAkComponent::UpdateObstructionAndOcclusion()
- {
- SCOPED_AKAUDIO_EVENT_2(TEXT("UAkComponent::UpdateObstructionAndOcclusion"));
- auto World = GetWorld();
- auto AudioDevice = FAkAudioDevice::Get();
- if (World && AudioDevice && AudioDevice->ShouldNotifySoundEngine(World->WorldType))
- {
- FScopeLock Lock(&ListenerCriticalSection);
- AkObstructionAndOcclusionService::ListenerMap ObsOccListenerMap;
- for (auto& Listener : Listeners)
- {
- AkObstructionAndOcclusionService::FListenerInfo ListenerInfo(Listener->GetPosition(), Listener->GetSpatialAudioRoomID());
- ObsOccListenerMap.Add(Listener->GetAkGameObjectID(), ListenerInfo);
- }
- AkObstructionAndOcclusionService::PortalMap ObsOccPortalMap;
- AudioDevice->GetObsOccServicePortalMap(GetSpatialAudioRoom(), GetWorld(), ObsOccPortalMap);
- ObstructionService.UpdateObstructionAndOcclusion(ObsOccListenerMap, ObsOccPortalMap, GetPosition(), GetOwner(), GetSpatialAudioRoomID(), GetOcclusionCollisionChannel(), OcclusionRefreshInterval);
- }
- }
- void UAkComponent::PostTrigger(const UAkTrigger* TriggerValue, FString Trigger)
- {
- if (FAkAudioDevice::Get())
- {
- auto* SoundEngine = IWwiseSoundEngineAPI::Get();
- if (UNLIKELY(!SoundEngine)) return;
- if (TriggerValue)
- {
- SoundEngine->PostTrigger(TriggerValue->TriggerCookedData.TriggerId, GetAkGameObjectID());
- }
- else
- {
- SoundEngine->PostTrigger(TCHAR_TO_AK(*Trigger), GetAkGameObjectID());
- }
- }
- }
- void UAkComponent::SetSwitch(const UAkSwitchValue* SwitchValue, FString SwitchGroup, FString SwitchState)
- {
- if (FAkAudioDevice::Get())
- {
- auto* SoundEngine = IWwiseSoundEngineAPI::Get();
- if (UNLIKELY(!SoundEngine)) return;
- if (SwitchValue)
- {
- SoundEngine->SetSwitch(SwitchValue->GroupValueCookedData.GroupId, SwitchValue->GroupValueCookedData.Id, GetAkGameObjectID());
- }
- else
- {
- uint32 SwitchGroupID = SoundEngine->GetIDFromString(TCHAR_TO_AK(*SwitchGroup));
- uint32 SwitchStateID = SoundEngine->GetIDFromString(TCHAR_TO_AK(*SwitchState));
- SoundEngine->SetSwitch(SwitchGroupID, SwitchStateID, GetAkGameObjectID());
- }
- }
- }
- void UAkComponent::SetStopWhenOwnerDestroyed(bool bStopWhenOwnerDestroyed)
- {
- StopWhenOwnerDestroyed = bStopWhenOwnerDestroyed;
- }
- void UAkComponent::SetListeners(const TArray<UAkComponent*>& NewListeners)
- {
- auto AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- FScopeLock Lock(&ListenerCriticalSection);
- bUseDefaultListeners = false;
- for(auto& Listener : Listeners)
- {
- Listener->IsListener = false;
- }
- Listeners.Reset();
-
- Listeners.Append(NewListeners);
- for(auto& Listener : Listeners)
- {
- Listener->IsListener = true;
- }
- AudioDevice->SetListeners(this, Listeners.Array());
- }
- }
- void UAkComponent::SetEarlyReflectionsAuxBus(const FString& AuxBusName)
- {
- FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- AudioDevice->SetEarlyReflectionsAuxBus(this, FAkAudioDevice::GetShortID(nullptr, AuxBusName));
- }
- }
- void UAkComponent::SetEarlyReflectionsVolume(float SendVolume)
- {
- FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- AudioDevice->SetEarlyReflectionsVolume(this, SendVolume);
- }
- }
- float UAkComponent::GetAttenuationRadius() const
- {
- return AkAudioEvent ? AttenuationScalingFactor * AkAudioEvent->MaxAttenuationRadius : 0.f;
- }
- void UAkComponent::SetOutputBusVolume(float BusVolume)
- {
- FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- FScopeLock Lock(&ListenerCriticalSection);
- for (auto It = Listeners.CreateIterator(); It; ++It)
- {
- AudioDevice->SetGameObjectOutputBusVolume(this, *It, BusVolume);
- }
- }
- }
- void UAkComponent::OnRegister()
- {
- UWorld* CurrentWorld = GetWorld();
- if(!IsRegisteredWithWwise && CurrentWorld->WorldType != EWorldType::Inactive && CurrentWorld->WorldType != EWorldType::None)
- RegisterGameObject(); // Done before parent so that OnUpdateTransform follows registration and updates position correctly.
- FAkAudioDevice* AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- ObstructionService.Init(GetAkGameObjectID(), CurrentWorld, OcclusionRefreshInterval, AudioDevice->UsingSpatialAudioRooms(CurrentWorld));
- }
- // It's possible for OnRegister to be called while the WorldType is inactive.
- // The game object will be registered again later when the WorldType is active.
- if (AudioDevice && IsRegisteredWithWwise)
- {
- if (EarlyReflectionAuxBus || !EarlyReflectionAuxBusName.IsEmpty())
- {
- AkUInt32 AuxBusID = FAkAudioDevice::GetShortID(EarlyReflectionAuxBus, EarlyReflectionAuxBusName);
- if (AuxBusID != AK_INVALID_UNIQUE_ID)
- AudioDevice->SetEarlyReflectionsAuxBus(this, AuxBusID);
- }
- if (EarlyReflectionBusSendGain != 1.0)
- AudioDevice->SetEarlyReflectionsVolume(this, EarlyReflectionBusSendGain);
- }
- Super::OnRegister();
- #if WITH_EDITORONLY_DATA
- if (bVisualizeComponent)
- {
- UpdateSpriteTexture();
- }
- #endif
- }
- #if WITH_EDITORONLY_DATA
- void UAkComponent::UpdateSpriteTexture()
- {
- if (SpriteComponent)
- {
- SpriteComponent->SetSprite(LoadObject<UTexture2D>(NULL, TEXT("/Wwise/S_AkComponent.S_AkComponent")));
- }
- }
- #endif
- void UAkComponent::OnUnregister()
- {
- // Route OnUnregister event.
- Super::OnUnregister();
- // Don't stop audio and clean up component if owner has been destroyed (default behaviour). This function gets
- // called from AActor::ClearComponents when an actor gets destroyed which is not usually what we want for one-
- // shot sounds.
- AActor* Owner = GetOwner();
- UWorld* CurrentWorld = GetWorld();
- if( !Owner || !CurrentWorld || StopWhenOwnerDestroyed || CurrentWorld->bIsTearingDown || (Owner->GetClass() == APlayerController::StaticClass() && CurrentWorld->WorldType == EWorldType::PIE))
- {
- Stop();
- }
- }
- void UAkComponent::OnComponentDestroyed( bool bDestroyingHierarchy )
- {
- UnregisterGameObject();
- Super::OnComponentDestroyed(bDestroyingHierarchy);
- }
- void UAkComponent::ShutdownAfterError( void )
- {
- UnregisterGameObject();
- Super::ShutdownAfterError();
- }
- bool UAkComponent::NeedToUpdateAuxSends(const TArray<AkAuxSendValue>& NewValues)
- {
- if (NewValues.Num() != CurrentAuxSendValues.Num())
- return true;
- for (int32 i = 0; i < NewValues.Num(); i++)
- {
- if (NewValues[i].listenerID != CurrentAuxSendValues[i].listenerID ||
- NewValues[i].auxBusID != CurrentAuxSendValues[i].auxBusID ||
- NewValues[i].fControlValue != CurrentAuxSendValues[i].fControlValue)
- {
- return true;
- }
- }
- return false;
- }
- void UAkComponent::ApplyAkReverbVolumeList(float DeltaTime)
- {
- for (int32 Idx = 0; Idx < ReverbFadeControls.Num(); )
- {
- if (!ReverbFadeControls[Idx].Update(DeltaTime))
- ReverbFadeControls.RemoveAt(Idx);
- else
- ++Idx;
- }
- if (ReverbFadeControls.Num() > 1)
- ReverbFadeControls.Sort(AkReverbFadeControl::Prioritize);
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (AkAudioDevice)
- {
- TArray<AkAuxSendValue> NewAuxSendValues;
- for (int32 Idx = 0; Idx < ReverbFadeControls.Num() && Idx < AkAudioDevice->GetMaxAuxBus(); Idx++)
- {
- AkAuxSendValue* FoundAuxSend = NewAuxSendValues.FindByPredicate([this, Idx](const AkAuxSendValue& ItemInArray) { return ItemInArray.auxBusID == ReverbFadeControls[Idx].AuxBusId; });
- if (FoundAuxSend)
- {
- FoundAuxSend->fControlValue += ReverbFadeControls[Idx].ToAkAuxSendValue().fControlValue;
- }
- else
- {
- NewAuxSendValues.Add(ReverbFadeControls[Idx].ToAkAuxSendValue());
- }
- }
- if (NeedToUpdateAuxSends(NewAuxSendValues))
- {
- AkAudioDevice->SetAuxSends(this, NewAuxSendValues);
- CurrentAuxSendValues = NewAuxSendValues;
- }
- }
- }
- void UAkComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
- {
- auto* SoundEngine = IWwiseSoundEngineAPI::Get();
- if (UNLIKELY(!SoundEngine)) return;
- if (SoundEngine->IsInitialized())
- {
- Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
- auto World = GetWorld();
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- // If we're a listener, update our position here instead of in OnUpdateTransform.
- // This is because PlayerController->GetAudioListenerPosition caches its value, and it can be out of sync
- if (IsDefaultListener && HasMoved())
- UpdateGameObjectPosition();
- if (AkAudioDevice && AkAudioDevice->WorldSpatialAudioVolumesUpdated(World))
- {
- UpdateSpatialAudioRoom(GetComponentLocation());
- // Find and apply all AkReverbVolumes at this location
- if (bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
- {
- UpdateAkLateReverbComponentList(GetComponentLocation());
- }
- }
- if (AkAudioDevice && bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
- ApplyAkReverbVolumeList(DeltaTime);
- if (World && AkAudioDevice && AkAudioDevice->ShouldNotifySoundEngine(World->WorldType))
- {
- FScopeLock Lock(&ListenerCriticalSection);
- AkObstructionAndOcclusionService::ListenerMap ObsOccListenerMap;
- for (auto& Listener : Listeners)
- {
- AkObstructionAndOcclusionService::FListenerInfo ListenerInfo(Listener->GetPosition(), Listener->GetSpatialAudioRoomID());
- ObsOccListenerMap.Add(Listener->GetAkGameObjectID(), ListenerInfo);
- }
- AkObstructionAndOcclusionService::PortalMap ObsOccPortalMap;
- if (AkAudioDevice)
- {
- AkAudioDevice->GetObsOccServicePortalMap(GetSpatialAudioRoom(), GetWorld(), ObsOccPortalMap);
- }
- ObstructionService.Tick(ObsOccListenerMap, ObsOccPortalMap, GetPosition(), GetOwner(), GetSpatialAudioRoomID(), GetOcclusionCollisionChannel(), DeltaTime, OcclusionRefreshInterval);
- }
- if (bAutoDestroy && bEventPosted && !HasActiveEvents())
- {
- DestroyComponent();
- }
- #if !UE_BUILD_SHIPPING
- if (DrawFirstOrderReflections || DrawSecondOrderReflections || DrawHigherOrderReflections)
- {
- DebugDrawReflections();
- }
- if (DrawDiffraction)
- {
- DebugDrawDiffraction();
- }
- #endif
- }
- }
- void UAkComponent::BeginPlay()
- {
- Super::BeginPlay();
- UpdateGameObjectPosition();
- // If spawned inside AkReverbVolume(s), we do not want the fade in effect to kick in.
- UpdateAkLateReverbComponentList(GetComponentLocation());
- for (auto& ReverbFadeControl : ReverbFadeControls)
- ReverbFadeControl.ForceCurrentToTargetValue();
- SetAttenuationScalingFactor(AttenuationScalingFactor);
- if (EnableSpotReflectors)
- AAkSpotReflector::UpdateSpotReflectors(this);
- }
- void UAkComponent::SetAttenuationScalingFactor(float Value)
- {
- AttenuationScalingFactor = Value;
- FAkAudioDevice* AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- AudioDevice->SetAttenuationScalingFactor(this, AttenuationScalingFactor);
- }
- void UAkComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport)
- {
- Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
- // If we're a listener, our position will be updated from Tick instead of here.
- // This is because PlayerController->GetAudioListenerPosition caches its value, and it can be out of sync
- if(!IsDefaultListener)
- UpdateGameObjectPosition();
- }
- UAkComponent* UAkComponent::GetAkComponent(AkGameObjectID GameObjectID)
- {
- return GameObjectID == DUMMY_GAMEOBJ ? nullptr : (UAkComponent*)GameObjectID;
- }
- void UAkComponent::GetAkGameObjectName(FString& Name) const
- {
- AActor* parentActor = GetOwner();
- if (parentActor)
- {
- #if WITH_EDITOR
- Name = parentActor->GetActorLabel() + ".";
- #else
- Name = parentActor->GetName() + ".";
- #endif
- }
- Name += GetName();
- UWorld* CurrentWorld = GetWorld();
- switch (CurrentWorld->WorldType)
- {
- case EWorldType::Editor:
- Name += "(Editor)";
- break;
- case EWorldType::EditorPreview:
- Name += "(EditorPreview)";
- break;
- case EWorldType::GamePreview:
- Name += "(GamePreview)";
- break;
- case EWorldType::Inactive:
- Name += "(Inactive)";
- break;
- }
- }
- void UAkComponent::PostRegisterGameObject() {}
- void UAkComponent::PostUnregisterGameObject() {}
- void UAkComponent::RegisterGameObject()
- {
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if ( AkAudioDevice )
- {
- if ( bUseDefaultListeners )
- {
- FScopeLock Lock(&ListenerCriticalSection);
- const auto& DefaultListeners = AkAudioDevice->GetDefaultListeners();
- Listeners.Empty(DefaultListeners.Num());
-
- for (auto Listener : DefaultListeners)
- {
- Listeners.Add(Listener);
- }
- }
- AkAudioDevice->RegisterComponent(this);
- IsRegisteredWithWwise = true;
- AkAudioDevice->SetGameObjectRadius(this, outerRadius, innerRadius);
- }
- PostRegisterGameObject();
- }
- void UAkComponent::UnregisterGameObject()
- {
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (AkAudioDevice)
- {
- AkAudioDevice->UnregisterComponent(this);
- IsRegisteredWithWwise = false;
- }
- if(IsListener)
- {
- for (TObjectIterator<UAkComponent> Emitter; Emitter; ++Emitter)
- {
- Emitter->OnListenerUnregistered(this);
- }
- }
-
- PostUnregisterGameObject();
- }
- void UAkComponent::UpdateAkLateReverbComponentList( FVector Loc )
- {
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (!AkAudioDevice)
- return;
- TArray<UAkLateReverbComponent*> FoundComponents = AkAudioDevice->FindLateReverbComponentsAtLocation(Loc, GetWorld());
- // Add the new volumes to the current list
- for (const auto& LateReverbComponent : FoundComponents)
- {
- const auto AuxBusId = LateReverbComponent->GetAuxBusId();
- const int32 FoundIdx = ReverbFadeControls.IndexOfByPredicate([&LateReverbComponent](const AkReverbFadeControl& Candidate)
- {
- return Candidate.FadeControlUniqueId == (void*)LateReverbComponent;
- });
- if (FoundIdx == INDEX_NONE)
- {
- // The volume was not found, add it to the list
- ReverbFadeControls.Add(AkReverbFadeControl(*LateReverbComponent));
- }
- else
- {
- // The volume was found. We still have to check if it is currently fading out, in case we are
- // getting back in a volume we just exited.
- ReverbFadeControls[FoundIdx].bIsFadingOut = false;
- // We need to update the late reverb values in case they have changed on the reverb component.
- ReverbFadeControls[FoundIdx].UpdateValues(*LateReverbComponent);
- }
- }
- // Fade out the current volumes not found in the new list
- for (auto& ReverbFadeControl : ReverbFadeControls)
- {
- const int32 FoundIdx = FoundComponents.IndexOfByPredicate([&ReverbFadeControl](const UAkLateReverbComponent* const Candidate)
- {
- return ReverbFadeControl.FadeControlUniqueId == (void*)Candidate;
- });
- if (FoundIdx == INDEX_NONE)
- ReverbFadeControl.bIsFadingOut = true;
- }
- }
- FVector UAkComponent::GetPosition() const
- {
- return FAkAudioDevice::AKVector64ToFVector(CurrentSoundPosition.Position());
- }
- bool UAkComponent::HasMoved()
- {
- AkSoundPosition soundpos;
- FVector Location, Front, Up;
- UAkComponentUtils::GetLocationFrontUp(this, Location, Front, Up);
- FAkAudioDevice::FVectorsToAKWorldTransform(Location, Front, Up, soundpos);
- return CurrentSoundPosition.Position().X != soundpos.Position().X || CurrentSoundPosition.Position().Y != soundpos.Position().Y || CurrentSoundPosition.Position().Z != soundpos.Position().Z ||
- CurrentSoundPosition.OrientationTop().X != soundpos.OrientationTop().X || CurrentSoundPosition.OrientationTop().Y != soundpos.OrientationTop().Y || CurrentSoundPosition.OrientationTop().Z != soundpos.OrientationTop().Z ||
- CurrentSoundPosition.OrientationFront().X != soundpos.OrientationFront().X || CurrentSoundPosition.OrientationFront().Y != soundpos.OrientationFront().Y || CurrentSoundPosition.OrientationFront().Z != soundpos.OrientationFront().Z;
- }
- void UAkComponent::UpdateGameObjectPosition()
- {
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (IsActive() && AkAudioDevice)
- {
- if (AllowAudioPlayback())
- {
- AkSoundPosition soundpos;
- FVector Location, Front, Up;
- UAkComponentUtils::GetLocationFrontUp(this, Location, Front, Up);
- FAkAudioDevice::FVectorsToAKWorldTransform(Location, Front, Up, soundpos);
- UpdateSpatialAudioRoom(Location);
- AkAudioDevice->SetPosition(this, soundpos);
- CurrentSoundPosition = soundpos;
- }
-
- // Find and apply all AkReverbVolumes at this location
- if (bUseReverbVolumes && AkAudioDevice->GetMaxAuxBus() > 0)
- {
- UpdateAkLateReverbComponentList(GetComponentLocation());
- }
- }
- }
- void UAkComponent::UpdateSpatialAudioRoom(FVector Location)
- {
- if (IsRegisteredWithWwise)
- {
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (AkAudioDevice)
- {
- AKRESULT result = AK_Fail;
- TArray<UAkRoomComponent*> RoomComponents = AkAudioDevice->FindRoomComponentsAtLocation(Location, GetWorld());
- if (RoomComponents.Num() == 0)
- {
- if (AkAudioDevice->WorldHasActiveRooms(GetWorld()) && CurrentRoom != nullptr)
- {
- CurrentRoom = nullptr;
- result = AkAudioDevice->SetInSpatialAudioRoom(GetAkGameObjectID(), GetSpatialAudioRoomID());
- }
- }
- else if (CurrentRoom != RoomComponents[0])
- {
- CurrentRoom = RoomComponents[0];
- result = AkAudioDevice->SetInSpatialAudioRoom(GetAkGameObjectID(), GetSpatialAudioRoomID());
- }
- if (EnableSpotReflectors && result == AK_Success)
- AAkSpotReflector::UpdateSpotReflectors(this);
- }
- }
- }
- void UAkComponent::_DebugDrawReflections( const AkVector64& akEmitterPos, const AkVector64& akListenerPos, const AkReflectionPathInfo* paths, AkUInt32 uNumPaths) const
- {
- ::FlushDebugStrings(GWorld);
- for (AkInt32 idxPath = uNumPaths-1; idxPath >= 0; --idxPath)
- {
- const AkReflectionPathInfo& path = paths[idxPath];
- unsigned int order = path.numReflections;
- if ((DrawFirstOrderReflections && order == 1) ||
- (DrawSecondOrderReflections && order == 2) ||
- (DrawHigherOrderReflections && order > 2))
- {
- FColor colorLight;
- FColor colorMed;
- FColor colorDark;
- switch ((order - 1))
- {
- case 0:
- colorLight = FColor(0x9DEBF3);
- colorMed = FColor(0x318087);
- colorDark = FColor(0x186067);
- break;
- case 1:
- colorLight = FColor(0xFCDBA2);
- colorMed = FColor(0xDEAB4E);
- colorDark = FColor(0xA97B27);
- break;
- case 2:
- default:
- colorLight = FColor(0xFCB1A2);
- colorMed = FColor(0xDE674E);
- colorDark = FColor(0xA93E27);
- break;
- }
- FColor colorLightGrey(75, 75, 75);
- FColor colorMedGrey(50, 50, 50);
- FColor colorDarkGrey(35, 35, 35);
- const int kPathThickness = 5.f;
- const float kRadiusSphere = 25.f;
- const int kNumSphereSegments = 8;
- const FVector emitterPos = FAkAudioDevice::AKVector64ToFVector(akEmitterPos);
- FVector listenerPt = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
- for (int idxSeg = path.numPathPoints-1; idxSeg >= 0; --idxSeg)
- {
- const FVector reflectionPt = FAkAudioDevice::AKVector64ToFVector(path.pathPoint[idxSeg]);
-
- if (idxSeg != path.numPathPoints - 1)
- {
- // Note: Not drawing the first leg of the path from the listener. Often hard to see because it is typically the camera position.
- ::DrawDebugLine(GWorld, listenerPt, reflectionPt, path.isOccluded ? colorLightGrey : colorLight, false, -1.f, (uint8)'\000', kPathThickness / order);
- ::DrawDebugSphere(GWorld, reflectionPt, (kRadiusSphere/2) / order, kNumSphereSegments, path.isOccluded ? colorLightGrey : colorLight);
- }
- else
- {
- ::DrawDebugSphere(GWorld, reflectionPt, kRadiusSphere / order, kNumSphereSegments, path.isOccluded ? colorMedGrey : colorMed);
- }
-
- // Draw image source point. Not as useful as I had hoped.
- //const FVector imageSrc = FAkAudioDevice::AKVectorToFVector(path.imageSource);
- //::DrawDebugSphere(GWorld, imageSrc, kRadiusSphere/order, kNumSphereSegments, colorDark);
- listenerPt = reflectionPt;
- }
- if (!path.isOccluded)
- {
- // Finally the last path segment towards the emitter.
- ::DrawDebugLine(GWorld, listenerPt, emitterPos, path.isOccluded ? colorLightGrey : colorLight, false, -1.f, (uint8)'\000', kPathThickness / order);
- }
- }
- }
-
- }
- void UAkComponent::_DebugDrawDiffraction(const AkVector64& akEmitterPos, const AkVector64& akListenerPos, const AkDiffractionPathInfo* paths, AkUInt32 uNumPaths) const
- {
- ::FlushDebugStrings(GWorld);
- for (AkInt32 idxPath = uNumPaths - 1; idxPath >= 0; --idxPath)
- {
- const AkDiffractionPathInfo& path = paths[idxPath];
-
- FColor purple(0x492E74);
- FColor green(0x267158);
- if (path.nodeCount > 0)
- {
- const int kPathThickness = 5.f;
- const float kRadiusSphereMax = 35.f;
- const float kRadiusSphereMin = 2.f;
- const FVector emitterPos = FAkAudioDevice::AKVector64ToFVector(akEmitterPos);
- const FVector listenerPos = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
- FVector prevPt = FAkAudioDevice::AKVector64ToFVector(akListenerPos);
- for (int idxSeg = 0; idxSeg < (int)path.nodeCount; ++idxSeg)
- {
- const FVector pt = FAkAudioDevice::AKVector64ToFVector(path.nodes[idxSeg]);
- if (idxSeg != 0)
- {
- ::DrawDebugLine(GWorld, prevPt, pt, green, false, -1.f, (uint8)'\000', kPathThickness);
- }
- float rad = kRadiusSphereMin + (1.f - path.angles[idxSeg] / PI) * (kRadiusSphereMax - kRadiusSphereMin);
- ::DrawDebugSphere(GWorld, pt, rad, 8, path.portals[idxSeg].IsValid() ? green : purple );
- prevPt = pt;
- }
- // Finally the last path segment towards the emitter.
- ::DrawDebugLine(GWorld, prevPt, emitterPos, green, false, -1.f, (uint8)'\000', kPathThickness);
- }
- }
- }
- void UAkComponent::DebugDrawReflections() const
- {
- auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
- if (UNLIKELY(!SpatialAudio)) return;
- enum { kMaxPaths = 64 };
- AkReflectionPathInfo paths[kMaxPaths];
- AkUInt32 uNumPaths = kMaxPaths;
- AkVector64 listenerPos, emitterPos;
-
- if (SpatialAudio->QueryReflectionPaths(GetAkGameObjectID(), 0, listenerPos, emitterPos, paths, uNumPaths) == AK_Success && uNumPaths > 0)
- _DebugDrawReflections(emitterPos, listenerPos, paths, uNumPaths);
- }
- void UAkComponent::DebugDrawDiffraction() const
- {
- auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
- if (UNLIKELY(!SpatialAudio)) return;
- enum { kMaxPaths = 16 };
- AkDiffractionPathInfo paths[kMaxPaths];
- AkUInt32 uNumPaths = kMaxPaths;
- AkVector64 listenerPos, emitterPos;
- if (SpatialAudio->QueryDiffractionPaths(GetAkGameObjectID(), 0, listenerPos, emitterPos, paths, uNumPaths) == AK_Success)
- {
- if (uNumPaths > 0)
- _DebugDrawDiffraction(emitterPos, listenerPos, paths, uNumPaths);
- }
- }
- void UAkComponent::SetGameObjectRadius(float in_outerRadius, float in_innerRadius)
- {
- outerRadius = in_outerRadius;
- innerRadius = in_innerRadius;
- FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
- if (AkAudioDevice && IsRegisteredWithWwise)
- {
- AkAudioDevice->SetGameObjectRadius(this, outerRadius, innerRadius);
- }
- }
- void UAkComponent::SetEnableSpotReflectors(bool in_enable)
- {
- if (EnableSpotReflectors != in_enable)
- {
- EnableSpotReflectors = in_enable;
- AAkSpotReflector::UpdateSpotReflectors(this);
- }
- }
- #if WITH_EDITOR
- void UAkComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
- {
- Super::PostEditChangeProperty(PropertyChangedEvent);
- if (PropertyChangedEvent.Property)
- {
- if ((PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, outerRadius) ||
- PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, innerRadius)) &&
- PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
- {
- if (innerRadius > outerRadius)
- innerRadius = outerRadius;
- SetGameObjectRadius(outerRadius, innerRadius);
- }
- if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UAkComponent, EnableSpotReflectors) &&
- PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
- {
- AAkSpotReflector::UpdateSpotReflectors(this);
- }
- }
- }
- #endif
|