newly updated FMODStudio plugin for UE5.3 migration

This commit is contained in:
Ji Yoon Rhee
2025-02-02 00:35:31 +09:00
parent 6ec77258e3
commit 547689631f
296 changed files with 4467 additions and 4042 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
@ -139,6 +139,7 @@ class FMODSTUDIO_API UFMODAudioComponent : public USceneComponent
GENERATED_UCLASS_BODY()
friend struct FFMODEventControlExecutionToken;
friend struct FPlayingToken;
friend FMOD_RESULT F_CALLBACK UFMODAudioComponent_EventCallback(FMOD_STUDIO_EVENT_CALLBACK_TYPE type, FMOD_STUDIO_EVENTINSTANCE *event, void *parameters);
public:
@ -223,6 +224,10 @@ public:
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
void SetPaused(bool paused);
/** Get the paused state of the audio component. Returns false if internal getPaused query fails. */
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
bool GetPaused();
/** Set a parameter of the Event. */
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
void SetParameter(FName Name, float Value);
@ -279,36 +284,67 @@ public:
/** Actual Studio instance handle. */
FMOD::Studio::EventInstance *StudioInstance;
// Begin UObject interface.
// Begin UObject interface.
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent &e) override;
#endif // WITH_EDITOR
virtual void PostLoad() override;
// End UObject interface.
// End UObject interface.
// Begin USceneComponent Interface
// Begin USceneComponent Interface
virtual void Activate(bool bReset = false) override;
virtual void Deactivate() override;
// End USceneComponent Interface
/** Called when a component is registered, after Scene is set, but before CreateRenderState_Concurrent or OnCreatePhysicsState are called. */
virtual void OnRegister() override;
/** Called when a component is unregistered. Called after DestroyRenderState_Concurrent and OnDestroyPhysicsState are called. */
virtual void OnUnregister() override;
// End USceneComponent Interface
// Begin ActorComponent interface.
/** Overridable native event for when play begins for this actor. */
virtual void BeginPlay() override;
/** Overridable function called whenever this actor is being removed from a level. */
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
/** Function called every frame on this ActorComponent. Only executes if the component is registered, and also PrimaryComponentTick.bCanEverTick must be set to true. */
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
// End ActorComponent interface.
protected:
// Begin UObject interface.
// Begin UObject interface.
virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
// End UObject interface.
// End UObject interface.
// Begin USceneComponent Interface
// Begin USceneComponent Interface
virtual FString GetDetailedInfoInternal() const override;
// End USceneComponent Interface
// End USceneComponent Interface
private:
bool bDefaultParameterValuesCached;
enum PauseContext
{
Explicit,
Implicit
};
/** Used for pausing from sequencer. */
bool bImplicitlyPaused = false;
/** Used for pausing from a direct call to pause. */
bool bExplicitlyPaused = false;
/** Stored properties to apply next time we create an instance. */
float StoredProperties[EFMODEventProperty::Count];
/** Internal play function which can play events in the editor. */
void PlayInternal(EFMODSystemContext::Type Context, bool bReset = false);
/** Pause the audio component from a sequencer call. */
void PauseInternal(PauseContext Pauser);
/** Resume the audio component from a sequencer call. */
void ResumeInternal(PauseContext Pauser);
/** Cache default event parameter values. */
void CacheDefaultParameterValues();
@ -342,24 +378,15 @@ private:
void EventCallbackSoundStopped();
bool TriggerSoundStoppedDelegate;
// Begin ActorComponent interface.
/** Called when a component is registered, after Scene is set, but before CreateRenderState_Concurrent or OnCreatePhysicsState are called. */
virtual void OnRegister() override;
/** Called when a component is unregistered. Called after DestroyRenderState_Concurrent and OnDestroyPhysicsState are called. */
virtual void OnUnregister() override;
/** Overridable function called whenever this actor is being removed from a level. */
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
/** Function called every frame on this ActorComponent. Only executes if the component is registered, and also PrimaryComponentTick.bCanEverTick must be set to true. */
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
// End ActorComponent interface.
#if WITH_EDITORONLY_DATA
void UpdateSpriteTexture();
#endif
#if WITH_EDITOR
/** Function assigned to the FMODStudioModule PreShutdown delegate to clean up before the Studio System is released. */
void Shutdown();
#endif
/** Release any cached parameters then the Studio Instance. */
void ReleaseEventCache();
@ -422,4 +449,10 @@ private:
bool NeedDestroyProgrammerSoundCallback;
/** The length of the current Event in milliseconds. */
int32 EventLength;
/** To prevent restarting by delayed state restore from sequencer. */
bool bPlayEnded;
FVector Velocity;
FVector LastLocation;
};

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
@ -232,7 +232,7 @@ public:
/**
* Enable live update in Editor for Auditioning. *Requires Restart*
*/
UPROPERTY(Config, EditAnywhere, Category = Basic)
UPROPERTY(Config, EditAnywhere, Category = Basic, meta = (ConfigRestartRequired = true))
bool bEnableEditorLiveUpdate;
/**
@ -258,13 +258,7 @@ public:
TArray<FFMODProjectLocale> Locales;
/**
* Whether to enable vol0virtual, which means voices with low volume will automatically go virtual to save CPU.
*/
UPROPERTY(config, EditAnywhere, Category = InitSettings)
bool bVol0Virtual;
/**
* If vol0virtual is enabled, the signal level at which to make channels virtual.
* The signal level at which channels are virtualized. Virtual channels are processed, but do not produce any output.
*/
UPROPERTY(config, EditAnywhere, Category = InitSettings)
float Vol0VirtualLevel;
@ -348,7 +342,7 @@ public:
/**
* Live update port to use while in editor for auditioning. *Requires Restart*
*/
UPROPERTY(config, EditAnywhere, Category = Advanced, meta = (EditCondition = "bEnableEditorLiveUpdate"))
UPROPERTY(config, EditAnywhere, Category = Advanced, meta = (EditCondition = "bEnableEditorLiveUpdate", ConfigRestartRequired = true))
int32 EditorLiveUpdatePort;
/**
@ -439,6 +433,12 @@ public:
UPROPERTY(config, EditAnywhere, Category = Advanced)
FString AmbientLPFParameter;
/**
* Enables/Disables the FMODAudioLink modules.
*/
UPROPERTY(config, EditAnywhere, Category = Advanced, meta = (ConfigRestartRequired=true))
bool bFMODAudioLinkEnabled;
/*
* Used to specify platform specific settings.
*/
@ -505,5 +505,7 @@ private:
};
EProblem Check() const;
virtual void PostEditChangeProperty(FPropertyChangedEvent& e) override;
#endif // WITH_EDITOR
};

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
using UnrealBuildTool;
using System;
using System.IO;
@ -229,6 +229,9 @@ namespace UnrealBuildTool.Rules
}
}
}
FMODAudioLink.Apply(this, Target);
FMODAudioLinkEditor.Apply(this, Target);
}
private System.Collections.Generic.List<string> GetPlugins(string BasePath)
@ -255,5 +258,18 @@ namespace UnrealBuildTool.Rules
}
return AllPlugins;
}
public void AddModule(string Module, bool AddPublic = true)
{
ConditionalAddModuleDirectory(
EpicGames.Core.DirectoryReference.Combine(new EpicGames.Core.DirectoryReference(ModuleDirectory), "..", Module));
ExternalDependencies.Add(Path.Combine(ModuleDirectory, "..", Module, Module + ".Build.cs"));
if (AddPublic)
{
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "..", Module, "Public"));
}
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "..", Module, "Private"));
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAmbientSound.h"
#include "FMODEvent.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAsset.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAssetTable.h"
@ -20,7 +20,8 @@
#include "UObject/Package.h"
FFMODAssetTable::FFMODAssetTable()
: BankLookup(nullptr),
: ActiveLocale(FString()),
BankLookup(nullptr),
AssetLookup(nullptr)
{
}
@ -56,17 +57,16 @@ void FFMODAssetTable::Load()
}
else
{
TCHAR msg[] = TEXT("Failed to load bank lookup");
if (IsRunningCommandlet())
{
// If we're running in a commandlet (maybe we're cooking or running FMODGenerateAssets
// commandlet) Display a message but don't cause the build to Error out.
UE_LOG(LogFMOD, Display, msg);
UE_LOG(LogFMOD, Display, TEXT("Failed to load bank lookup"));
}
else
{
// If we're running in game or in editor, log this as an Error
UE_LOG(LogFMOD, Error, msg);
UE_LOG(LogFMOD, Error, TEXT("Failed to load bank lookup"));
}
}
@ -81,17 +81,16 @@ void FFMODAssetTable::Load()
}
else
{
TCHAR msg[] = TEXT("Failed to load asset lookup");
if (IsRunningCommandlet())
{
// If we're running in a commandlet (maybe we're cooking or running FMODGenerateAssets
// commandlet) Display a message but don't cause the build to Error out.
UE_LOG(LogFMOD, Display, msg);
UE_LOG(LogFMOD, Display, TEXT("Failed to load asset lookup"));
}
else
{
// If we're running in game or in editor, log this as an Error
UE_LOG(LogFMOD, Error, msg);
UE_LOG(LogFMOD, Error, TEXT("Failed to load asset lookup"));
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAudioComponent.h"
#include "FMODStudioModule.h"
@ -43,6 +43,9 @@ UFMODAudioComponent::UFMODAudioComponent(const FObjectInitializer &ObjectInitial
, ProgrammerSound(nullptr)
, NeedDestroyProgrammerSoundCallback(false)
, EventLength(0)
, bPlayEnded(false)
, Velocity(ForceInit)
, LastLocation(ForceInit)
{
bAutoActivate = true;
bNeverNeedsRenderUpdate = true;
@ -160,7 +163,7 @@ void UFMODAudioComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransfor
attr.position = FMODUtils::ConvertWorldVector(GetComponentTransform().GetLocation());
attr.up = FMODUtils::ConvertUnitVector(GetComponentTransform().GetUnitAxis(EAxis::Z));
attr.forward = FMODUtils::ConvertUnitVector(GetComponentTransform().GetUnitAxis(EAxis::X));
attr.velocity = FMODUtils::ConvertWorldVector(GetOwner()->GetVelocity());
attr.velocity = FMODUtils::ConvertWorldVector(Velocity);
StudioInstance->set3DAttributes(&attr);
@ -185,7 +188,7 @@ void UFMODAudioComponent::UpdateInteriorVolumes()
FInteriorSettings *Ambient =
(FInteriorSettings *)alloca(sizeof(FInteriorSettings)); // FinteriorSetting::FInteriorSettings() isn't exposed (possible UE4 bug???)
const FVector &Location = GetOwner()->GetTransform().GetTranslation();
const FVector &Location = GetComponentLocation();
AAudioVolume *AudioVolume = GetWorld()->GetAudioSettings(Location, NULL, Ambient);
const FFMODListener &Listener = GetStudioModule().GetNearestListener(Location);
@ -275,7 +278,7 @@ void UFMODAudioComponent::UpdateAttenuation()
static FName NAME_SoundOcclusion = FName(TEXT("SoundOcclusion"));
FCollisionQueryParams Params(NAME_SoundOcclusion, OcclusionDetails.bUseComplexCollisionForOcclusion, GetOwner());
const FVector &Location = GetOwner()->GetTransform().GetTranslation();
const FVector &Location = GetComponentLocation();
const FFMODListener &Listener = GetStudioModule().GetNearestListener(Location);
bool bIsOccluded = GWorld->LineTraceTestByChannel(Location, Listener.Transform.GetLocation(), OcclusionDetails.OcclusionTraceChannel, Params);
@ -340,7 +343,7 @@ void UFMODAudioComponent::CacheDefaultParameterValues()
Event->GetParameterDescriptions(ParameterDescriptions);
for (const FMOD_STUDIO_PARAMETER_DESCRIPTION &ParameterDescription : ParameterDescriptions)
{
if (ShouldCacheParameter(ParameterDescription))
if (!ParameterCache.Find(ParameterDescription.name) && ShouldCacheParameter(ParameterDescription))
{
ParameterCache.Add(ParameterDescription.name, ParameterDescription.defaultvalue);
}
@ -377,8 +380,19 @@ void UFMODAudioComponent::OnUnregister()
Super::OnUnregister();
}
void UFMODAudioComponent::BeginPlay()
{
#if WITH_EDITOR
IFMODStudioModule::Get().PreEndPIEEvent().AddUObject(this, &UFMODAudioComponent::Shutdown);
#endif
Super::BeginPlay();
}
void UFMODAudioComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
#if WITH_EDITOR
IFMODStudioModule::Get().PreEndPIEEvent().RemoveAll(this);
#endif
Super::EndPlay(EndPlayReason);
bool shouldStop = false;
@ -407,12 +421,24 @@ void UFMODAudioComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
OnEventStopped.Broadcast();
}
Release();
bPlayEnded = true;
}
void UFMODAudioComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (DeltaTime > 0.f)
{
FVector pos = GetComponentTransform().GetTranslation();
if (LastLocation != FVector::ZeroVector)
{
Velocity = (pos - LastLocation) / DeltaTime;
}
LastLocation = pos;
}
if (IsActive())
{
FMOD_STUDIO_PLAYBACK_STATE state = FMOD_STUDIO_PLAYBACK_STOPPED;
@ -709,7 +735,8 @@ void UFMODAudioComponent::PlayInternal(EFMODSystemContext::Type Context, bool bR
{
Stop();
if (!FMODUtils::IsWorldAudible(GetWorld(), Context == EFMODSystemContext::Editor))
if (!FMODUtils::IsWorldAudible(GetWorld(), Context == EFMODSystemContext::Editor
|| Context == EFMODSystemContext::Auditioning))
{
return;
}
@ -802,6 +829,37 @@ void UFMODAudioComponent::PlayInternal(EFMODSystemContext::Type Context, bool bR
}
}
void UFMODAudioComponent::PauseInternal(PauseContext Pauser)
{
if (Pauser == Implicit)
{
bImplicitlyPaused = true;
}
if (Pauser == Explicit)
{
bExplicitlyPaused = true;
}
SetPaused(true);
}
void UFMODAudioComponent::ResumeInternal(PauseContext Pauser)
{
if (GetPaused())
{
if (Pauser == Implicit)
{
bImplicitlyPaused = false;
}
if (Pauser == Explicit)
{
bExplicitlyPaused = false;
}
SetPaused(bImplicitlyPaused || bExplicitlyPaused);
}
}
void UFMODAudioComponent::Stop()
{
UE_LOG(LogFMOD, Verbose, TEXT("UFMODAudioComponent %p Stop"), this);
@ -818,6 +876,14 @@ void UFMODAudioComponent::Release()
ReleaseEventInstance();
}
#if WITH_EDITOR
void UFMODAudioComponent::Shutdown()
{
Stop();
Release();
}
#endif
void UFMODAudioComponent::ReleaseEventCache()
{
ParameterCache.Empty();
@ -917,6 +983,20 @@ void UFMODAudioComponent::SetPaused(bool Paused)
}
}
bool UFMODAudioComponent::GetPaused()
{
bool Paused = false;
if (StudioInstance)
{
FMOD_RESULT Result = StudioInstance->getPaused(&Paused);
if (Result != FMOD_OK)
{
UE_LOG(LogFMOD, Warning, TEXT("Failed to get paused state"));
}
}
return Paused;
}
void UFMODAudioComponent::SetParameter(FName Name, float Value)
{
if (StudioInstance)

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODBank.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODBlueprintStatics.h"
#include "FMODAudioComponent.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODBus.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEvent.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODListener.h"
#include "Misc/App.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
#include "Containers/UnrealString.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODPort.h"
#include "FMODStudioModule.h"

View File

@ -1,10 +1,11 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODSettings.h"
#include "Misc/Paths.h"
#if WITH_EDITOR
#include "Settings/ProjectPackagingSettings.h"
#include <ObjectTools.h>
#endif
#ifdef FMOD_PLATFORM_HEADER
@ -43,7 +44,6 @@ UFMODSettings::UFMODSettings(const FObjectInitializer &ObjectInitializer)
, bEnableEditorLiveUpdate(false)
, OutputFormat(EFMODSpeakerMode::Surround_5_1)
, OutputType(EFMODOutput::TYPE_AUTODETECT)
, bVol0Virtual(true)
, Vol0VirtualLevel(0.001f)
, SampleRate(0)
, bMatchHardwareSampleRate(true)
@ -62,6 +62,7 @@ UFMODSettings::UFMODSettings(const FObjectInitializer &ObjectInitializer)
, ContentBrowserPrefix(TEXT("/Game/FMOD/"))
, MasterBankName(TEXT("Master"))
, LoggingLevel(LEVEL_WARNING)
, bFMODAudioLinkEnabled(false)
{
BankOutputDirectory.Path = TEXT("FMOD");
}
@ -187,6 +188,56 @@ UFMODSettings::EProblem UFMODSettings::Check() const
return Okay;
}
void UFMODSettings::PostEditChangeProperty(FPropertyChangedEvent& e)
{
FName PropertyName = (e.Property != NULL) ? e.Property->GetFName() : NAME_None;
// Validate ContentBrowserPrefix, as Unreal can crash if the prefix is improperly configured
if (PropertyName == GET_MEMBER_NAME_CHECKED(UFMODSettings, ContentBrowserPrefix))
{
FStrProperty* prop = CastField<FStrProperty>(e.Property);
void* propertyAddress = e.Property->ContainerPtrToValuePtr<void>(this);
FString contentBrowserPrefix = prop->GetPropertyValue(propertyAddress);
// Check for empty prefix
if (contentBrowserPrefix.IsEmpty()) {
contentBrowserPrefix = "/";
}
else {
// FName's max length is 1023, but FMOD needs to append additional directories
// 512 is an arbitary length that should cover most prefix lengths
const int ContentBrowserPrefixMaxLength = 512;
// Ensure that length doesn't exceed max prefix length
if (contentBrowserPrefix.Len() > ContentBrowserPrefixMaxLength) {
contentBrowserPrefix.LeftChopInline(ContentBrowserPrefixMaxLength);
}
// Remove invalid long package characters
contentBrowserPrefix = ObjectTools::SanitizeInvalidChars(contentBrowserPrefix, INVALID_LONGPACKAGE_CHARACTERS);
// Remove double slashes
int32 index = contentBrowserPrefix.Find(FString("//"));
while (index != INDEX_NONE) {
contentBrowserPrefix.RemoveAt(index);
index = contentBrowserPrefix.Find(FString("//"));
}
// Check for starting and ending with slash
if (!contentBrowserPrefix.StartsWith("/")) {
contentBrowserPrefix = "/" + contentBrowserPrefix;
}
if (!contentBrowserPrefix.EndsWith("/")) {
contentBrowserPrefix += "/";
}
}
prop->SetPropertyValue(propertyAddress, contentBrowserPrefix);
}
Super::PostEditChangeProperty(e);
}
#endif // WITH_EDITOR
EFMODSpeakerMode::Type UFMODSettings::GetSpeakerMode() const

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODSnapshot.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODSnapshotReverb.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODStudioModule.h"
#include "FMODSettings.h"
@ -11,6 +11,11 @@
#include "FMODListener.h"
#include "FMODSnapshotReverb.h"
#include "FMODAudioLinkModule.h"
#if WITH_EDITOR
#include "FMODAudioLinkEditorModule.h"
#endif
#include "Async/Async.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/App.h"
@ -149,6 +154,10 @@ public:
class FFMODStudioModule : public IFMODStudioModule
{
TUniquePtr<FFMODAudioLinkModule> FMODAudioLinkModule;
#if WITH_EDITOR
TUniquePtr<FFMODAudioLinkEditorModule> FMODAudioLinkEditorModule;
#endif
public:
/** IModuleInterface implementation */
FFMODStudioModule()
@ -178,10 +187,6 @@ public:
void HandleApplicationHasReactivated()
{
#if PLATFORM_IOS || PLATFORM_TVOS
ActivateAudioSession();
#endif
AsyncTask(ENamedThreads::GameThread, [&]() { SetSystemPaused(false); });
}
@ -197,7 +202,12 @@ public:
void UnloadBanks(EFMODSystemContext::Type Type);
#if WITH_EDITOR
FSimpleMulticastDelegate PreEndPIEDelegate;
FSimpleMulticastDelegate &PreEndPIEEvent() override { return PreEndPIEDelegate; };
virtual void PreEndPIE() override;
void ReloadBanks();
void LoadEditorBanks();
void UnloadEditorBanks();
#endif
void CreateStudioSystem(EFMODSystemContext::Type Type);
@ -220,8 +230,6 @@ public:
virtual bool HasListenerMoved() override;
virtual void RefreshSettings();
virtual void SetSystemPaused(bool paused) override;
virtual void SetInPIE(bool bInPIE, bool simulating) override;
@ -255,11 +263,12 @@ public:
virtual FString GetLocale() override;
virtual FString GetDefaultLocale() override;
void ResetInterpolation();
#if PLATFORM_IOS || PLATFORM_TVOS
void InitializeAudioSession();
void ActivateAudioSession();
#endif
/** The studio system handle. */
@ -497,10 +506,10 @@ void FFMODStudioModule::StartupModule()
AcquireFMODFileSystem();
RefreshSettings();
if (GIsEditor)
{
AssetTable.Load();
AssetTable.SetLocale(GetDefaultLocale());
CreateStudioSystem(EFMODSystemContext::Auditioning);
CreateStudioSystem(EFMODSystemContext::Editor);
}
@ -508,6 +517,18 @@ void FFMODStudioModule::StartupModule()
{
SetInPIE(true, false);
}
// Load AudioLink module
bool bFMODAudioLinkEnabled = Settings.bFMODAudioLinkEnabled;
if (bFMODAudioLinkEnabled)
{
UE_LOG(LogFMOD, Log, TEXT("FFMODAudioLinkModule startup"));
FMODAudioLinkModule = MakeUnique<FFMODAudioLinkModule>();
#if WITH_EDITOR
UE_LOG(LogFMOD, Log, TEXT("FFMODAudioLinkEditorModule startup"));
FMODAudioLinkEditorModule = MakeUnique<FFMODAudioLinkEditorModule>();
#endif
}
}
OnTick = FTickerDelegate::CreateRaw(this, &FFMODStudioModule::Tick);
@ -679,11 +700,7 @@ void FFMODStudioModule::CreateStudioSystem(EFMODSystemContext::Type Type)
FMOD_ADVANCEDSETTINGS advSettings = { 0 };
advSettings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS);
if (Settings.bVol0Virtual)
{
advSettings.vol0virtualvol = Settings.Vol0VirtualLevel;
InitFlags |= FMOD_INIT_VOL0_BECOMES_VIRTUAL;
}
advSettings.vol0virtualvol = Settings.Vol0VirtualLevel;
if (!Settings.SetCodecs(advSettings))
{
@ -776,10 +793,13 @@ void FFMODStudioModule::DestroyStudioSystem(EFMODSystemContext::Type Type)
ClockSinks[Type].Reset();
}
UnloadBanks(Type);
if (StudioSystem[Type])
{
FMOD::Studio::Bus* mBus;
StudioSystem[Type]->getBus("bus:/", &mBus);
mBus->setMute(true);
StudioSystem[Type]->flushCommands();
verifyfmod(StudioSystem[Type]->release());
StudioSystem[Type] = nullptr;
}
@ -1007,19 +1027,19 @@ void FFMODStudioModule::FinishSetListenerPosition(int NumListeners)
}
// Apply a reverb snapshot from the listener position(s)
AAudioVolume *BestVolume = nullptr;
TWeakObjectPtr<AAudioVolume> BestVolume = nullptr;
for (int i = 0; i < ListenerCount; ++i)
{
AAudioVolume *CandidateVolume = Listeners[i].Volume;
if (BestVolume == nullptr || (IsValid(CandidateVolume) && IsValid(BestVolume) && CandidateVolume->GetPriority() > BestVolume->GetPriority()))
if (BestVolume == nullptr || (IsValid(CandidateVolume) && BestVolume.IsValid() && CandidateVolume->GetPriority() > BestVolume->GetPriority()))
{
BestVolume = CandidateVolume;
}
}
UFMODSnapshotReverb *NewSnapshot = nullptr;
if (IsValid(BestVolume) && BestVolume->GetReverbSettings().bApplyReverb)
if (BestVolume.IsValid() && BestVolume->GetReverbSettings().bApplyReverb)
{
NewSnapshot = Cast<UFMODSnapshotReverb>(BestVolume->GetReverbSettings().ReverbEffect);
}
@ -1097,12 +1117,6 @@ void FFMODStudioModule::FinishSetListenerPosition(int NumListeners)
}
}
void FFMODStudioModule::RefreshSettings()
{
AssetTable.Load();
AssetTable.SetLocale(GetLocale());
}
void FFMODStudioModule::SetInPIE(bool bInPIE, bool simulating)
{
bIsInPIE = bInPIE;
@ -1129,6 +1143,9 @@ void FFMODStudioModule::SetInPIE(bool bInPIE, bool simulating)
// TODO: Stop sounds for the Editor system? What should happen if the user previews a sequence with transport
// controls then starts a PIE session? What does happen?
AssetTable.Load();
AssetTable.SetLocale(GetDefaultLocale());
ListenerCount = 1;
CreateStudioSystem(EFMODSystemContext::Runtime);
LoadBanks(EFMODSystemContext::Runtime);
@ -1205,6 +1222,17 @@ void FFMODStudioModule::SetSystemPaused(bool paused)
}
}
#if WITH_EDITOR
void FFMODStudioModule::PreEndPIE()
{
UE_LOG(LogFMOD, Verbose, TEXT("PreEndPIE"));
if (PreEndPIEDelegate.IsBound())
{
PreEndPIEDelegate.Broadcast();
}
}
#endif
void FFMODStudioModule::ShutdownModule()
{
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioModule shutdown"));
@ -1213,6 +1241,17 @@ void FFMODStudioModule::ShutdownModule()
DestroyStudioSystem(EFMODSystemContext::Runtime);
DestroyStudioSystem(EFMODSystemContext::Editor);
if (FMODAudioLinkModule)
{
FMODAudioLinkModule.Reset();
}
#if WITH_EDITOR
if (FMODAudioLinkEditorModule)
{
FMODAudioLinkEditorModule.Reset();
}
#endif
if (StudioLibHandle && LowLevelLibHandle)
{
ReleaseFMODFileSystem();
@ -1282,6 +1321,11 @@ bool FFMODStudioModule::SetLocale(const FString& LocaleName)
}
FString FFMODStudioModule::GetLocale()
{
return AssetTable.GetLocale();
}
FString FFMODStudioModule::GetDefaultLocale()
{
FString LocaleCode = "";
const UFMODSettings& Settings = *GetDefault<UFMODSettings>();
@ -1456,11 +1500,21 @@ void FFMODStudioModule::ReloadBanks()
UnloadBanks(EFMODSystemContext::Auditioning);
DestroyStudioSystem(EFMODSystemContext::Editor);
RefreshSettings();
AssetTable.Load();
LoadBanks(EFMODSystemContext::Auditioning);
CreateStudioSystem(EFMODSystemContext::Editor);
}
void FFMODStudioModule::LoadEditorBanks()
{
LoadBanks(EFMODSystemContext::Editor);
}
void FFMODStudioModule::UnloadEditorBanks()
{
UnloadBanks(EFMODSystemContext::Editor);
}
#endif
FMOD::Studio::System *FFMODStudioModule::GetStudioSystem(EFMODSystemContext::Type Context)
@ -1518,57 +1572,120 @@ void FFMODStudioModule::StopAuditioningInstance()
}
#if PLATFORM_IOS || PLATFORM_TVOS
static bool gIsSuspended = false;
static bool gNeedsReset = false;
void FFMODStudioModule::InitializeAudioSession()
{
[[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionInterruptionNotification object:nil queue:nil usingBlock:^(NSNotification *notification)
{
switch ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue])
AVAudioSessionInterruptionType type = (AVAudioSessionInterruptionType)[[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (type == AVAudioSessionInterruptionTypeBegan)
{
case AVAudioSessionInterruptionTypeBegan:
UE_LOG(LogFMOD, Log, TEXT("Interruption Began"));
// Ignore deprecated warnings regarding AVAudioSessionInterruptionReasonAppWasSuspended and
// AVAudioSessionInterruptionWasSuspendedKey, we protect usage for the versions where they are available
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// If the audio session was deactivated while the app was in the background, the app receives the
// notification when relaunched. Identify this reason for interruption and ignore it.
if (@available(iOS 16.0, tvOS 14.5, *))
{
if (@available(iOS 10.3, *))
// Delayed suspend-in-background notifications no longer exist, this must be a real interruption
}
#if !PLATFORM_TVOS // tvOS never supported "AVAudioSessionInterruptionReasonAppWasSuspended"
else if (@available(iOS 14.5, *))
{
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionReasonKey] intValue] == AVAudioSessionInterruptionReasonAppWasSuspended)
{
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionWasSuspendedKey] boolValue])
{
// If the system suspended the app process and deactivated the audio session then we get a delayed
// interruption notification when the app is re-activated. Just ignore that here.
return;
}
return; // Ignore delayed suspend-in-background notification
}
SetSystemPaused(true);
break;
}
case AVAudioSessionInterruptionTypeEnded:
#endif
else
{
ActivateAudioSession();
SetSystemPaused(false);
break;
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionWasSuspendedKey] boolValue])
{
return; // Ignore delayed suspend-in-background notification
}
}
SetSystemPaused(true);
gIsSuspended = true;
#pragma clang diagnostic pop
}
else if (type == AVAudioSessionInterruptionTypeEnded)
{
UE_LOG(LogFMOD, Log, TEXT("Interruption Ended"));
NSError *ActiveError = nil;
if (![[AVAudioSession sharedInstance] setActive:TRUE error:&ActiveError])
{
// Interruption like Siri can prevent session activation, wait for did-become-active notification
UE_LOG(LogFMOD, Error, TEXT("Failed to set audio session to active = %d [Error = %s]"), TRUE, *FString([ActiveError description]));
return;
}
SetSystemPaused(false);
gIsSuspended = false;
}
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification *notification)
{
#if PLATFORM_TVOS
SetSystemPaused(true);
#endif
ActivateAudioSession();
SetSystemPaused(false);
// If the Media Services were reset while we were in the background we need to reset
// To reset we need to suspend so that we can resume.
if (gNeedsReset)
{
SetSystemPaused(true);
gIsSuspended = true;
}
NSError *ActiveError = nil;
if (![[AVAudioSession sharedInstance] setActive:TRUE error:&ActiveError])
{
if ([ActiveError code] == AVAudioSessionErrorCodeCannotStartPlaying)
{
// Interruption like Screen Time can prevent session activation, but will not trigger an interruption-ended notification.
// There is no other callback or trigger to hook into after this point, we are not in the background and there is no other audio playing.
// Our only option is to have a sleep loop until the Audio Session can be activated again.
while (![[AVAudioSession sharedInstance] setActive:TRUE error:nil])
{
FPlatformProcess::Sleep(0.02f);
}
}
else
{
// Interruption like Siri can prevent session activation, wait for interruption-ended notification.
UE_LOG(LogFMOD, Warning, TEXT("UIApplicationDidBecomeActiveNotification: Failed to set audio session to active = %d [Error = %s]"), TRUE, *FString([ActiveError description]));
return;
}
}
// It's possible the system missed sending us an interruption end, so recover here
if (gIsSuspended)
{
SetSystemPaused(false);
gNeedsReset = false;
gIsSuspended = false;
}
}];
ActivateAudioSession();
}
void FFMODStudioModule::ActivateAudioSession()
{
NSError* ActiveError = nil;
[[AVAudioSession sharedInstance] setActive:TRUE error:&ActiveError];
if (ActiveError)
[[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionMediaServicesWereResetNotification object:nil queue:nil usingBlock:^(NSNotification *notification)
{
UE_LOG(LogFMOD, Error, TEXT("Failed to set audio session to active = %d [Error = %s]"), TRUE, *FString([ActiveError description]));
}
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground || gIsSuspended)
{
// Received the reset notification while in the background, need to reset the AudioUnit when we come back to foreground.
gNeedsReset = true;
}
else
{
// In the foregound but something chopped the media services, need to do a reset.
SetSystemPaused(true);
SetSystemPaused(false);
}
}];
}
#endif
#undef LOCTEXT_NAMESPACE
#undef LOCTEXT_NAMESPACE

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
#include "CoreMinimal.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODVCA.h"
#include "FMODStudioModule.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventControlSection.h"
#include "Channels/MovieSceneChannelProxy.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
@ -15,7 +15,8 @@ UENUM()
enum class EFMODEventControlKey : uint8
{
Stop = 0,
Play = 1
Play = 1,
Pause = 2
};
USTRUCT()

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventControlSectionTemplate.h"
#include "FMODAmbientSound.h"
@ -6,30 +6,62 @@
#include "Evaluation/MovieSceneEvaluation.h"
#include "IMovieScenePlayer.h"
enum EventControlKeyInternal
{
Stop,
Play,
Pause,
SequencePause,
SequenceResume,
MAX
};
EventControlKeyInternal MapControlKey(EFMODEventControlKey key)
{
switch (key)
{
case EFMODEventControlKey::Stop:
return EventControlKeyInternal::Stop;
break;
case EFMODEventControlKey::Play:
return EventControlKeyInternal::Play;
break;
case EFMODEventControlKey::Pause:
return EventControlKeyInternal::Pause;
break;
default:
return EventControlKeyInternal::MAX;
break;
}
}
struct FPlayingToken : IMovieScenePreAnimatedToken
{
FPlayingToken(UObject &InObject)
{
bPlaying = false;
TimelinePosition = 0;
if (UFMODAudioComponent *AudioComponent = Cast<UFMODAudioComponent>(&InObject))
{
if (IsValid(AudioComponent))
{
bPlaying = AudioComponent->IsPlaying();
TimelinePosition = AudioComponent->GetTimelinePosition();
}
}
}
virtual void RestoreState(UObject &Object, const UE::MovieScene::FRestoreStateParams& Params) override
virtual void RestoreState(UObject &Object, const UE::MovieScene::FRestoreStateParams &Params) override
{
UFMODAudioComponent *AudioComponent = CastChecked<UFMODAudioComponent>(&Object);
if (AudioComponent)
{
if (bPlaying)
if (bPlaying && !AudioComponent->bPlayEnded)
{
AudioComponent->Play();
AudioComponent->SetTimelinePosition(TimelinePosition);
}
else
{
@ -40,6 +72,7 @@ struct FPlayingToken : IMovieScenePreAnimatedToken
private:
bool bPlaying;
int32 TimelinePosition;
};
struct FPlayingTokenProducer : IMovieScenePreAnimatedTokenProducer
@ -50,15 +83,9 @@ private:
virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject &Object) const override { return FPlayingToken(Object); }
};
struct FFMODEventKeyState : IPersistentEvaluationData
{
FKeyHandle LastKeyHandle;
FKeyHandle InvalidKeyHandle;
};
struct FFMODEventControlExecutionToken : IMovieSceneExecutionToken
{
FFMODEventControlExecutionToken(EFMODEventControlKey InEventControlKey, FFrameTime InKeyTime)
FFMODEventControlExecutionToken(EventControlKeyInternal InEventControlKey, FFrameTime InKeyTime)
: EventControlKey(InEventControlKey)
, KeyTime(InKeyTime)
{
@ -80,45 +107,119 @@ struct FFMODEventControlExecutionToken : IMovieSceneExecutionToken
if (IsValid(AudioComponent))
{
Player.SavePreAnimatedState(*AudioComponent, FPlayingTokenProducer::GetAnimTypeID(), FPlayingTokenProducer());
EFMODSystemContext::Type SystemContext =
(GWorld && GWorld->WorldType == EWorldType::Editor) ? EFMODSystemContext::Editor : EFMODSystemContext::Runtime;
if (EventControlKey == EFMODEventControlKey::Play)
if (EventControlKey == EventControlKeyInternal::Stop && KeyTime == 0 && SystemContext == EFMODSystemContext::Editor)
{
if (AudioComponent->IsPlaying())
{
AudioComponent->Stop();
}
EFMODSystemContext::Type SystemContext =
(GWorld && GWorld->WorldType == EWorldType::Editor) ? EFMODSystemContext::Editor : EFMODSystemContext::Runtime;
AudioComponent->PlayInternal(SystemContext);
// Skip state saving when auditioning sequencer
}
else if (EventControlKey == EFMODEventControlKey::Stop)
else
{
Player.SavePreAnimatedState(*AudioComponent, FPlayingTokenProducer::GetAnimTypeID(), FPlayingTokenProducer());
}
if (EventControlKey == EventControlKeyInternal::Play)
{
if (AudioComponent->GetPaused())
{
AudioComponent->ResumeInternal(UFMODAudioComponent::PauseContext::Explicit);
}
else
{
if (AudioComponent->IsPlaying())
{
AudioComponent->Stop();
}
AudioComponent->PlayInternal(SystemContext);
}
}
else if (EventControlKey == EventControlKeyInternal::Stop)
{
AudioComponent->Stop();
}
else if (EventControlKey == EventControlKeyInternal::Pause)
{
AudioComponent->PauseInternal(UFMODAudioComponent::PauseContext::Explicit);
}
else if (EventControlKey == EventControlKeyInternal::SequencePause)
{
AudioComponent->PauseInternal(UFMODAudioComponent::PauseContext::Implicit);
}
else if (EventControlKey == EventControlKeyInternal::SequenceResume)
{
AudioComponent->ResumeInternal(UFMODAudioComponent::PauseContext::Implicit);
}
}
}
}
EFMODEventControlKey EventControlKey;
EventControlKeyInternal EventControlKey;
FFrameTime KeyTime;
};
static bool RuntimeSequenceSetup = false;
FFMODEventControlSectionTemplate::FFMODEventControlSectionTemplate(const UFMODEventControlSection &Section)
: ControlKeys(Section.ControlKeys)
{
EnableOverrides(FMovieSceneEvalTemplateBase::EOverrideMask::RequiresSetupFlag);
EnableOverrides(FMovieSceneEvalTemplateBase::EOverrideMask::RequiresTearDownFlag);
}
void FFMODEventControlSectionTemplate::Setup(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const
{
IsEditorSequence = GWorld && GWorld->WorldType == EWorldType::Editor;
if (!IsEditorSequence)
{
RuntimeSequenceSetup = true;
}
#if WITH_EDITOR
if (!RuntimeSequenceSetup)
{
IFMODStudioModule::Get().LoadEditorBanks();
}
#endif
}
void FFMODEventControlSectionTemplate::TearDown(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const
{
if (!IsEditorSequence)
{
RuntimeSequenceSetup = false;
}
#if WITH_EDITOR
if (!RuntimeSequenceSetup)
{
IFMODStudioModule::Get().UnloadEditorBanks();
}
#endif
}
void FFMODEventControlSectionTemplate::Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context,
const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const
{
if (IsEditorSequence && RuntimeSequenceSetup)
{
// If the Sequence Editor is open during PIE, it will also try to play its Sequence.
// Don't let it, otherwise Execution Tokens will be double-issued.
return;
}
const bool bPlaying = Context.IsSilent() == false && Context.GetDirection() == EPlayDirection::Forwards &&
Context.GetRange().Size<FFrameTime>() >= FFrameTime(0) && Context.GetStatus() == EMovieScenePlayerStatus::Playing;
if (!bPlaying)
if (!bPlaying && IsEditorSequence && !RuntimeSequenceSetup)
{
ExecutionTokens.Add(FFMODEventControlExecutionToken(EFMODEventControlKey::Stop, FFrameTime(0)));
if (Context.GetStatus() == EMovieScenePlayerStatus::Paused)
{
ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::Pause, FFrameTime(0)));
}
else
{
ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::Stop, FFrameTime(0)));
}
}
else
{
@ -132,8 +233,18 @@ void FFMODEventControlSectionTemplate::Evaluate(const FMovieSceneEvaluationOpera
const int32 LastKeyIndex = Algo::UpperBound(Times, PlaybackRange.GetUpperBoundValue()) - 1;
if (LastKeyIndex >= 0 && PlaybackRange.Contains(Times[LastKeyIndex]))
{
FFMODEventControlExecutionToken NewToken((EFMODEventControlKey)Values[LastKeyIndex], Times[LastKeyIndex]);
FFMODEventControlExecutionToken NewToken(MapControlKey((EFMODEventControlKey)Values[LastKeyIndex]), Times[LastKeyIndex]);
ExecutionTokens.Add(MoveTemp(NewToken));
}
}
// Handle direct pause/unpause calls on sequence
if (Context.GetStatus() == EMovieScenePlayerStatus::Stopped)
{
ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::SequencePause, FFrameTime(0)));
}
else
{
ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::SequenceResume, FFrameTime(0)));
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
@ -21,6 +21,10 @@ struct FFMODEventControlSectionTemplate : public FMovieSceneEvalTemplate
private:
virtual UScriptStruct &GetScriptStructImpl() const override { return *StaticStruct(); }
virtual void Setup(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const override;
virtual void TearDown(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const override;
virtual void Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context,
const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const override;
};
mutable bool IsEditorSequence;
};

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventControlTrack.h"
#include "FMODEventControlSection.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventParameterTrack.h"
#include "FMODEventParameterSectionTemplate.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - C header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header in conjunction with fmod_common.h (which contains all the constants / */
/* callbacks) to develop using the C interface */

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - C++ header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header in conjunction with fmod_common.h (which contains all the constants / */
/* callbacks) to develop using the C++ language. */

View File

@ -1 +1,7 @@
/* Placeholder */
#pragma once
#include "fmod_common.h"
#include <jni.h>
extern "C" FMOD_RESULT F_API FMOD_Android_JNI_Init(JavaVM *vm, jobject javaActivity);
extern "C" FMOD_RESULT F_API FMOD_Android_JNI_Close();

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - Codec development header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header if you are wanting to develop your own file format plugin to use with */
/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - Common C/C++ header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* This header is included by fmod.hpp (C++ interface) and fmod.h (C interface) */
/* */
@ -56,7 +56,7 @@ typedef struct FMOD_ASYNCREADINFO FMOD_ASYNCREADINFO;
/*
FMOD constants
*/
#define FMOD_VERSION 0x00020214 /* 0xaaaabbcc -> aaaa = product version, bb = major version, cc = minor version.*/
#define FMOD_VERSION 0x00020226 /* 0xaaaabbcc -> aaaa = product version, bb = major version, cc = minor version.*/
typedef unsigned int FMOD_DEBUG_FLAGS;
#define FMOD_DEBUG_LEVEL_NONE 0x00000000
@ -439,6 +439,7 @@ typedef enum FMOD_OUTPUTTYPE
FMOD_OUTPUTTYPE_AAUDIO,
FMOD_OUTPUTTYPE_AUDIOWORKLET,
FMOD_OUTPUTTYPE_PHASE,
FMOD_OUTPUTTYPE_OHAUDIO,
FMOD_OUTPUTTYPE_MAX,
FMOD_OUTPUTTYPE_FORCEINT = 65536
@ -795,6 +796,7 @@ typedef struct FMOD_ADVANCEDSETTINGS
unsigned int randomSeed;
int maxConvolutionThreads;
int maxOpusCodecs;
int maxSpatialObjects;
} FMOD_ADVANCEDSETTINGS;
typedef struct FMOD_TAG

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - DSP header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header if you are wanting to develop your own DSP plugin to use with FMODs */
/* dsp system. With this header you can make your own DSP plugin that FMOD can */

