Select Git revision
VAAbstractSourceComponent.cpp
-
Jonathan Ehret authoredJonathan Ehret authored
VAAbstractSourceComponent.cpp 15.14 KiB
// Fill out your copyright notice in the Description page of Project Settings.
#include "SoundSource/VAAbstractSourceComponent.h"
#include "SoundSource/VASoundSource.h"
#include "VAReceiverActor.h"
#include "VAPlugin.h"
#include "VAUtils.h"
#include "ImageSourceModel/VAImageSourceModel.h"
#include "SignalSources/VAAudiofileSignalSource.h"
#include "SignalSources/VAJetEngineSignalSource.h"
#include "Directivity/VADirectivityManager.h"
#include "Components/SkeletalMeshComponent.h" // Skeletons
#include "Kismet/GameplayStatics.h" // Get Actors of Class
#include "Utility/VirtualRealityUtilities.h"
// Sets default values for this component's properties
UVAAbstractSourceComponent::UVAAbstractSourceComponent()
{
PrimaryComponentTick.bCanEverTick = true;
//Default objects for subcomponents does not work
//SignalSource = CreateDefaultSubobject<UVAAudiofileSignalSource>(TEXT("SignalSource"), false);
}
// Called when the game starts
void UVAAbstractSourceComponent::BeginPlay()
{
Super::BeginPlay();
// If the receiver Actor is initialized but this sound Component not, this Component is spawned at runtime and has to be initialized
// Otherwise it will be later on initialized from the Receiver Actor
TArray<AActor*> ReceiverActors;
UGameplayStatics::GetAllActorsOfClass(this->GetWorld(), AVAReceiverActor::StaticClass(), ReceiverActors);
if (ReceiverActors.Num() >= 1 && Cast<AVAReceiverActor>(ReceiverActors[0])->IsInitialized() && !bInitialized)
{
Initialize();
}
}
void UVAAbstractSourceComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
SoundSource.Reset();
Super::EndPlay(EndPlayReason);
}
// Called every frame
void UVAAbstractSourceComponent::TickComponent(const float DeltaTime, const ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!FVAPlugin::GetUseVA() || !UVirtualRealityUtilities::IsMaster())
{
return;
}
if (!bInitialized)
{
if(!bInformedNotInitialized)
{
FVAUtils::OpenMessageBox("[UVASourceComponent::TickComponent()]: Sound source is not initialized", true);
bInformedNotInitialized = true;
}
return;
}
if (bFirstTick && UVirtualRealityUtilities::IsMaster())
{
TimeSinceUpdate = 1.0f;
}
bFirstTick = false;
TimeSinceUpdate += DeltaTime;
if ((MovementSetting == EMovement::AttachToBone || MovementSetting == EMovement::MoveWithObject) &&
TimeSinceUpdate > (1.0f / float(UpdateRate)))
{
UpdatePose();
TimeSinceUpdate = 0.0f;
}
}
void UVAAbstractSourceComponent::UpdateSkeletalMeshIfAttachToBone()
{
if (MovementSetting == EMovement::AttachToBone)
{
AActor* Owner = GetOwner();
bool bFoundSkelMesh = false;
while(!bFoundSkelMesh && Owner != nullptr)
{
TArray<UActorComponent*> MeshComponents = Owner->GetComponentsByClass(USkeletalMeshComponent::StaticClass());
for (UActorComponent* Component : MeshComponents)
{
USkeletalMeshComponent* MeshComp = Cast<USkeletalMeshComponent>(Component);
if (MeshComp && MeshComp->DoesSocketExist(FName(*BoneName)))
{
//found the right mesh component
SkeletalMeshComponent = MeshComp;
bFoundSkelMesh = true;
break;
}
}
Owner = Owner->GetAttachParentActor();
}
if (SkeletalMeshComponent == nullptr)
{
FVAUtils::OpenMessageBox("[UVASourceComponent::Initialize()]: Could not find bone " +
BoneName + ", using MoveWithObject instead.", true);
MovementSetting = EMovement::MoveWithObject;
}
}
}
void UVAAbstractSourceComponent::Initialize()
{
if (!FVAPlugin::GetUseVA() || bInitialized)
{
return;
}
bFirstTick = true;
TArray<AActor*> ReceiverActors;
UGameplayStatics::GetAllActorsOfClass(this->GetWorld(), AVAReceiverActor::StaticClass(), ReceiverActors);
AVAReceiverActor* ReceiverActorTmp = nullptr;
if (ReceiverActors.Num() == 0)
{
// If no Rec Actor found spawn one with default parameters
if (ReceiverActorTmp == nullptr)
{
FVAUtils::LogStuff("[UVASourceComponent::BeginPlay()]: No AVAReceiver found! Spawning one with default values", false);
ReceiverActorTmp = this->GetWorld()->SpawnActor<AVAReceiverActor>(AVAReceiverActor::StaticClass());
}
}
else if (ReceiverActors.Num() == 1)
{
ReceiverActorTmp = dynamic_cast<AVAReceiverActor*>(ReceiverActors[0]);
FVAUtils::LogStuff("[UVASourceComponent::BeginPlay()]: Receiver found!", false);
}
else if (ReceiverActors.Num() >= 2)
{
FVAPlugin::SetUseVA(false);
FVAUtils::OpenMessageBox("There are more than 1 Receiver Actors in the world. Stopping VAPlugin. Make sure to remove the wrong one.", true);
FVAUtils::LogStuff("[UVASourceComponent::BeginPlay()]: More than 1 Receiver found! Stopping VAPlugin. Make sure to remove the wrong one", true);
return;
}
CurrentReceiverActor = ReceiverActorTmp;
UpdateRate = ReceiverActorTmp->GetUpdateRate();
UpdateSkeletalMeshIfAttachToBone();
SpawnPosition = GetOwner()->GetTransform().GetLocation();
SpawnRotation = GetOwner()->GetTransform().GetRotation().Rotator();
const std::string ExplicitRendererID = bRendererExplicit ? std::string( TCHAR_TO_UTF8(*RendererID) ): ""; // Empty ID => general source
const std::string SoundSourceName = std::string( TCHAR_TO_UTF8(*GetName()) );
SoundSource = MakeShared<FVASoundSource>(GetWorld(), GetPosition(), GetRotation(), SoundPower, SoundSourceName, ExplicitRendererID);
if (UVirtualRealityUtilities::IsMaster())
{
switch (DirectivitySetting)
{
case EDirectivitySetting::DefaultDirectivity:
SoundSource->SetDirectivity(FVADirectivityManager::GetDefaultDirectivity());
break;
case EDirectivitySetting::ManualFile:
SoundSource->SetDirectivity(
CurrentReceiverActor->GetDirectivityByFileName(DirectivityByFileName));
break;
case EDirectivitySetting::Phoneme:
SoundSource->SetDirectivity(
CurrentReceiverActor->GetDirectivityByMapping(DirectivityByMapping));
break;
default:
break;
}
}
if (bHandleReflections)
{
TArray<AVAReflectionWall*> ReflWalls = CurrentReceiverActor->GetReflectionWalls();
ImageSourceModel = MakeShared<FVAImageSourceModel>(GetWorld(), SoundSource.ToSharedRef(), ReflWalls);
}
if (SignalSource)
{
SignalSource->Initialize();
SetSignalSourceID(SignalSource->GetID());
}
FVAUtils::LogStuff("[UVASourceComponent::Initialize()]: SoundSourceComponent initialized successfully", false);
bInitialized = true;
}
void UVAAbstractSourceComponent::UpdatePose()
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return;
}
SoundSource->SetPosition(GetPosition());
SoundSource->SetRotation(GetRotation());
if (bHandleReflections && ImageSourceModel.IsValid())
{
ImageSourceModel->UpdateISPositions();
ImageSourceModel->UpdateISRotations();
}
}
bool UVAAbstractSourceComponent::SetSignalSourceID(const std::string& SignalSourceID)
{
if (!SoundSource.IsValid())
{
FVAUtils::OpenMessageBox(FString("[UVASourceComponent::SetSignalSourceID]: VA sound source not initialized"), true);
return false;
}
if (!SoundSource->SetSignalSource(SignalSourceID))
{
return false;
}
if (bHandleReflections && ImageSourceModel.IsValid())
{
return ImageSourceModel->UpdateISSignalSource();
}
return true;
}
bool UVAAbstractSourceComponent::ShouldSendCommand() const
{
return (bInitialized && FVAPlugin::GetUseVA() && UVirtualRealityUtilities::IsMaster());
}
// ****************************************************************** //
// ******* Sound Source Settings ************************************ //
// ****************************************************************** //
bool UVAAbstractSourceComponent::MuteSound(const bool bMute)
{
if (!ShouldSendCommand())
{
return false;
}
if (!SoundSource->MuteSound(bMute))
{
return false;
}
if (bHandleReflections && ImageSourceModel.IsValid())
{
return ImageSourceModel->MuteIS(bMute);
}
return true;
}
bool UVAAbstractSourceComponent::SetSoundPower(const float Power)
{
if (!ShouldSendCommand())
{
return false;
}
if (!SoundSource->SetPower(Power))
{
return false;
}
SoundPower = Power;
if (bHandleReflections && ImageSourceModel.IsValid())
{
return ImageSourceModel->UpdateISPower();
}
return true;
}
float UVAAbstractSourceComponent::GetSoundPower() const
{
return SoundPower;
}
// ****************************************************************** //
// ******* Image Sources / Reflections ****************************** //
// ****************************************************************** //
bool UVAAbstractSourceComponent::GetHandleReflections() const
{
return bHandleReflections;
}
// ****************************************************************** //
// ******* Sound Pose *********************************************** //
// ****************************************************************** //
FVector UVAAbstractSourceComponent::GetPosition() const
{
FVector Pos;
switch (MovementSetting)
{
case EMovement::MoveWithObject:
Pos = GetOwner()->GetTransform().GetLocation();
break;
case EMovement::ObjectSpawnPoint:
Pos = SpawnPosition;
break;
case EMovement::AttachToBone:
Pos = SkeletalMeshComponent->GetSocketLocation(FName(*BoneName));
break;
default:
Pos = FVector::ZeroVector;
FVAUtils::LogStuff(FString("[UVASourceComponent::GetPosition()]: In default, Unreachable Error", true));
break;
}
if (bUsePoseOffset)
{
Pos = Pos + OffsetPosition;
}
return Pos;
}
FRotator UVAAbstractSourceComponent::GetRotation() const
{
FRotator Rot;
switch (MovementSetting)
{
case EMovement::MoveWithObject:
Rot = GetOwner()->GetTransform().GetRotation().Rotator();
break;
case EMovement::ObjectSpawnPoint:
Rot = SpawnRotation;
break;
case EMovement::AttachToBone:
Rot = SkeletalMeshComponent->GetSocketRotation(FName(*BoneName));
break;
default:
FVAUtils::LogStuff(FString("[UVASourceComponent::GetRotation()]: In default, Unreachable Error", true));
Rot = FRotator::ZeroRotator;
break;
}
if (bUsePoseOffset)
{
Rot = FRotator(FQuat(Rot) * FQuat(OffsetRotation));
}
return Rot;
}
bool UVAAbstractSourceComponent::SetMovementSetting(const EMovement::Type NewMovementSetting)
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return false;
}
if (MovementSetting == NewMovementSetting)
{
return true;
}
MovementSetting = NewMovementSetting;
UpdateSkeletalMeshIfAttachToBone();
UpdatePose();
return true;
}
bool UVAAbstractSourceComponent::SetUsePoseOffset(const bool bNewUsePoseOffset)
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return false;
}
if (bUsePoseOffset == bNewUsePoseOffset)
{
return true;
}
bUsePoseOffset = bNewUsePoseOffset;
UpdatePose();
return true;
}
bool UVAAbstractSourceComponent::SetOffsetPosition(const FVector Pos)
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return false;
}
if (OffsetPosition == Pos && bUsePoseOffset)
{
return true;
}
bUsePoseOffset = true;
OffsetPosition = Pos;
UpdatePose();
return true;
}
bool UVAAbstractSourceComponent::SetOffsetRotation(const FRotator Rot)
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return false;
}
if (OffsetRotation == Rot && bUsePoseOffset)
{
return true;
}
bUsePoseOffset = true;
OffsetRotation = Rot;
UpdatePose();
return true;
}
// ****************************************************************** //
// ******* Directivity stuff **************************************** //
// ****************************************************************** //
bool UVAAbstractSourceComponent::SetDirectivityByMapping(const FString Phoneme)
{
if (!ShouldSendCommand())
{
return false;
}
DirectivitySetting = EDirectivitySetting::Phoneme;
DirectivityByMapping = Phoneme;
return SoundSource->SetDirectivity(CurrentReceiverActor->GetDirectivityByMapping(Phoneme));
}
bool UVAAbstractSourceComponent::SetDirectivityByFileName(const FString FileName)
{
if (!ShouldSendCommand())
{
return false;
}
DirectivitySetting = EDirectivitySetting::ManualFile;
DirectivityByFileName = FileName;
if (FileName == "")
{
return SoundSource->RemoveDirectivity();
}
return SoundSource->SetDirectivity(CurrentReceiverActor->GetDirectivityByFileName(FileName));
}
FString UVAAbstractSourceComponent::GetDirectivityFileName() const
{
if (SoundSource.IsValid())
{
return SoundSource->GetDirectivityFilename();
}
return "";
}
// ****************************************************************** //
// ******* Graphical Representation ********************************* //
// ****************************************************************** //
bool UVAAbstractSourceComponent::SetVisibility(const bool bVis)
{
if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid())
{
return false;
}
SoundSource->SetVisibility(bVis);
if (bHandleReflections && ImageSourceModel.IsValid())
{
ImageSourceModel->SetISVisibility(bVis);
}
return true;
}
bool UVAAbstractSourceComponent::GetVisibility() const
{
return SoundSource->GetVisibility();
}
int UVAAbstractSourceComponent::GetSoundSourceID() const
{
if (!SoundSource)
{
return -1;
}
return SoundSource->GetSoundSourceID();
}
bool UVAAbstractSourceComponent::SetBoneName(const FString NewBoneName)
{
if (!FVAPlugin::GetUseVA())
{
return false;
}
if (BoneName == NewBoneName)
{
return true;
}
// Check if the bone exists
if (SkeletalMeshComponent != nullptr
&& SkeletalMeshComponent->DoesSocketExist(FName(*NewBoneName)))
{
BoneName = NewBoneName;
MovementSetting = EMovement::AttachToBone;
FVAUtils::LogStuff("[UVASourceComponent::SetBoneName()]: Successfully found bone with name" +
BoneName + "and set Movement Setting to follow the bone", false);
return true;
}
FVAUtils::OpenMessageBox(
"[UVASourceComponent::SetBoneName()]: Could not find the bone, using old settings instead.");
return false;
}
FString UVAAbstractSourceComponent::GetBoneName() const
{
if (MovementSetting != EMovement::AttachToBone)
{
FVAUtils::LogStuff("[UVASourceComponent::GetBoneName()]: Movement is not set to AttachToBone..", true);
return "SoundSource is not attached to bone, but current bone is: " + BoneName;
}
return BoneName;
}
// ****************************************************************** //
// ******* Blueprint Settings *************************************** //
// ****************************************************************** //
#if WITH_EDITOR
bool UVAAbstractSourceComponent::CanEditChange(const FProperty* InProperty) const
{
const bool ParentVal = Super::CanEditChange(InProperty);
// Check Bone Name
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UVAAbstractSourceComponent, BoneName))
{
return MovementSetting == EMovement::AttachToBone;
}
// Check Directivity Config
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UVAAbstractSourceComponent, DirectivityByFileName))
{
return DirectivitySetting == EDirectivitySetting::ManualFile;
}
// Check Bone Name
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UVAAbstractSourceComponent, DirectivityByMapping))
{
return DirectivitySetting == EDirectivitySetting::Phoneme;
}
// Check Bone Name
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UVAAbstractSourceComponent, OffsetPosition) ||
InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UVAAbstractSourceComponent, OffsetRotation))
{
return bUsePoseOffset;
}
return ParentVal;
}
#endif