1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126 |
- /*******************************************************************************
- 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 "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());
- }
- void UAkComponent::PostAssociatedAkEventAndWaitForEndAsync(int32& PlayingID, FLatentActionInfo LatentInfo)
- {
- PostAkEventAndWaitForEndAsync(AkAudioEvent, PlayingID, LatentInfo);
- }
- int32 UAkComponent::PostAssociatedAkEventAndWaitForEnd(FLatentActionInfo LatentInfo)
- {
- return PostAkEventAndWaitForEnd(AkAudioEvent, EventName, LatentInfo);
- }
- AkPlayingID UAkComponent::PostAkEventByNameWithDelegate(UAkAudioEvent* AkEvent, const FString& in_EventName, int32 CallbackMask,
- const FOnAkPostEventCallback& PostEventCallback)
- {
- AkPlayingID PlayingID = AK_INVALID_PLAYING_ID;
- if (AkEvent)
- {
- return AkEvent->PostOnComponent(this, PostEventCallback, CallbackMask, StopWhenOwnerDestroyed);
- }
- auto AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- const AkUInt32 ShortID = AudioDevice->GetShortID(AkEvent, in_EventName);
- PlayingID = AudioDevice->PostEventOnAkGameObject(ShortID, this, PostEventCallback, CallbackMask, {});
- }
- return PlayingID;
- }
- AkPlayingID UAkComponent::PostAkEventByIdWithCallback(const AkUInt32 EventShortID, AkUInt32 Flags /*= 0*/,
- AkCallbackFunc UserCallback/*= NULL*/, void * UserCookie /*= NULL*/, const TArray<AkExternalSourceInfo>& ExternalSources)
- {
- AkPlayingID PlayingID = AK_INVALID_PLAYING_ID;
- auto AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- PlayingID = AudioDevice->PostEventOnAkComponent(EventShortID, this, Flags, UserCallback, UserCookie, ExternalSources);
- }
- return PlayingID;
- }
- int32 UAkComponent::PostAkEventAndWaitForEnd(class UAkAudioEvent * AkEvent, const FString& in_EventName, FLatentActionInfo LatentInfo)
- {
- if (LIKELY(!AkEvent))
- {
- return AkEvent->PostOnComponentAndWait(this, StopWhenOwnerDestroyed, LatentInfo);
- }
- AkPlayingID PlayingID = AK_INVALID_PLAYING_ID;
- auto AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- const AkUInt32 ShortID = AudioDevice->GetShortID(AkEvent, in_EventName);
- auto* World = GetWorld();
- if (UNLIKELY(!World))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to post latent AkAudioEvent with actor '%s' world that's not valid."), *GetName());
- return AK_INVALID_PLAYING_ID;
- }
- FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
- FWaitEndOfEventAction* LatentAction = new FWaitEndOfEventAction(LatentInfo);
- LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, LatentAction);
- PlayingID = AudioDevice->PostEventOnComponentWithLatentAction(ShortID, this, LatentAction);
- if (PlayingID == AK_INVALID_PLAYING_ID)
- {
- LatentAction->EventFinished = true;
- }
- }
- return PlayingID;
- }
- void UAkComponent::PostAkEventAndWaitForEndAsync(UAkAudioEvent* AkEvent, int32& PlayingID, FLatentActionInfo LatentInfo)
- {
- if (!AkEvent)
- {
- UE_LOG(LogAkAudio, Warning, TEXT("UAkComponent::PostAkEventAndWaitForEnd: No Event specified!"));
- PlayingID = AK_INVALID_PLAYING_ID;
- return;
- }
- PlayingID = AkEvent->PostOnComponentAndWait(this, StopWhenOwnerDestroyed, LatentInfo);
- }
- int32 UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, int32 CallbackMask,
- const FOnAkPostEventCallback& PostEventCallback, const FString& InEventName)
- {
- if (LIKELY(IsValid(AkEvent)))
- {
- return AkEvent->PostOnComponent(this, PostEventCallback, CallbackMask, StopWhenOwnerDestroyed);
- }
- AkPlayingID playingID = AK_INVALID_PLAYING_ID;
- auto AudioDevice = FAkAudioDevice::Get();
- if (AudioDevice)
- {
- playingID = AudioDevice->PostEventOnAkGameObject(AudioDevice->GetShortID(AkEvent, InEventName), this, PostEventCallback, CallbackMask, {});
- if (playingID != AK_INVALID_PLAYING_ID)
- {
- bEventPosted = true;
- }
- }
-
- return playingID;
- }
- AkPlayingID UAkComponent::PostAkEvent(UAkAudioEvent* AkEvent, AkUInt32 Flags, AkCallbackFunc UserCallback,
- void* UserCookie)
- {
- if (UNLIKELY(!IsValid(AkEvent)))
- {
- UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on component '%s'."), *GetName());
- return AK_INVALID_PLAYING_ID;
- }
- return AkEvent->PostOnComponent(this, nullptr, UserCallback, UserCookie, static_cast<AkCallbackType>(Flags), nullptr, StopWhenOwnerDestroyed);
- }
- AkRoomID UAkComponent::GetSpatialAudioRoom() const
- {
- AkRoomID RoomID;
- if (CurrentRoom)
- {
- RoomID = CurrentRoom->GetRoomID();
- }
- return RoomID;
- }
- 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)
- {
- if (!bUseDefaultListeners)
- {
- for (auto Listener : Listeners)
- {
- Listener->Emitters.Remove(this);
- }
- }
- bUseDefaultListeners = false;
- Listeners.Reset();
- Listeners.Append(NewListeners);
- for (auto Listener : Listeners)
- {
- Listener->Emitters.Add(this);
- }
- AudioDevice->SetListeners(this, Listeners.Array());
- }
- }
- void UAkComponent::UseReverbVolumes(bool inUseReverbVolumes)
- {
- bUseReverbVolumes = inUseReverbVolumes;
- }
- void UAkComponent::UseEarlyReflections(
- class UAkAuxBus* AuxBus,
- int Order,
- float BusSendGain,
- float MaxPathLength,
- bool SpotReflectors,
- const FString& AuxBusName)
- {
- // Deprecated
- }
- 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)
- {
- 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.
- ObstructionService.Init(this, OcclusionRefreshInterval);
- // 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.
- FAkAudioDevice * AudioDevice = FAkAudioDevice::Get();
- 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
- 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([=](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);
- 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(GetWorld()))
- {
- 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);
- ObstructionService.Tick(Listeners, GetPosition(), GetOwner(), GetSpatialAudioRoom(), 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 )
- {
- const auto& DefaultListeners = AkAudioDevice->GetDefaultListeners();
- Listeners.Empty(DefaultListeners.Num());
-
- for (auto Listener : DefaultListeners)
- {
- Listeners.Add(Listener);
- // NOTE: We do not add this to Listener's emitter list, the list is only for user specified (non-default) emitters.
- }
- }
- 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;
- }
- for (auto Listener : Listeners)
- Listener->Emitters.Remove(this);
- for (auto Emitter : Emitters)
- Emitter->Listeners.Remove(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([=](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([=](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()
- {
- #ifdef _DEBUG
- CheckEmitterListenerConsistancy();
- #endif
- 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(), GetSpatialAudioRoom());
- }
- }
- else if (CurrentRoom != RoomComponents[0])
- {
- CurrentRoom = RoomComponents[0];
- result = AkAudioDevice->SetInSpatialAudioRoom(GetAkGameObjectID(), GetSpatialAudioRoom());
- }
- if (EnableSpotReflectors && result == AK_Success)
- AAkSpotReflector::UpdateSpotReflectors(this);
- }
- }
- }
- const TSet<UAkComponent*>& UAkComponent::GetEmitters()
- {
- FAkAudioDevice* Device = FAkAudioDevice::Get();
- if (Device)
- {
- auto DefaultListeners = Device->GetDefaultListeners();
- if (DefaultListeners.Contains(this))
- return Device->GetDefaultEmitters();
- else
- return Emitters;
- }
- return Emitters;
- }
- void UAkComponent::CheckEmitterListenerConsistancy()
- {
- for (auto Emitter : GetEmitters())
- {
- check(Emitter->Listeners.Contains(this));
- }
- for (auto Listener : Listeners)
- {
- check(Listener->GetEmitters().Contains(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
|