Skip to content
Snippets Groups Projects
Commit ec0774f1 authored by Philipp Schäfer's avatar Philipp Schäfer
Browse files

AudioSignalSource

- added manager for audiofiles which is to replace SignalBufferManager
- added Event which is bound by SoundSourceComponent to update internal VA signal source via id

Signal sources
- created function to check ID for validity

General
- changed some variable names to match Unreal syntax
parent 6089ffd4
No related branches found
No related tags found
No related merge requests found
Showing
with 298 additions and 71 deletions
......@@ -10,10 +10,15 @@ std::string UVAAbstractSignalSource::GetPrototypeName()
std::string UVAAbstractSignalSource::GetID() const
{
return sID;
return ID;
}
bool UVAAbstractSignalSource::IsValid() const
{
return !bool( FString(sID.c_str()).Equals(FString("-1")) );
return IsValidID(ID);
}
bool UVAAbstractSignalSource::IsValidID(const std::string& ID)
{
return !ID.empty() && ID != "-1";
}
......@@ -15,7 +15,7 @@ class UVAAbstractSignalSource : public UActorComponent
GENERATED_BODY()
protected:
std::string sID = "-1";
std::string ID = "-1";
bool bInitialized = false;
public:
......@@ -24,7 +24,8 @@ public:
// Creates the signal source in VA and sets the ID accordingly
virtual void Initialize() PURE_VIRTUAL(UVAAbstractSignalSource::Initialize, );
//used for prototype interface of VA, to implement arbitrary signal source
//Used for prototype interface of VA, to implement arbitrary signal source.
// Only overload in derived class if corresponding signal source can be created via prototype function
virtual std::string GetPrototypeName();
// Returns the VA signal source identifier (string)
......@@ -32,4 +33,6 @@ public:
// Checks whether this signal source was properly initialized and has a valid ID
bool IsValid() const;
static bool IsValidID(const std::string& ID);
};
#include "VAAudiofileManager.h"
#include "VAUtils.h"
#include "VAPlugin.h"
std::string FVAAudiofileManager::GetAudiofileSignalSourceID(FString Filename)
{
auto it = AudiofileIDMap.find(Filename);
if (it != AudiofileIDMap.end())
{
FVAUtils::LogStuff("[FVAAudiofileManager::GetAudiofileSignalSourceID()]: Signal source based on audiofile " + Filename + " was found!", false);
return it->second;
}
FVAUtils::LogStuff("[FVAAudiofileManager::GetAudiofileSignalSourceID()]: Signal source based on audiofile " +
Filename + " cannot be found! Creating one now...", false);
std::string ID = FVAPlugin::CreateNewBuffer(Filename);
if (ID == "-1")
{
FVAUtils::LogStuff("[FVAAudiofileManager::GetAudiofileSignalSourceID()]: Could not create signal source from audiofile " + Filename, true);
}
return ID;
}
bool FVAAudiofileManager::PreLoadAudiofile(FString Filename)
{
if (AudiofileIDMap.count(Filename))
{
FVAUtils::LogStuff("[FVAAudiofileManager::PreLoadAudiofile()]: Trying to pre-load file that has already been loaded: " + Filename, false);
return true;
}
std::string ID = FVAPlugin::CreateNewBuffer(Filename);
if (ID == "-1")
{
FVAUtils::LogStuff("[FVAAudiofileManager::PreLoadAudiofile()]: Could not create signal source from audiofile " + Filename, true);
return false;
}
FVAUtils::LogStuff("[FVAAudiofileManager::PreLoadAudiofile()]: Created signal source from audiofile " + Filename, false);
AudiofileIDMap[Filename] = ID;
return true;
}
// Class to manage all the Signal Buffer
#pragma once
#include <map>
#include <string>
class FVAAudiofileManager
{
public:
FVAAudiofileManager() = default;
// Returns the signal source ID referring to the given filename. Creates a new signal source if required.
// Returns "-1", if the signal source could not be created
std::string GetAudiofileSignalSourceID(FString Filename);
// Creates an audio file from the given filename (if not existing already) and stores it in the map
// Returns true on success.
bool PreLoadAudiofile(FString Filename);
private:
//Maps a filename to a given signal source ID
std::map<FString, std::string> AudiofileIDMap;
};
......@@ -18,15 +18,15 @@ void UVAAudiofileSignalSource::Initialize()
return;
}
sID = FVAPlugin::CreateNewBuffer(SoundFile, bLoop, StartingTime);
if (sID == "-1")
ID = FVAPlugin::CreateNewBuffer(SoundFile, bLoop, StartingTime);
if (!IsValidID(ID))
{
FVAUtils::LogStuff("[UVAAudiofileSignalSource::Initialize()]: Error creating Audiofile Signal Source", true);
return;
}
bInitialized = true;
if (!FVAPlugin::SetSoundBufferAction(sID, StartingPlayAction))
if (!FVAPlugin::SetSoundBufferAction(ID, StartingPlayAction))
FVAUtils::LogStuff("[UVAAudiofileSignalSource::Initialize()]: Could not set Play Action during initializing", true);
}
......@@ -57,11 +57,43 @@ bool UVAAudiofileSignalSource::Stop()
return SetPlayAction(EPlayAction::Stop);
}
bool UVAAudiofileSignalSource::LoadAudiofile(FString Filename)
{
return false;
}
// ****************************************************************** //
// ******* Setter Functions ***************************************** //
// ****************************************************************** //
bool UVAAudiofileSignalSource::SetAudiofile(FString Filename)
{
std::string NewID = AudiofileManager.GetAudiofileSignalSourceID(Filename);
if (!IsValidID(NewID))
{
FVAUtils::LogStuff("[UVAAudiofileSignalSource::SetAudiofile()]: Audiofile " + Filename + " was loaded incorrectly!", true);
return false;
}
if (ID == NewID)
{
//TODO: Should the signal source really be stopped here as in old version?
//Stop();
return true;
}
if (!CopySignalSourceSettings(NewID))
{
FVAUtils::LogStuff("[UVAAudiofileSignalSource::SetAudiofile()]: Could not copy settings to signal source of new audiofile: " + Filename, true);
return false;
}
ID = NewID;
AudiofileChangedEvent.Broadcast(ID);
return true;
}
bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN)
{
if (!FVAPlugin::GetIsMaster())
......@@ -75,16 +107,16 @@ bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN)
}
bLoop = bLoopN;
return FVAPlugin::SetSoundBufferLoop(sID, bLoop);
return FVAPlugin::SetSoundBufferLoop(ID, bLoop);
}
bool UVAAudiofileSignalSource::SetPlayBackPosition(const float fTime)
bool UVAAudiofileSignalSource::SetPlayBackPosition(const float Time)
{
if (!FVAPlugin::GetIsMaster())
{
return false;
}
return FVAPlugin::SetSoundBufferTime(sID, fTime);
return FVAPlugin::SetSoundBufferTime(ID, Time);
}
bool UVAAudiofileSignalSource::SetPlayAction(const int Action)
......@@ -98,7 +130,7 @@ bool UVAAudiofileSignalSource::SetPlayAction(const int Action)
{
return true;
}
return FVAPlugin::SetSoundBufferAction(sID, EPlayAction::Type(Action));
return FVAPlugin::SetSoundBufferAction(ID, EPlayAction::Type(Action));
}
......@@ -123,5 +155,24 @@ int UVAAudiofileSignalSource::GetPlayAction() const
{
return -1;
}
return FVAPlugin::GetSoundBufferAction(sID);
return FVAPlugin::GetSoundBufferAction(ID);
}
bool UVAAudiofileSignalSource::CopySignalSourceSettings(const std::string& OtherID)
{
if (!FVAPlugin::GetIsMaster())
{
return false;
}
if (!FVAPlugin::SetSoundBufferLoop(OtherID, bLoop))
{
return false;
}
int PlayAction = GetPlayAction();
if (PlayAction == -1)
{
return false;
}
return FVAPlugin::SetSoundBufferAction(OtherID, EPlayAction::Type(PlayAction));
}
......@@ -16,8 +16,8 @@ void UVAJetEngineSignalSource::Initialize()
}
sID = FVAPlugin::CreateSignalSourcePrototype(this);
if (sID == "-1")
ID = FVAPlugin::CreateSignalSourcePrototype(this);
if (!IsValidID(ID))
{
FVAUtils::LogStuff("[UVAJetEngineSignalSource::Initialize()]: Error initializing Jet Engine Signal Source", true);
return;
......@@ -26,7 +26,7 @@ void UVAJetEngineSignalSource::Initialize()
bInitialized = true;
if (!FVAPlugin::SetSignalSourceParameter(sID, "rpm", JetRPM))
if (!FVAPlugin::SetSignalSourceParameter(ID, "rpm", JetRPM))
{
FVAUtils::LogStuff("[UVAJetEngineSignalSource::Initialize()]: Could not set Jet RPM during initialization", true);
}
......@@ -37,15 +37,15 @@ std::string UVAJetEngineSignalSource::GetPrototypeName()
return "jet_engine";
}
bool UVAJetEngineSignalSource::SetJetRPM(float fRPM)
bool UVAJetEngineSignalSource::SetJetRPM(float RPM)
{
if (!bInitialized)
return false;
if (!FVAPlugin::SetSignalSourceParameter(sID, "rpm", fRPM))
if (!FVAPlugin::SetSignalSourceParameter(ID, "rpm", RPM))
return false;
JetRPM = fRPM;
JetRPM = RPM;
return true;
}
......
......@@ -31,6 +31,7 @@ UVASourceComponent::UVASourceComponent()
void UVASourceComponent::OnComponentCreated()
{
Super::OnComponentCreated();
ForceUpdateSignalSourceType(SignalSourceType);
}
......@@ -38,11 +39,13 @@ void UVASourceComponent::OnComponentCreated()
void UVASourceComponent::BeginPlay()
{
Super::BeginPlay();
BindSignalSourceEvents();
}
void UVASourceComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
SoundSource.Reset();
UnbindSignalSourceEvents();
}
......@@ -155,8 +158,10 @@ void UVASourceComponent::Initialize()
SpawnRotation = GetOwner()->GetTransform().GetRotation().Rotator();
if (SignalSource)
{
SignalSource->Initialize();
}
TArray<AVAReflectionWall*> WallArray = CurrentReceiverActor->GetReflectionWalls();
SoundSource = MakeShared<FVASoundSource>(this, WallArray);
......@@ -190,8 +195,58 @@ void UVASourceComponent::Initialize()
bool UVASourceComponent::ForceUpdateSignalSourceType(TSubclassOf<UVAAbstractSignalSource> SignalSourceTypeN)
{
SignalSourceType = nullptr;
return SetSignalSourceType(SignalSourceTypeN);
if (SignalSource != nullptr)
{
UnbindSignalSourceEvents();
SignalSource->Rename(*MakeUniqueObjectName(this, UVAAbstractSignalSource::StaticClass(), "Settings_EXPIRED").ToString());
SignalSource->MarkPendingKill();
SignalSource = nullptr;
}
if (SignalSourceTypeN == UVAAudiofileSignalSource::StaticClass())
{
SignalSource = NewObject<UVAAbstractSignalSource>(this, SignalSourceTypeN);
}
else if (SignalSourceTypeN == UVAJetEngineSignalSource::StaticClass())
{
SignalSource = NewObject<UVAAbstractSignalSource>(this, SignalSourceTypeN);
}
else if (SignalSourceTypeN != nullptr)
{
FVAUtils::OpenMessageBox("[UVASourceComponent::PostEditChangeProperty()]: Signal source type is not supported", true);
return false;
}
SignalSourceType = SignalSourceTypeN;
BindSignalSourceEvents();
return true;
}
void UVASourceComponent::SetSignalSourceID(const std::string& ID)
{
//TODO: Implement
}
void UVASourceComponent::BindSignalSourceEvents()
{
UVAAudiofileSignalSource* AudioSignalSource = Cast<UVAAudiofileSignalSource>(SignalSource);
if (AudioSignalSource && !AudioSignalSource->OnAudiofileChanged().IsBoundToObject(this))
{
SignalSourceChangedDelegate = AudioSignalSource->OnAudiofileChanged().AddUObject(this, &UVASourceComponent::SetSignalSourceID);
}
}
void UVASourceComponent::UnbindSignalSourceEvents()
{
if (SignalSourceChangedDelegate.IsValid())
{
UVAAudiofileSignalSource* AudioSignalSource = Cast<UVAAudiofileSignalSource>(SignalSource);
if (AudioSignalSource)
{
AudioSignalSource->OnAudiofileChanged().Remove(SignalSourceChangedDelegate);
}
SignalSourceChangedDelegate.Reset();
}
}
bool UVASourceComponent::ShouldSendCommand() const
......@@ -259,29 +314,7 @@ bool UVASourceComponent::SetSignalSourceType(TSubclassOf<UVAAbstractSignalSource
if(SignalSourceType == SignalSourceTypeN)
return true;
if (SignalSource != nullptr)
{
SignalSource->Rename(*MakeUniqueObjectName(this, UVAAbstractSignalSource::StaticClass(), "Settings_EXPIRED").ToString());
SignalSource->MarkPendingKill();
SignalSource = nullptr;
}
if (SignalSourceTypeN == UVAAudiofileSignalSource::StaticClass())
{
SignalSource = NewObject<UVAAbstractSignalSource>(this, SignalSourceTypeN);
}
else if (SignalSourceTypeN == UVAJetEngineSignalSource::StaticClass())
{
SignalSource = NewObject<UVAAbstractSignalSource>(this, SignalSourceTypeN);
}
else
{
FVAUtils::OpenMessageBox("[UVASourceComponent::PostEditChangeProperty()]: Signal source type is not supported", true);
return false;
}
SignalSourceType = SignalSourceTypeN;
return true;
return ForceUpdateSignalSourceType(SignalSourceTypeN);
}
......@@ -671,12 +704,24 @@ float UVASourceComponent::GetSoundTimeOffset() const
#if WITH_EDITOR
void UVASourceComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
void UVASourceComponent::PreEditChange(UProperty* PropertyWhatWillChange)
{
if (PropertyChangedEvent.GetPropertyName() != GET_MEMBER_NAME_CHECKED(UVASourceComponent, SignalSourceType))
return;
//If user directly changes the signal source component to "None"
if (PropertyWhatWillChange->GetFName() == GET_MEMBER_NAME_CHECKED(UVASourceComponent, SignalSource))
{
UnbindSignalSourceEvents();
SignalSourceType = nullptr;
}
Super::PreEditChange(PropertyWhatWillChange);
}
void UVASourceComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UVASourceComponent, SignalSourceType))
{
ForceUpdateSignalSourceType(SignalSourceType);
}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
......
......@@ -3,11 +3,15 @@
#pragma once
#include "VAEnums.h"
#include "../../Private/SignalSources/VAAudiofileManager.h"
#include <string>
#include "CoreMinimal.h"
#include "SignalSources/VAAbstractSignalSource.h"
#include "VAAudiofileSignalSource.generated.h"
/**
*
*/
......@@ -16,29 +20,14 @@ class VAPLUGIN_API UVAAudiofileSignalSource : public UVAAbstractSignalSource
{
GENERATED_BODY()
protected:
// Action of the sound source at the first tick
UPROPERTY(EditAnywhere, meta = (DisplayName = "Action", Category = "Audio file"))
TEnumAsByte<EPlayAction::Type> StartingPlayAction = EPlayAction::Type::Stop;
// Name of Sound file. Folder are possible too: "folder/soundfile.wav"
UPROPERTY(EditAnywhere, meta = (DisplayName = "Filename", Category = "Audio file"))
FString SoundFile = "WelcomeToVA.wav";
// Sets Buffer to a specific time stamp when playing back at the first tick (see Action)
UPROPERTY(EditAnywhere, meta = (DisplayName = "Play from x [s]", Category = "Audio file"))
float StartingTime = 0.0f;
// Check if the sound should be played back in a loop
UPROPERTY(EditAnywhere, meta = (DisplayName = "Loop", Category = "Audio file"))
bool bLoop = false;
public:
UVAAudiofileSignalSource() = default;
// Creates the signal source in VA and sets the ID accordingly
void Initialize() override;
// *** Playback Settings *** //
UFUNCTION(BlueprintCallable)
bool Play();
UFUNCTION(BlueprintCallable)
......@@ -48,14 +37,65 @@ public:
UFUNCTION(BlueprintCallable)
bool Stop();
// Setter
// *** Audiofile related *** //
UFUNCTION(BlueprintCallable)
// (Pre-) loads an audiofile for later usage
// Internally, VA creates a signal source and the ID is stored. See FVAAudiofileManager
// @return True on success
bool LoadAudiofile(FString Filename);
UFUNCTION(BlueprintCallable)
// Switches the internal signal source to match the corresponding ID. Creates a new signal source, if audiofile is not pre-loaded.
// Raises an even broadcasting the ID of the internal audiofile signal source which is "-1", if signal source could not be created.
// @return True on success
bool SetAudiofile(FString Filename);
// *** Setter *** //
bool SetLoop(bool bLoopN);
bool SetPlayBackPosition(float fTime);
bool SetPlayAction(int iAction);
bool SetPlayBackPosition(float Time);
bool SetPlayAction(int Action);
// Getter
// *** Getter *** //
FString GetFileName() const;
bool GetLoop() const;
int GetPlayAction() const;
// *** Events/Delegates *** //
DECLARE_EVENT_OneParam(UVAAudiofileSignalSource, FChangedAudiofileEvent, const std::string&)
//Get the delegate for the event broadcasted on an audiofile change, which provides the new signal source ID
FChangedAudiofileEvent& OnAudiofileChanged() { return AudiofileChangedEvent; }
protected:
// Copies the loop bool and play action of the current signal source to the one with given ID
// @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 = "Action", Category = "Audio file"))
TEnumAsByte<EPlayAction::Type> StartingPlayAction = EPlayAction::Type::Stop;
// Name of Sound file. Folder are possible too: "folder/soundfile.wav"
UPROPERTY(EditAnywhere, meta = (DisplayName = "Filename", Category = "Audio file"))
FString SoundFile = "WelcomeToVA.wav";
// Sets Buffer to a specific time stamp when playing back at the first tick (see Action)
UPROPERTY(EditAnywhere, meta = (DisplayName = "Play from x [s]", Category = "Audio file"))
float StartingTime = 0.0f;
// Check if the sound should be played back in a loop
UPROPERTY(EditAnywhere, meta = (DisplayName = "Loop", Category = "Audio file"))
bool bLoop = false;
private:
FVAAudiofileManager AudiofileManager;
};
......@@ -27,7 +27,7 @@ public:
std::string GetPrototypeName() override;
// Sets the rounds per minute (RPM) of the jet
bool SetJetRPM(float fRPM);
bool SetJetRPM(float RPM);
// Returns the rounds per minute (RPM) of the jet
float GetJetRPM() const;
......
......@@ -9,6 +9,8 @@
#include "GameFramework/Actor.h"
#include "SharedPointer.h"
#include <string>
#include "VASourceComponent.generated.h"
//forward declarations to not include private header files
......@@ -257,6 +259,15 @@ protected:
bool ForceUpdateSignalSourceType(TSubclassOf<UVAAbstractSignalSource> SignalSourceTypeN);
void SetSignalSourceID(const std::string& ID);
// *** Event/Delegates *** //
void BindSignalSourceEvents();
void UnbindSignalSourceEvents();
AVAReceiverActor* CurrentReceiverActor;
TSharedPtr<FVASoundSource> SoundSource;
......@@ -276,7 +287,10 @@ protected:
bool bMuted = false;
int UpdateRate;
FDelegateHandle SignalSourceChangedDelegate;
#if WITH_EDITOR
virtual void PreEditChange(UProperty* PropertyWhatWillChange) override;
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
// Function to improve settings displayed in Editor, can only be used in editor mode
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment