diff --git a/README.md b/README.md index 1bca72e8ed300e666c5800f6d3a33e146d0b6a46..a2234b1385a15ad3489294ad084b62c244493751 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,28 @@ This Plugin allows the user to use the [VA Server](http://www.virtualacoustics.org/) from the [Institute of Acoustics](https://www.akustik.rwth-aachen.de/cms/~dwma/Technische-Akustik/lidx/1/) (ITA) of the RWTH Aachen to playback sounds in Unreal. -# Installation -To install the Plugin, clone the repository into the "Plugins" folder of your Unreal Engine 4 Project. Moreover make sure to have the VA Server prepared. +## Installation +If you used the [RWTH VR Project Template](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unrealprojecttemplate) to create your project you can use the setup script to add the Virtual Acoustics Plugin. +Otherwise, add repository as submodule in the "Plugins" folder of your Unreal Engine 4 Project (``git submodule add https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/unreal-va-plugin.git Plugins/VAPlugin``. -The Server can either be used in its original form ([Link](http://www.virtualacoustics.org/)) or with the especially for this Plugin optimized Python Connection script ([Link](https://devhub.vr.rwth-aachen.de/VR-Group/vaserver), Recommended). -Using the Version with the Python script has the adventage of not needing to Restart the Server all the time manually and make sure to follow the instructions which are currently in its Readme file. -If you are using the automatic VAServer launching either have VAServer cloned out next to the folder of your project or specify the VALauncher Path in the Engine/Virtual Acoustics(VA) section of the project settings. +Moreover make sure to have the VAServer prepared: -The Plugin requires to have the [nDisplayExtensions](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/ndisplayextensions) installed. +While the VAServer can be used in its original form ([Link](http://www.virtualacoustics.org/)) we highly recommend using the [VAServerLauncher](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/vaserverlauncher) script (Recommended), an especially for this Plugin optimized Python script including a lot of config possibilities and providing VAServer binaries. +Using the [VAServerLauncher](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/vaserverlauncher) has following the advantages: +* You don't need to (re)start the VAServer all the time manually. Even the VAServerLauncher script is (if configured correctly, see below) started automatically by Unreal. +* The VAServerLauncher can transfer used audio files from you Unreal project to the VAServer (even in networked environments), so you don't have to do this manually. Just use audio paths relative to your Content folder. (:warning: when using packaged builds, e.g., in the CAVE, make sure to have the paths where your audio files are packed as nonUFS, so not added to the pak files, this can be configured in the project settings at ``DirectoriesToAlwaysStageAsNonUFS``). +* This copying over is also true for VAServer ini files (e.g., having different acoustical renderers in different scenes), see [VAServerLAuncher documentation](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/VAServerLauncher/-/blob/master/README.md) for more information. + +If you are using the automatic VAServerLauncher either have VAServerLauncher cloned next to the folder of your project or specify the VALauncher Path in the Engine/Virtual Acoustics(VA) section of the project settings. +Make sure to follow the instructions which are currently in [its Readme file](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/VAServerLauncher/-/blob/master/README.md). + +The Plugin requires to have the [RWTH VR Toolkit](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit) used in your project. ## Usage -For a more detailed C++ / Blueprint usage and a Documentation of the Plugins public functions, please check out the matching wiki page for each public Class and Enum: -* [VAReceiverActor](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unreal-va-plugin/-/wikis/Documentation/VAReceiverActor) +For a more detailed C++ / Blueprint usage and a Documentation of the Plugins public functions, please check out the matching [wiki page](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/unreal-va-plugin/-/wikis/home) for each public class: +* [VAReceiverActor](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/unreal-va-plugin/-/wikis/Documentation/VAReceiverActor) * Actor handling the Connection and Scene Settings for the current world, as well as the Position updates for the Receiver. If there is no Receiver Actor placed in the Scene, there will be created a new one with Default values at Runtime. -* [VAReflectionWall](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unreal-va-plugin/-/wikis/Documentation/VAReflectionWall) - * Actor representing a wall on which the Sound Sources should reflect on. Make sure that its shape alligns with the wall. Please make sure to use symmetrical Directivities for the Sound Sources due to the fact that the directivities cannot be mirrored among the wall. -* [VASoundSourceComponent](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unreal-va-plugin/-/wikis/Documentation/VASoundSourceComponent) - * Actor Component representing a Sound Source. Has to be attatched to something. It can have a graphical representation and reflecitons, which can be created with the Reflection Walls -* [VAEnums](https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unreal-va-plugin/-/wikis/Documentation/VAEnmus) - * All Enums used within the Plugin. At current state, only the EPlayAction is used for the Interface functions \ No newline at end of file +* [VASoundSourceComponent](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/unreal-va-plugin/-/wikis/Documentation/VASoundSourceComponent) + * Actor Component representing a Sound Source. Has to be attatched to something. It can have a graphical representation and reflections, which can be created with the [VAReflectionWall](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/unreal-va-plugin/-/wikis/Documentation/VAReflectionWall) diff --git a/Source/VAPlugin/Private/SignalSources/VAAudioInputSignalSource.cpp b/Source/VAPlugin/Private/SignalSources/VAAudioInputSignalSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc2389610aba4ef4954eb10da8a6d08ec1956cbf --- /dev/null +++ b/Source/VAPlugin/Private/SignalSources/VAAudioInputSignalSource.cpp @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SignalSources/VAAudioInputSignalSource.h" + +#include "VAUtils.h" +#include "VAPlugin.h" + +void UVAAudioInputSignalSource::Initialize() +{ + if (bInitialized) + { + FVAUtils::LogStuff("[UVAAudioInputSignalSource::Initialize()]: Signal source is already initialized, aborting...", true); + return; + } + + + ID = FVAPlugin::GetAudioInputSignalSourceID(Channel); + if (!IsValidID(ID)) + { + FVAUtils::LogStuff("[UVAAudioInputSignalSource::Initialize()]: Error initializing Audio Input Signal Source", true); + return; + } + + bInitialized = true; +} diff --git a/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp b/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp index 5ed4c1edf3498e74aca805c95146be5173e868e0..c9b838ec70a7b29b3a3c8426dece1618ea0ba1f2 100644 --- a/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp +++ b/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp @@ -13,6 +13,7 @@ void UVAAudiofileSignalSource::Initialize() { + StorePlayStateInternallyEvent.Attach(this); if (bInitialized) { FVAUtils::LogStuff("[UVAAudiofileSignalSource::Initialize()]: Signal source is already initialized, aborting...", false); @@ -27,6 +28,15 @@ void UVAAudiofileSignalSource::Initialize() bInitialized = true; } +UVAAudiofileSignalSource::~UVAAudiofileSignalSource() +{ + if(bInitialized) + { + StorePlayStateInternallyEvent.Detach(); + //otherwise it was never attached and would throw a warning + } +} + // ****************************************************************** // // ******* Bluepring Functions ************************************** // // ****************************************************************** // @@ -111,6 +121,7 @@ bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN) return true; } + bLoop = bLoopN; if (!UVirtualRealityUtilities::IsMaster()) { @@ -122,7 +133,6 @@ bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN) return true; } - bLoop = bLoopN; return FVAPlugin::SetSignalSourceBufferLooping(ID, bLoop); } @@ -137,15 +147,18 @@ bool UVAAudiofileSignalSource::SetPlayBackPosition(const float Time) bool UVAAudiofileSignalSource::SetPlayAction(const int Action) { - if (!UVirtualRealityUtilities::IsMaster()) + if (!bInitialized) { return false; } + InterallyStoredPlayAction = Action; + StorePlayStateInternallyEvent.Send(Action); //also send this to all slaves, so potentially still pending send numbers from GetPlayAction are overwritten - if (int(GetPlayAction()) == Action) + if (!UVirtualRealityUtilities::IsMaster()) { - return true; + return false; } + return FVAPlugin::SetSignalSourceBufferPlayAction(ID, EPlayAction::Type(Action)); } @@ -165,18 +178,33 @@ bool UVAAudiofileSignalSource::GetLoop() const return bLoop; } -EPlayAction::Type UVAAudiofileSignalSource::GetPlayActionEnum() const +EPlayAction::Type UVAAudiofileSignalSource::GetPlayActionEnum(bool bDirectOnMaster /*= false*/) { - return EPlayAction::Type(GetPlayAction()); + return EPlayAction::Type(GetPlayAction(bDirectOnMaster)); } -int UVAAudiofileSignalSource::GetPlayAction() const +int UVAAudiofileSignalSource::GetPlayAction(bool bDirectOnMaster /*= false*/) { - if (!UVirtualRealityUtilities::IsMaster()) + if(!bInitialized) { return -1; } - return FVAPlugin::GetSignalSourceBufferPlayAction(ID); + //we return the internally stored action in case this is in cluster and not the master + //but also update the internally stored data by the one which the master can get from the VAServer + //However, using cluster events to sync, so new data might only be available next frame! + if (UVirtualRealityUtilities::IsMaster()) + { + // in case of not being in cluster mode this directly calls StorePlayStateInternally() updating InterallyStoredPlayAction directly + // otherwise (in cluster mode) this emits acluster event, so the internal data will be updated before next Tick + int VAServerPlayAction = FVAPlugin::GetSignalSourceBufferPlayAction(ID); + StorePlayStateInternallyEvent.Send(VAServerPlayAction); + if(bDirectOnMaster) + { + return VAServerPlayAction; + } + } + + return InterallyStoredPlayAction; } bool UVAAudiofileSignalSource::CopySignalSourceSettings(const std::string& OtherID) @@ -202,3 +230,8 @@ bool UVAAudiofileSignalSource::CopySignalSourceSettings(const std::string& Other } return FVAPlugin::SetSignalSourceBufferPlayAction(OtherID, EPlayAction::Type(PlayAction)); } + +void UVAAudiofileSignalSource::StorePlayStateInternally(int PlayAction) +{ + InterallyStoredPlayAction = PlayAction; +} diff --git a/Source/VAPlugin/Private/SoundSource/VAAbstractSourceComponent.cpp b/Source/VAPlugin/Private/SoundSource/VAAbstractSourceComponent.cpp index a85a86d318f62be9593143c2736223decfd9b4b5..f6cf224e60291e64395746c7fe69db025f08a6e0 100644 --- a/Source/VAPlugin/Private/SoundSource/VAAbstractSourceComponent.cpp +++ b/Source/VAPlugin/Private/SoundSource/VAAbstractSourceComponent.cpp @@ -53,14 +53,18 @@ void UVAAbstractSourceComponent::TickComponent(const float DeltaTime, const ELev { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - if (!FVAPlugin::GetUseVA() || !UVirtualRealityUtilities::IsMaster()) + if (!FVAPlugin::GetUseVA() || !SoundSource.IsValid()) { return; } if (!bInitialized) { - FVAUtils::OpenMessageBox("[UVASourceComponent::TickComponent()]: Sound source is not initialized", true); + if(!bInformedNotInitialized) + { + FVAUtils::OpenMessageBox("[UVASourceComponent::TickComponent()]: Sound source is not initialized", true); + bInformedNotInitialized = true; + } return; } @@ -83,6 +87,38 @@ void UVAAbstractSourceComponent::TickComponent(const float DeltaTime, const ELev } +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) @@ -126,25 +162,7 @@ void UVAAbstractSourceComponent::Initialize() UpdateRate = ReceiverActorTmp->GetUpdateRate(); - if (MovementSetting == EMovement::AttachToBone) - { - TArray<UActorComponent*> MeshComponents = GetOwner()->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; - } - } - if (SkeletalMeshComponent == nullptr) - { - FVAUtils::OpenMessageBox("[UVASourceComponent::Initialize()]: Could not find bone " + - BoneName + ", using MoveWithObject instead.", true); - MovementSetting = EMovement::MoveWithObject; - } - } + UpdateSkeletalMeshIfAttachToBone(); SpawnPosition = GetOwner()->GetTransform().GetLocation(); @@ -371,6 +389,7 @@ bool UVAAbstractSourceComponent::SetMovementSetting(const EMovement::Type NewMov } MovementSetting = NewMovementSetting; + UpdateSkeletalMeshIfAttachToBone(); UpdatePose(); return true; @@ -468,6 +487,24 @@ bool UVAAbstractSourceComponent::SetDirectivityByFileName(const FString FileName return SoundSource->SetDirectivity(CurrentReceiverActor->GetDirectivityByFileName(FileName)); } +bool UVAAbstractSourceComponent::SetDefaultDirectivity() +{ + if (!ShouldSendCommand()) + { + return false; + } + return SoundSource->SetDirectivity(FVADirectivityManager::GetDefaultDirectivity()); +} + +bool UVAAbstractSourceComponent::SetNoDirectivity() +{ + if (!ShouldSendCommand()) + { + return false; + } + return SoundSource->RemoveDirectivity(); +} + FString UVAAbstractSourceComponent::GetDirectivityFileName() const { if (SoundSource.IsValid()) diff --git a/Source/VAPlugin/Private/SoundSource/VAAudioInputSourceComponent.cpp b/Source/VAPlugin/Private/SoundSource/VAAudioInputSourceComponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9624a50d2316210816f65ee045e9699b5dcd09ba --- /dev/null +++ b/Source/VAPlugin/Private/SoundSource/VAAudioInputSourceComponent.cpp @@ -0,0 +1,12 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SoundSource/VAAudioInputSourceComponent.h" + +#include "SignalSources/VAAudioInputSignalSource.h" + + +UVAAudioInputSourceComponent::UVAAudioInputSourceComponent() : Super() +{ + SignalSource = CreateDefaultSubobject<UVAAudioInputSignalSource>("AudioInputSignalSource"); +} diff --git a/Source/VAPlugin/Private/SoundSource/VASoundSource.cpp b/Source/VAPlugin/Private/SoundSource/VASoundSource.cpp index 4398f169da874689f1d920935296e7359c4bde1a..f18c61972a5ab5edc6e95e0d791c5b2ae09e0ff3 100644 --- a/Source/VAPlugin/Private/SoundSource/VASoundSource.cpp +++ b/Source/VAPlugin/Private/SoundSource/VASoundSource.cpp @@ -8,6 +8,7 @@ #include "SoundSource/VASoundSourceRepresentation.h" #include "Engine/World.h" +#include "Utility/VirtualRealityUtilities.h" // ****************************************************************** // @@ -73,7 +74,7 @@ void FVASoundSource::SetPosition(const FVector NewPosition) { Position = NewPosition; - if (!FVAPlugin::SetSoundSourcePosition(SoundSourceID, Position)) + if (!FVAPlugin::SetSoundSourcePosition(SoundSourceID, Position) && UVirtualRealityUtilities::IsMaster()) { FVAUtils::LogStuff("[FVASoundSource::SetPosition()]:" + FString(" Could not set sound source position in VA. Position of visual and auditive representation might mismatch now."), true); @@ -86,7 +87,7 @@ void FVASoundSource::SetRotation(const FRotator NewRotation) { Rotation = NewRotation; - if (!FVAPlugin::SetSoundSourceRotation(SoundSourceID, Rotation)) + if (!FVAPlugin::SetSoundSourceRotation(SoundSourceID, Rotation) && UVirtualRealityUtilities::IsMaster()) { FVAUtils::LogStuff("[FVASoundSource::SetRotation()]:" + FString(" Could not set sound source rotation in VA. Orientation of visual and auditive representation might mismatch now."), true); diff --git a/Source/VAPlugin/Private/VAPlugin.cpp b/Source/VAPlugin/Private/VAPlugin.cpp index 87eeda9c65b1cfa9c59396ea1fcd459990c90bc9..1984b5f349e149df4fa6ea13260f8cf453607dc7 100644 --- a/Source/VAPlugin/Private/VAPlugin.cpp +++ b/Source/VAPlugin/Private/VAPlugin.cpp @@ -409,6 +409,9 @@ bool FVAPlugin::DisconnectServer() void FVAPlugin::AddVAServerSearchPath(const std::string& SearchPath) { + if (!ShouldInteractWithServer()) + return; + // This checking whether it already exists, led to undeterministic runtime error, due to std::string dtor. // So keep track whether it was added before yourself ;-) /*CVAStruct Searchpaths = VAServer->GetSearchPaths(); @@ -557,6 +560,25 @@ bool FVAPlugin::SetSignalSourceBufferLooping(const std::string& SignalSourceID, } } +std::string FVAPlugin::GetAudioInputSignalSourceID(const int Channel) +{ + if (!ShouldInteractWithServer()) + return VA_SLAVE_ID_STRING; + + const std::string SignalSourceID = "audioinput" + std::to_string(Channel); + + //TODO: Check if signal source really exist, otherwise return invalid ID + + //PSC: I was trying to use CVASignalSourceInfo for that. But when the local variable is destroyed, the program crashes. + //std::vector<CVASignalSourceInfo> Infos; + //VAServer->GetSignalSourceInfos(Infos); + //CVASignalSourceInfo Info = VAServer->GetSignalSourceInfo(SignalSourceID); + //if (false) + // return VA_INVALID_ID_STRING; + + return SignalSourceID; +} + std::string FVAPlugin::CreateSignalSourcePrototype(UVAAbstractSignalSource* SignalSource) { if (!ShouldInteractWithServer()) @@ -1237,8 +1259,8 @@ void FVAPlugin::SetScale(const float ScaleN) void FVAPlugin::SetUseVA(const bool bUseVAN) { - // VA cannot be activated once it was deactivated - if(bUseVA == false || bUseVA == bUseVAN) + // VA cannot be activated once it was deactivated (we need to check bPluginInitialized because we can reset it on beginning a new session) + if((bUseVA == false && bPluginInitialized) || bUseVA == bUseVAN) { return; } diff --git a/Source/VAPlugin/Private/VAPlugin.h b/Source/VAPlugin/Private/VAPlugin.h index 9fa2bcf31aeff46e6841c4f23cdbecf26fd9adf4..d4874d279772cba27745b138d443a2fc9364993f 100644 --- a/Source/VAPlugin/Private/VAPlugin.h +++ b/Source/VAPlugin/Private/VAPlugin.h @@ -76,6 +76,9 @@ public: static bool SetSignalSourceBufferPlaybackPosition(const std::string& SignalSourceID, float Time); static bool SetSignalSourceBufferLooping(const std::string& SignalSourceID, bool bLoop); + // Returns the ID of the signal source referring the given audio input channel. Invalid ID, if channel does not exist + static std::string GetAudioInputSignalSourceID(const int Channel); + static std::string CreateSignalSourcePrototype(UVAAbstractSignalSource* SignalSource); // Deletes a signal source with given ID. Use with great care! static bool DeleteSignalSource(const std::string& SignalSourceID); @@ -153,7 +156,7 @@ public: static AVAReceiverActor* GetReceiverActor(); - // ******* VAServer Launcher ******* // + // ******* VAServerLauncher ******* // static FVAServerLauncher VAServerLauncher; diff --git a/Source/VAPlugin/Private/VAReceiverActor.cpp b/Source/VAPlugin/Private/VAReceiverActor.cpp index 794ada27190d04c570d6986d4ffef87cab73edaf..3505eda61bd636786f58b547f5a761e6f9d013a3 100644 --- a/Source/VAPlugin/Private/VAReceiverActor.cpp +++ b/Source/VAPlugin/Private/VAReceiverActor.cpp @@ -57,7 +57,7 @@ void AVAReceiverActor::BeginPlay() if (bAutomaticRemoteVAStart) { FVAPlugin::VAServerLauncher.StartVAServerLauncher(); //if possible - bStartedVAServer = FVAPlugin::VAServerLauncher.RemoteStartVAServer(GetIPAddress(), RemoteVAStarterPort, WhichVAServerVersionToStart); + bStartedVAServer = FVAPlugin::VAServerLauncher.RemoteStartVAServer(GetIPAddress(), RemoteVAStarterPort, WhichVAServerVersionToStart, VARendererIniFile, ReproductionInputType); if(bStartedVAServer){ FVAPlugin::SetUseVA(true); } @@ -257,13 +257,28 @@ bool AVAReceiverActor::UpdateVirtualWorldPose() if(TrackingSource == ETrackingSource::VirtualRealityPawn) { - // Auralization Pose is coppled to the Virtual Reality Pawn, e.g, HMD, CAVE - FVector ViewPos; - FRotator ViewRot; - GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(ViewPos, ViewRot); + // Auralization Pose is coupled to the Virtual Reality Pawn, e.g, HMD, CAVE + + AVirtualRealityPawn* VirtualRealityPawn = Cast<AVirtualRealityPawn>(GetWorld()->GetFirstPlayerController()->AcknowledgedPawn); + if (VirtualRealityPawn == nullptr) + { + return false; + } + + USceneComponent* Head = VirtualRealityPawn->Head; + + if (!Head) + { + return false; + } + + FVector ViewPos = Head->GetComponentLocation(); + FRotator ViewRot = Head->GetComponentRotation(); + //Offset from ViewPoint (between eyes) to head center, rotate according to view rotation + ViewPos += ViewRot.RotateVector(ViewpointToHeadcenterOffset); bool bResult = true; - bResult &= FVAPlugin::SetSoundReceiverPosition(ReceiverID, ViewPos + ViewRot.RotateVector(ViewpointToHeadcenterOffset)); //Offset from ViewPoint (between eyes) to head center, rotate according to view rotation + bResult &= FVAPlugin::SetSoundReceiverPosition(ReceiverID, ViewPos); bResult &= FVAPlugin::SetSoundReceiverRotation(ReceiverID, ViewRot); return bResult; } @@ -518,6 +533,14 @@ bool AVAReceiverActor::CanEditChange(const FProperty* InProperty) const return AddressSetting == EConnectionSetting::Manual; } + if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, RemoteVAStarterPort) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, WhichVAServerVersionToStart) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, VARendererIniFile) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, ReproductionInputType)) + { + return bAutomaticRemoteVAStart; + } + if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, DirMappingFileName)) { return bReadInitialMappingFile; diff --git a/Source/VAPlugin/Private/VAServerLauncher.cpp b/Source/VAPlugin/Private/VAServerLauncher.cpp index a418dc26b840613352ba9e707ead52a409df3273..b8c38ff820470b8b6a4d0a55869993813fda840a 100644 --- a/Source/VAPlugin/Private/VAServerLauncher.cpp +++ b/Source/VAPlugin/Private/VAServerLauncher.cpp @@ -11,9 +11,10 @@ #include "VAUtils.h" #include "VASettings.h" #include "VAPlugin.h" +#include "HAL/FileManagerGeneric.h" -bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, const FString& VersionName) +bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, const FString& VersionName, const FString& VARendererIniFile, const EReproductionInput ReproductionInputType) { if (!UVirtualRealityUtilities::IsMaster()) { @@ -53,12 +54,30 @@ bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, } FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Successfully connected to Launcher", false); + const bool bSendVARendererIni = !VARendererIniFile.IsEmpty(); + if (bSendVARendererIni) + { + if (!SendFileToVAServer(VARendererIniFile)) + { + FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: VARenderer.ini file '" + VARendererIniFile + + "' could not be copied to VAServerLauncher. Does the file exist? See error log for additional info. VAServerLauncher will run with default settings.", true); + } + } + + + if (!SendReproductionInputSignalType(ReproductionInputType)) + { + FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: ReproductionInputType '" + EnumToString(ReproductionInputType) + + "' could not be sent to VAServerLauncher. See error log for additional info. VAServerLauncher will run with default settings.", true); + } + + //Send requested version - TArray<uint8> RequestData = ConvertString(VersionName); + TArray<uint8> RequestData = ConvertString(VersionName); int BytesSend = 0; VAServerLauncherSocket->Send(RequestData.GetData(), RequestData.Num(), BytesSend); FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Send " + FString::FromInt(BytesSend) + - " bytes to the VAServer Launcher, with version name: " + VersionName + " Waiting for answer.", false); + " bytes to the VAServerLauncher, with version name: " + VersionName + " Waiting for answer.", false); //Receive response const int32 BufferSize = 16; @@ -90,7 +109,7 @@ bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, VAServerLauncherSocket = nullptr; return false; default: - FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: Unexpected response from VAServer Launcher: " + + FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: Unexpected response from VAServerLauncher: " + FString(reinterpret_cast<char*>(&Response[0])), true); VAServerLauncherSocket = nullptr; return false; @@ -98,10 +117,11 @@ bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, } else { - FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Error while receiving response from VAServer Launcher", true); + FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Error while receiving response from VAServerLauncher", true); VAServerLauncherSocket = nullptr; return false; } + return true; } @@ -128,9 +148,36 @@ bool FVAServerLauncher::StartVAServerLauncher() FString LauncherScript = TEXT("VirtualAcousticsStarterServer.py"); if (FPaths::FileExists(FPaths::Combine(LauncherScriptDir, LauncherScript))) { - FString command = "cd/d "+ LauncherScriptDir+" & start python " + LauncherScript; - system(TCHAR_TO_ANSI(*command)); - return true; + FString CMDCommand = "cd/d " + LauncherScriptDir + " & "; + + //check whether py or python exist + auto DoesCommandExist = [&](FString Command) + { + //this checks whether a given command returns a result + FString TmpCmdResultFile = "tmpPyVersion.txt"; + TmpCmdResultFile = FPaths::Combine(LauncherScriptDir, TmpCmdResultFile); + Command = Command + " >> \"" + TmpCmdResultFile + "\""; + system(TCHAR_TO_ANSI(*Command)); + FString Result; + FFileHelper::LoadFileToString(Result, *TmpCmdResultFile); + IFileManager::Get().Delete(*TmpCmdResultFile); + return !Result.IsEmpty(); + }; + + bool bPyExists = DoesCommandExist("py --version"); + bool bPythonExists = DoesCommandExist("python --version"); + + if(bPythonExists || bPyExists) + { + FString Command = CMDCommand + "start " + (bPythonExists?"python":"py") + " " + LauncherScript; + system(TCHAR_TO_ANSI(*Command)); + return true; + } + else + { + FVAUtils::OpenMessageBox("VA Launcher cannot be started since neither \"py\" nor \"python\" can be found. If it is installed add it to PATH (and restart Visual Studio)", true); + return false; + } } else { @@ -166,16 +213,24 @@ bool FVAServerLauncher::SendFileToVAServer(const FString& RelativeFilename) } TArray<uint8> FileBinaryArray; - FFileHelper::LoadFileToArray(FileBinaryArray, *FPaths::Combine(FPaths::ProjectContentDir(),RelativeFilename)); + FFileHelper::LoadFileToArray(FileBinaryArray, *FPaths::Combine(FPaths::ProjectContentDir(),RelativeFilename)); + FString FullPath = FPaths::Combine(FPaths::ProjectContentDir(), RelativeFilename); + const TCHAR* charFilePath = *FullPath; + FFileManagerGeneric fm; + FDateTime LastModification = fm.GetTimeStamp(charFilePath); const FString ProjectName = GetDefault<UGeneralProjectSettings>()->ProjectName; - FString MetaInfo = "file:"+RelativeFilename+":"+FString::FromInt(FileBinaryArray.Num())+":"+ProjectName; + FString MetaInfo = "file:" + +RelativeFilename+":" + +FString::FromInt(FileBinaryArray.Num())+":" + +ProjectName+":" + +FString::FromInt(LastModification.ToUnixTimestamp()); TArray<uint8> MetaInfoBinary = ConvertString(MetaInfo); int32 BytesSend; VAServerLauncherSocket->Send(MetaInfoBinary.GetData(), MetaInfoBinary.Num(), BytesSend); //Receive response - const int32 BufferSize = 16; + const int32 BufferSize = 128; int32 BytesRead = 0; uint8 Response[16]; if (VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead)) @@ -193,7 +248,8 @@ bool FVAServerLauncher::SendFileToVAServer(const FString& RelativeFilename) } FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: Entire file ("+RelativeFilename+") send!", false); VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead); - if(BytesRead==3 && Response[0]=='a' && Response[1]=='c' && Response[2]=='k') + ResponseString = ByteArrayToString(Response, BytesRead); + if(ResponseString == "ack") { FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: File was received by VAServerLauncher successfully!", false); //the search path is added potenitally multiple times, but can only be added once the folder is created (which the above guarantees) @@ -244,6 +300,33 @@ bool FVAServerLauncher::IsVAServerLauncherConnected() return VAServerLauncherSocket!=nullptr; } +bool FVAServerLauncher::SendReproductionInputSignalType(const EReproductionInput ReproductionInputType) +{ + const FString ProjectName = GetDefault<UGeneralProjectSettings>()->ProjectName; + FString CommandMsg = "reproduction_input_type:" + EnumToString(ReproductionInputType); + TArray<uint8> CommandMsgBinary = ConvertString(CommandMsg); + + int32 BytesSend; + VAServerLauncherSocket->Send(CommandMsgBinary.GetData(), CommandMsgBinary.Num(), BytesSend); + + const int32 BufferSize = 16; + int32 BytesRead = 0; + uint8 Response[16]; + if (VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead)) + { + FString ResponseString = ByteArrayToString(Response, BytesRead); + if (ResponseString == "ack") + { + FVAUtils::LogStuff("[FVAServerLauncher::SendReproductionInputSignalType()]: ReproductionInputType was successfully received by VAServerLauncher!", false); + return true; + } + FVAUtils::LogStuff("[FVAServerLauncher::SendReproductionInputSignalType()]: ReproductionInputType not accepted by VAServerLauncher! Answer: " + ResponseString, false); + return false; + } + FVAUtils::LogStuff("[FVAServerLauncher::SendReproductionInputSignalType()]: VAServerLauncher did not answer!", true); + return false; +} + TArray<uint8> FVAServerLauncher::ConvertString(const FString& String) { TArray<uint8> RequestData; @@ -275,3 +358,19 @@ FString FVAServerLauncher::ByteArrayToString(const uint8* In, int32 Count) } return Result; } + +FString FVAServerLauncher::EnumToString(EReproductionInput Enum) +{ + switch (Enum) + { + case EReproductionInput::Binaural: + return TEXT("binaural"); + case EReproductionInput::Ambisonics: + return TEXT("ambisonics"); + case EReproductionInput::Custom: + return TEXT("custom"); + default: + return TEXT("invalid"); + } + +} diff --git a/Source/VAPlugin/Private/VAServerLauncher.h b/Source/VAPlugin/Private/VAServerLauncher.h index 69db7155dafbde41e233020a9fddbda2fe1e0642..13f112c47d7211628a70391d3f756f4429e00241 100644 --- a/Source/VAPlugin/Private/VAServerLauncher.h +++ b/Source/VAPlugin/Private/VAServerLauncher.h @@ -2,12 +2,14 @@ #include "Sockets.h" +#include "VAEnums.h" + class FVAServerLauncher { public: // Remote Start VAServer bool RemoteStartVAServer(const FString& Host, int Port, - const FString& VersionName); + const FString& VersionName, const FString& VARendererIni, const EReproductionInput ReproductionInputType); bool StartVAServerLauncher(); @@ -22,10 +24,14 @@ public: private: + bool SendReproductionInputSignalType(const EReproductionInput ReproductionInputType); + TArray<uint8> ConvertString(const FString& String); FString ByteArrayToString(const uint8* In, int32 Count); + static FString EnumToString(EReproductionInput Enum); + - //Socket connection to the VAServer Launcher, has to be held open until the program ends + //Socket connection to the VAServerLauncher, has to be held open until the program ends FSocket* VAServerLauncherSocket=nullptr; }; diff --git a/Source/VAPlugin/Public/SignalSources/VAAudioInputSignalSource.h b/Source/VAPlugin/Public/SignalSources/VAAudioInputSignalSource.h new file mode 100644 index 0000000000000000000000000000000000000000..603e4d14d1575d2eb0618d1797d6291d89fa43d2 --- /dev/null +++ b/Source/VAPlugin/Public/SignalSources/VAAudioInputSignalSource.h @@ -0,0 +1,28 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "SignalSources/VAAbstractSignalSource.h" +#include "VAAudioInputSignalSource.generated.h" + +/** + * + */ +UCLASS(ClassGroup = (VA)) +class VAPLUGIN_API UVAAudioInputSignalSource : public UVAAbstractSignalSource +{ + GENERATED_BODY() + +protected: + // Input channel used to stream into signal source + UPROPERTY(EditAnywhere, meta = (DisplayName = "Input Channel ID", Category = "Audio Input", ClampMin = "1")) + int Channel = 1; + +public: + UVAAudioInputSignalSource() = default; + + // Creates the signal source in VA and sets the ID accordingly + void Initialize() override; + +}; diff --git a/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h b/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h index a7639b52290a130887bc336dc08fc3af91f5f88b..38761bd3a30ed6061ec88f14ed5a3c039ba78942 100644 --- a/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h +++ b/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h @@ -5,10 +5,13 @@ #include "VAEnums.h" #include "../../Private/SignalSources/VAAudiofileManager.h" + +#include "Events/DisplayClusterEventWrapper.h" #include <string> #include "CoreMinimal.h" #include "SignalSources/VAAbstractSignalSource.h" + #include "VAAudiofileSignalSource.generated.h" @@ -22,6 +25,7 @@ class VAPLUGIN_API UVAAudiofileSignalSource : public UVAAbstractSignalSource public: UVAAudiofileSignalSource() = default; + ~UVAAudiofileSignalSource(); // Creates the signal source in VA and sets the ID accordingly void Initialize() override; @@ -58,8 +62,6 @@ public: bool SetLoop(bool bLoopN); UFUNCTION(BlueprintCallable) bool SetPlayBackPosition(float Time); - UFUNCTION(BlueprintCallable) - bool SetPlayAction(int Action); // *** Getter *** // @@ -68,10 +70,16 @@ public: FString GetFilename() const; UFUNCTION(BlueprintCallable) bool GetLoop() const; - UFUNCTION(BlueprintCallable) - EPlayAction::Type GetPlayActionEnum() const; - int GetPlayAction() const; + //CAUTION when used in cluster mode (e.g., CAVE): + // GetPlayActionEnum() might be one tick behind in cluster mode, since the current play action is only synced between master and slaves after this is called + // so make sure to, e.g., call this every frame or at least multiple times (if you, e.g., want to observe a change from play to pause) + // Alternatively, you can also set the bDirectOnMaster flag to get the status directly from the master, in that case you should make sure + // that everything is synced to the slaves, e.g., using sync components, as data will be delayed on the slaves!!! + UFUNCTION(BlueprintCallable) + EPlayAction::Type GetPlayActionEnum(bool bDirectOnMaster = false); + + // *** Events/Delegates *** // @@ -84,11 +92,6 @@ protected: // @return True on success bool CopySignalSourceSettings(const std::string& ID); -private: - FChangedAudiofileEvent AudiofileChangedEvent; - - -protected: // Action of the sound source at the first tick UPROPERTY(EditAnywhere, meta = (DisplayName = "Starting State", Category = "Audio file")) TEnumAsByte<EPlayAction::Type> StartingPlayAction = EPlayAction::Type::Stop; @@ -108,5 +111,16 @@ protected: bool bLoop = false; private: + + bool SetPlayAction(int Action); + int GetPlayAction(bool bDirectOnMaster=false); + + void StorePlayStateInternally(int PlayAction); + DECLARE_DISPLAY_CLUSTER_EVENT(UVAAudiofileSignalSource, StorePlayStateInternally); + int InterallyStoredPlayAction = -1; + + + FChangedAudiofileEvent AudiofileChangedEvent; + FVAAudiofileManager AudiofileManager; }; diff --git a/Source/VAPlugin/Public/SoundSource/VAAbstractSourceComponent.h b/Source/VAPlugin/Public/SoundSource/VAAbstractSourceComponent.h index fdc43f488dd05293d47550c73553acaa907aa0c0..4575805e77962f723c74eecedc5414cbe8debb6e 100644 --- a/Source/VAPlugin/Public/SoundSource/VAAbstractSourceComponent.h +++ b/Source/VAPlugin/Public/SoundSource/VAAbstractSourceComponent.h @@ -156,6 +156,12 @@ public: // Sets Directivity by a File Name, Passing a empty string "" removes the directivity, passing "default" sets the default directivity UFUNCTION(BlueprintCallable) bool SetDirectivityByFileName(FString FileName); + + UFUNCTION(BlueprintCallable) + bool SetDefaultDirectivity(); + + UFUNCTION(BlueprintCallable) + bool SetNoDirectivity(); // Gets the File Name of the Directivity UFUNCTION(BlueprintCallable) @@ -185,6 +191,7 @@ protected: // initialize Sound Source with the settings set // virtual void Initialize(); + void UpdateSkeletalMeshIfAttachToBone(); void UpdatePose(); bool SetSignalSourceID(const std::string& ID); @@ -198,6 +205,7 @@ protected: // Class data bool bFirstTick = true; bool bInitialized = false; + bool bInformedNotInitialized = false; float TimeSinceUpdate; bool ShouldSendCommand() const; float Timer; diff --git a/Source/VAPlugin/Public/SoundSource/VAAudioInputSourceComponent.h b/Source/VAPlugin/Public/SoundSource/VAAudioInputSourceComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..8c97ff80133f7a947db94ddd46ebe83bbb7d3ede --- /dev/null +++ b/Source/VAPlugin/Public/SoundSource/VAAudioInputSourceComponent.h @@ -0,0 +1,20 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "SoundSource/VAAbstractSourceComponent.h" +#include "VAAudioInputSourceComponent.generated.h" + +/** + * + */ +UCLASS(ClassGroup = (VA), meta = (BlueprintSpawnableComponent)) +class VAPLUGIN_API UVAAudioInputSourceComponent : public UVAAbstractSourceComponent +{ + GENERATED_BODY() +public: + + UVAAudioInputSourceComponent(); + +}; diff --git a/Source/VAPlugin/Public/VAEnums.h b/Source/VAPlugin/Public/VAEnums.h index 56f69caf060264c2d655adf729d7bc476b15a8b6..9e1ca33586d83d24af4bfa4cd92d30db45ba364c 100644 --- a/Source/VAPlugin/Public/VAEnums.h +++ b/Source/VAPlugin/Public/VAEnums.h @@ -34,6 +34,17 @@ namespace EConnectionSetting }; } +UENUM() +enum class EReproductionInput : uint8 +{ + // Use reproduction modules for binaural signals + Binaural, + // Use reproduction modules for ambisonics signals + Ambisonics, + // Use reproduction modules for custom purposes (e.g. mixed signal types) + Custom +}; + UENUM(BlueprintType) namespace EDirectivitySetting diff --git a/Source/VAPlugin/Public/VAReceiverActor.h b/Source/VAPlugin/Public/VAReceiverActor.h index ee7b7d59c2660d9ae7f8d841f58dc37f2cbd3a70..583ec5c9c7c458b53a2ca00901e57f040f3749a4 100644 --- a/Source/VAPlugin/Public/VAReceiverActor.h +++ b/Source/VAPlugin/Public/VAReceiverActor.h @@ -46,28 +46,55 @@ protected: UPROPERTY(EditAnywhere, meta = (DisplayName = "Ask for Debug mode?", Category = "General Settings")) bool bAskForDebugMode = false; - // Check if should try to use Python Automatic Remote star - UPROPERTY(EditAnywhere, meta = (DisplayName = "Use Automatic Remote VA Start via Python?", Category = "General Settings")) - bool bAutomaticRemoteVAStart = true; + // View point to head center offset (x forward-dir, y right-dir, z up-dir) in cm. Note that x and z most probably need to be negative! + UPROPERTY(EditAnywhere, meta = (Category = "General Settings")) + FVector ViewpointToHeadcenterOffset = FVector(0, 0, 0); + + // Source for tracking data, e.g., VirtualRealityPawn, ManualData (e.g., manually passed on from Optitrack) + UPROPERTY(EditAnywhere, meta = (Category = "General Settings")) + ETrackingSource TrackingSource = ETrackingSource::VirtualRealityPawn; + // Choose how to connect to the Server (automatic: build with windows connect with 127.0.0.1:12340, build with linux connect to cave) UPROPERTY(EditAnywhere, meta = (DisplayName = "Usecase", Category = "Connection")) TEnumAsByte<EConnectionSetting::Type> AddressSetting = EConnectionSetting::Type::Automatic; // IP Address for manual input - UPROPERTY(EditAnywhere, meta = (DisplayName = "IP Adress", Category = "Connection")) // CanEditChange used + UPROPERTY(EditAnywhere, meta = (DisplayName = "IP Adress", Category = "Connection")) FString ServerIPAddress = "10.0.1.240"; // Port for manual input - UPROPERTY(EditAnywhere, meta = (DisplayName = "Port [0, 65535]", Category = "Connection", // CanEditChange used + UPROPERTY(EditAnywhere, meta = (DisplayName = "Port [0, 65535]", Category = "Connection", ClampMin = "0", ClampMax = "65535", UIMin = "0", UIMax = "65535")) uint16 ServerPort = 12340; - // Port for manual input - UPROPERTY(EditAnywhere, meta = (Category = "Connection", DisplayName = "Always reconnect to VAServer when this level is started?")) + // Always reconnect to VAServer when this level is started? + UPROPERTY(EditAnywhere, meta = (Category = "Connection", DisplayName = "Automatic Reconnect")) bool bReconnecToVAServer = true; - // Read in File? + // Activate automatic remote VAServer start via Python (VAServerLauncher) + UPROPERTY(EditAnywhere, meta = (DisplayName = "Use VAServerLauncher", Category = "VAServerLauncher")) + bool bAutomaticRemoteVAStart = true; + + // Port for remote VAServerLauncher [0, 65535] + UPROPERTY(EditAnywhere, meta = (DisplayName = "VAServerLauncher Port", Category = "VAServerLauncher", + ClampMin = "0", ClampMax = "65535", UIMin = "0", UIMax = "65535")) + uint16 RemoteVAStarterPort = 41578; + + // ID for VAServer version being started automatically, configurable in the Config of the VAServerLauncher + UPROPERTY(EditAnywhere, meta = (DisplayName = "VAServer Version ID", Category = "VAServerLauncher")) + FString WhichVAServerVersionToStart = TEXT("2022.a"); + + // Ini file with VA renderer settings. File will be sent to VAServer launcher on startup if filename is not empty. + UPROPERTY(EditAnywhere, meta = (DisplayName = "VARenderer.ini file", Category = "VAServerLauncher")) + FString VARendererIniFile = TEXT(""); + + //Used to select the group of reproduction modules specified in VAServerLauncher config. + UPROPERTY(EditAnywhere, meta = (DisplayName = "Reproduction input signal type", Category = "VAServerLauncher")) + EReproductionInput ReproductionInputType = EReproductionInput::Binaural; + + + // Read an initial mapping file for directivities? UPROPERTY(EditAnywhere, meta = (DisplayName = "Read an initial mapping file?", Category = "Directivity Manager")) bool bReadInitialMappingFile = false; @@ -76,30 +103,9 @@ protected: UPROPERTY(EditAnywhere, meta = (DisplayName = "Name of ini file for directivities", Category = "Directivity Manager")) FString DirMappingFileName = ""; - // Port for remote VAServer starting - UPROPERTY(EditAnywhere, meta = (DisplayName = "Remote VAServer Start Port [0, 65535]", Category = "Connection", - // CanEditChange used - ClampMin = "0", ClampMax = "65535", UIMin = "0", UIMax = "65535")) - uint16 RemoteVAStarterPort = 41578; - - // Which version should be started automatically - UPROPERTY(EditAnywhere, meta = (DisplayName = - "Which VAServer version should be started, configurable in the Config of the VAServer Launcher", Category = - "General Settings")) - FString WhichVAServerVersionToStart = TEXT("2020.a"); - // Controller for global auraliztion modes UPROPERTY(EditAnywhere, Instanced, NoClear, meta = (DisplayName = "Auraliztion Mode Controller", Category = "Auralization Modes")) - UVAAuralizationModeController* AuralizationModeController; - - // View point to head center offset (x forward-dir, y right-dir, z up-dir) in cm. Note that x and z most probably need to be negative! - UPROPERTY(EditAnywhere, meta = (Category = "General Settings")) - FVector ViewpointToHeadcenterOffset = FVector(0, 0, 0); - - // Source for tracking data, e.g., VirtualRealityPawn, ManualData (e.g., manually passed on from Optitrack) - UPROPERTY(EditAnywhere, meta = (Category = "General Settings")) - ETrackingSource TrackingSource = ETrackingSource::VirtualRealityPawn; - + UVAAuralizationModeController* AuralizationModeController; public: diff --git a/Source/VAPlugin/Public/VASettings.h b/Source/VAPlugin/Public/VASettings.h index b217d9fca3c59ba7ae5faae749be8f5f6000c07c..cef52ca867030ad61e166f0327cf814318713658 100644 --- a/Source/VAPlugin/Public/VASettings.h +++ b/Source/VAPlugin/Public/VASettings.h @@ -11,7 +11,7 @@ class UVASettings : public UDeveloperSettings public: UPROPERTY(EditAnywhere, config, Category = "General", meta = (DisplayName = "Relative Path of this project to VAServer")) - FString VALauncherPath = "../VAServer"; + FString VALauncherPath = "../VAServerLauncher"; UPROPERTY(EditAnywhere, config, Category = "General", meta = (DisplayName = "Copy audio files over network to VAServer")) bool VALauncherCopyFiles = true; };