View File

@ -1,6 +1,6 @@
/* ============================================================================================================= */
/* FMOD Core API - Built-in effects header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* In this header you can find parameter structures for FMOD system registered DSP effects */
/* and generators. */

View File

@ -1,6 +1,6 @@
/* ============================================================================================== */
/* FMOD Core / Studio API - Error string header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header if you want to store or display a string version / english explanation */
/* of the FMOD error codes. */
@ -49,7 +49,7 @@ static const char *FMOD_ErrorString(FMOD_RESULT errcode)
case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out.";
case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function.";
case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init.";
case FMOD_ERR_INTERNAL: return "An error occurred that wasn't supposed to. Contact support.";
case FMOD_ERR_INTERNAL: return "An error occured in the FMOD system. Use the logging version of FMOD for more information.";
case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float.";
case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used.";
case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function.";
@ -87,7 +87,7 @@ static const char *FMOD_ErrorString(FMOD_RESULT errcode)
case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags.";
case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the 'maxinputchannels' parameter in System::setSoftwareFormat.";
case FMOD_ERR_TRUNCATED: return "The retrieved string is too long to fit in the supplied buffer and has been truncated.";
case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support!";
case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be. Contact support.";
case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called.";
case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified.";
case FMOD_ERR_VERSION: return "The version number of this file format is not supported.";

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Core API - output development header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header if you are wanting to develop your own output plugin to use with */
/* FMOD's output system. With this header you can make your own output plugin that FMOD */

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Studio API - C header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header in conjunction with fmod_studio_common.h (which contains all the */
/* constants / callbacks) to develop using the C language. */

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Studio API - C++ header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* Use this header in conjunction with fmod_studio_common.h (which contains all the */
/* constants / callbacks) to develop using the C++ language. */

View File

@ -1,6 +1,6 @@
/* ======================================================================================== */
/* FMOD Studio API - Common C/C++ header file. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2023. */
/* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2024. */
/* */
/* This header defines common enumerations, structs and callbacks that are shared between */
/* the C and C++ interfaces. */

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
@ -72,11 +72,6 @@ public:
*/
virtual void SetSystemPaused(bool paused) = 0;
/**
* Called when user changes any studio settings
*/
virtual void RefreshSettings() = 0;
/**
* Called when we enter of leave PIE mode
*/
@ -163,12 +158,25 @@ public:
/** Set active locale. Locale must be the locale name of one of the configured project locales */
virtual bool SetLocale(const FString& Locale) = 0;
/** Get ative locale. */
/** Get active locale. */
virtual FString GetLocale() = 0;
/** Get default locale. */
virtual FString GetDefaultLocale() = 0;
#if WITH_EDITOR
/** Multicast delegate that is triggered before the module is shutdown. */
virtual FSimpleMulticastDelegate &PreEndPIEEvent() = 0;
virtual void PreEndPIE() = 0;
/** Called by the editor module when banks have been modified on disk */
virtual void ReloadBanks() = 0;
/** Load Editor banks for auditioning in Sequnecer. */
virtual void LoadEditorBanks() = 0;
/** Unload Editor banks. */
virtual void UnloadEditorBanks() = 0;
#endif
};

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
using System.IO;
namespace UnrealBuildTool.Rules

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "AssetTypeActions_FMODEvent.h"
#include "AssetTypeActions_Base.h"
@ -7,9 +7,9 @@
#include "FMODUtils.h"
#include "FMODStudioModule.h"
#include "FMODStudioEditorModule.h"
#include "UnrealEd/Public/Editor.h"
#include "Editor.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "EditorStyle/Public/EditorStyleSet.h"
#include "Editor/EditorStyle/Public/EditorStyleSet.h"
#define LOCTEXT_NAMESPACE "AssetTypeActions"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,10 +1,10 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAmbientSoundActorFactory.h"
#include "FMODStudioEditorPrivatePCH.h"
#include "FMODAmbientSound.h"
#include "FMODEvent.h"
#include "AssetRegistry/Public/AssetData.h"
#include "AssetRegistry/AssetData.h"
#include "Editor/EditorEngine.h"
UFMODAmbientSoundActorFactory::UFMODAmbientSoundActorFactory(const FObjectInitializer &ObjectInitializer)

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -209,8 +209,6 @@ void FFMODAssetBuilder::BuildAssets(const UFMODSettings& InSettings, const FStri
}
}
const FString BankExtensions[] = { TEXT(".assets"), TEXT(".streams"), TEXT(".bank")};
void FFMODAssetBuilder::BuildBankLookup(const FString &AssetName, const FString &PackagePath, const UFMODSettings &InSettings,
TArray<UObject*>& AssetsToSave)
{
@ -245,56 +243,29 @@ void FFMODAssetBuilder::BuildBankLookup(const FString &AssetName, const FString
return;
}
TMap<FString, FString> BankGuids;
TArray<FString> LocalizedEntriesVisited;
for (FString BankPath : BankPaths)
{
FMOD::Studio::Bank* Bank;
FMOD_RESULT result = StudioSystem->loadBankFile(TCHAR_TO_UTF8(*BankPath), FMOD_STUDIO_LOAD_BANK_NORMAL, &Bank);
FMOD_GUID BankID;
FMOD_RESULT result = StudioSystem->loadBankFile(TCHAR_TO_UTF8(*BankPath), FMOD_STUDIO_LOAD_BANK_NORMAL, &Bank);
if (result == FMOD_OK)
{
result = Bank->getID(&BankID);
Bank->unload();
}
if (result == FMOD_OK)
{
FString GUID = FMODUtils::ConvertGuid(BankID).ToString(EGuidFormats::DigitsWithHyphensInBraces);
FString* otherBankPath = BankGuids.Find(GUID);
if (otherBankPath != nullptr)
{
bool foundLocale = false;
for (const FFMODProjectLocale& Locale : InSettings.Locales)
{
if (Locale.bDefault && BankPath.EndsWith(FString("_") + Locale.LocaleCode + FString(".bank")))
{
foundLocale = true;
break;
}
}
if (!foundLocale)
{
UE_LOG(LogFMOD, Warning, TEXT("Ignoring bank %s as another bank with the same GUID is already being used.\n"
"Bank %s does not match any locales in the FMOD Studio plugin settings."), *BankPath, *BankPath);
continue;
}
}
BankGuids.Add(GUID, BankPath);
}
else
if (result != FMOD_OK)
{
UE_LOG(LogFMOD, Error, TEXT("Failed to add bank %s to lookup."), *BankPath);
continue;
}
}
FString GUID = FMODUtils::ConvertGuid(BankID).ToString(EGuidFormats::DigitsWithHyphensInBraces);
FName OuterRowName(*GUID);
for (TPair<FString,FString> GUIDPath : BankGuids)
{
FName OuterRowName(*GUIDPath.Key);
FFMODLocalizedBankTable* Row = BankLookup->DataTable->FindRow<FFMODLocalizedBankTable>(OuterRowName, nullptr, false);
if (Row)
{
StaleBanks.RemoveSingle(OuterRowName);
@ -302,33 +273,48 @@ void FFMODAssetBuilder::BuildBankLookup(const FString &AssetName, const FString
else
{
FFMODLocalizedBankTable NewRow{};
NewRow.Banks = NewObject<UDataTable>(BankLookup->DataTable, *GUIDPath.Key, RF_NoFlags);
NewRow.Banks = NewObject<UDataTable>(BankLookup->DataTable, *BankPath, RF_NoFlags);
NewRow.Banks->RowStruct = FFMODLocalizedBankRow::StaticStruct();
BankLookup->DataTable->AddRow(OuterRowName, NewRow);
Row = BankLookup->DataTable->FindRow<FFMODLocalizedBankTable>(OuterRowName, nullptr, false);
bModified = true;
}
FString CurFilename = FPaths::GetCleanFilename(GUIDPath.Value);
FString FilenamePart = CurFilename;
for (const FString& extension : BankExtensions)
{
FilenamePart.ReplaceInline(*extension, TEXT(""));
}
FString InnerRowName("<NON-LOCALIZED>");
// Set InnerRowName to either "<NON-LOCALIZED>" or a locale code based on the BankPath e.g. "JP"
FName InnerRowName("<NON-LOCALIZED>");
for (const FFMODProjectLocale& Locale : InSettings.Locales)
{
if (FilenamePart.EndsWith(FString("_") + Locale.LocaleCode))
// Remove all expected extensions from end of filename before checking for locale code.
// Note, we may encounter multiple extensions e.g. "Dialogue.assets.bank"
const FString BankExtensions[] = { TEXT(".assets"), TEXT(".streams"), TEXT(".strings") };
FString Filename = FPaths::GetCleanFilename(BankPath);
Filename.RemoveFromEnd(TEXT(".bank"));
for (const FString& extension : BankExtensions)
{
InnerRowName = Locale.LocaleCode;
Filename.RemoveFromEnd(extension);
}
if (Filename.EndsWith(FString("_") + Locale.LocaleCode))
{
InnerRowName = FName(*Locale.LocaleCode);
break;
}
}
FFMODLocalizedBankRow* InnerRow = Row->Banks->FindRow<FFMODLocalizedBankRow>(FName(*InnerRowName), nullptr, false);
FString RelativeBankPath = GUIDPath.Value.RightChop(InSettings.GetFullBankPath().Len() + 1);
// See if we've visited this OuterRowName + InnerRowName already and skip it if so. This is mainly to
// avoid setting "<NON-LOCALIZED>" multiple times (and causing BankLookup to be modified) when no
// locales are set up in Unreal.
FString LocalizedEntryKey = OuterRowName.ToString() + InnerRowName.ToString();
if (LocalizedEntriesVisited.Find(LocalizedEntryKey) != INDEX_NONE)
{
UE_LOG(LogFMOD, Warning, TEXT("Ignoring bank %s as another bank with the same GUID is already being used.\n"
"Bank %s does not match any locales in the FMOD Studio plugin settings."), *BankPath, *BankPath);
continue;
}
LocalizedEntriesVisited.Add(LocalizedEntryKey);
FFMODLocalizedBankRow* InnerRow = Row->Banks->FindRow<FFMODLocalizedBankRow>(InnerRowName, nullptr, false);
FString RelativeBankPath = BankPath.RightChop(InSettings.GetFullBankPath().Len() + 1);
if (InnerRow)
{
@ -342,10 +328,12 @@ void FFMODAssetBuilder::BuildBankLookup(const FString &AssetName, const FString
{
FFMODLocalizedBankRow NewRow{};
NewRow.Path = RelativeBankPath;
Row->Banks->AddRow(FName(*InnerRowName), NewRow);
Row->Banks->AddRow(InnerRowName, NewRow);
bModified = true;
}
FString CurFilename = FPaths::GetCleanFilename(BankPath);
if (CurFilename == InSettings.GetMasterBankFilename() && BankLookup->MasterBankPath != RelativeBankPath)
{
BankLookup->MasterBankPath = RelativeBankPath;
@ -376,15 +364,54 @@ void FFMODAssetBuilder::BuildBankLookup(const FString &AssetName, const FString
bModified = true;
}
// Remove stale localized bank entries from lookup
for (auto& outer : BankLookup->DataTable->GetRowMap())
{
FName outerrowname = outer.Key;
FFMODLocalizedBankTable* outerrow = reinterpret_cast<FFMODLocalizedBankTable*>(outer.Value);
TArray<FName> RowsToRemove;
for (auto& inner : outerrow->Banks->GetRowMap())
{
FName innerrowname = inner.Key;
FFMODLocalizedBankRow* innerrow = reinterpret_cast<FFMODLocalizedBankRow*>(inner.Value);
FString LocalizedEntryKey = outerrowname.ToString() + innerrowname.ToString();
if (LocalizedEntriesVisited.Find(LocalizedEntryKey) == INDEX_NONE)
{
RowsToRemove.Add(innerrowname);
}
}
for (auto& rowname : RowsToRemove)
{
outerrow->Banks->RemoveRow(rowname);
bModified = true;
}
}
if (bCreated)
{
UE_LOG(LogFMOD, Log, TEXT("BankLookup created.\n"));
FAssetRegistryModule::AssetCreated(BankLookup);
}
if (bCreated || bModified)
{
UE_LOG(LogFMOD, Log, TEXT("BankLookup modified.\n"));
AssetsToSave.Add(BankLookup);
}
UE_LOG(LogFMOD, Log, TEXT("===== BankLookup =====\n"));
for (auto& outer : BankLookup->DataTable->GetRowMap())
{
FName outerrowname = outer.Key;
FFMODLocalizedBankTable* outerrow = reinterpret_cast<FFMODLocalizedBankTable*>(outer.Value);
UE_LOG(LogFMOD, Log, TEXT("GUID: %s\n"), *(outerrowname.ToString()));
for (auto& inner : outerrow->Banks->GetRowMap())
{
FName innerrowname = inner.Key;
FFMODLocalizedBankRow* innerrow = reinterpret_cast<FFMODLocalizedBankRow*>(inner.Value);
UE_LOG(LogFMOD, Log, TEXT(" Locale: %s Path: %s\n"), *(innerrowname.ToString()), *innerrow->Path);
}
}
}
FString FFMODAssetBuilder::GetAssetClassName(UClass* AssetClass)
@ -501,7 +528,7 @@ UFMODAsset *FFMODAssetBuilder::CreateAsset(const AssetCreateInfo& CreateInfo, TA
}
else
{
SanitizedPackagePath = ObjectTools::SanitizeInvalidChars(PackagePath, INVALID_OBJECTPATH_CHARACTERS);
SanitizedPackagePath = ObjectTools::SanitizeInvalidChars(PackagePath, INVALID_LONGPACKAGE_CHARACTERS);
UE_LOG(LogFMOD, Log, TEXT("'%s' cannot be used as a UE4 asset path. %s. Using '%s' instead."), *PackagePath, *OutReason.ToString(),
*SanitizedPackagePath);
}

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAudioComponentDetails.h"
#include "Subsystems/AssetEditorSubsystem.h"
@ -6,10 +6,10 @@
#include "FMODStudioModule.h"
#include "FMODEvent.h"
#include "fmod_studio.hpp"
#include "UnrealEd/Public/Editor.h"
#include "Editor.h"
#include "Widgets/Input/SButton.h"
#include "PropertyEditor/Public/DetailLayoutBuilder.h"
#include "PropertyEditor/Public/DetailCategoryBuilder.h"
#include "Editor/PropertyEditor/Public/DetailLayoutBuilder.h"
#include "Editor/PropertyEditor/Public/DetailCategoryBuilder.h"
#define LOCTEXT_NAMESPACE "FMODStudio"

View File

@ -1,10 +1,12 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
//#include "PropertyEditing.h"
#include "PropertyCustomizationHelpers.h"
#include "PropertyEditor/Public/IDetailCustomization.h"
#include "IDetailCustomization.h"
class IDetailLayoutBuilder;
class FFMODAudioComponentDetails : public IDetailCustomization
{

View File

@ -1,12 +1,12 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODAudioComponentVisualizer.h"
#include "FMODAudioComponent.h"
#include "FMODUtils.h"
#include "FMODEvent.h"
#include "fmod_studio.hpp"
#include "Engine/Public/SceneView.h"
#include "Engine/Public/SceneManagement.h"
#include "SceneView.h"
#include "SceneManagement.h"
void FFMODAudioComponentVisualizer::DrawVisualization(const UActorComponent *Component, const FSceneView *View, FPrimitiveDrawInterface *PDI)
{

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODBankUpdateNotifier.h"
#include "FMODSettings.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventEditor.h"
#include "FMODEvent.h"
@ -8,7 +8,7 @@
#include "SFMODEventEditorPanel.h"
#include "Widgets/Docking/SDockTab.h"
#include "fmod_studio.hpp"
#include "UnrealEd/Public/Editor.h"
#include "Editor.h"
#define LOCTEXT_NAMESPACE "FMODEventEditor"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -36,11 +36,21 @@ int32 UFMODGenerateAssetsCommandlet::Main(const FString& CommandLine)
// Rebuild switch
if (Switches.Contains(RebuildSwitch))
{
FString FolderToDelete;
IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
/*
Combine the ProjectContentDir + ContentBrowserPrefix to make a filesystem path
to where the FMOD generated assets directories live e.g.
../../../../UnrealProjects/MyProject/Content/FMOD
Should work for non-default values of ContentBrowserPrefix e.g. /Game/foo/bar/baz/
*/
FString folderPath = Settings.ContentBrowserPrefix.TrimChar('/'); // /Game/FMOD/ -> Game/FMOD
folderPath.Split(TEXT("/"), 0, &folderPath); // Game/FMOD -> FMOD
folderPath = FPaths::ProjectContentDir() + folderPath + "/"; // FMOD -> ../../../../UnrealProjects/MyProject/Content/FMOD/
for (FString folder : Settings.GeneratedFolders)
{
FolderToDelete = FPaths::ProjectContentDir() + Settings.ContentBrowserPrefix + folder;
FString FolderToDelete = folderPath + folder;
bool removed = FileManager.DeleteDirectoryRecursively(*FolderToDelete);
if (!removed)
{

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2024.
#include "FMODSettingsCustomization.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODStudioEditorModule.h"
#include "FMODStudioModule.h"
@ -20,31 +20,32 @@
#include "Sequencer/FMODEventParameterTrackEditor.h"
#include "AssetTypeActions_FMODEvent.h"
#include "Framework/Application/SlateApplication.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "UnrealEd/Public/AssetSelection.h"
#include "Slate/Public/Framework/Notifications/NotificationManager.h"
#include "Slate/Public/Widgets/Notifications/SNotificationList.h"
#include "AssetSelection.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Developer/Settings/Public/ISettingsModule.h"
#include "Developer/Settings/Public/ISettingsSection.h"
#include "UnrealEd/Public/Editor.h"
#include "Editor.h"
#include "Slate/SceneViewport.h"
#include "LevelEditor/Public/LevelEditor.h"
#include "Sockets/Public/SocketSubsystem.h"
#include "Sockets/Public/Sockets.h"
#include "Sockets/Public/IPAddress.h"
#include "UnrealEd/Public/FileHelpers.h"
#include "Sequencer/Public/ISequencerModule.h"
#include "Sequencer/Public/SequencerChannelInterface.h"
#include "MovieSceneTools/Public/ClipboardTypes.h"
#include "Engine/Public/DebugRenderSceneProxy.h"
#include "Engine/Classes/Debug/DebugDrawService.h"
#include "Editor/LevelEditor/Public/LevelEditor.h"
#include "SocketSubsystem.h"
#include "Sockets.h"
#include "IPAddress.h"
#include "FileHelpers.h"
#include "ISequencerModule.h"
#include "SequencerChannelInterface.h"
#include "ClipboardTypes.h"
#include "DebugRenderSceneProxy.h"
#include "Debug/DebugDrawService.h"
#include "Settings/ProjectPackagingSettings.h"
#include "UnrealEdGlobals.h"
#include "UnrealEd/Public/LevelEditorViewport.h"
#include "LevelEditorViewport.h"
#include "ActorFactories/ActorFactory.h"
#include "Engine/Canvas.h"
#include "Editor/UnrealEdEngine.h"
#include "Slate/Public/Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Misc/MessageDialog.h"
#include "HAL/FileManager.h"
#include "Interfaces/IMainFrameModule.h"
@ -333,7 +334,7 @@ void FFMODStudioEditorModule::OnPostEngineInit()
{
RegisterHelpMenuEntries();
MainMenuExtender = MakeShareable(new FExtender);
MainMenuExtender->AddMenuExtension("FileLoadAndSave", EExtensionHook::After, NULL,
MainMenuExtender->AddMenuExtension("FileOpen", EExtensionHook::After, NULL,
FMenuExtensionDelegate::CreateRaw(this, &FFMODStudioEditorModule::AddFileMenuExtension));
LevelEditor->GetMenuExtensibilityManager()->AddExtender(MainMenuExtender);
}
@ -388,8 +389,6 @@ void FFMODStudioEditorModule::ProcessBanks()
BankUpdateNotifier.SetFilePath(Settings.GetFullBankPath());
BankUpdateNotifier.EnableUpdate(true);
IFMODStudioModule::Get().RefreshSettings();
}
}
@ -791,9 +790,12 @@ void FFMODStudioEditorModule::ValidateFMOD()
if (FMessageDialog::Open(EAppMsgType::YesNo, Message) == EAppReturnType::Yes)
{
Settings.Locales = StudioLocales;
Settings.Locales[0].bDefault = true;
if (Settings.Locales.Num() > 0)
{
Settings.Locales[0].bDefault = true;
}
SettingsSection->Save();
IFMODStudioModule::Get().RefreshSettings();
IFMODStudioModule::Get().ReloadBanks();
}
}
}
@ -1109,6 +1111,7 @@ void FFMODStudioEditorModule::BeginPIE(bool simulating)
void FFMODStudioEditorModule::EndPIE(bool simulating)
{
IFMODStudioModule::Get().PreEndPIE();
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule EndPIE: %d"), simulating);
bSimulating = false;
bIsInPIE = false;

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
#include "Runtime/Engine/Classes/Components/SceneComponent.h"

View File

@ -1,8 +1,8 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODStudioStyle.h"
#include "Styling/SlateStyleRegistry.h"
#include "EditorStyle/Public/Interfaces/IEditorStyleModule.h"
#include "Editor/EditorStyle/Public/Interfaces/IEditorStyleModule.h"
#include "Modules/ModuleManager.h"

View File

@ -1,8 +1,8 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once
#include "SlateCore/Public/Styling/SlateStyle.h"
#include "EditorStyle/Public/EditorStyleSet.h"
#include "Styling/SlateStyle.h"
#include "EditorStyleSet.h"
class FFMODStudioStyle
{

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "SFMODEventEditorPanel.h"
#include "FMODStudioModule.h"
@ -6,7 +6,7 @@
#include "Input/Reply.h"
#include "Widgets/Input/SNumericEntryBox.h"
#include "Widgets/Layout/SExpandableArea.h"
#include "EditorStyle/Public/EditorStyleSet.h"
#include "Editor/EditorStyle/Public/EditorStyleSet.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SScrollBox.h"
#include "fmod_studio.hpp"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "Sequencer/FMODChannelEditors.h"
#include "ISequencerChannelInterface.h"
@ -7,7 +7,7 @@
#include "MovieSceneTimeHelpers.h"
#include "MovieSceneToolHelpers.h"
#include "ScopedTransaction.h"
#include "EditorWidgets/Public/SEnumCombo.h"
#include "Editor/EditorWidgets/Public/SEnumCombo.h"
#include "EditorStyleSet.h"
#include "Channels/MovieSceneChannelTraits.h"

View File

@ -1,16 +1,17 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventControlTrackEditor.h"
#include "FMODAmbientSound.h"
#include "Sequencer/FMODEventControlSection.h"
#include "Sequencer/FMODEventControlTrack.h"
#include "AnimatedRange.h"
#include "Rendering/DrawElements.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Curves/IntegralCurve.h"
#include "SequencerSectionPainter.h"
#include "EditorStyleSet.h"
#include "Editor/UnrealEdEngine.h"
#include "Sequencer/FMODEventControlSection.h"
#include "Sequencer/FMODEventControlTrack.h"
#include "ISectionLayoutBuilder.h"
#include "FMODAmbientSound.h"
#include "CommonMovieSceneTools.h"
#include "Channels/MovieSceneChannelProxy.h"
#include "Channels/MovieSceneChannelEditorData.h"
@ -103,13 +104,13 @@ int32 FFMODEventControlSection::OnPaintSection(FSequencerSectionPainter &InPaint
float XSize = TimeToPixelConverter.SecondsToPixel(DrawRange.GetUpperBoundValue()) - XOffset;
FSlateDrawElement::MakeBox(InPainter.DrawElements, InPainter.LayerId,
InPainter.SectionGeometry.ToPaintGeometry(
FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2),
FVector2D(XSize, SequencerSectionConstants::KeySize.Y)),
FVector2D(XSize, SequencerSectionConstants::KeySize.Y),
FSlateLayoutTransform(1.0f, FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2))),
FAppStyle::GetBrush("Sequencer.Section.Background"), DrawEffects);
FSlateDrawElement::MakeBox(InPainter.DrawElements, InPainter.LayerId,
InPainter.SectionGeometry.ToPaintGeometry(
FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2),
FVector2D(XSize, SequencerSectionConstants::KeySize.Y)),
FVector2D(XSize, SequencerSectionConstants::KeySize.Y),
FSlateLayoutTransform(1.0f, FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2))),
FAppStyle::GetBrush("Sequencer.Section.BackgroundTint"), DrawEffects, TrackColor);
}

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODEventParameterTrackEditor.h"
#include "FMODAmbientSound.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#include "FMODParameterSection.h"
#include "ISectionLayoutBuilder.h"

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once

View File

@ -1,4 +1,4 @@
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2023.
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
#pragma once