├── FMODStudio ├── Content │ └── AnimNotify_FMODPlayEvent.uasset ├── FMODStudio.uplugin ├── Resources │ └── Icon128.png └── Source │ ├── FMODStudio │ ├── Classes │ │ ├── FMODAmbientSound.h │ │ ├── FMODAnimNotifyPlay.h │ │ ├── FMODAsset.h │ │ ├── FMODAudioComponent.h │ │ ├── FMODBank.h │ │ ├── FMODBlueprintStatics.h │ │ ├── FMODBus.h │ │ ├── FMODEvent.h │ │ ├── FMODPort.h │ │ ├── FMODSettings.h │ │ ├── FMODSnapshot.h │ │ ├── FMODSnapshotReverb.h │ │ └── FMODVCA.h │ ├── FMODStudio.Build.cs │ ├── FMODStudioL_APL.xml │ ├── FMODStudio_APL.xml │ ├── Private │ │ ├── FMODAmbientSound.cpp │ │ ├── FMODAnimNotifyPlay.cpp │ │ ├── FMODAsset.cpp │ │ ├── FMODAssetLookup.cpp │ │ ├── FMODAssetLookup.h │ │ ├── FMODAssetTable.cpp │ │ ├── FMODAssetTable.h │ │ ├── FMODAudioComponent.cpp │ │ ├── FMODBank.cpp │ │ ├── FMODBankLookup.cpp │ │ ├── FMODBankLookup.h │ │ ├── FMODBlueprintStatics.cpp │ │ ├── FMODBus.cpp │ │ ├── FMODEvent.cpp │ │ ├── FMODFileCallbacks.cpp │ │ ├── FMODFileCallbacks.h │ │ ├── FMODListener.cpp │ │ ├── FMODListener.h │ │ ├── FMODPlatform.h │ │ ├── FMODPort.cpp │ │ ├── FMODSettings.cpp │ │ ├── FMODSnapshot.cpp │ │ ├── FMODSnapshotReverb.cpp │ │ ├── FMODStudioModule.cpp │ │ ├── FMODStudioPrivatePCH.h │ │ ├── FMODVCA.cpp │ │ └── Sequencer │ │ │ ├── FMODEventControlSection.cpp │ │ │ ├── FMODEventControlSection.h │ │ │ ├── FMODEventControlSectionTemplate.cpp │ │ │ ├── FMODEventControlSectionTemplate.h │ │ │ ├── FMODEventControlTrack.cpp │ │ │ ├── FMODEventControlTrack.h │ │ │ ├── FMODEventParameterSectionTemplate.cpp │ │ │ ├── FMODEventParameterSectionTemplate.h │ │ │ ├── FMODEventParameterTrack.cpp │ │ │ └── FMODEventParameterTrack.h │ └── Public │ │ ├── FMOD │ │ ├── fmod.h │ │ ├── fmod.hpp │ │ ├── fmod_android.h │ │ ├── fmod_codec.h │ │ ├── fmod_common.h │ │ ├── fmod_dsp.h │ │ ├── fmod_dsp_effects.h │ │ ├── fmod_errors.h │ │ ├── fmod_output.h │ │ ├── fmod_studio.h │ │ ├── fmod_studio.hpp │ │ └── fmod_studio_common.h │ │ ├── FMODStudioModule.h │ │ └── FMODUtils.h │ └── FMODStudioEditor │ ├── Classes │ ├── FMODAmbientSoundActorFactory.h │ ├── FMODAssetBuilder.h │ └── FMODGenerateAssetsCommandlet.h │ ├── FMODStudioEditor.Build.cs │ ├── Private │ ├── AssetTypeActions_FMODEvent.cpp │ ├── AssetTypeActions_FMODEvent.h │ ├── FMODAmbientSoundActorFactory.cpp │ ├── FMODAssetBroker.h │ ├── FMODAssetBuilder.cpp │ ├── FMODAudioComponentDetails.cpp │ ├── FMODAudioComponentDetails.h │ ├── FMODAudioComponentVisualizer.cpp │ ├── FMODAudioComponentVisualizer.h │ ├── FMODBankUpdateNotifier.cpp │ ├── FMODBankUpdateNotifier.h │ ├── FMODEventEditor.cpp │ ├── FMODEventEditor.h │ ├── FMODGenerateAssetsCommandlet.cpp │ ├── FMODSettingsCustomization.cpp │ ├── FMODSettingsCustomization.h │ ├── FMODStudioEditorModule.cpp │ ├── FMODStudioEditorPrivatePCH.h │ ├── FMODStudioStyle.cpp │ ├── FMODStudioStyle.h │ ├── SFMODEventEditorPanel.cpp │ ├── SFMODEventEditorPanel.h │ └── Sequencer │ │ ├── FMODChannelEditors.cpp │ │ ├── FMODChannelEditors.h │ │ ├── FMODEventControlTrackEditor.cpp │ │ ├── FMODEventControlTrackEditor.h │ │ ├── FMODEventParameterTrackEditor.cpp │ │ ├── FMODEventParameterTrackEditor.h │ │ ├── FMODParameterSection.cpp │ │ └── FMODParameterSection.h │ └── Public │ └── FMODStudioEditorModule.h ├── FMODStudioNiagara ├── Content │ ├── ENiagara_FMODParamType.uasset │ ├── PlayFMODEvent.uasset │ ├── PlayPersistentFMODEvent.uasset │ ├── Templates │ │ └── PlayFMODEventEmitter.uasset │ └── UpdatePersistentFMODEvent.uasset ├── FMODStudioNiagara.uplugin └── Source │ └── FMODStudioNiagara │ ├── FMODStudioNiagara.Build.cs │ ├── Private │ ├── FMODNiagaraEventPlayer.cpp │ └── FMODStudioNiagara.cpp │ └── Public │ ├── FMODNiagaraEventPlayer.h │ └── FMODStudioNiagara.h ├── LICENSE └── README.md /FMODStudio/Content/AnimNotify_FMODPlayEvent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudio/Content/AnimNotify_FMODPlayEvent.uasset -------------------------------------------------------------------------------- /FMODStudio/FMODStudio.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion" : 3, 3 | 4 | "FriendlyName" : "FMOD Studio Integration", 5 | "Version" : 20228, 6 | "VersionName" : "2.02.28", 7 | "CreatedBy" : "Firelight Technologies", 8 | "CreatedByURL" : "http://fmod.com", 9 | "Description" : "FMOD Studio Integration.", 10 | "Category" : "Audio", 11 | "EnabledByDefault" : true, 12 | 13 | "Modules": [ 14 | { 15 | "Name": "FMODStudio", 16 | "Type": "Runtime", 17 | "LoadingPhase": "PreDefault" 18 | }, 19 | { 20 | "Name": "FMODStudioEditor", 21 | "Type": "Editor", 22 | "LoadingPhase": "Default" 23 | } 24 | ], 25 | 26 | "CanContainContent" : true, 27 | "Installed" : true 28 | } -------------------------------------------------------------------------------- /FMODStudio/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudio/Resources/Icon128.png -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODAmbientSound.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAudioComponent.h" 6 | #include "FMODAmbientSound.generated.h" 7 | 8 | /** FMOD Ambient Sound. 9 | */ 10 | UCLASS(AutoExpandCategories = Audio, ClassGroup = Sounds, hidecategories(Collision, Input)) 11 | class FMODSTUDIO_API AFMODAmbientSound : public AActor 12 | { 13 | GENERATED_UCLASS_BODY() 14 | 15 | public: 16 | /** The Audio component for this actor */ 17 | UPROPERTY(Category = Sound, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Sound")) 18 | UFMODAudioComponent *AudioComponent; 19 | 20 | // Begin AActor interface. 21 | #if WITH_EDITOR 22 | virtual void CheckForErrors() override; 23 | virtual bool GetReferencedContentObjects(TArray &Objects) const override; 24 | #endif 25 | // End AActor interface. 26 | }; 27 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODAnimNotifyPlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Animation/AnimNotifies/AnimNotify.h" 4 | #include "FMODEvent.h" 5 | #include "FMODAnimNotifyPlay.generated.h" 6 | 7 | UCLASS(const, hidecategories = Object, collapsecategories, meta = (DisplayName = "Play FMOD Event")) 8 | class FMODSTUDIO_API UFMODAnimNotifyPlay : public UAnimNotify 9 | { 10 | GENERATED_BODY() 11 | 12 | public: 13 | UFMODAnimNotifyPlay(); 14 | 15 | // Begin UAnimNotify interface 16 | virtual void Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *AnimSeq) override; 17 | virtual FString GetNotifyName_Implementation() const override; 18 | // End UAnimNotify interface 19 | 20 | // If this sound should follow its owner 21 | UPROPERTY(EditAnywhere, Category = "FMOD Anim Notify") 22 | uint32 bFollow : 1; 23 | 24 | // Socket or bone name to attach sound to 25 | UPROPERTY(EditAnywhere, Category = "FMOD Anim Notify", meta = (EditCondition = "bFollow")) 26 | FString AttachName; 27 | 28 | // Sound to Play 29 | UPROPERTY(EditAnywhere, Category = "FMOD Anim Notify", BlueprintReadWrite) 30 | class UFMODEvent* Event; 31 | }; 32 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODAsset.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "Misc/Guid.h" 6 | #include "CoreMinimal.h" 7 | #include "FMODAsset.generated.h" 8 | 9 | /** 10 | * FMOD Asset. 11 | */ 12 | UCLASS(BlueprintType) 13 | class FMODSTUDIO_API UFMODAsset : public UObject 14 | { 15 | GENERATED_UCLASS_BODY() 16 | 17 | public: 18 | /** The unique Guid, which matches the one exported from FMOD Studio */ 19 | UPROPERTY() 20 | FGuid AssetGuid; 21 | 22 | protected: 23 | /** Get tags to show in content view */ 24 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 25 | 26 | private: 27 | /** Non default instances of UFMODAsset are assets */ 28 | virtual bool IsAsset() const override; 29 | }; 30 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODBank.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "FMODBank.generated.h" 7 | 8 | /** 9 | * FMOD Bank Asset. 10 | */ 11 | UCLASS() 12 | class FMODSTUDIO_API UFMODBank : public UFMODAsset 13 | { 14 | GENERATED_UCLASS_BODY() 15 | 16 | private: 17 | /** Get tags to show in content view */ 18 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 19 | 20 | /** Descriptive name */ 21 | virtual FString GetDesc() override; 22 | }; 23 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODBus.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "FMODBus.generated.h" 7 | 8 | /** 9 | * FMOD Bus Asset. 10 | */ 11 | UCLASS() 12 | class FMODSTUDIO_API UFMODBus : public UFMODAsset 13 | { 14 | GENERATED_UCLASS_BODY() 15 | 16 | private: 17 | /** Get tags to show in content view */ 18 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 19 | 20 | /** Descriptive name */ 21 | virtual FString GetDesc() override; 22 | }; 23 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODEvent.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "FMODEvent.generated.h" 7 | 8 | struct FMOD_STUDIO_PARAMETER_DESCRIPTION; 9 | 10 | /** 11 | * FMOD Event Asset. 12 | */ 13 | UCLASS() 14 | class FMODSTUDIO_API UFMODEvent : public UFMODAsset 15 | { 16 | GENERATED_UCLASS_BODY() 17 | 18 | public: 19 | /** Get parameter descriptions for this event */ 20 | void GetParameterDescriptions(TArray &Parameters) const; 21 | 22 | private: 23 | /** Get tags to show in content view */ 24 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 25 | 26 | /** Descriptive name */ 27 | virtual FString GetDesc() override; 28 | }; 29 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODPort.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "FMODPort.generated.h" 7 | 8 | /** 9 | * FMOD Port Asset. 10 | */ 11 | UCLASS() 12 | class FMODSTUDIO_API UFMODPort : public UFMODAsset 13 | { 14 | GENERATED_UCLASS_BODY() 15 | 16 | private: 17 | /** Get tags to show in content view */ 18 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 19 | 20 | /** Descriptive name */ 21 | virtual FString GetDesc() override; 22 | }; 23 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODSnapshot.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODEvent.h" 6 | #include "FMODSnapshot.generated.h" 7 | 8 | /** 9 | * FMOD Snapshot Asset. 10 | */ 11 | UCLASS() 12 | class FMODSTUDIO_API UFMODSnapshot : public UFMODEvent 13 | { 14 | GENERATED_UCLASS_BODY() 15 | 16 | private: 17 | /** Descriptive name */ 18 | virtual FString GetDesc() override; 19 | }; 20 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODSnapshotReverb.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "Sound/ReverbEffect.h" 7 | #include "FMODSnapshotReverb.generated.h" 8 | 9 | /** 10 | * FMOD Event Asset. 11 | */ 12 | UCLASS() 13 | class FMODSTUDIO_API UFMODSnapshotReverb : public UReverbEffect 14 | { 15 | GENERATED_UCLASS_BODY() 16 | 17 | public: 18 | /** The unique Guid, which matches the one exported from FMOD Studio */ 19 | UPROPERTY() 20 | FGuid AssetGuid; 21 | 22 | private: 23 | /** Non default instances of UFMODAsset are assets */ 24 | virtual bool IsAsset() const override; 25 | 26 | #if WITH_EDITORONLY_DATA 27 | virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override; 28 | #endif // EDITORONLY_DATA 29 | }; 30 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Classes/FMODVCA.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODAsset.h" 6 | #include "FMODVCA.generated.h" 7 | 8 | /** 9 | * FMOD VCA Asset. 10 | */ 11 | UCLASS() 12 | class FMODSTUDIO_API UFMODVCA : public UFMODAsset 13 | { 14 | GENERATED_UCLASS_BODY() 15 | 16 | private: 17 | /** Get tags to show in content view */ 18 | virtual void GetAssetRegistryTags(TArray &OutTags) const override; 19 | 20 | /** Descriptive name */ 21 | virtual FString GetDesc() override; 22 | }; 23 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/FMODStudioL_APL.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -keep class org.fmod.** { 14 | *; 15 | } 16 | -dontwarn org.fmod.** 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | // Initialize FMOD Studio jar file 35 | org.fmod.FMOD.init(this); 36 | 37 | 38 | 39 | 40 | 41 | 42 | // Shutdown FMOD Studio jar file 43 | org.fmod.FMOD.close(); 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/FMODStudio_APL.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -keep class org.fmod.** { 14 | *; 15 | } 16 | -dontwarn org.fmod.** 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | // Initialize FMOD Studio jar file 35 | org.fmod.FMOD.init(this); 36 | 37 | 38 | 39 | 40 | 41 | 42 | // Shutdown FMOD Studio jar file 43 | org.fmod.FMOD.close(); 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAmbientSound.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAmbientSound.h" 4 | #include "FMODEvent.h" 5 | #include "Logging/MessageLog.h" 6 | #include "Misc/UObjectToken.h" 7 | #include "Misc/MapErrors.h" 8 | 9 | #define LOCTEXT_NAMESPACE "FMODAmbientSound" 10 | 11 | AFMODAmbientSound::AFMODAmbientSound(const FObjectInitializer &ObjectInitializer) 12 | : Super(ObjectInitializer) 13 | { 14 | AudioComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT("FMODAudioComponent0")); 15 | 16 | AudioComponent->bAutoActivate = true; 17 | AudioComponent->bStopWhenOwnerDestroyed = true; 18 | AudioComponent->Mobility = EComponentMobility::Movable; 19 | 20 | RootComponent = AudioComponent; 21 | 22 | bReplicates = false; 23 | SetHidden(true); 24 | SetCanBeDamaged(true); 25 | } 26 | 27 | #if WITH_EDITOR 28 | 29 | void AFMODAmbientSound::CheckForErrors(void) 30 | { 31 | Super::CheckForErrors(); 32 | 33 | if (!AudioComponent) 34 | { 35 | FFormatNamedArguments Arguments; 36 | Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); 37 | FMessageLog("MapCheck") 38 | .Warning() 39 | ->AddToken(FUObjectToken::Create(this)) 40 | ->AddToken(FTextToken::Create(FText::Format( 41 | LOCTEXT("MapCheck_Message_AudioComponentNull", "{ActorName} : Ambient sound actor has NULL AudioComponent property - please delete"), 42 | Arguments))) 43 | ->AddToken(FMapErrorToken::Create(FMapErrors::AudioComponentNull)); 44 | } 45 | else if (AudioComponent->Event == NULL) 46 | { 47 | FFormatNamedArguments Arguments; 48 | Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); 49 | FMessageLog("MapCheck") 50 | .Warning() 51 | ->AddToken(FUObjectToken::Create(this)) 52 | ->AddToken(FTextToken::Create( 53 | FText::Format(LOCTEXT("MapCheck_Message_EventNull", "{ActorName} : Ambient sound actor has NULL Event property"), Arguments))) 54 | ->AddToken(FMapErrorToken::Create(FMapErrors::SoundCueNull)); 55 | } 56 | } 57 | 58 | bool AFMODAmbientSound::GetReferencedContentObjects(TArray &Objects) const 59 | { 60 | if (IsValid(AudioComponent) && AudioComponent->Event) 61 | { 62 | Objects.Add(AudioComponent->Event); 63 | } 64 | return true; 65 | } 66 | 67 | #endif 68 | 69 | #undef LOCTEXT_NAMESPACE -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAnimNotifyPlay.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "FMODAnimNotifyPlay.h" 3 | #include "FMODBlueprintStatics.h" 4 | #include "Components/SkeletalMeshComponent.h" 5 | #include "Kismet/KismetSystemLibrary.h" 6 | 7 | UFMODAnimNotifyPlay::UFMODAnimNotifyPlay() 8 | : Super() 9 | { 10 | bFollow = false; 11 | Event = nullptr; 12 | 13 | #if WITH_EDITORONLY_DATA 14 | NotifyColor = FColor(196, 142, 255, 255); 15 | #endif // WITH_EDITORONLY_DATA 16 | } 17 | 18 | void UFMODAnimNotifyPlay::Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *AnimSeq) 19 | { 20 | if (Event) 21 | { 22 | if (bFollow) 23 | { 24 | // Play event attached 25 | UFMODBlueprintStatics::PlayEventAttached( 26 | Event, MeshComp, *AttachName, FVector(0, 0, 0), EAttachLocation::KeepRelativeOffset, false, true, true); 27 | } 28 | else 29 | { 30 | // Play event at location 31 | UFMODBlueprintStatics::PlayEventAtLocation(MeshComp, Event, MeshComp->GetComponentTransform(), true); 32 | } 33 | } 34 | } 35 | 36 | FString UFMODAnimNotifyPlay::GetNotifyName_Implementation() const 37 | { 38 | if (Event) 39 | { 40 | return Event->GetName(); 41 | } 42 | else 43 | { 44 | return Super::GetNotifyName_Implementation(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAsset.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAsset.h" 4 | #include "FMODStudioModule.h" 5 | 6 | static const TCHAR *FMODAssetTypeStrings[] = { TEXT("Bank"), TEXT("Event"), TEXT("VCA"), TEXT("Bus"), TEXT("Invalid") }; 7 | 8 | UFMODAsset::UFMODAsset(const FObjectInitializer &ObjectInitializer) 9 | : Super(ObjectInitializer) 10 | { 11 | } 12 | 13 | bool UFMODAsset::IsAsset() const 14 | { 15 | return this != GetClass()->GetDefaultObject(); 16 | } 17 | 18 | /** Get tags to show in content view */ 19 | void UFMODAsset::GetAssetRegistryTags(TArray &OutTags) const 20 | { 21 | Super::GetAssetRegistryTags(OutTags); 22 | OutTags.Add( 23 | UObject::FAssetRegistryTag("Guid", AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces), UObject::FAssetRegistryTag::TT_Alphabetical)); 24 | } 25 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAssetLookup.cpp: -------------------------------------------------------------------------------- 1 | #include "FMODAssetLookup.h" 2 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAssetLookup.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Engine/DataTable.h" 7 | #include "FMODAssetLookup.generated.h" 8 | 9 | USTRUCT() 10 | struct FMODSTUDIO_API FFMODAssetLookupRow : public FTableRowBase 11 | { 12 | GENERATED_BODY() 13 | 14 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|AssetLookup") 15 | FString PackageName; 16 | 17 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|AssetLookup") 18 | FString AssetName; 19 | }; 20 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAssetTable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAssetTable.h" 4 | 5 | #include "FMODAssetLookup.h" 6 | #include "FMODEvent.h" 7 | #include "FMODSnapshot.h" 8 | #include "FMODSnapshotReverb.h" 9 | #include "FMODBank.h" 10 | #include "FMODBankLookup.h" 11 | #include "FMODBus.h" 12 | #include "FMODVCA.h" 13 | #include "FMODUtils.h" 14 | #include "FMODSettings.h" 15 | #include "FMODFileCallbacks.h" 16 | #include "FMODStudioPrivatePCH.h" 17 | #include "fmod_studio.hpp" 18 | #include "HAL/FileManager.h" 19 | #include "Misc/Paths.h" 20 | #include "UObject/Package.h" 21 | 22 | FFMODAssetTable::FFMODAssetTable() 23 | : ActiveLocale(FString()), 24 | BankLookup(nullptr), 25 | AssetLookup(nullptr) 26 | { 27 | } 28 | 29 | void FFMODAssetTable::AddReferencedObjects(FReferenceCollector& Collector) 30 | { 31 | // The garbage collector will clean up any objects which aren't referenced, doing this tells the garbage collector our lookups are referenced 32 | // (the GC knows not to remove objects referenced by a UPROPERTY, doing this manually is required because our members aren't UPROPERTYs) 33 | if (BankLookup) 34 | { 35 | Collector.AddReferencedObject(BankLookup); 36 | } 37 | 38 | if (AssetLookup) 39 | { 40 | Collector.AddReferencedObject(AssetLookup); 41 | } 42 | } 43 | 44 | void FFMODAssetTable::Load() 45 | { 46 | const UFMODSettings &Settings = *GetDefault(); 47 | FString PackagePath = Settings.GetFullContentPath() / PrivateDataPath(); 48 | 49 | FString PackageName = PackagePath + BankLookupName(); 50 | UPackage *Package = CreatePackage(*PackageName); 51 | Package->FullyLoad(); 52 | BankLookup = FindObject(Package, *BankLookupName(), true); 53 | 54 | if (BankLookup) 55 | { 56 | UE_LOG(LogFMOD, Display, TEXT("Loaded bank lookup")); 57 | } 58 | else 59 | { 60 | TCHAR msg[] = TEXT("Failed to load bank lookup"); 61 | if (IsRunningCommandlet()) 62 | { 63 | // If we're running in a commandlet (maybe we're cooking or running FMODGenerateAssets 64 | // commandlet) Display a message but don't cause the build to Error out. 65 | UE_LOG(LogFMOD, Display, msg); 66 | } 67 | else 68 | { 69 | // If we're running in game or in editor, log this as an Error 70 | UE_LOG(LogFMOD, Error, msg); 71 | } 72 | } 73 | 74 | PackageName = PackagePath + AssetLookupName(); 75 | Package = CreatePackage(*PackageName); 76 | Package->FullyLoad(); 77 | AssetLookup = FindObject(Package, *AssetLookupName(), true); 78 | 79 | if (AssetLookup) 80 | { 81 | UE_LOG(LogFMOD, Display, TEXT("Loaded asset lookup")); 82 | } 83 | else 84 | { 85 | TCHAR msg[] = TEXT("Failed to load asset lookup"); 86 | if (IsRunningCommandlet()) 87 | { 88 | // If we're running in a commandlet (maybe we're cooking or running FMODGenerateAssets 89 | // commandlet) Display a message but don't cause the build to Error out. 90 | UE_LOG(LogFMOD, Display, msg); 91 | } 92 | else 93 | { 94 | // If we're running in game or in editor, log this as an Error 95 | UE_LOG(LogFMOD, Error, msg); 96 | } 97 | } 98 | } 99 | 100 | FString FFMODAssetTable::GetBankPathByGuid(const FGuid& Guid) const 101 | { 102 | FString BankPath; 103 | 104 | if (!BankLookup) 105 | { 106 | UE_LOG(LogFMOD, Error, TEXT("Bank lookup not loaded")); 107 | return BankPath; 108 | } 109 | 110 | FString GUID = Guid.ToString(EGuidFormats::DigitsWithHyphensInBraces); 111 | FName BankTableName(*GUID); 112 | FFMODLocalizedBankTable *BankTable = BankLookup->DataTable->FindRow(BankTableName, nullptr, false); 113 | 114 | if (BankTable) 115 | { 116 | BankPath = GetLocalizedBankPath(BankTable->Banks); 117 | } 118 | 119 | return BankPath; 120 | } 121 | 122 | FString FFMODAssetTable::GetLocalizedBankPath(const UDataTable* BankTable) const 123 | { 124 | FName RowName(*ActiveLocale); 125 | FFMODLocalizedBankRow *Row = BankTable->FindRow(RowName, nullptr, false); 126 | 127 | if (!Row) 128 | { 129 | RowName = FName(""); 130 | Row = BankTable->FindRow(RowName, nullptr, false); 131 | } 132 | 133 | FString BankPath; 134 | 135 | if (Row) 136 | { 137 | BankPath = Row->Path; 138 | } 139 | 140 | return BankPath; 141 | } 142 | 143 | FString FFMODAssetTable::GetBankPath(const UFMODBank &Bank) const 144 | { 145 | FString BankPath = GetBankPathByGuid(Bank.AssetGuid); 146 | 147 | if (BankPath.IsEmpty()) 148 | { 149 | UE_LOG(LogFMOD, Warning, TEXT("Could not find disk file for bank %s"), *Bank.GetName()); 150 | } 151 | 152 | return BankPath; 153 | } 154 | 155 | FString FFMODAssetTable::GetMasterBankPath() const 156 | { 157 | return BankLookup ? BankLookup->MasterBankPath : FString(); 158 | } 159 | 160 | FString FFMODAssetTable::GetMasterStringsBankPath() const 161 | { 162 | return BankLookup ? BankLookup->MasterStringsBankPath : FString(); 163 | } 164 | 165 | FString FFMODAssetTable::GetMasterAssetsBankPath() const 166 | { 167 | return BankLookup ? BankLookup->MasterAssetsBankPath : FString(); 168 | } 169 | 170 | void FFMODAssetTable::SetLocale(const FString &LocaleCode) 171 | { 172 | ActiveLocale = LocaleCode; 173 | } 174 | 175 | FString FFMODAssetTable::GetLocale() const 176 | { 177 | return ActiveLocale; 178 | } 179 | 180 | void FFMODAssetTable::GetAllBankPaths(TArray &Paths, bool IncludeMasterBank) const 181 | { 182 | if (BankLookup) 183 | { 184 | const UFMODSettings &Settings = *GetDefault(); 185 | 186 | BankLookup->DataTable->ForeachRow(nullptr, [this, &Paths, IncludeMasterBank, &Settings](const FName &, const FFMODLocalizedBankTable& OuterRow) { 187 | FString BankPath = GetLocalizedBankPath(OuterRow.Banks); 188 | bool Skip = false; 189 | 190 | if (BankPath.IsEmpty()) 191 | { 192 | // Never expect to be in here, but should skip empty paths 193 | return; 194 | } 195 | 196 | if (!IncludeMasterBank) 197 | { 198 | Skip = (BankPath == Settings.GetMasterBankFilename() || BankPath == Settings.GetMasterAssetsBankFilename() || BankPath == Settings.GetMasterStringsBankFilename()); 199 | } 200 | 201 | if (!Skip) 202 | { 203 | Paths.Push(Settings.GetFullBankPath() / BankPath); 204 | } 205 | }); 206 | } 207 | else 208 | { 209 | UE_LOG(LogFMOD, Error, TEXT("Bank lookup not loaded")); 210 | } 211 | } 212 | 213 | UFMODAsset *FFMODAssetTable::GetAssetByStudioPath(const FString &InStudioPath) const 214 | { 215 | UFMODAsset *Asset = nullptr; 216 | 217 | if (AssetLookup) 218 | { 219 | FFMODAssetLookupRow *Row = AssetLookup->FindRow(FName(*InStudioPath), nullptr); 220 | 221 | if (Row) 222 | { 223 | UPackage *Package = CreatePackage(*(Row->PackageName)); 224 | Package->FullyLoad(); 225 | Asset = FindObject(Package, *(Row->AssetName)); 226 | } 227 | 228 | } 229 | 230 | return Asset; 231 | } 232 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODAssetTable.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "UObject/GCObject.h" 6 | 7 | class UDataTable; 8 | class UFMODAsset; 9 | class UFMODBank; 10 | class UFMODBankLookup; 11 | 12 | class FFMODAssetTable : public FGCObject 13 | { 14 | public: 15 | FFMODAssetTable(); 16 | 17 | //~ FGCObject 18 | void AddReferencedObjects(FReferenceCollector& Collector) override; 19 | 20 | void Load(); 21 | 22 | FString GetBankPath(const UFMODBank &Bank) const; 23 | FString GetMasterBankPath() const; 24 | FString GetMasterStringsBankPath() const; 25 | FString GetMasterAssetsBankPath() const; 26 | void SetLocale(const FString &LocaleCode); 27 | FString GetLocale() const; 28 | void GetAllBankPaths(TArray &BankPaths, bool IncludeMasterBank) const; 29 | 30 | UFMODAsset *GetAssetByStudioPath(const FString &InStudioPath) const; 31 | 32 | static inline FString PrivateDataPath() { return FString(TEXT("PrivateIntegrationData/")); } 33 | static inline FString BankLookupName() { return FString(TEXT("BankLookup")); } 34 | static inline FString AssetLookupName() { return FString(TEXT("AssetLookup")); } 35 | 36 | private: 37 | FString GetBankPathByGuid(const FGuid& Guid) const; 38 | FString GetLocalizedBankPath(const UDataTable* BankTable) const; 39 | 40 | FString ActiveLocale; 41 | UFMODBankLookup *BankLookup; 42 | UDataTable *AssetLookup; 43 | }; 44 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODBank.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODBank.h" 4 | #include "FMODStudioModule.h" 5 | 6 | UFMODBank::UFMODBank(const FObjectInitializer &ObjectInitializer) 7 | : Super(ObjectInitializer) 8 | { 9 | } 10 | 11 | /** Get tags to show in content view */ 12 | void UFMODBank::GetAssetRegistryTags(TArray &OutTags) const 13 | { 14 | Super::GetAssetRegistryTags(OutTags); 15 | } 16 | 17 | FString UFMODBank::GetDesc() 18 | { 19 | return FString::Printf(TEXT("Bank %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 20 | } 21 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODBankLookup.cpp: -------------------------------------------------------------------------------- 1 | #include "FMODBankLookup.h" 2 | 3 | UFMODBankLookup::UFMODBankLookup(const FObjectInitializer& ObjectInitializer) 4 | : Super(ObjectInitializer) 5 | , DataTable(nullptr) 6 | {} -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODBankLookup.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Engine/DataTable.h" 7 | #include "FMODBankLookup.generated.h" 8 | 9 | USTRUCT() 10 | struct FMODSTUDIO_API FFMODLocalizedBankRow : public FTableRowBase 11 | { 12 | GENERATED_BODY() 13 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 14 | FString Path; 15 | }; 16 | 17 | USTRUCT() 18 | struct FMODSTUDIO_API FFMODLocalizedBankTable : public FTableRowBase 19 | { 20 | GENERATED_BODY() 21 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 22 | UDataTable *Banks = nullptr; 23 | }; 24 | 25 | UCLASS() 26 | class FMODSTUDIO_API UFMODBankLookup : public UObject 27 | { 28 | GENERATED_UCLASS_BODY() 29 | 30 | public: 31 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 32 | UDataTable *DataTable; 33 | 34 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 35 | FString MasterBankPath; 36 | 37 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 38 | FString MasterAssetsBankPath; 39 | 40 | UPROPERTY(VisibleAnywhere, Category="FMOD|Internal|BankLookup") 41 | FString MasterStringsBankPath; 42 | }; 43 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODBus.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODBus.h" 4 | #include "FMODStudioModule.h" 5 | 6 | UFMODBus::UFMODBus(const FObjectInitializer &ObjectInitializer) 7 | : Super(ObjectInitializer) 8 | { 9 | } 10 | 11 | /** Get tags to show in content view */ 12 | void UFMODBus::GetAssetRegistryTags(TArray &OutTags) const 13 | { 14 | Super::GetAssetRegistryTags(OutTags); 15 | } 16 | 17 | FString UFMODBus::GetDesc() 18 | { 19 | return FString::Printf(TEXT("Bus %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 20 | } 21 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODEvent.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEvent.h" 4 | #include "FMODStudioModule.h" 5 | #include "fmod_studio.hpp" 6 | 7 | UFMODEvent::UFMODEvent(const FObjectInitializer &ObjectInitializer) 8 | : Super(ObjectInitializer) 9 | { 10 | } 11 | 12 | /** Get tags to show in content view */ 13 | void UFMODEvent::GetAssetRegistryTags(TArray &OutTags) const 14 | { 15 | Super::GetAssetRegistryTags(OutTags); 16 | if (IFMODStudioModule::Get().AreBanksLoaded()) 17 | { 18 | FMOD::Studio::EventDescription *EventDesc = IFMODStudioModule::Get().GetEventDescription(this, EFMODSystemContext::Max); 19 | 20 | bool bOneshot = false; 21 | bool bStream = false; 22 | bool b3D = false; 23 | if (EventDesc) 24 | { 25 | EventDesc->isOneshot(&bOneshot); 26 | EventDesc->isStream(&bStream); 27 | EventDesc->is3D(&b3D); 28 | } 29 | 30 | OutTags.Add(UObject::FAssetRegistryTag("Oneshot", bOneshot ? TEXT("True") : TEXT("False"), UObject::FAssetRegistryTag::TT_Alphabetical)); 31 | OutTags.Add(UObject::FAssetRegistryTag("Streaming", bStream ? TEXT("True") : TEXT("False"), UObject::FAssetRegistryTag::TT_Alphabetical)); 32 | OutTags.Add(UObject::FAssetRegistryTag("3D", b3D ? TEXT("True") : TEXT("False"), UObject::FAssetRegistryTag::TT_Alphabetical)); 33 | } 34 | } 35 | 36 | FString UFMODEvent::GetDesc() 37 | { 38 | return FString::Printf(TEXT("Event %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 39 | } 40 | 41 | void UFMODEvent::GetParameterDescriptions(TArray &Parameters) const 42 | { 43 | if (IFMODStudioModule::Get().AreBanksLoaded()) 44 | { 45 | FMOD::Studio::EventDescription *EventDesc = IFMODStudioModule::Get().GetEventDescription(this, EFMODSystemContext::Auditioning); 46 | 47 | if (EventDesc) 48 | { 49 | int ParameterCount; 50 | EventDesc->getParameterDescriptionCount(&ParameterCount); 51 | Parameters.SetNumUninitialized(ParameterCount); 52 | for (int ParameterIndex = 0; ParameterIndex < ParameterCount; ++ParameterIndex) 53 | { 54 | EventDesc->getParameterDescriptionByIndex(ParameterIndex, &Parameters[ParameterIndex]); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODFileCallbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "fmod.hpp" 6 | #include "GenericPlatform/GenericPlatform.h" 7 | 8 | FMOD_RESULT F_CALLBACK FMODLogCallback(FMOD_DEBUG_FLAGS flags, const char *file, int line, const char *func, const char *message); 9 | FMOD_RESULT F_CALLBACK FMODErrorCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void *userdata); 10 | 11 | void AcquireFMODFileSystem(); 12 | void ReleaseFMODFileSystem(); 13 | void AttachFMODFileSystem(FMOD::System *system, FGenericPlatformTypes::int32 fileBufferSize); 14 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODListener.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODListener.h" 4 | #include "Misc/App.h" 5 | #include "AudioDefines.h" 6 | #include "Sound/AudioVolume.h" 7 | 8 | float FFMODListener::Interpolate(const double EndTime) 9 | { 10 | if (FApp::GetCurrentTime() < InteriorStartTime) 11 | { 12 | return (0.0f); 13 | } 14 | 15 | if (FApp::GetCurrentTime() >= EndTime) 16 | { 17 | return (1.0f); 18 | } 19 | 20 | float InterpValue = (float)((FApp::GetCurrentTime() - InteriorStartTime) / (EndTime - InteriorStartTime)); 21 | return (InterpValue); 22 | } 23 | 24 | void FFMODListener::UpdateCurrentInteriorSettings() 25 | { 26 | // Store the interpolation value, not the actual value 27 | InteriorVolumeInterp = Interpolate(InteriorEndTime); 28 | ExteriorVolumeInterp = Interpolate(ExteriorEndTime); 29 | InteriorLPFInterp = Interpolate(InteriorLPFEndTime); 30 | ExteriorLPFInterp = Interpolate(ExteriorLPFEndTime); 31 | } 32 | 33 | void FFMODListener::ApplyInteriorSettings(class AAudioVolume *InVolume, const FInteriorSettings &Settings) 34 | { 35 | if (InteriorSettings != Settings) 36 | { 37 | // Use previous/ current interpolation time if we're transitioning to the default worldsettings zone. 38 | InteriorStartTime = FApp::GetCurrentTime(); 39 | InteriorEndTime = InteriorStartTime + (Settings.bIsWorldSettings ? InteriorSettings.InteriorTime : Settings.InteriorTime); 40 | ExteriorEndTime = InteriorStartTime + (Settings.bIsWorldSettings ? InteriorSettings.ExteriorTime : Settings.ExteriorTime); 41 | InteriorLPFEndTime = InteriorStartTime + (Settings.bIsWorldSettings ? InteriorSettings.InteriorLPFTime : Settings.InteriorLPFTime); 42 | ExteriorLPFEndTime = InteriorStartTime + (Settings.bIsWorldSettings ? InteriorSettings.ExteriorLPFTime : Settings.ExteriorLPFTime); 43 | 44 | InteriorSettings = Settings; 45 | } 46 | Volume = InVolume; 47 | } 48 | 49 | FFMODInteriorSettings::FFMODInteriorSettings() 50 | : bIsWorldSettings(false) 51 | , ExteriorVolume(1.0f) 52 | , ExteriorTime(0.5f) 53 | , ExteriorLPF(MAX_FILTER_FREQUENCY) 54 | , ExteriorLPFTime(0.5f) 55 | , InteriorVolume(1.0f) 56 | , InteriorTime(0.5f) 57 | , InteriorLPF(MAX_FILTER_FREQUENCY) 58 | , InteriorLPFTime(0.5f) 59 | { 60 | } 61 | 62 | bool FFMODInteriorSettings::operator==(const FInteriorSettings &Other) const 63 | { 64 | return (this->bIsWorldSettings == Other.bIsWorldSettings) && (this->ExteriorVolume == Other.ExteriorVolume) && 65 | (this->ExteriorTime == Other.ExteriorTime) && (this->ExteriorLPF == Other.ExteriorLPF) && 66 | (this->ExteriorLPFTime == Other.ExteriorLPFTime) && (this->InteriorVolume == Other.InteriorVolume) && 67 | (this->InteriorTime == Other.InteriorTime) && (this->InteriorLPF == Other.InteriorLPF) && (this->InteriorLPFTime == Other.InteriorLPFTime); 68 | } 69 | bool FFMODInteriorSettings::operator!=(const FInteriorSettings &Other) const 70 | { 71 | return !(*this == Other); 72 | } 73 | 74 | FFMODInteriorSettings &FFMODInteriorSettings::operator=(FInteriorSettings Other) 75 | { 76 | bIsWorldSettings = Other.bIsWorldSettings; 77 | ExteriorVolume = Other.ExteriorVolume; 78 | ExteriorTime = Other.ExteriorTime; 79 | ExteriorLPF = Other.ExteriorLPF; 80 | ExteriorLPFTime = Other.ExteriorLPFTime; 81 | InteriorVolume = Other.InteriorVolume; 82 | InteriorTime = Other.InteriorTime; 83 | InteriorLPF = Other.InteriorLPF; 84 | InteriorLPFTime = Other.InteriorLPFTime; 85 | return *this; 86 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODListener.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "GenericPlatform/GenericPlatform.h" 6 | #include "UObject/Object.h" 7 | #include "Math/Vector.h" 8 | 9 | struct FInteriorSettings; 10 | 11 | /** Struct encapsulating settings for interior areas. */ 12 | struct FFMODInteriorSettings 13 | { 14 | uint32 bIsWorldSettings : 1; 15 | float ExteriorVolume; 16 | float ExteriorTime; 17 | float ExteriorLPF; 18 | float ExteriorLPFTime; 19 | float InteriorVolume; 20 | float InteriorTime; 21 | float InteriorLPF; 22 | float InteriorLPFTime; 23 | 24 | FFMODInteriorSettings(); 25 | bool operator==(const FInteriorSettings &Other) const; 26 | bool operator!=(const FInteriorSettings &Other) const; 27 | FFMODInteriorSettings &operator=(FInteriorSettings Other); 28 | }; 29 | 30 | /** A direct copy of FListener (which doesn't have external linkage, unfortunately) **/ 31 | struct FFMODListener 32 | { 33 | FTransform Transform; 34 | FVector Velocity; 35 | 36 | struct FFMODInteriorSettings InteriorSettings; 37 | /** The volume the listener resides in */ 38 | class AAudioVolume *Volume; 39 | 40 | /** The times of interior volumes fading in and out */ 41 | double InteriorStartTime; 42 | double InteriorEndTime; 43 | double ExteriorEndTime; 44 | double InteriorLPFEndTime; 45 | double ExteriorLPFEndTime; 46 | float InteriorVolumeInterp; 47 | float InteriorLPFInterp; 48 | float ExteriorVolumeInterp; 49 | float ExteriorLPFInterp; 50 | 51 | FVector GetUp() const { return Transform.GetUnitAxis(EAxis::Z); } 52 | FVector GetFront() const { return Transform.GetUnitAxis(EAxis::Y); } 53 | FVector GetRight() const { return Transform.GetUnitAxis(EAxis::X); } 54 | 55 | /** 56 | * Works out the interp value between source and end 57 | */ 58 | float Interpolate(const double EndTime); 59 | 60 | /** 61 | * Gets the current state of the interior settings for the listener 62 | */ 63 | void UpdateCurrentInteriorSettings(); 64 | 65 | /** 66 | * Apply the interior settings to ambient sounds 67 | */ 68 | void ApplyInteriorSettings(class AAudioVolume *Volume, const FInteriorSettings &Settings); 69 | 70 | FFMODListener() 71 | : Transform(FTransform::Identity) 72 | , Velocity(ForceInit) 73 | , Volume(NULL) 74 | , InteriorStartTime(0.0) 75 | , InteriorEndTime(0.0) 76 | , ExteriorEndTime(0.0) 77 | , InteriorLPFEndTime(0.0) 78 | , ExteriorLPFEndTime(0.0) 79 | , InteriorVolumeInterp(0.f) 80 | , InteriorLPFInterp(0.f) 81 | , ExteriorVolumeInterp(0.f) 82 | , ExteriorLPFInterp(0.f) 83 | { 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODPlatform.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | #pragma once 3 | 4 | #include "Containers/UnrealString.h" 5 | #include "fmod_common.h" 6 | #include "FMODSettings.h" 7 | 8 | FString FMODPlatform_GetDllPath(const TCHAR *ShortName, bool bExplicitPath, bool bUseLibPrefix); 9 | 10 | EFMODPlatforms::Type FMODPlatform_CurrentPlatform(); 11 | 12 | FString FMODPlatform_PlatformName(); 13 | 14 | void FMODPlatform_SetRealChannelCount(FMOD_ADVANCEDSETTINGS* advSettings); 15 | 16 | int FMODPlatform_MemoryPoolSize(); 17 | 18 | #ifdef FMOD_PLATFORM_LOAD_DLL 19 | void* FMODPlatformLoadDll(const TCHAR* LibToLoad); 20 | #endif 21 | 22 | FMOD_RESULT FMODPlatformSystemSetup(); -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODPort.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODPort.h" 4 | #include "FMODStudioModule.h" 5 | 6 | UFMODPort::UFMODPort(const FObjectInitializer &ObjectInitializer) 7 | : Super(ObjectInitializer) 8 | { 9 | } 10 | 11 | /** Get tags to show in content view */ 12 | void UFMODPort::GetAssetRegistryTags(TArray &OutTags) const 13 | { 14 | Super::GetAssetRegistryTags(OutTags); 15 | } 16 | 17 | FString UFMODPort::GetDesc() 18 | { 19 | return FString::Printf(TEXT("Port %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 20 | } 21 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODSettings.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODSettings.h" 4 | #include "Misc/Paths.h" 5 | 6 | #if WITH_EDITOR 7 | #include "Settings/ProjectPackagingSettings.h" 8 | #include 9 | #endif 10 | 11 | #ifdef FMOD_PLATFORM_HEADER 12 | #include "FMODPlatform.h" 13 | #endif 14 | 15 | ////////////////////////////////////////////////////////////////////////// 16 | // UPaperRuntimeSettings 17 | 18 | inline EFMODPlatforms::Type CurrentPlatform() 19 | { 20 | EFMODPlatforms::Type platform; 21 | #if defined(FMOD_PLATFORM_HEADER) 22 | platform = FMODPlatform_CurrentPlatform(); 23 | #elif WITH_EDITOR 24 | platform = EFMODPlatforms::Editor; 25 | #elif PLATFORM_WINDOWS 26 | platform = EFMODPlatforms::Windows; 27 | #elif PLATFORM_LINUX 28 | platform = EFMODPlatforms::Linux; 29 | #elif PLATFORM_MAC 30 | platform = EFMODPlatforms::Mac; 31 | #elif PLATFORM_ANDROID 32 | platform = EFMODPlatforms::Android; 33 | #elif PLATFORM_IOS || PLATFORM_TVOS 34 | platform = EFMODPlatforms::IOS; 35 | #endif 36 | return platform; 37 | } 38 | 39 | UFMODSettings::UFMODSettings(const FObjectInitializer &ObjectInitializer) 40 | : Super(ObjectInitializer) 41 | , bLoadAllBanks(true) 42 | , bLoadAllSampleData(false) 43 | , bEnableLiveUpdate(true) 44 | , bEnableEditorLiveUpdate(false) 45 | , OutputFormat(EFMODSpeakerMode::Surround_5_1) 46 | , OutputType(EFMODOutput::TYPE_AUTODETECT) 47 | , Vol0VirtualLevel(0.001f) 48 | , SampleRate(0) 49 | , bMatchHardwareSampleRate(true) 50 | , RealChannelCount(64) 51 | , TotalChannelCount(512) 52 | , DSPBufferLength(0) 53 | , DSPBufferCount(0) 54 | , FileBufferSize(2048) 55 | , StudioUpdatePeriod(0) 56 | , bLockAllBuses(false) 57 | , LiveUpdatePort(9264) 58 | , EditorLiveUpdatePort(9265) 59 | , ReloadBanksDelay(5) 60 | , bEnableAPIErrorLogging(false) 61 | , bEnableMemoryTracking(false) 62 | , ContentBrowserPrefix(TEXT("/Game/FMOD/")) 63 | , MasterBankName(TEXT("Master")) 64 | , LoggingLevel(LEVEL_WARNING) 65 | { 66 | BankOutputDirectory.Path = TEXT("FMOD"); 67 | } 68 | 69 | FString UFMODSettings::GetFullBankPath() const 70 | { 71 | FString FullPath = BankOutputDirectory.Path; 72 | if (FPaths::IsRelative(FullPath)) 73 | { 74 | FullPath = FPaths::ProjectContentDir() / FullPath; 75 | } 76 | 77 | if (ForcePlatformName == TEXT(".")) 78 | { 79 | // Leave path without subdirectory 80 | } 81 | else if (!ForcePlatformName.IsEmpty()) 82 | { 83 | FullPath = FullPath / ForcePlatformName; 84 | } 85 | else 86 | { 87 | #ifdef FMOD_PLATFORM_HEADER 88 | FString PlatformName = FMODPlatform_PlatformName(); 89 | #elif PLATFORM_IOS || PLATFORM_TVOS || PLATFORM_ANDROID 90 | FString PlatformName = "Mobile"; 91 | #elif PLATFORM_PS4 92 | FString PlatformName = "PS4"; 93 | #elif PLATFORM_XBOXONE 94 | FString PlatformName = "XboxOne"; 95 | #elif PLATFORM_SWITCH 96 | FString PlatformName = "Switch"; 97 | #else 98 | FString PlatformName = "Desktop"; 99 | #endif 100 | FullPath = FullPath / PlatformName; 101 | } 102 | return FullPath; 103 | } 104 | 105 | FString UFMODSettings::GetMasterBankFilename() const 106 | { 107 | return MasterBankName + TEXT(".bank"); 108 | } 109 | 110 | FString UFMODSettings::GetMasterAssetsBankFilename() const 111 | { 112 | return MasterBankName + TEXT(".assets.bank"); 113 | } 114 | 115 | FString UFMODSettings::GetMasterStringsBankFilename() const 116 | { 117 | return MasterBankName + TEXT(".strings.bank"); 118 | } 119 | 120 | FString UFMODSettings::GetFullContentPath() const 121 | { 122 | return ContentBrowserPrefix; 123 | } 124 | 125 | #if WITH_EDITOR 126 | FString UFMODSettings::GetDesktopBankPath() const 127 | { 128 | FString Path = BankOutputDirectory.Path; 129 | 130 | if (ForcePlatformName.IsEmpty()) 131 | { 132 | Path = Path / "Desktop"; 133 | } 134 | else if (ForcePlatformName != TEXT(".")) 135 | { 136 | Path = Path / ForcePlatformName; 137 | } 138 | 139 | return Path; 140 | } 141 | 142 | UFMODSettings::EProblem UFMODSettings::Check() const 143 | { 144 | if (!IsBankPathSet()) 145 | { 146 | return BankPathNotSet; 147 | } 148 | 149 | // Check packaging settings to ensure that only the correct bank output directory for desktop (or forced platform) banks is set-up for staging 150 | FString DesktopBankPath = GetDesktopBankPath(); 151 | UProjectPackagingSettings* PackagingSettings = Cast(UProjectPackagingSettings::StaticClass()->GetDefaultObject()); 152 | bool bCorrectPathAdded = false; 153 | bool bOtherPathsAdded = false; 154 | bool bAssetsToCookAdded = false; 155 | 156 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysStageAsNonUFS.Num(); ++i) 157 | { 158 | if (PackagingSettings->DirectoriesToAlwaysStageAsNonUFS[i].Path.StartsWith(BankOutputDirectory.Path)) 159 | { 160 | if (PackagingSettings->DirectoriesToAlwaysStageAsNonUFS[i].Path == DesktopBankPath) 161 | { 162 | bCorrectPathAdded = true; 163 | } 164 | else 165 | { 166 | bOtherPathsAdded = true; 167 | } 168 | } 169 | } 170 | 171 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysStageAsUFS.Num(); ++i) 172 | { 173 | if (PackagingSettings->DirectoriesToAlwaysStageAsUFS[i].Path.StartsWith(BankOutputDirectory.Path)) 174 | { 175 | bOtherPathsAdded = true; 176 | break; 177 | } 178 | } 179 | 180 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysCook.Num(); ++i) 181 | { 182 | if (PackagingSettings->DirectoriesToAlwaysCook[i].Path.StartsWith(GetFullContentPath())) 183 | { 184 | bAssetsToCookAdded = true; 185 | break; 186 | } 187 | } 188 | 189 | if (!bCorrectPathAdded || bOtherPathsAdded || !bAssetsToCookAdded) 190 | { 191 | return PackagingSettingsBad; 192 | } 193 | 194 | return Okay; 195 | } 196 | 197 | void UFMODSettings::PostEditChangeProperty(FPropertyChangedEvent& e) 198 | { 199 | FName PropertyName = (e.Property != NULL) ? e.Property->GetFName() : NAME_None; 200 | // Validate ContentBrowserPrefix, as Unreal can crash if the prefix is improperly configured 201 | if (PropertyName == GET_MEMBER_NAME_CHECKED(UFMODSettings, ContentBrowserPrefix)) 202 | { 203 | FStrProperty* prop = CastField(e.Property); 204 | void* propertyAddress = e.Property->ContainerPtrToValuePtr(this); 205 | FString contentBrowserPrefix = prop->GetPropertyValue(propertyAddress); 206 | 207 | // Check for empty prefix 208 | if (contentBrowserPrefix.IsEmpty()) { 209 | contentBrowserPrefix = "/"; 210 | } 211 | else { 212 | 213 | // FName's max length is 1023, but FMOD needs to append additional directories 214 | // 512 is an arbitary length that should cover most prefix lengths 215 | const int ContentBrowserPrefixMaxLength = 512; 216 | 217 | // Ensure that length doesn't exceed max prefix length 218 | if (contentBrowserPrefix.Len() > ContentBrowserPrefixMaxLength) { 219 | contentBrowserPrefix.LeftChopInline(ContentBrowserPrefixMaxLength); 220 | } 221 | 222 | // Remove invalid long package characters 223 | contentBrowserPrefix = ObjectTools::SanitizeInvalidChars(contentBrowserPrefix, INVALID_LONGPACKAGE_CHARACTERS); 224 | 225 | // Remove double slashes 226 | int32 index = contentBrowserPrefix.Find(FString("//")); 227 | while (index != INDEX_NONE) { 228 | contentBrowserPrefix.RemoveAt(index); 229 | index = contentBrowserPrefix.Find(FString("//")); 230 | } 231 | 232 | // Check for starting and ending with slash 233 | if (!contentBrowserPrefix.StartsWith("/")) { 234 | contentBrowserPrefix = "/" + contentBrowserPrefix; 235 | } 236 | if (!contentBrowserPrefix.EndsWith("/")) { 237 | contentBrowserPrefix += "/"; 238 | } 239 | } 240 | 241 | prop->SetPropertyValue(propertyAddress, contentBrowserPrefix); 242 | 243 | } 244 | Super::PostEditChangeProperty(e); 245 | } 246 | #endif // WITH_EDITOR 247 | 248 | EFMODSpeakerMode::Type UFMODSettings::GetSpeakerMode() const 249 | { 250 | return Platforms.Contains(CurrentPlatform()) ? Platforms.Find(CurrentPlatform())->SpeakerMode : OutputFormat; 251 | } 252 | 253 | EFMODOutput::Type UFMODSettings::GetOutputType() const 254 | { 255 | return Platforms.Contains(CurrentPlatform()) ? Platforms.Find(CurrentPlatform())->OutputType : OutputType; 256 | } 257 | 258 | int32 UFMODSettings::GetSampleRate() const 259 | { 260 | return Platforms.Contains(CurrentPlatform()) ? Platforms.Find(CurrentPlatform())->SampleRate : SampleRate; 261 | } 262 | 263 | int32 UFMODSettings::GetMemoryPoolSize() const 264 | { 265 | return (Platforms.Contains(CurrentPlatform()) ? Platforms.Find(CurrentPlatform())->CustomPoolSize : 0); 266 | } 267 | 268 | int32 UFMODSettings::GetRealChannelCount() const 269 | { 270 | return Platforms.Contains(CurrentPlatform()) ? Platforms.Find(CurrentPlatform())->RealChannelCount : RealChannelCount; 271 | } 272 | 273 | bool UFMODSettings::SetCodecs(FMOD_ADVANCEDSETTINGS& advSettings) const 274 | { 275 | const FFMODPlatformSettings* platform = Platforms.Find(CurrentPlatform()); 276 | if (platform == nullptr) 277 | { 278 | return false; 279 | } 280 | TMap, int32> codecList = platform->Codecs; 281 | 282 | for (const TPair, int32>& pair : codecList) 283 | { 284 | switch (pair.Key) 285 | { 286 | case EFMODCodec::XMA: 287 | advSettings.maxXMACodecs = pair.Value; 288 | break; 289 | case EFMODCodec::AT9: 290 | advSettings.maxAT9Codecs = pair.Value; 291 | break; 292 | case EFMODCodec::FADPCM: 293 | advSettings.maxFADPCMCodecs = pair.Value; 294 | break; 295 | case EFMODCodec::OPUS: 296 | advSettings.maxOpusCodecs = pair.Value; 297 | break; 298 | case EFMODCodec::VORBIS: 299 | default: 300 | advSettings.maxVorbisCodecs = pair.Value; 301 | break; 302 | } 303 | } 304 | return true; 305 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODSnapshot.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODSnapshot.h" 4 | #include "FMODStudioModule.h" 5 | 6 | UFMODSnapshot::UFMODSnapshot(const FObjectInitializer &ObjectInitializer) 7 | : Super(ObjectInitializer) 8 | { 9 | } 10 | 11 | FString UFMODSnapshot::GetDesc() 12 | { 13 | return FString::Printf(TEXT("Snapshot %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 14 | } 15 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODSnapshotReverb.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODSnapshotReverb.h" 4 | 5 | UFMODSnapshotReverb::UFMODSnapshotReverb(const FObjectInitializer &ObjectInitializer) 6 | : Super(ObjectInitializer) 7 | { 8 | } 9 | 10 | bool UFMODSnapshotReverb::IsAsset() const 11 | { 12 | return this != GetClass()->GetDefaultObject(); 13 | } 14 | 15 | #if WITH_EDITORONLY_DATA 16 | void UFMODSnapshotReverb::PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) 17 | { 18 | } 19 | #endif // EDITORONLY_DATA -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODStudioPrivatePCH.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | #pragma once 3 | 4 | #include "CoreMinimal.h" 5 | #include "UObject/NoExportTypes.h" 6 | #include "Components/SceneComponent.h" 7 | #include "Runtime/Launch/Resources/Version.h" 8 | 9 | DECLARE_LOG_CATEGORY_EXTERN(LogFMOD, Log, All); -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/FMODVCA.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODVCA.h" 4 | #include "FMODStudioModule.h" 5 | 6 | UFMODVCA::UFMODVCA(const FObjectInitializer &ObjectInitializer) 7 | : Super(ObjectInitializer) 8 | { 9 | } 10 | 11 | /** Get tags to show in content view */ 12 | void UFMODVCA::GetAssetRegistryTags(TArray &OutTags) const 13 | { 14 | Super::GetAssetRegistryTags(OutTags); 15 | } 16 | 17 | FString UFMODVCA::GetDesc() 18 | { 19 | return FString::Printf(TEXT("VCA %s"), *AssetGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); 20 | } 21 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlSection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventControlSection.h" 4 | #include "Channels/MovieSceneChannelProxy.h" 5 | #include "UObject/SequencerObjectVersion.h" 6 | #include "UObject/Package.h" 7 | #include "Modules/ModuleManager.h" 8 | 9 | FFMODEventControlChannel::FFMODEventControlChannel() 10 | { 11 | #if WITH_HOT_RELOAD 12 | if (!GIsHotReload) 13 | #endif 14 | { 15 | SetEnum(StaticEnum()); 16 | } 17 | } 18 | 19 | UFMODEventControlSection::UFMODEventControlSection(const FObjectInitializer &ObjectInitializer) 20 | : Super(ObjectInitializer) 21 | { 22 | SetRange(TRange::All()); 23 | 24 | int32 LinkerCustomVersion = GetLinkerCustomVersion(FSequencerObjectVersion::GUID); 25 | EMovieSceneCompletionMode CompletionMode; 26 | 27 | if (LinkerCustomVersion < FSequencerObjectVersion::WhenFinishedDefaultsToRestoreState) 28 | { 29 | CompletionMode = EMovieSceneCompletionMode::KeepState; 30 | } 31 | else if (LinkerCustomVersion < FSequencerObjectVersion::WhenFinishedDefaultsToProjectDefault) 32 | { 33 | CompletionMode = EMovieSceneCompletionMode::RestoreState; 34 | } 35 | else 36 | { 37 | CompletionMode = EMovieSceneCompletionMode::ProjectDefault; 38 | } 39 | 40 | EvalOptions.EnableAndSetCompletionMode(CompletionMode); 41 | 42 | #if WITH_EDITOR 43 | 44 | ChannelProxy = MakeShared(ControlKeys, FMovieSceneChannelMetaData(), TMovieSceneExternalValue()); 45 | 46 | #else 47 | 48 | ChannelProxy = MakeShared(ControlKeys); 49 | 50 | #endif 51 | } 52 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlSection.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/ObjectMacros.h" 7 | #include "Curves/KeyHandle.h" 8 | #include "MovieSceneClipboard.h" 9 | #include "MovieSceneSection.h" 10 | #include "Channels/MovieSceneByteChannel.h" 11 | #include "FMODEventControlSection.generated.h" 12 | 13 | /** Defines the types of FMOD event control keys. */ 14 | UENUM() 15 | enum class EFMODEventControlKey : uint8 16 | { 17 | Stop = 0, 18 | Play = 1, 19 | Pause = 2 20 | }; 21 | 22 | USTRUCT() 23 | struct FFMODEventControlChannel : public FMovieSceneByteChannel 24 | { 25 | GENERATED_BODY() 26 | 27 | FFMODEventControlChannel(); 28 | }; 29 | 30 | template <> 31 | struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 32 | { 33 | enum { WithStructuredSerializeFromMismatchedTag = true }; 34 | }; 35 | 36 | template <> 37 | struct TMovieSceneChannelTraits : TMovieSceneChannelTraitsBase 38 | { 39 | enum { SupportsDefaults = false }; 40 | 41 | #if WITH_EDITOR 42 | 43 | /** Byte channels can have external values (ie, they can get their values from external objects for UI purposes) */ 44 | typedef TMovieSceneExternalValue ExtendedEditorDataType; 45 | 46 | #endif 47 | }; 48 | 49 | /** FMOD Event control section */ 50 | UCLASS(MinimalAPI) 51 | class UFMODEventControlSection : public UMovieSceneSection 52 | { 53 | GENERATED_UCLASS_BODY() 54 | 55 | public: 56 | /** Channel containing the event control keys */ 57 | UPROPERTY() 58 | FFMODEventControlChannel ControlKeys; 59 | }; 60 | 61 | inline void AssignValue(FFMODEventControlChannel *InChannel, FKeyHandle InKeyHandle, EFMODEventControlKey InValue) 62 | { 63 | TMovieSceneChannelData ChannelData = InChannel->GetData(); 64 | int32 ValueIndex = ChannelData.GetIndex(InKeyHandle); 65 | 66 | if (ValueIndex != INDEX_NONE) 67 | { 68 | ChannelData.GetValues()[ValueIndex] = (uint8)InValue; 69 | } 70 | } 71 | 72 | inline bool EvaluateChannel(const FFMODEventControlChannel *InChannel, FFrameTime InTime, EFMODEventControlKey &OutValue) 73 | { 74 | uint8 RawValue = 0; 75 | if (InChannel->Evaluate(InTime, RawValue)) 76 | { 77 | OutValue = (EFMODEventControlKey)RawValue; 78 | return true; 79 | } 80 | return false; 81 | } 82 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlSectionTemplate.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventControlSectionTemplate.h" 4 | #include "FMODAmbientSound.h" 5 | #include "FMODAudioComponent.h" 6 | #include "Evaluation/MovieSceneEvaluation.h" 7 | #include "IMovieScenePlayer.h" 8 | 9 | enum EventControlKeyInternal 10 | { 11 | Stop, 12 | Play, 13 | Pause, 14 | SequencePause, 15 | SequenceResume, 16 | MAX 17 | }; 18 | 19 | EventControlKeyInternal MapControlKey(EFMODEventControlKey key) 20 | { 21 | switch (key) 22 | { 23 | case EFMODEventControlKey::Stop: 24 | return EventControlKeyInternal::Stop; 25 | break; 26 | case EFMODEventControlKey::Play: 27 | return EventControlKeyInternal::Play; 28 | break; 29 | case EFMODEventControlKey::Pause: 30 | return EventControlKeyInternal::Pause; 31 | break; 32 | default: 33 | return EventControlKeyInternal::MAX; 34 | break; 35 | } 36 | } 37 | 38 | struct FPlayingToken : IMovieScenePreAnimatedToken 39 | { 40 | FPlayingToken(UObject &InObject) 41 | { 42 | bPlaying = false; 43 | TimelinePosition = 0; 44 | 45 | if (UFMODAudioComponent *AudioComponent = Cast(&InObject)) 46 | { 47 | if (IsValid(AudioComponent)) 48 | { 49 | bPlaying = AudioComponent->IsPlaying(); 50 | TimelinePosition = AudioComponent->GetTimelinePosition(); 51 | } 52 | } 53 | } 54 | 55 | virtual void RestoreState(UObject &Object, const UE::MovieScene::FRestoreStateParams& Params) override 56 | { 57 | UFMODAudioComponent *AudioComponent = CastChecked(&Object); 58 | 59 | if (AudioComponent) 60 | { 61 | if (bPlaying && !AudioComponent->bPlayEnded) 62 | { 63 | AudioComponent->Play(); 64 | AudioComponent->SetTimelinePosition(TimelinePosition); 65 | } 66 | else 67 | { 68 | AudioComponent->Stop(); 69 | } 70 | } 71 | } 72 | 73 | private: 74 | bool bPlaying; 75 | int32 TimelinePosition; 76 | }; 77 | 78 | struct FPlayingTokenProducer : IMovieScenePreAnimatedTokenProducer 79 | { 80 | static FMovieSceneAnimTypeID GetAnimTypeID() { return TMovieSceneAnimTypeID(); } 81 | 82 | private: 83 | virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject &Object) const override { return FPlayingToken(Object); } 84 | }; 85 | 86 | struct FFMODEventControlExecutionToken : IMovieSceneExecutionToken 87 | { 88 | FFMODEventControlExecutionToken(EventControlKeyInternal InEventControlKey, FFrameTime InKeyTime) 89 | : EventControlKey(InEventControlKey) 90 | , KeyTime(InKeyTime) 91 | { 92 | } 93 | 94 | /** Execute this token, operating on all objects referenced by 'Operand' */ 95 | virtual void Execute(const FMovieSceneContext &Context, const FMovieSceneEvaluationOperand &Operand, FPersistentEvaluationData &PersistentData, 96 | IMovieScenePlayer &Player) 97 | { 98 | for (TWeakObjectPtr<> &WeakObject : Player.FindBoundObjects(Operand)) 99 | { 100 | UFMODAudioComponent *AudioComponent = Cast(WeakObject.Get()); 101 | 102 | if (!AudioComponent) 103 | { 104 | AFMODAmbientSound *AmbientSound = Cast(WeakObject.Get()); 105 | AudioComponent = AmbientSound ? AmbientSound->AudioComponent : nullptr; 106 | } 107 | 108 | if (IsValid(AudioComponent)) 109 | { 110 | EFMODSystemContext::Type SystemContext = 111 | (GWorld && GWorld->WorldType == EWorldType::Editor) ? EFMODSystemContext::Editor : EFMODSystemContext::Runtime; 112 | 113 | if (EventControlKey == EventControlKeyInternal::Stop && KeyTime == 0 && SystemContext == EFMODSystemContext::Editor) 114 | { 115 | // Skip state saving when auditioning sequencer 116 | } 117 | else 118 | { 119 | Player.SavePreAnimatedState(*AudioComponent, FPlayingTokenProducer::GetAnimTypeID(), FPlayingTokenProducer()); 120 | } 121 | 122 | if (EventControlKey == EventControlKeyInternal::Play) 123 | { 124 | if (AudioComponent->GetPaused()) 125 | { 126 | AudioComponent->ResumeInternal(UFMODAudioComponent::PauseContext::Explicit); 127 | } 128 | else 129 | { 130 | if (AudioComponent->IsPlaying()) 131 | { 132 | AudioComponent->Stop(); 133 | } 134 | AudioComponent->PlayInternal(SystemContext); 135 | } 136 | } 137 | else if (EventControlKey == EventControlKeyInternal::Stop) 138 | { 139 | AudioComponent->Stop(); 140 | } 141 | else if (EventControlKey == EventControlKeyInternal::Pause) 142 | { 143 | AudioComponent->PauseInternal(UFMODAudioComponent::PauseContext::Explicit); 144 | } 145 | else if (EventControlKey == EventControlKeyInternal::SequencePause) 146 | { 147 | AudioComponent->PauseInternal(UFMODAudioComponent::PauseContext::Implicit); 148 | } 149 | else if (EventControlKey == EventControlKeyInternal::SequenceResume) 150 | { 151 | AudioComponent->ResumeInternal(UFMODAudioComponent::PauseContext::Implicit); 152 | } 153 | 154 | } 155 | } 156 | } 157 | 158 | EventControlKeyInternal EventControlKey; 159 | FFrameTime KeyTime; 160 | }; 161 | 162 | static bool RuntimeSequenceSetup = false; 163 | 164 | FFMODEventControlSectionTemplate::FFMODEventControlSectionTemplate(const UFMODEventControlSection &Section) 165 | : ControlKeys(Section.ControlKeys) 166 | { 167 | EnableOverrides(FMovieSceneEvalTemplateBase::EOverrideMask::RequiresSetupFlag); 168 | EnableOverrides(FMovieSceneEvalTemplateBase::EOverrideMask::RequiresTearDownFlag); 169 | } 170 | 171 | void FFMODEventControlSectionTemplate::Setup(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const 172 | { 173 | IsEditorSequence = GWorld && GWorld->WorldType == EWorldType::Editor; 174 | if (!IsEditorSequence) 175 | { 176 | RuntimeSequenceSetup = true; 177 | } 178 | } 179 | 180 | void FFMODEventControlSectionTemplate::TearDown(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const 181 | { 182 | if (!IsEditorSequence) 183 | { 184 | RuntimeSequenceSetup = false; 185 | } 186 | } 187 | 188 | void FFMODEventControlSectionTemplate::Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context, 189 | const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const 190 | { 191 | if (IsEditorSequence && RuntimeSequenceSetup) 192 | { 193 | // If the Sequence Editor is open during PIE, it will also try to play its Sequence. 194 | // Don't let it, otherwise Execution Tokens will be double-issued. 195 | return; 196 | } 197 | 198 | const bool bPlaying = Context.IsSilent() == false && Context.GetDirection() == EPlayDirection::Forwards && 199 | Context.GetRange().Size() >= FFrameTime(0) && Context.GetStatus() == EMovieScenePlayerStatus::Playing; 200 | 201 | if (!bPlaying && IsEditorSequence && !RuntimeSequenceSetup) 202 | { 203 | if (Context.GetStatus() == EMovieScenePlayerStatus::Paused) 204 | { 205 | ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::Pause, FFrameTime(0))); 206 | } 207 | else 208 | { 209 | ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::Stop, FFrameTime(0))); 210 | } 211 | } 212 | else 213 | { 214 | TRange PlaybackRange = Context.GetFrameNumberRange(); 215 | TMovieSceneChannelData ChannelData = ControlKeys.GetData(); 216 | 217 | // Find the index of the key handle that exists before this time 218 | TArrayView Times = ChannelData.GetTimes(); 219 | TArrayView Values = ChannelData.GetValues(); 220 | 221 | const int32 LastKeyIndex = Algo::UpperBound(Times, PlaybackRange.GetUpperBoundValue()) - 1; 222 | if (LastKeyIndex >= 0 && PlaybackRange.Contains(Times[LastKeyIndex])) 223 | { 224 | FFMODEventControlExecutionToken NewToken(MapControlKey((EFMODEventControlKey)Values[LastKeyIndex]), Times[LastKeyIndex]); 225 | ExecutionTokens.Add(MoveTemp(NewToken)); 226 | } 227 | } 228 | 229 | // Handle direct pause/unpause calls on sequence 230 | if (Context.GetStatus() == EMovieScenePlayerStatus::Stopped) 231 | { 232 | ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::SequencePause, FFrameTime(0))); 233 | } 234 | else 235 | { 236 | ExecutionTokens.Add(FFMODEventControlExecutionToken(EventControlKeyInternal::SequenceResume, FFrameTime(0))); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlSectionTemplate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/ObjectMacros.h" 7 | #include "Evaluation/MovieSceneEvalTemplate.h" 8 | #include "FMODEventControlSection.h" 9 | #include "FMODEventControlSectionTemplate.generated.h" 10 | 11 | USTRUCT() 12 | struct FFMODEventControlSectionTemplate : public FMovieSceneEvalTemplate 13 | { 14 | GENERATED_BODY() 15 | 16 | FFMODEventControlSectionTemplate() {} 17 | FFMODEventControlSectionTemplate(const UFMODEventControlSection &Section); 18 | 19 | UPROPERTY() 20 | FFMODEventControlChannel ControlKeys; 21 | 22 | private: 23 | virtual UScriptStruct &GetScriptStructImpl() const override { return *StaticStruct(); } 24 | virtual void Setup(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const override; 25 | virtual void TearDown(FPersistentEvaluationData &PersistentData, IMovieScenePlayer &Player) const override; 26 | virtual void Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context, 27 | const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const override; 28 | 29 | mutable bool IsEditorSequence; 30 | }; 31 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlTrack.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventControlTrack.h" 4 | #include "FMODEventControlSection.h" 5 | #include "IMovieScenePlayer.h" 6 | #include "FMODEventControlSectionTemplate.h" 7 | #include "MovieSceneCommonHelpers.h" 8 | 9 | #define LOCTEXT_NAMESPACE "FMODEventControlTrack" 10 | 11 | UFMODEventControlTrack::UFMODEventControlTrack(const FObjectInitializer &ObjectInitializer) 12 | : Super(ObjectInitializer) 13 | { 14 | #if WITH_EDITORONLY_DATA 15 | TrackTint = FColor(255, 255, 255, 160); 16 | #endif 17 | } 18 | 19 | const TArray &UFMODEventControlTrack::GetAllSections() const 20 | { 21 | return ControlSections; 22 | } 23 | 24 | bool UFMODEventControlTrack::HasSection(const UMovieSceneSection &Section) const 25 | { 26 | return ControlSections.Contains(&Section); 27 | } 28 | 29 | void UFMODEventControlTrack::AddSection(UMovieSceneSection &Section) 30 | { 31 | ControlSections.Add(&Section); 32 | } 33 | 34 | void UFMODEventControlTrack::RemoveSection(UMovieSceneSection &Section) 35 | { 36 | ControlSections.Remove(&Section); 37 | } 38 | 39 | bool UFMODEventControlTrack::IsEmpty() const 40 | { 41 | return ControlSections.Num() == 0; 42 | } 43 | 44 | void UFMODEventControlTrack::AddNewSection(FFrameNumber SectionTime) 45 | { 46 | if (MovieSceneHelpers::FindSectionAtTime(ControlSections, SectionTime) == nullptr) 47 | { 48 | UFMODEventControlSection *NewSection = Cast(CreateNewSection()); 49 | ControlSections.Add(NewSection); 50 | } 51 | } 52 | 53 | bool UFMODEventControlTrack::SupportsType(TSubclassOf SectionClass) const 54 | { 55 | return SectionClass == UFMODEventControlSection::StaticClass(); 56 | } 57 | 58 | UMovieSceneSection *UFMODEventControlTrack::CreateNewSection() 59 | { 60 | return NewObject(this); 61 | } 62 | 63 | FMovieSceneEvalTemplatePtr UFMODEventControlTrack::CreateTemplateForSection(const UMovieSceneSection& InSection) const 64 | { 65 | return FFMODEventControlSectionTemplate(*CastChecked(&InSection)); 66 | } 67 | 68 | #if WITH_EDITORONLY_DATA 69 | FText UFMODEventControlTrack::GetDefaultDisplayName() const 70 | { 71 | return LOCTEXT("DisplayName", "FMOD Event"); 72 | } 73 | #endif 74 | 75 | #undef LOCTEXT_NAMESPACE 76 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventControlTrack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/ObjectMacros.h" 7 | #include "MovieSceneNameableTrack.h" 8 | #include "Compilation/IMovieSceneTrackTemplateProducer.h" 9 | #include "FMODEventControlTrack.generated.h" 10 | 11 | /** Handles control of an FMOD Event */ 12 | UCLASS(MinimalAPI) 13 | class UFMODEventControlTrack : public UMovieSceneNameableTrack, public IMovieSceneTrackTemplateProducer 14 | { 15 | GENERATED_UCLASS_BODY() 16 | 17 | public: 18 | virtual TArray GetAllControlSections() const { return ControlSections; } 19 | 20 | public: 21 | // Begin UMovieSceneTrack interface 22 | virtual bool HasSection(const UMovieSceneSection &Section) const override; 23 | virtual void AddSection(UMovieSceneSection &Section) override; 24 | virtual void RemoveSection(UMovieSceneSection &Section) override; 25 | virtual bool IsEmpty() const override; 26 | virtual const TArray &GetAllSections() const override; 27 | virtual void AddNewSection(FFrameNumber SectionTime); 28 | virtual bool SupportsType(TSubclassOf SectionClass) const override; 29 | virtual UMovieSceneSection *CreateNewSection() override; 30 | // End UMovieSceneTrack interface 31 | 32 | // IMovieSceneTrackTemplateProducer interface 33 | virtual FMovieSceneEvalTemplatePtr CreateTemplateForSection(const UMovieSceneSection& InSection) const override; 34 | 35 | #if WITH_EDITORONLY_DATA 36 | virtual FText GetDefaultDisplayName() const override; 37 | #endif 38 | 39 | private: 40 | /** List of all event control sections. */ 41 | UPROPERTY() 42 | TArray ControlSections; 43 | }; 44 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventParameterSectionTemplate.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2017. 2 | 3 | #include "FMODEventParameterSectionTemplate.h" 4 | #include "FMODAmbientSound.h" 5 | #include "FMODEvent.h" 6 | #include "FMODEventParameterTrack.h" 7 | #include "IMovieScenePlayer.h" 8 | #include "fmod_studio.hpp" 9 | 10 | struct FFMODEventParameterPreAnimatedToken : IMovieScenePreAnimatedToken 11 | { 12 | FFMODEventParameterPreAnimatedToken() {} 13 | 14 | FFMODEventParameterPreAnimatedToken(FFMODEventParameterPreAnimatedToken &&) = default; 15 | FFMODEventParameterPreAnimatedToken &operator=(FFMODEventParameterPreAnimatedToken &&) = default; 16 | 17 | virtual void RestoreState(UObject &Object, const UE::MovieScene::FRestoreStateParams& Params) override 18 | { 19 | UFMODAudioComponent *AudioComponent = CastChecked(&Object); 20 | 21 | if (IsValid(AudioComponent)) 22 | { 23 | for (FScalarParameterNameAndValue &Value : Values) 24 | { 25 | AudioComponent->SetParameter(Value.ParameterName, Value.Value); 26 | } 27 | } 28 | } 29 | 30 | TArray Values; 31 | }; 32 | 33 | struct FFMODEventParameterPreAnimatedTokenProducer : IMovieScenePreAnimatedTokenProducer 34 | { 35 | virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject &Object) const override 36 | { 37 | UFMODAudioComponent *AudioComponent = CastChecked(&Object); 38 | 39 | FFMODEventParameterPreAnimatedToken Token; 40 | 41 | if (IsValid(AudioComponent) && AudioComponent->Event) 42 | { 43 | TArray ParameterDescriptions; 44 | AudioComponent->Event->GetParameterDescriptions(ParameterDescriptions); 45 | 46 | for (const FMOD_STUDIO_PARAMETER_DESCRIPTION &ParameterDescription : ParameterDescriptions) 47 | { 48 | float Value = AudioComponent->GetParameter(ParameterDescription.name); 49 | Token.Values.Add(FScalarParameterNameAndValue(ParameterDescription.name, Value)); 50 | } 51 | } 52 | 53 | return MoveTemp(Token); 54 | } 55 | }; 56 | 57 | struct FFMODEventParameterExecutionToken : IMovieSceneExecutionToken 58 | { 59 | FFMODEventParameterExecutionToken() = default; 60 | 61 | FFMODEventParameterExecutionToken(FFMODEventParameterExecutionToken &&) = default; 62 | FFMODEventParameterExecutionToken &operator=(FFMODEventParameterExecutionToken &&) = default; 63 | 64 | // Non-copyable 65 | FFMODEventParameterExecutionToken(const FFMODEventParameterExecutionToken &) = delete; 66 | FFMODEventParameterExecutionToken &operator=(const FFMODEventParameterExecutionToken &) = delete; 67 | 68 | virtual void Execute(const FMovieSceneContext &Context, const FMovieSceneEvaluationOperand &Operand, FPersistentEvaluationData &PersistentData, 69 | IMovieScenePlayer &Player) 70 | { 71 | for (TWeakObjectPtr<> &WeakObject : Player.FindBoundObjects(Operand)) 72 | { 73 | UFMODAudioComponent *AudioComponent = Cast(WeakObject.Get()); 74 | 75 | if (!AudioComponent) 76 | { 77 | AFMODAmbientSound *AmbientSound = Cast(WeakObject.Get()); 78 | AudioComponent = AmbientSound ? AmbientSound->AudioComponent : nullptr; 79 | } 80 | 81 | if (IsValid(AudioComponent)) 82 | { 83 | Player.SavePreAnimatedState( 84 | *AudioComponent, TMovieSceneAnimTypeID(), FFMODEventParameterPreAnimatedTokenProducer()); 85 | 86 | for (const FScalarParameterNameAndValue &NameAndValue : Values.ScalarValues) 87 | { 88 | AudioComponent->SetParameter(NameAndValue.ParameterName, NameAndValue.Value); 89 | } 90 | } 91 | } 92 | } 93 | 94 | FEvaluatedParameterSectionValues Values; 95 | }; 96 | 97 | FFMODEventParameterSectionTemplate::FFMODEventParameterSectionTemplate( 98 | const UMovieSceneParameterSection &Section, const UFMODEventParameterTrack &Track) 99 | : FMovieSceneParameterSectionTemplate(Section) 100 | { 101 | } 102 | 103 | void FFMODEventParameterSectionTemplate::Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context, 104 | const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const 105 | { 106 | FFMODEventParameterExecutionToken ExecutionToken; 107 | EvaluateCurves(Context, ExecutionToken.Values); 108 | ExecutionTokens.Add(MoveTemp(ExecutionToken)); 109 | } 110 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventParameterSectionTemplate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/ObjectMacros.h" 7 | #include "Evaluation/MovieSceneParameterTemplate.h" 8 | #include "FMODEventParameterSectionTemplate.generated.h" 9 | 10 | class UFMODEventParameterTrack; 11 | 12 | USTRUCT() 13 | struct FFMODEventParameterSectionTemplate : public FMovieSceneParameterSectionTemplate 14 | { 15 | GENERATED_BODY() 16 | 17 | FFMODEventParameterSectionTemplate() {} 18 | FFMODEventParameterSectionTemplate(const UMovieSceneParameterSection &Section, const UFMODEventParameterTrack &Track); 19 | 20 | private: 21 | virtual UScriptStruct &GetScriptStructImpl() const override { return *StaticStruct(); } 22 | virtual void Evaluate(const FMovieSceneEvaluationOperand &Operand, const FMovieSceneContext &Context, 23 | const FPersistentEvaluationData &PersistentData, FMovieSceneExecutionTokens &ExecutionTokens) const override; 24 | }; 25 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventParameterTrack.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventParameterTrack.h" 4 | #include "FMODEventParameterSectionTemplate.h" 5 | #include "IMovieScenePlayer.h" 6 | #include "MovieSceneCommonHelpers.h" 7 | 8 | #define LOCTEXT_NAMESPACE "FMODEventParameterTrack" 9 | 10 | UFMODEventParameterTrack::UFMODEventParameterTrack(const FObjectInitializer &ObjectInitializer) 11 | : Super(ObjectInitializer) 12 | { 13 | #if WITH_EDITORONLY_DATA 14 | TrackTint = FColor(0, 170, 255, 65); 15 | #endif 16 | } 17 | 18 | FMovieSceneEvalTemplatePtr UFMODEventParameterTrack::CreateTemplateForSection(const UMovieSceneSection &InSection) const 19 | { 20 | return FFMODEventParameterSectionTemplate(*CastChecked(&InSection), *this); 21 | } 22 | 23 | UMovieSceneSection *UFMODEventParameterTrack::CreateNewSection() 24 | { 25 | return NewObject(this, UMovieSceneParameterSection::StaticClass(), NAME_None, RF_Transactional); 26 | } 27 | 28 | void UFMODEventParameterTrack::RemoveAllAnimationData() 29 | { 30 | Sections.Empty(); 31 | } 32 | 33 | bool UFMODEventParameterTrack::HasSection(const UMovieSceneSection &Section) const 34 | { 35 | return Sections.Contains(&Section); 36 | } 37 | 38 | void UFMODEventParameterTrack::AddSection(UMovieSceneSection &Section) 39 | { 40 | Sections.Add(&Section); 41 | } 42 | 43 | void UFMODEventParameterTrack::RemoveSection(UMovieSceneSection &Section) 44 | { 45 | Sections.Remove(&Section); 46 | } 47 | 48 | bool UFMODEventParameterTrack::IsEmpty() const 49 | { 50 | return Sections.Num() == 0; 51 | } 52 | 53 | const TArray &UFMODEventParameterTrack::GetAllSections() const 54 | { 55 | return Sections; 56 | } 57 | 58 | #if WITH_EDITORONLY_DATA 59 | FText UFMODEventParameterTrack::GetDefaultDisplayName() const 60 | { 61 | return LOCTEXT("DisplayName", "FMOD Event Parameter"); 62 | } 63 | #endif 64 | 65 | void UFMODEventParameterTrack::AddParameterKey(FName ParameterName, FFrameNumber Time, float Value) 66 | { 67 | UMovieSceneParameterSection *NearestSection = Cast(MovieSceneHelpers::FindNearestSectionAtTime(Sections, Time)); 68 | if (NearestSection == nullptr) 69 | { 70 | NearestSection = Cast(CreateNewSection()); 71 | NearestSection->SetRange(TRange::Inclusive(Time, Time)); 72 | Sections.Add(NearestSection); 73 | } 74 | NearestSection->AddScalarParameterKey(ParameterName, Time, Value); 75 | } 76 | 77 | #undef LOCTEXT_NAMESPACE 78 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Private/Sequencer/FMODEventParameterTrack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/ObjectMacros.h" 7 | #include "Sections/MovieSceneParameterSection.h" 8 | #include "MovieSceneNameableTrack.h" 9 | #include "Compilation/IMovieSceneTrackTemplateProducer.h" 10 | #include "FMODEventParameterTrack.generated.h" 11 | 12 | /** Handles manipulation of event parameters in a movie scene. */ 13 | UCLASS(MinimalAPI) 14 | class UFMODEventParameterTrack : public UMovieSceneNameableTrack, public IMovieSceneTrackTemplateProducer 15 | { 16 | GENERATED_UCLASS_BODY() 17 | 18 | public: 19 | // UMovieSceneTrack interface 20 | virtual UMovieSceneSection *CreateNewSection() override; 21 | virtual void RemoveAllAnimationData() override; 22 | virtual bool HasSection(const UMovieSceneSection &Section) const override; 23 | virtual void AddSection(UMovieSceneSection &Section) override; 24 | virtual void RemoveSection(UMovieSceneSection &Section) override; 25 | virtual bool IsEmpty() const override; 26 | virtual const TArray &GetAllSections() const override; 27 | 28 | // ~IMovieSceneTrackTemplateProducer interface 29 | virtual FMovieSceneEvalTemplatePtr CreateTemplateForSection(const UMovieSceneSection &InSection) const override; 30 | 31 | // End UMovieSceneTrack interface 32 | 33 | #if WITH_EDITORONLY_DATA 34 | virtual FText GetDefaultDisplayName() const override; 35 | #endif 36 | 37 | public: 38 | /** Adds a (scalar) event parameter key to the track. */ 39 | void FMODSTUDIO_API AddParameterKey(FName ParameterName, FFrameNumber Time, float Value); 40 | 41 | private: 42 | /** The sections owned by this track. */ 43 | UPROPERTY() 44 | TArray Sections; 45 | }; 46 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Public/FMOD/fmod_android.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fmod_common.h" 4 | #include 5 | 6 | extern "C" FMOD_RESULT F_API FMOD_Android_JNI_Init(JavaVM *vm, jobject javaActivity); 7 | extern "C" FMOD_RESULT F_API FMOD_Android_JNI_Close(); 8 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Public/FMOD/fmod_codec.h: -------------------------------------------------------------------------------- 1 | /* ======================================================================================== */ 2 | /* FMOD Core API - Codec development header file. */ 3 | /* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2025. */ 4 | /* */ 5 | /* Use this header if you are wanting to develop your own file format plugin to use with */ 6 | /* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ 7 | /* can register and use. See the documentation and examples on how to make a working */ 8 | /* plugin. */ 9 | /* */ 10 | /* For more detail visit: */ 11 | /* https://fmod.com/docs/2.02/api/core-api.html */ 12 | /* ======================================================================================== */ 13 | #ifndef _FMOD_CODEC_H 14 | #define _FMOD_CODEC_H 15 | 16 | /* 17 | Codec types 18 | */ 19 | typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE; 20 | typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT; 21 | 22 | /* 23 | Codec constants 24 | */ 25 | #define FMOD_CODEC_PLUGIN_VERSION 1 26 | 27 | typedef int FMOD_CODEC_SEEK_METHOD; 28 | #define FMOD_CODEC_SEEK_METHOD_SET 0 29 | #define FMOD_CODEC_SEEK_METHOD_CURRENT 1 30 | #define FMOD_CODEC_SEEK_METHOD_END 2 31 | 32 | /* 33 | Codec callbacks 34 | */ 35 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPEN_CALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo); 36 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSE_CALLBACK) (FMOD_CODEC_STATE *codec_state); 37 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READ_CALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int samples_in, unsigned int *samples_out); 38 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTH_CALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype); 39 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITION_CALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype); 40 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITION_CALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype); 41 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATE_CALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound); 42 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT_CALLBACK)(FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat); 43 | 44 | /* 45 | Codec functions 46 | */ 47 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATA_FUNC) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique); 48 | typedef void * (F_CALLBACK *FMOD_CODEC_ALLOC_FUNC) (unsigned int size, unsigned int align, const char *file, int line); 49 | typedef void (F_CALLBACK *FMOD_CODEC_FREE_FUNC) (void *ptr, const char *file, int line); 50 | typedef void (F_CALLBACK *FMOD_CODEC_LOG_FUNC) (FMOD_DEBUG_FLAGS level, const char *file, int line, const char *function, const char *string, ...); 51 | 52 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_FILE_READ_FUNC) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread); 53 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_FILE_SEEK_FUNC) (FMOD_CODEC_STATE *codec_state, unsigned int pos, FMOD_CODEC_SEEK_METHOD method); 54 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_FILE_TELL_FUNC) (FMOD_CODEC_STATE *codec_state, unsigned int *pos); 55 | typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_FILE_SIZE_FUNC) (FMOD_CODEC_STATE *codec_state, unsigned int *size); 56 | 57 | /* 58 | Codec structures 59 | */ 60 | typedef struct FMOD_CODEC_DESCRIPTION 61 | { 62 | unsigned int apiversion; 63 | const char *name; 64 | unsigned int version; 65 | int defaultasstream; 66 | FMOD_TIMEUNIT timeunits; 67 | FMOD_CODEC_OPEN_CALLBACK open; 68 | FMOD_CODEC_CLOSE_CALLBACK close; 69 | FMOD_CODEC_READ_CALLBACK read; 70 | FMOD_CODEC_GETLENGTH_CALLBACK getlength; 71 | FMOD_CODEC_SETPOSITION_CALLBACK setposition; 72 | FMOD_CODEC_GETPOSITION_CALLBACK getposition; 73 | FMOD_CODEC_SOUNDCREATE_CALLBACK soundcreate; 74 | FMOD_CODEC_GETWAVEFORMAT_CALLBACK getwaveformat; 75 | } FMOD_CODEC_DESCRIPTION; 76 | 77 | struct FMOD_CODEC_WAVEFORMAT 78 | { 79 | const char* name; 80 | FMOD_SOUND_FORMAT format; 81 | int channels; 82 | int frequency; 83 | unsigned int lengthbytes; 84 | unsigned int lengthpcm; 85 | unsigned int pcmblocksize; 86 | int loopstart; 87 | int loopend; 88 | FMOD_MODE mode; 89 | FMOD_CHANNELMASK channelmask; 90 | FMOD_CHANNELORDER channelorder; 91 | float peakvolume; 92 | }; 93 | 94 | typedef struct FMOD_CODEC_STATE_FUNCTIONS 95 | { 96 | FMOD_CODEC_METADATA_FUNC metadata; 97 | FMOD_CODEC_ALLOC_FUNC alloc; 98 | FMOD_CODEC_FREE_FUNC free; 99 | FMOD_CODEC_LOG_FUNC log; 100 | FMOD_CODEC_FILE_READ_FUNC read; 101 | FMOD_CODEC_FILE_SEEK_FUNC seek; 102 | FMOD_CODEC_FILE_TELL_FUNC tell; 103 | FMOD_CODEC_FILE_SIZE_FUNC size; 104 | } FMOD_CODEC_STATE_FUNCTIONS; 105 | 106 | struct FMOD_CODEC_STATE 107 | { 108 | void *plugindata; 109 | FMOD_CODEC_WAVEFORMAT *waveformat; 110 | FMOD_CODEC_STATE_FUNCTIONS *functions; 111 | int numsubsounds; 112 | }; 113 | 114 | /* 115 | Codec macros 116 | */ 117 | #define FMOD_CODEC_METADATA(_state, _tagtype, _name, _data, _datalen, _datatype, _unique) \ 118 | (_state)->functions->metadata(_state, _tagtype, _name, _data, _datalen, _datatype, _unique) 119 | #define FMOD_CODEC_ALLOC(_state, _size, _align) \ 120 | (_state)->functions->alloc(_size, _align, __FILE__, __LINE__) 121 | #define FMOD_CODEC_FREE(_state, _ptr) \ 122 | (_state)->functions->free(_ptr, __FILE__, __LINE__) 123 | #define FMOD_CODEC_LOG(_state, _level, _location, _format, ...) \ 124 | (_state)->functions->log(_level, __FILE__, __LINE__, _location, _format, __VA_ARGS__) 125 | #define FMOD_CODEC_FILE_READ(_state, _buffer, _sizebytes, _bytesread) \ 126 | (_state)->functions->read(_state, _buffer, _sizebytes, _bytesread) 127 | #define FMOD_CODEC_FILE_SEEK(_state, _pos, _method) \ 128 | (_state)->functions->seek(_state, _pos, _method) 129 | #define FMOD_CODEC_FILE_TELL(_state, _pos) \ 130 | (_state)->functions->tell(_state, _pos) 131 | #define FMOD_CODEC_FILE_SIZE(_state, _size) \ 132 | (_state)->functions->size(_state, _size) 133 | 134 | #endif 135 | 136 | 137 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Public/FMOD/fmod_output.h: -------------------------------------------------------------------------------- 1 | /* ======================================================================================== */ 2 | /* FMOD Core API - output development header file. */ 3 | /* Copyright (c), Firelight Technologies Pty, Ltd. 2004-2025. */ 4 | /* */ 5 | /* Use this header if you are wanting to develop your own output plugin to use with */ 6 | /* FMOD's output system. With this header you can make your own output plugin that FMOD */ 7 | /* can register and use. See the documentation and examples on how to make a working */ 8 | /* plugin. */ 9 | /* */ 10 | /* For more detail visit: */ 11 | /* https://fmod.com/docs/2.02/api/plugin-api-output.html */ 12 | /* ======================================================================================== */ 13 | #ifndef _FMOD_OUTPUT_H 14 | #define _FMOD_OUTPUT_H 15 | 16 | typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE; 17 | typedef struct FMOD_OUTPUT_OBJECT3DINFO FMOD_OUTPUT_OBJECT3DINFO; 18 | 19 | /* 20 | Output constants 21 | */ 22 | #define FMOD_OUTPUT_PLUGIN_VERSION 5 23 | 24 | typedef unsigned int FMOD_OUTPUT_METHOD; 25 | #define FMOD_OUTPUT_METHOD_MIX_DIRECT 0 26 | #define FMOD_OUTPUT_METHOD_MIX_BUFFERED 1 27 | 28 | /* 29 | Output callbacks 30 | */ 31 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_GETNUMDRIVERS_CALLBACK) (FMOD_OUTPUT_STATE *output_state, int *numdrivers); 32 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_GETDRIVERINFO_CALLBACK) (FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen, FMOD_GUID *guid, int *systemrate, FMOD_SPEAKERMODE *speakermode, int *speakermodechannels); 33 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_INIT_CALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, FMOD_SPEAKERMODE *speakermode, int *speakermodechannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int *dspnumbuffers, int *dspnumadditionalbuffers, void *extradriverdata); 34 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_START_CALLBACK) (FMOD_OUTPUT_STATE *output_state); 35 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_STOP_CALLBACK) (FMOD_OUTPUT_STATE *output_state); 36 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_CLOSE_CALLBACK) (FMOD_OUTPUT_STATE *output_state); 37 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_UPDATE_CALLBACK) (FMOD_OUTPUT_STATE *output_state); 38 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_GETHANDLE_CALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle); 39 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_MIXER_CALLBACK) (FMOD_OUTPUT_STATE *output_state); 40 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_OBJECT3DGETINFO_CALLBACK) (FMOD_OUTPUT_STATE *output_state, int *maxhardwareobjects); 41 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_OBJECT3DALLOC_CALLBACK) (FMOD_OUTPUT_STATE *output_state, void **object3d); 42 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_OBJECT3DFREE_CALLBACK) (FMOD_OUTPUT_STATE *output_state, void *object3d); 43 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_OBJECT3DUPDATE_CALLBACK) (FMOD_OUTPUT_STATE *output_state, void *object3d, const FMOD_OUTPUT_OBJECT3DINFO *info); 44 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_OPENPORT_CALLBACK) (FMOD_OUTPUT_STATE *output_state, FMOD_PORT_TYPE portType, FMOD_PORT_INDEX portIndex, int *portId, int *portRate, int *portChannels, FMOD_SOUND_FORMAT *portFormat); 45 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_CLOSEPORT_CALLBACK) (FMOD_OUTPUT_STATE *output_state, int portId); 46 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_DEVICELISTCHANGED_CALLBACK)(FMOD_OUTPUT_STATE *output_state); 47 | 48 | /* 49 | Output functions 50 | */ 51 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_READFROMMIXER_FUNC) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length); 52 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_COPYPORT_FUNC) (FMOD_OUTPUT_STATE *output_state, int portId, void *buffer, unsigned int length); 53 | typedef FMOD_RESULT (F_CALL *FMOD_OUTPUT_REQUESTRESET_FUNC) (FMOD_OUTPUT_STATE *output_state); 54 | typedef void * (F_CALL *FMOD_OUTPUT_ALLOC_FUNC) (unsigned int size, unsigned int align, const char *file, int line); 55 | typedef void (F_CALL *FMOD_OUTPUT_FREE_FUNC) (void *ptr, const char *file, int line); 56 | typedef void (F_CALL *FMOD_OUTPUT_LOG_FUNC) (FMOD_DEBUG_FLAGS level, const char *file, int line, const char *function, const char *string, ...); 57 | 58 | /* 59 | Output structures 60 | */ 61 | typedef struct FMOD_OUTPUT_DESCRIPTION 62 | { 63 | unsigned int apiversion; 64 | const char *name; 65 | unsigned int version; 66 | FMOD_OUTPUT_METHOD method; 67 | FMOD_OUTPUT_GETNUMDRIVERS_CALLBACK getnumdrivers; 68 | FMOD_OUTPUT_GETDRIVERINFO_CALLBACK getdriverinfo; 69 | FMOD_OUTPUT_INIT_CALLBACK init; 70 | FMOD_OUTPUT_START_CALLBACK start; 71 | FMOD_OUTPUT_STOP_CALLBACK stop; 72 | FMOD_OUTPUT_CLOSE_CALLBACK close; 73 | FMOD_OUTPUT_UPDATE_CALLBACK update; 74 | FMOD_OUTPUT_GETHANDLE_CALLBACK gethandle; 75 | FMOD_OUTPUT_MIXER_CALLBACK mixer; 76 | FMOD_OUTPUT_OBJECT3DGETINFO_CALLBACK object3dgetinfo; 77 | FMOD_OUTPUT_OBJECT3DALLOC_CALLBACK object3dalloc; 78 | FMOD_OUTPUT_OBJECT3DFREE_CALLBACK object3dfree; 79 | FMOD_OUTPUT_OBJECT3DUPDATE_CALLBACK object3dupdate; 80 | FMOD_OUTPUT_OPENPORT_CALLBACK openport; 81 | FMOD_OUTPUT_CLOSEPORT_CALLBACK closeport; 82 | FMOD_OUTPUT_DEVICELISTCHANGED_CALLBACK devicelistchanged; 83 | } FMOD_OUTPUT_DESCRIPTION; 84 | 85 | struct FMOD_OUTPUT_STATE 86 | { 87 | void *plugindata; 88 | FMOD_OUTPUT_READFROMMIXER_FUNC readfrommixer; 89 | FMOD_OUTPUT_ALLOC_FUNC alloc; 90 | FMOD_OUTPUT_FREE_FUNC free; 91 | FMOD_OUTPUT_LOG_FUNC log; 92 | FMOD_OUTPUT_COPYPORT_FUNC copyport; 93 | FMOD_OUTPUT_REQUESTRESET_FUNC requestreset; 94 | }; 95 | 96 | struct FMOD_OUTPUT_OBJECT3DINFO 97 | { 98 | float *buffer; 99 | unsigned int bufferlength; 100 | FMOD_VECTOR position; 101 | float gain; 102 | float spread; 103 | float priority; 104 | }; 105 | 106 | /* 107 | Output macros 108 | */ 109 | #define FMOD_OUTPUT_READFROMMIXER(_state, _buffer, _length) \ 110 | (_state)->readfrommixer(_state, _buffer, _length) 111 | #define FMOD_OUTPUT_ALLOC(_state, _size, _align) \ 112 | (_state)->alloc(_size, _align, __FILE__, __LINE__) 113 | #define FMOD_OUTPUT_FREE(_state, _ptr) \ 114 | (_state)->free(_ptr, __FILE__, __LINE__) 115 | #define FMOD_OUTPUT_LOG(_state, _level, _location, _format, ...) \ 116 | (_state)->log(_level, __FILE__, __LINE__, _location, _format, ##__VA_ARGS__) 117 | #define FMOD_OUTPUT_COPYPORT(_state, _id, _buffer, _length) \ 118 | (_state)->copyport(_state, _id, _buffer, _length) 119 | #define FMOD_OUTPUT_REQUESTRESET(_state) \ 120 | (_state)->requestreset(_state) 121 | 122 | #endif /* _FMOD_OUTPUT_H */ 123 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Public/FMODStudioModule.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "Modules/ModuleManager.h" 6 | 7 | namespace FMOD 8 | { 9 | namespace Studio 10 | { 11 | class System; 12 | class EventDescription; 13 | class EventInstance; 14 | } 15 | } 16 | 17 | class UFMODAsset; 18 | class UFMODBank; 19 | class UFMODEvent; 20 | class UWorld; 21 | class AAudioVolume; 22 | struct FInteriorSettings; 23 | struct FFMODListener; // Currently only for private use, we don't export this type 24 | 25 | // Which FMOD Studio system to use 26 | namespace EFMODSystemContext 27 | { 28 | enum Type 29 | { 30 | // For use auditioning sounds within the editor 31 | Auditioning, 32 | 33 | // For use in PIE and in-game 34 | Runtime, 35 | 36 | // For use when playing events in an editor world (e.g. previewing a level sequence) 37 | Editor, 38 | 39 | // Max number of types 40 | Max 41 | }; 42 | } 43 | 44 | /** 45 | * The public interface to this module 46 | */ 47 | class IFMODStudioModule : public IModuleInterface 48 | { 49 | public: 50 | /** 51 | * Singleton-like access to this module's interface. This is just for convenience! 52 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 53 | * 54 | * @return Returns singleton instance, loading the module on demand if needed 55 | */ 56 | static inline IFMODStudioModule &Get() { return FModuleManager::LoadModuleChecked("FMODStudio"); } 57 | 58 | /** 59 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 60 | * 61 | * @return True if the module is loaded and ready to use 62 | */ 63 | static inline bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("FMODStudio"); } 64 | 65 | /** 66 | * Get a pointer to the runtime studio system (only valid in-game or in PIE) 67 | */ 68 | virtual FMOD::Studio::System *GetStudioSystem(EFMODSystemContext::Type Context) = 0; 69 | 70 | /** 71 | * Set system paused (for PIE pause) 72 | */ 73 | virtual void SetSystemPaused(bool paused) = 0; 74 | 75 | /** 76 | * Called when we enter of leave PIE mode 77 | */ 78 | virtual void SetInPIE(bool bInPIE, bool bSimulating) = 0; 79 | 80 | /** 81 | * Look up an asset given its name 82 | */ 83 | virtual UFMODAsset *FindAssetByName(const FString &Name) = 0; 84 | 85 | /** 86 | * Look up an event given its name 87 | */ 88 | virtual UFMODEvent *FindEventByName(const FString &Name) = 0; 89 | 90 | /** 91 | * Get the disk path for a Bank asset 92 | */ 93 | virtual FString GetBankPath(const UFMODBank &Bank) = 0; 94 | 95 | /** 96 | * Get the disk paths for all Banks 97 | */ 98 | virtual void GetAllBankPaths(TArray &Paths, bool IncludeMasterBank) const = 0; 99 | 100 | /** 101 | * Get an event description. 102 | * The system type can control which Studio system to use, or leave it as System_Max for it to choose automatically. 103 | */ 104 | virtual FMOD::Studio::EventDescription *GetEventDescription( 105 | const UFMODEvent *Event, EFMODSystemContext::Type Context = EFMODSystemContext::Max) = 0; 106 | 107 | /** 108 | * Create a single auditioning instance using the auditioning system 109 | */ 110 | virtual FMOD::Studio::EventInstance *CreateAuditioningInstance(const UFMODEvent *Event) = 0; 111 | 112 | /** 113 | * Stop any auditioning instance 114 | */ 115 | virtual void StopAuditioningInstance() = 0; 116 | 117 | /** 118 | * Return whether the listener(s) have moved 119 | */ 120 | virtual bool HasListenerMoved() = 0; 121 | 122 | /** 123 | * Called to change the listener position for editor mode 124 | */ 125 | virtual void SetListenerPosition(int ListenerIndex, UWorld *World, const FTransform &ListenerTransform, float DeltaSeconds) = 0; 126 | 127 | /** 128 | * Called to change the listener position for editor mode 129 | */ 130 | virtual void FinishSetListenerPosition(int NumListeners) = 0; 131 | 132 | /** 133 | * Return the audio settings for the listener nearest the given location 134 | */ 135 | virtual const FFMODListener &GetNearestListener(const FVector &Location) = 0; 136 | 137 | /** Return a list of banks that failed to load due to an error */ 138 | virtual TArray GetFailedBankLoads(EFMODSystemContext::Type Context) = 0; 139 | 140 | /** Return a list of plugins that appear to be needed */ 141 | virtual TArray GetRequiredPlugins() = 0; 142 | 143 | /** Register a plugin that is required */ 144 | virtual void AddRequiredPlugin(const FString &Plugin) = 0; 145 | 146 | /** Returns whether sound is enabled for the game */ 147 | virtual bool UseSound() = 0; 148 | 149 | /** Attempts to load a plugin by name */ 150 | virtual bool LoadPlugin(EFMODSystemContext::Type Context, const TCHAR *ShortName) = 0; 151 | 152 | /** Log a FMOD error */ 153 | virtual void LogError(int result, const char *function) = 0; 154 | 155 | /** Returns if the banks have been loaded */ 156 | virtual bool AreBanksLoaded() = 0; 157 | 158 | /** Set active locale. Locale must be the locale name of one of the configured project locales */ 159 | virtual bool SetLocale(const FString& Locale) = 0; 160 | 161 | /** Get active locale. */ 162 | virtual FString GetLocale() = 0; 163 | 164 | /** Get default locale. */ 165 | virtual FString GetDefaultLocale() = 0; 166 | 167 | #if WITH_EDITOR 168 | /** Multicast delegate that is triggered before the module is shutdown. */ 169 | virtual FSimpleMulticastDelegate &PreEndPIEEvent() = 0; 170 | 171 | virtual void PreEndPIE() = 0; 172 | 173 | /** Called by the editor module when banks have been modified on disk */ 174 | virtual void ReloadBanks() = 0; 175 | #endif 176 | }; 177 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudio/Public/FMODUtils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "fmod_studio.hpp" 6 | #include "fmod.hpp" 7 | 8 | #include "Runtime/Launch/Resources/Version.h" 9 | #include "Engine/Engine.h" 10 | 11 | #include "FMODStudioModule.h" 12 | 13 | #define verifyfmod(fn) \ 14 | { \ 15 | FMOD_RESULT _result = (fn); \ 16 | if (_result != FMOD_OK) \ 17 | { \ 18 | FMODUtils::LogError(_result, #fn); \ 19 | } \ 20 | } 21 | 22 | namespace FMODUtils 23 | { 24 | 25 | // Unreal defines 1 unit == 1cm, so convert to metres for Studio automatically 26 | #define FMOD_VECTOR_SCALE_DEFAULT 0.01f 27 | 28 | // Just call into module 29 | inline void LogError(FMOD_RESULT result, const char *function) 30 | { 31 | IFMODStudioModule::Get().LogError(result, function); 32 | } 33 | 34 | inline void Assign(FMOD_VECTOR &Dest, const FVector &Src) 35 | { 36 | Dest.x = Src.X; 37 | Dest.y = Src.Y; 38 | Dest.z = Src.Z; 39 | } 40 | 41 | inline FMOD_VECTOR ConvertWorldVector(const FVector &Src) 42 | { 43 | static FMatrix UE4toFMOD(FVector(0.0f, 0.0f, FMOD_VECTOR_SCALE_DEFAULT), FVector(FMOD_VECTOR_SCALE_DEFAULT, 0.0f, 0.0f), 44 | FVector(0.0f, FMOD_VECTOR_SCALE_DEFAULT, 0.0f), FVector::ZeroVector); 45 | 46 | FMOD_VECTOR Dest; 47 | Assign(Dest, UE4toFMOD.TransformPosition(Src)); 48 | return Dest; 49 | } 50 | 51 | inline FMOD_VECTOR ConvertUnitVector(const FVector &Src) 52 | { 53 | static FMatrix UE4toFMOD(FVector(0.0f, 0.0f, 1.0f), FVector(1.0f, 0.0f, 0.0f), FVector(0.0f, 1.0f, 0.0f), FVector::ZeroVector); 54 | 55 | FMOD_VECTOR Dest; 56 | Assign(Dest, UE4toFMOD.TransformVector(Src)); 57 | return Dest; 58 | } 59 | 60 | inline void Assign(FMOD_3D_ATTRIBUTES &Dest, const FTransform &Src) 61 | { 62 | Dest.position = ConvertWorldVector(Src.GetTranslation()); 63 | Dest.forward = ConvertUnitVector(Src.GetUnitAxis(EAxis::X)); 64 | Dest.up = ConvertUnitVector(Src.GetUnitAxis(EAxis::Z)); 65 | } 66 | 67 | inline float DistanceToUEScale(float FMODDistance) 68 | { 69 | return FMODDistance / FMOD_VECTOR_SCALE_DEFAULT; 70 | } 71 | 72 | inline bool IsWorldAudible(UWorld *World, bool AllowInEditor) 73 | { 74 | if (GEngine && IFMODStudioModule::Get().UseSound()) 75 | { 76 | if (!IsValid(World)) 77 | { 78 | return true; 79 | } 80 | 81 | if (World->bAllowAudioPlayback && World->GetNetMode() != NM_DedicatedServer) 82 | { 83 | EWorldType::Type previewEnum; 84 | previewEnum = EWorldType::EditorPreview; 85 | if (World->IsGameWorld() || World->WorldType == previewEnum || (AllowInEditor && World->WorldType == EWorldType::Editor)) 86 | { 87 | return true; 88 | } 89 | } 90 | } 91 | return false; 92 | } 93 | 94 | inline FMOD::Studio::ID ConvertGuid(const FGuid &UnrealGuid) 95 | { 96 | // Unreal doesn't follow the usual windows GUID format, instead it parses 97 | // them as 4 integers 98 | FMOD::Studio::ID StudioGuid; 99 | FMemory::Memcpy(&StudioGuid, &UnrealGuid, sizeof(StudioGuid)); 100 | Swap(StudioGuid.Data2, StudioGuid.Data3); 101 | Swap(StudioGuid.Data4[0], StudioGuid.Data4[3]); 102 | Swap(StudioGuid.Data4[1], StudioGuid.Data4[2]); 103 | Swap(StudioGuid.Data4[4], StudioGuid.Data4[7]); 104 | Swap(StudioGuid.Data4[5], StudioGuid.Data4[6]); 105 | return StudioGuid; 106 | } 107 | 108 | inline FGuid ConvertGuid(const FMOD::Studio::ID &StudioGuid) 109 | { 110 | // Unreal doesn't follow the usual windows GUID format, instead it parses 111 | // them as 4 integers 112 | FMOD::Studio::ID CopiedGuid; 113 | FMemory::Memcpy(&CopiedGuid, &StudioGuid, sizeof(StudioGuid)); 114 | Swap(CopiedGuid.Data2, CopiedGuid.Data3); 115 | Swap(CopiedGuid.Data4[0], CopiedGuid.Data4[3]); 116 | Swap(CopiedGuid.Data4[1], CopiedGuid.Data4[2]); 117 | Swap(CopiedGuid.Data4[4], CopiedGuid.Data4[7]); 118 | Swap(CopiedGuid.Data4[5], CopiedGuid.Data4[6]); 119 | FGuid UnrealGuid; 120 | FMemory::Memcpy(&UnrealGuid, &CopiedGuid, sizeof(CopiedGuid)); 121 | return UnrealGuid; 122 | } 123 | 124 | template 125 | inline FGuid GetID(StudioType *Instance) 126 | { 127 | FMOD::Studio::ID StudioID = { 0 }; 128 | verifyfmod(Instance->getID(&StudioID)); 129 | return FMODUtils::ConvertGuid(StudioID); 130 | } 131 | 132 | template 133 | inline FString GetPath(StudioType *Instance) 134 | { 135 | int ActualSize = 128; // Start with expected enough space 136 | TArray RawBuffer; 137 | FMOD_RESULT Result; 138 | do 139 | { 140 | RawBuffer.SetNum(ActualSize); 141 | Result = Instance->getPath(RawBuffer.GetData(), ActualSize, &ActualSize); 142 | } while (Result == FMOD_ERR_TRUNCATED); 143 | 144 | if (Result == FMOD_OK) 145 | { 146 | return FString(UTF8_TO_TCHAR(RawBuffer.GetData())); 147 | } 148 | else 149 | { 150 | return FString(); 151 | } 152 | } 153 | 154 | inline FString LookupNameFromGuid(FMOD::Studio::System *StudioSystem, const FMOD::Studio::ID &Guid) 155 | { 156 | int ActualSize = 128; // Start with expected enough space 157 | TArray RawBuffer; 158 | FMOD_RESULT Result; 159 | do 160 | { 161 | RawBuffer.SetNum(ActualSize); 162 | Result = StudioSystem->lookupPath(&Guid, RawBuffer.GetData(), ActualSize, &ActualSize); 163 | } while (Result == FMOD_ERR_TRUNCATED); 164 | 165 | if (Result == FMOD_OK) 166 | { 167 | return FString(UTF8_TO_TCHAR(RawBuffer.GetData())); 168 | } 169 | else 170 | { 171 | return FString(); 172 | } 173 | } 174 | 175 | inline FString LookupNameFromGuid(FMOD::Studio::System *StudioSystem, const FGuid &Guid) 176 | { 177 | return LookupNameFromGuid(StudioSystem, ConvertGuid(Guid)); 178 | } 179 | 180 | inline FString ParameterTypeToString(FMOD_STUDIO_PARAMETER_TYPE Type) 181 | { 182 | switch (Type) 183 | { 184 | case FMOD_STUDIO_PARAMETER_GAME_CONTROLLED: 185 | return FString("Game Controlled"); 186 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_DISTANCE: 187 | return FString("Distance (Auto)"); 188 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_EVENT_CONE_ANGLE: 189 | return FString("Event Cone Angle (Auto)"); 190 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_EVENT_ORIENTATION: 191 | return FString("Event Orientation (Auto)"); 192 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_DIRECTION: 193 | return FString("Direction (Auto)"); 194 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_ELEVATION: 195 | return FString("Elevation (Auto)"); 196 | case FMOD_STUDIO_PARAMETER_AUTOMATIC_LISTENER_ORIENTATION: 197 | return FString("Listener Orientation (Auto)"); 198 | } 199 | 200 | return FString(); 201 | } 202 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Classes/FMODAmbientSoundActorFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "ActorFactories/ActorFactory.h" 6 | #include "FMODAmbientSoundActorFactory.generated.h" 7 | 8 | /** FMOD Ambient Sound Actor Factory. 9 | */ 10 | UCLASS(MinimalAPI, config = Editor, collapsecategories, hidecategories = Object) 11 | class UFMODAmbientSoundActorFactory : public UActorFactory 12 | { 13 | GENERATED_UCLASS_BODY() 14 | 15 | // Begin UActorFactory Interface 16 | virtual void PostSpawnActor(UObject *Asset, AActor *NewActor) override; 17 | virtual void PostCreateBlueprint(UObject *Asset, AActor *CDO) override; 18 | virtual bool CanCreateActorFrom(const FAssetData &AssetData, FText &OutErrorMsg) override; 19 | virtual UObject *GetAssetFromActorInstance(AActor *ActorInstance) override; 20 | // End UActorFactory Interface 21 | }; 22 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Classes/FMODAssetBuilder.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | namespace FMOD 8 | { 9 | namespace Studio 10 | { 11 | class System; 12 | } 13 | } // namespace FMOD 14 | 15 | class UFMODAsset; 16 | class UFMODBankLookup; 17 | class UFMODSettings; 18 | 19 | class FFMODAssetBuilder 20 | { 21 | public: 22 | ~FFMODAssetBuilder(); 23 | 24 | /** Create studio system for asset building */ 25 | void Create(); 26 | 27 | /** Process FMOD banks into UE4 assets */ 28 | void ProcessBanks(); 29 | 30 | /** Path of strings bank */ 31 | FString GetMasterStringsBankPath(); 32 | 33 | private: 34 | struct AssetCreateInfo 35 | { 36 | UClass *Class; 37 | FGuid Guid; 38 | FString StudioPath; 39 | FString AssetName; 40 | FString PackagePath; 41 | FString Path; 42 | }; 43 | 44 | void BuildBankLookup(const FString &AssetName, const FString &PackagePath, const UFMODSettings &InSettings, TArray& AssetsToSave); 45 | void BuildAssets(const UFMODSettings &InSettings, const FString &AssetLookupName, const FString &AssetLookupPath, TArray& AssetsToSave, 46 | TArray& AssetsToDelete); 47 | 48 | FString GetAssetClassName(UClass *AssetClass); 49 | bool MakeAssetCreateInfo(const FGuid &AssetGuid, const FString &StudioPath, AssetCreateInfo *CreateInfo); 50 | UFMODAsset *CreateAsset(const AssetCreateInfo& CreateInfo, TArray& AssetsToSave); 51 | void SaveAssets(TArray& AssetsToSave); 52 | void DeleteAssets(TArray& AssetsToDelete); 53 | 54 | FMOD::Studio::System *StudioSystem{}; 55 | UFMODBankLookup *BankLookup{}; 56 | }; 57 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Classes/FMODGenerateAssetsCommandlet.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Commandlets/Commandlet.h" 7 | #include "FMODGenerateAssetsCommandlet.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class UFMODGenerateAssetsCommandlet : public UCommandlet 14 | { 15 | GENERATED_UCLASS_BODY() 16 | 17 | //~ Begin UCommandlet Interface 18 | virtual int32 Main(const FString &Params) override; 19 | //~ End UCommandlet Interface 20 | }; 21 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/FMODStudioEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | using System.IO; 3 | 4 | namespace UnrealBuildTool.Rules 5 | { 6 | public class FMODStudioEditor : ModuleRules 7 | { 8 | #if WITH_FORWARDED_MODULE_RULES_CTOR 9 | public FMODStudioEditor(ReadOnlyTargetRules Target) : base(Target) 10 | #else 11 | public FMODStudioEditor(TargetInfo Target) 12 | #endif 13 | { 14 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 15 | PrivatePCHHeaderFile = "Private/FMODStudioEditorPrivatePCH.h"; 16 | 17 | bUseUnity = false; 18 | 19 | PrivateIncludePaths.AddRange( 20 | new string[] { 21 | "FMODStudio/Private", 22 | "FMODStudio/Public/FMOD", 23 | Path.Combine(ModuleDirectory, "Classes") 24 | } 25 | ); 26 | 27 | PublicDependencyModuleNames.AddRange( 28 | new string[] 29 | { 30 | "Core", 31 | "CoreUObject", 32 | "Engine", 33 | "FMODStudio", 34 | "InputCore", 35 | "UnrealEd", 36 | "Sequencer" 37 | } 38 | ); 39 | 40 | PrivateDependencyModuleNames.AddRange( 41 | new string[] 42 | { 43 | "AssetRegistry", 44 | "AssetTools", 45 | "EditorStyle", 46 | "LevelEditor", 47 | "LevelSequence", 48 | "MainFrame", 49 | "MovieScene", 50 | "MovieSceneTracks", 51 | "MovieSceneTools", 52 | "PropertyEditor", 53 | "Settings", 54 | "Slate", 55 | "SlateCore", 56 | "Sockets", 57 | "SourceControl", 58 | "ToolMenus", 59 | "WorkspaceMenuStructure", 60 | } 61 | ); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/AssetTypeActions_FMODEvent.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "AssetTypeActions_FMODEvent.h" 4 | #include "AssetTypeActions_Base.h" 5 | #include "FMODEventEditor.h" 6 | #include "FMODEvent.h" 7 | #include "FMODUtils.h" 8 | #include "FMODStudioModule.h" 9 | #include "FMODStudioEditorModule.h" 10 | #include "UnrealEd/Public/Editor.h" 11 | #include "Framework/MultiBox/MultiBoxBuilder.h" 12 | #include "EditorStyle/Public/EditorStyleSet.h" 13 | 14 | #define LOCTEXT_NAMESPACE "AssetTypeActions" 15 | 16 | FAssetTypeActions_FMODEvent::FAssetTypeActions_FMODEvent() 17 | : CurrentPreviewEventInstance(nullptr) 18 | { 19 | BeginPIEDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FAssetTypeActions_FMODEvent::HandleBeginPIE); 20 | IFMODStudioEditorModule::Get().BanksReloadedEvent().AddRaw(this, &FAssetTypeActions_FMODEvent::HandleBanksReloaded); 21 | } 22 | 23 | FAssetTypeActions_FMODEvent::~FAssetTypeActions_FMODEvent() 24 | { 25 | if (GIsRunning) 26 | { 27 | FEditorDelegates::BeginPIE.Remove(BeginPIEDelegateHandle); 28 | IFMODStudioEditorModule::Get().BanksReloadedEvent().RemoveAll(this); 29 | IFMODStudioModule::Get().StopAuditioningInstance(); 30 | } 31 | } 32 | 33 | UClass *FAssetTypeActions_FMODEvent::GetSupportedClass() const 34 | { 35 | return UFMODEvent::StaticClass(); 36 | } 37 | 38 | void FAssetTypeActions_FMODEvent::GetActions(const TArray &InObjects, FMenuBuilder &MenuBuilder) 39 | { 40 | auto Events = GetTypedWeakObjectPtrs(InObjects); 41 | 42 | MenuBuilder.AddMenuEntry(LOCTEXT("FMODEvent_Play", "Play"), LOCTEXT("FMODEvent_PlayTooltip", "Plays the selected FMOD event."), 43 | FSlateIcon(FEditorStyle::GetStyleSetName(), "MediaAsset.AssetActions.Play"), 44 | FUIAction(FExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::ExecutePlay, Events), 45 | FCanExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::CanExecutePlayCommand, Events))); 46 | 47 | MenuBuilder.AddMenuEntry(LOCTEXT("FMODEvent_Stop", "Stop"), LOCTEXT("FMODEvent_StopTooltip", "Stops the currently playing FMOD event."), 48 | FSlateIcon(FEditorStyle::GetStyleSetName(), "MediaAsset.AssetActions.Stop"), 49 | FUIAction(FExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::ExecuteStop, Events), FCanExecuteAction())); 50 | } 51 | 52 | void FAssetTypeActions_FMODEvent::OpenAssetEditor(const TArray &InObjects, TSharedPtr EditWithinLevelEditor) 53 | { 54 | EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; 55 | 56 | for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) 57 | { 58 | auto Event = Cast(*ObjIt); 59 | if (IsValid(Event)) 60 | { 61 | TSharedRef NewFMODEventEditor(new FFMODEventEditor()); 62 | NewFMODEventEditor->InitFMODEventEditor(Mode, EditWithinLevelEditor, Event); 63 | } 64 | } 65 | } 66 | 67 | bool FAssetTypeActions_FMODEvent::CanExecutePlayCommand(TArray> Objects) const 68 | { 69 | return Objects.Num() == 1; 70 | } 71 | 72 | bool FAssetTypeActions_FMODEvent::AssetsActivatedOverride(const TArray &InObjects, EAssetTypeActivationMethod::Type ActivationType) 73 | { 74 | if (ActivationType == EAssetTypeActivationMethod::Previewed) 75 | { 76 | for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) 77 | { 78 | UFMODEvent *Event = Cast(*ObjIt); 79 | if (IsValid(Event)) 80 | { 81 | // Only play the first valid event 82 | PlayEvent(Event); 83 | break; 84 | } 85 | } 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | void FAssetTypeActions_FMODEvent::ExecuteEdit(TArray> Objects) 92 | { 93 | for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) 94 | { 95 | auto Object = (*ObjIt).Get(); 96 | if (IsValid(Object)) 97 | { 98 | GEditor->GetEditorSubsystem()->OpenEditorForAsset(Object); 99 | } 100 | } 101 | } 102 | 103 | void FAssetTypeActions_FMODEvent::ExecutePlay(TArray> Objects) 104 | { 105 | for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) 106 | { 107 | UFMODEvent *Event = (*ObjIt).Get(); 108 | if (IsValid(Event)) 109 | { 110 | // Only play the first valid event 111 | PlayEvent(Event); 112 | break; 113 | } 114 | } 115 | } 116 | 117 | void FAssetTypeActions_FMODEvent::ExecuteStop(TArray> Objects) 118 | { 119 | IFMODStudioModule::Get().StopAuditioningInstance(); 120 | } 121 | 122 | void FAssetTypeActions_FMODEvent::PlayEvent(UFMODEvent *Event) 123 | { 124 | if (IsValid(Event)) 125 | { 126 | CurrentPreviewEventInstance = IFMODStudioModule::Get().CreateAuditioningInstance(Event); 127 | if (CurrentPreviewEventInstance != nullptr) 128 | { 129 | CurrentPreviewEventInstance->start(); 130 | } 131 | } 132 | } 133 | 134 | void FAssetTypeActions_FMODEvent::HandleBeginPIE(bool bSimulating) 135 | { 136 | // Studio module will handle its own auditioning, just clear the handle 137 | CurrentPreviewEventInstance = nullptr; 138 | } 139 | 140 | void FAssetTypeActions_FMODEvent::HandleBanksReloaded() 141 | { 142 | // Studio module will handle its own auditioning, just clear the handle 143 | CurrentPreviewEventInstance = nullptr; 144 | } 145 | 146 | #undef LOCTEXT_NAMESPACE 147 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/AssetTypeActions_FMODEvent.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "AssetTypeActions_Base.h" 6 | 7 | namespace FMOD 8 | { 9 | namespace Studio 10 | { 11 | class EventInstance; 12 | } 13 | } 14 | 15 | class UFMODEvent; 16 | 17 | class FAssetTypeActions_FMODEvent : public FAssetTypeActions_Base 18 | { 19 | public: 20 | FAssetTypeActions_FMODEvent(); 21 | ~FAssetTypeActions_FMODEvent(); 22 | 23 | // IAssetTypeActions Implementation 24 | virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_FMODEvent", "FMOD Event"); } 25 | virtual FColor GetTypeColor() const override { return FColor(0, 175, 255); } 26 | virtual UClass *GetSupportedClass() const override; 27 | virtual bool HasActions(const TArray &InObjects) const override { return true; } 28 | virtual void GetActions(const TArray &InObjects, FMenuBuilder &MenuBuilder) override; 29 | virtual bool AssetsActivatedOverride(const TArray &InObjects, EAssetTypeActivationMethod::Type ActivationType) override; 30 | virtual void OpenAssetEditor( 31 | const TArray &InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; 32 | virtual bool CanFilter() override { return false; } 33 | virtual uint32 GetCategories() override { return EAssetTypeCategories::Sounds; } 34 | 35 | private: 36 | /** Returns true if only one event is selected to play */ 37 | bool CanExecutePlayCommand(TArray> Objects) const; 38 | 39 | /** Handler for when Edit is selected */ 40 | void ExecuteEdit(TArray> Objects); 41 | 42 | /** Handler for when Play is selected */ 43 | void ExecutePlay(TArray> Objects); 44 | 45 | /** Handler for when Stop is selected */ 46 | void ExecuteStop(TArray> Objects); 47 | 48 | /** Plays the event */ 49 | void PlayEvent(UFMODEvent *Event); 50 | 51 | void HandleBeginPIE(bool bSimulating); 52 | void HandleBanksReloaded(); 53 | 54 | FMOD::Studio::EventInstance *CurrentPreviewEventInstance; 55 | FDelegateHandle BeginPIEDelegateHandle; 56 | }; 57 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAmbientSoundActorFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAmbientSoundActorFactory.h" 4 | #include "FMODStudioEditorPrivatePCH.h" 5 | #include "FMODAmbientSound.h" 6 | #include "FMODEvent.h" 7 | #include "AssetRegistry/Public/AssetData.h" 8 | #include "Editor/EditorEngine.h" 9 | 10 | UFMODAmbientSoundActorFactory::UFMODAmbientSoundActorFactory(const FObjectInitializer &ObjectInitializer) 11 | : Super(ObjectInitializer) 12 | { 13 | DisplayName = NSLOCTEXT("FMOD", "FMODAmbientSoundDisplayName", "FMOD Ambient Sound"); 14 | NewActorClass = AFMODAmbientSound::StaticClass(); 15 | } 16 | 17 | bool UFMODAmbientSoundActorFactory::CanCreateActorFrom(const FAssetData &AssetData, FText &OutErrorMsg) 18 | { 19 | //We allow creating AAmbientSounds without an existing sound asset 20 | if (UActorFactory::CanCreateActorFrom(AssetData, OutErrorMsg)) 21 | { 22 | return true; 23 | } 24 | 25 | if (AssetData.IsValid() && !AssetData.GetClass()->IsChildOf(UFMODEvent::StaticClass())) 26 | { 27 | OutErrorMsg = NSLOCTEXT("FMOD", "CanCreateActorFrom_NoFMODEventAsset", "A valid FMOD Event asset must be specified."); 28 | return false; 29 | } 30 | 31 | return true; 32 | } 33 | 34 | void UFMODAmbientSoundActorFactory::PostSpawnActor(UObject *Asset, AActor *NewActor) 35 | { 36 | UFMODEvent *Event = Cast(Asset); 37 | 38 | if (Event != NULL) 39 | { 40 | AFMODAmbientSound *NewSound = CastChecked(NewActor); 41 | FActorLabelUtilities::SetActorLabelUnique(NewSound, Event->GetName()); 42 | NewSound->AudioComponent->Event = Event; 43 | } 44 | } 45 | 46 | UObject *UFMODAmbientSoundActorFactory::GetAssetFromActorInstance(AActor *Instance) 47 | { 48 | check(Instance->IsA(NewActorClass)); 49 | AFMODAmbientSound *SoundActor = CastChecked(Instance); 50 | 51 | check(SoundActor->AudioComponent); 52 | return SoundActor->AudioComponent->Event; 53 | } 54 | 55 | void UFMODAmbientSoundActorFactory::PostCreateBlueprint(UObject *Asset, AActor *CDO) 56 | { 57 | if (Asset != NULL && CDO != NULL) 58 | { 59 | UFMODEvent *Event = Cast(Asset); 60 | 61 | if (Event != NULL) 62 | { 63 | AFMODAmbientSound *NewSound = CastChecked(CDO); 64 | NewSound->AudioComponent->Event = Event; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAssetBroker.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "ComponentAssetBroker.h" 6 | #include "FMODEvent.h" 7 | 8 | ////////////////////////////////////////////////////////////////////////// 9 | // FFMODAssetBroker 10 | 11 | class FFMODAssetBroker : public IComponentAssetBroker 12 | { 13 | public: 14 | UClass *GetSupportedAssetClass() override { return UFMODEvent::StaticClass(); } 15 | 16 | virtual bool AssignAssetToComponent(UActorComponent *InComponent, UObject *InAsset) override 17 | { 18 | if (UFMODAudioComponent *AudioComp = Cast(InComponent)) 19 | { 20 | UFMODEvent *Event = Cast(InAsset); 21 | 22 | if ((Event != NULL) || (InAsset == NULL)) 23 | { 24 | AudioComp->Event = Event; 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | virtual UObject *GetAssetFromComponent(UActorComponent *InComponent) override 32 | { 33 | if (UFMODAudioComponent *AudioComp = Cast(InComponent)) 34 | { 35 | return AudioComp->Event; 36 | } 37 | return NULL; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAudioComponentDetails.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAudioComponentDetails.h" 4 | #include "Toolkits/AssetEditorManager.h" 5 | #include "FMODAmbientSound.h" 6 | #include "FMODStudioModule.h" 7 | #include "FMODEvent.h" 8 | #include "fmod_studio.hpp" 9 | #include "UnrealEd/Public/Editor.h" 10 | #include "Widgets/Input/SButton.h" 11 | #include "PropertyEditor/Public/DetailLayoutBuilder.h" 12 | #include "PropertyEditor/Public/DetailCategoryBuilder.h" 13 | 14 | #define LOCTEXT_NAMESPACE "FMODStudio" 15 | 16 | TSharedRef FFMODAudioComponentDetails::MakeInstance() 17 | { 18 | return MakeShareable(new FFMODAudioComponentDetails); 19 | } 20 | 21 | void FFMODAudioComponentDetails::CustomizeDetails(IDetailLayoutBuilder &DetailBuilder) 22 | { 23 | const TArray> &SelectedObjects = DetailBuilder.GetSelectedObjects(); 24 | 25 | for (int32 ObjectIndex = 0; !AudioComponent.IsValid() && ObjectIndex < SelectedObjects.Num(); ++ObjectIndex) 26 | { 27 | const TWeakObjectPtr &CurrentObject = SelectedObjects[ObjectIndex]; 28 | if (CurrentObject.Get()->GetClass()->IsChildOf(UFMODAudioComponent::StaticClass())) 29 | { 30 | AudioComponent = Cast(CurrentObject.Get()); 31 | } 32 | else 33 | { 34 | AudioComponent = Cast(CurrentObject.Get())->FindComponentByClass(); 35 | } 36 | } 37 | 38 | DetailBuilder.EditCategory(TEXT("FMODAudio")) 39 | .AddCustomRow( 40 | FText::GetEmpty())[SNew(SVerticalBox) + 41 | SVerticalBox::Slot() 42 | .Padding(0, 2.0f, 0, 0) 43 | .FillHeight(1.0f) 44 | .VAlign( 45 | VAlign_Center)[SNew(SHorizontalBox) + 46 | SHorizontalBox::Slot() 47 | .AutoWidth() 48 | .Padding(2.0f, 0.0f) 49 | .VAlign(VAlign_Center) 50 | .HAlign(HAlign_Left)[SNew(SButton) 51 | .VAlign(VAlign_Center) 52 | .OnClicked(this, &FFMODAudioComponentDetails::OnEditSoundClicked) 53 | .Text(LOCTEXT("View Details", "Details"))] + 54 | SHorizontalBox::Slot() 55 | .AutoWidth() 56 | .Padding(2.0f, 0.0f) 57 | .VAlign(VAlign_Center) 58 | .HAlign(HAlign_Left)[SNew(SButton) 59 | .VAlign(VAlign_Center) 60 | .OnClicked(this, &FFMODAudioComponentDetails::OnPlaySoundClicked) 61 | .Text(LOCTEXT("Play FMOD Event", "Play"))] + 62 | SHorizontalBox::Slot() 63 | .AutoWidth() 64 | .Padding(2.0f, 0.0f) 65 | .VAlign(VAlign_Center) 66 | .HAlign(HAlign_Left)[SNew(SButton) 67 | .VAlign(VAlign_Center) 68 | .OnClicked(this, &FFMODAudioComponentDetails::OnStopSoundClicked) 69 | .Text(LOCTEXT("Stop FMOD Event", "Stop"))]]]; 70 | } 71 | 72 | FReply FFMODAudioComponentDetails::OnEditSoundClicked() 73 | { 74 | if (AudioComponent.IsValid()) 75 | { 76 | UFMODEvent *Event = AudioComponent.Get()->Event; 77 | if (Event) 78 | { 79 | GEditor->GetEditorSubsystem()->OpenEditorForAsset(Event); 80 | } 81 | } 82 | 83 | return FReply::Handled(); 84 | } 85 | 86 | FReply FFMODAudioComponentDetails::OnPlaySoundClicked() 87 | { 88 | if (AudioComponent.IsValid()) 89 | { 90 | UFMODEvent *Event = AudioComponent.Get()->Event; 91 | if (IsValid(Event)) 92 | { 93 | FMOD::Studio::EventInstance *Instance = IFMODStudioModule::Get().CreateAuditioningInstance(Event); 94 | if (Instance) 95 | { 96 | for (auto param : AudioComponent->ParameterCache) 97 | { 98 | Instance->setParameterByName(TCHAR_TO_UTF8(*param.Key.ToString()), param.Value); 99 | } 100 | Instance->start(); 101 | } 102 | } 103 | } 104 | 105 | return FReply::Handled(); 106 | } 107 | 108 | FReply FFMODAudioComponentDetails::OnStopSoundClicked() 109 | { 110 | IFMODStudioModule::Get().StopAuditioningInstance(); 111 | 112 | return FReply::Handled(); 113 | } 114 | 115 | #undef LOCTEXT_NAMESPACE 116 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAudioComponentDetails.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | //#include "PropertyEditing.h" 6 | #include "PropertyCustomizationHelpers.h" 7 | #include "PropertyEditor/Public/IDetailCustomization.h" 8 | 9 | class FFMODAudioComponentDetails : public IDetailCustomization 10 | { 11 | public: 12 | /** Makes a new instance of this detail layout class for a specific detail view requesting it */ 13 | static TSharedRef MakeInstance(); 14 | 15 | private: 16 | /** IDetailCustomization interface */ 17 | virtual void CustomizeDetails(IDetailLayoutBuilder &DetailBuilder) override; 18 | 19 | FReply OnEditSoundClicked(); 20 | FReply OnPlaySoundClicked(); 21 | FReply OnStopSoundClicked(); 22 | 23 | TWeakObjectPtr AudioComponent; 24 | }; -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAudioComponentVisualizer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODAudioComponentVisualizer.h" 4 | #include "FMODAudioComponent.h" 5 | #include "FMODUtils.h" 6 | #include "FMODEvent.h" 7 | #include "fmod_studio.hpp" 8 | #include "Engine/Public/SceneView.h" 9 | #include "Engine/Public/SceneManagement.h" 10 | 11 | void FFMODAudioComponentVisualizer::DrawVisualization(const UActorComponent *Component, const FSceneView *View, FPrimitiveDrawInterface *PDI) 12 | { 13 | if (View->Family->EngineShowFlags.AudioRadius) 14 | { 15 | const UFMODAudioComponent *AudioComp = Cast(Component); 16 | if (IsValid(AudioComp) && AudioComp->Event) 17 | { 18 | FMOD::Studio::EventDescription *EventDesc = 19 | IFMODStudioModule::Get().GetEventDescription(AudioComp->Event, EFMODSystemContext::Auditioning); 20 | if (EventDesc != nullptr) 21 | { 22 | bool bIs3D = false; 23 | EventDesc->is3D(&bIs3D); 24 | if (bIs3D) 25 | { 26 | const FColor AudioOuterRadiusColor(255, 153, 0); 27 | const FColor AudioInnerRadiusColor(216, 130, 0); 28 | 29 | const FTransform &Transform = AudioComp->GetComponentTransform(); 30 | 31 | float MinDistance = 0.0f; 32 | float MaxDistance = 0.0f; 33 | if (AudioComp->AttenuationDetails.bOverrideAttenuation) 34 | { 35 | MinDistance = AudioComp->AttenuationDetails.MinimumDistance; 36 | MaxDistance = AudioComp->AttenuationDetails.MaximumDistance; 37 | } 38 | else 39 | { 40 | EventDesc->getMinMaxDistance(&MinDistance, &MaxDistance); 41 | } 42 | MinDistance = FMODUtils::DistanceToUEScale(MinDistance); 43 | MaxDistance = FMODUtils::DistanceToUEScale(MaxDistance); 44 | 45 | DrawWireSphereAutoSides(PDI, Transform.GetTranslation(), AudioOuterRadiusColor, MinDistance, SDPG_World); 46 | if (MaxDistance != MinDistance) 47 | { 48 | DrawWireSphereAutoSides(PDI, Transform.GetTranslation(), AudioInnerRadiusColor, MaxDistance, SDPG_World); 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODAudioComponentVisualizer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "ComponentVisualizer.h" 6 | 7 | class FFMODAudioComponentVisualizer : public FComponentVisualizer 8 | { 9 | public: 10 | // Begin FComponentVisualizer interface 11 | virtual void DrawVisualization(const UActorComponent *Component, const FSceneView *View, FPrimitiveDrawInterface *PDI) override; 12 | // End FComponentVisualizer interface 13 | }; 14 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODBankUpdateNotifier.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODBankUpdateNotifier.h" 4 | #include "FMODSettings.h" 5 | #include "HAL/FileManager.h" 6 | 7 | #include "FMODStudioEditorPrivatePCH.h" 8 | 9 | FFMODBankUpdateNotifier::FFMODBankUpdateNotifier() 10 | : bUpdateEnabled(true) 11 | , NextRefreshTime(FDateTime::MinValue()) 12 | , FileTime(FDateTime::MinValue()) 13 | , Countdown(0.0f) 14 | { 15 | } 16 | 17 | void FFMODBankUpdateNotifier::SetFilePath(const FString &InPath) 18 | { 19 | FilePath = InPath; 20 | NextRefreshTime = FDateTime::MinValue(); 21 | FileTime = MostRecentFileTime(); 22 | } 23 | 24 | void FFMODBankUpdateNotifier::Update(float DeltaTime) 25 | { 26 | if (bUpdateEnabled) 27 | { 28 | FDateTime CurTime = FDateTime::UtcNow(); 29 | 30 | if (CurTime >= NextRefreshTime) 31 | { 32 | Refresh(); 33 | NextRefreshTime = CurTime + FTimespan(0, 0, 1); 34 | } 35 | 36 | if (Countdown > 0.0f) 37 | { 38 | Countdown -= DeltaTime; 39 | 40 | if (Countdown <= 0.0f) 41 | { 42 | BanksUpdatedEvent.Broadcast(); 43 | } 44 | } 45 | } 46 | } 47 | 48 | void FFMODBankUpdateNotifier::EnableUpdate(bool bEnable) 49 | { 50 | bUpdateEnabled = bEnable; 51 | 52 | if (bEnable) 53 | { 54 | // Refreshing right after update is enabled is not desirable 55 | NextRefreshTime = FDateTime::UtcNow() + FTimespan(0, 0, 1); 56 | 57 | // Cancel any pending countdown 58 | Countdown = 0.0f; 59 | } 60 | } 61 | 62 | void FFMODBankUpdateNotifier::Refresh() 63 | { 64 | if (!FilePath.IsEmpty()) 65 | { 66 | FDateTime NewFileTime = MostRecentFileTime(); 67 | 68 | if (NewFileTime != FileTime) 69 | { 70 | const UFMODSettings &Settings = *GetDefault(); 71 | Countdown = (float)Settings.ReloadBanksDelay; 72 | FileTime = NewFileTime; 73 | } 74 | } 75 | } 76 | 77 | FDateTime FFMODBankUpdateNotifier::MostRecentFileTime() 78 | { 79 | // Get the most recent modified timestamp of all the bank files in the directory we are watching. 80 | FDateTime MostRecent = FDateTime::MinValue(); 81 | 82 | TArray BankPaths; 83 | IFileManager::Get().FindFilesRecursive(BankPaths, *FilePath, TEXT("*.bank"), true, false, false); 84 | 85 | for (const auto& Path : BankPaths) 86 | { 87 | FDateTime ModifiedTime = IFileManager::Get().GetTimeStamp(*Path); 88 | 89 | if (ModifiedTime > MostRecent) 90 | { 91 | MostRecent = ModifiedTime; 92 | } 93 | } 94 | 95 | return MostRecent; 96 | } 97 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODBankUpdateNotifier.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "Containers/UnrealString.h" 6 | #include "Misc/DateTime.h" 7 | #include "Delegates/Delegate.h" 8 | 9 | class FFMODBankUpdateNotifier 10 | { 11 | public: 12 | FFMODBankUpdateNotifier(); 13 | 14 | void SetFilePath(const FString &InPath); 15 | void Update(float DeltaTime); 16 | 17 | void EnableUpdate(bool bEnable); 18 | 19 | FSimpleMulticastDelegate BanksUpdatedEvent; 20 | 21 | private: 22 | void Refresh(); 23 | FDateTime MostRecentFileTime(); 24 | 25 | bool bUpdateEnabled; 26 | FString FilePath; 27 | FDateTime NextRefreshTime; 28 | FDateTime FileTime; 29 | float Countdown; 30 | }; 31 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODEventEditor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventEditor.h" 4 | #include "FMODEvent.h" 5 | #include "FMODStudioEditorModule.h" 6 | #include "FMODStudioModule.h" 7 | #include "FMODUtils.h" 8 | #include "SFMODEventEditorPanel.h" 9 | #include "Widgets/Docking/SDockTab.h" 10 | #include "fmod_studio.hpp" 11 | #include "UnrealEd/Public/Editor.h" 12 | 13 | #define LOCTEXT_NAMESPACE "FMODEventEditor" 14 | 15 | DEFINE_LOG_CATEGORY_STATIC(LogFMODEventEditor, Log, All); 16 | 17 | const FName FFMODEventEditor::EventEditorTabId(TEXT("FFMODEventEditor_EventView")); 18 | const FName FFMODEventEditor::FMODEventEditorAppIdentifier(TEXT("FMODEventEditorApp")); 19 | 20 | void FFMODEventEditor::RegisterTabSpawners(const TSharedRef &NewTabManager) 21 | { 22 | WorkspaceMenuCategory = NewTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_FMODEventEditor", "FMOD Event Editor")); 23 | auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); 24 | 25 | FAssetEditorToolkit::RegisterTabSpawners(NewTabManager); 26 | 27 | NewTabManager->RegisterTabSpawner(EventEditorTabId, FOnSpawnTab::CreateSP(this, &FFMODEventEditor::SpawnTab_EventEditor)) 28 | .SetDisplayName(LOCTEXT("EventTab", "FMOD Event")) 29 | .SetGroup(WorkspaceMenuCategoryRef); 30 | } 31 | 32 | void FFMODEventEditor::UnregisterTabSpawners(const TSharedRef &NewTabManager) 33 | { 34 | FAssetEditorToolkit::UnregisterTabSpawners(NewTabManager); 35 | 36 | NewTabManager->UnregisterTabSpawner(EventEditorTabId); 37 | } 38 | 39 | FFMODEventEditor::FFMODEventEditor() 40 | : CurrentPreviewEventInstance(nullptr) 41 | , EditedEvent(nullptr) 42 | { 43 | IFMODStudioEditorModule::Get().BanksReloadedEvent().AddRaw(this, &FFMODEventEditor::HandleBanksReloaded); 44 | BeginPIEDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FFMODEventEditor::HandleBeginPIE); 45 | } 46 | 47 | FFMODEventEditor::~FFMODEventEditor() 48 | { 49 | IFMODStudioEditorModule::Get().BanksReloadedEvent().RemoveAll(this); 50 | FEditorDelegates::BeginPIE.Remove(BeginPIEDelegateHandle); 51 | 52 | CurrentPreviewEventInstance = nullptr; 53 | } 54 | 55 | UFMODEvent *FFMODEventEditor::GetEditedEvent() const 56 | { 57 | return EditedEvent; 58 | } 59 | 60 | FMOD::Studio::EventDescription *FFMODEventEditor::GetEventDescription() const 61 | { 62 | return IFMODStudioModule::Get().GetEventDescription(EditedEvent, EFMODSystemContext::Auditioning); 63 | } 64 | 65 | void FFMODEventEditor::PlayEvent() 66 | { 67 | CurrentPreviewEventInstance = IFMODStudioModule::Get().CreateAuditioningInstance(EditedEvent); 68 | if (CurrentPreviewEventInstance != nullptr) 69 | { 70 | TArray values; 71 | TArray ids; 72 | 73 | ParameterValues.GenerateKeyArray(ids); 74 | ParameterValues.GenerateValueArray(values); 75 | 76 | CurrentPreviewEventInstance->setParametersByIDs(ids.GetData(), values.GetData(), ParameterValues.Num()); 77 | 78 | CurrentPreviewEventInstance->start(); 79 | } 80 | } 81 | 82 | void FFMODEventEditor::PauseEvent() 83 | { 84 | if (CurrentPreviewEventInstance != nullptr) 85 | { 86 | bool bIsPaused = false; 87 | CurrentPreviewEventInstance->getPaused(&bIsPaused); 88 | CurrentPreviewEventInstance->setPaused(!bIsPaused); 89 | } 90 | } 91 | 92 | void FFMODEventEditor::StopEvent() 93 | { 94 | IFMODStudioModule::Get().StopAuditioningInstance(); 95 | } 96 | 97 | void FFMODEventEditor::SetParameterValue(FMOD_STUDIO_PARAMETER_ID ParameterId, float Value) 98 | { 99 | ParameterValues[ParameterId] = Value; 100 | 101 | if (CurrentPreviewEventInstance != nullptr) 102 | { 103 | CurrentPreviewEventInstance->setParameterByID(ParameterId, Value); 104 | } 105 | } 106 | 107 | void FFMODEventEditor::AddParameter(FMOD_STUDIO_PARAMETER_ID ParameterId, float Value) 108 | { 109 | ParameterValues.Add(ParameterId, Value); 110 | } 111 | 112 | float FFMODEventEditor::GetParameterValue(FMOD_STUDIO_PARAMETER_ID Id) 113 | { 114 | return ParameterValues[Id]; 115 | } 116 | 117 | void FFMODEventEditor::InitFMODEventEditor(const EToolkitMode::Type Mode, const TSharedPtr &InitToolkitHost, UFMODEvent *Event) 118 | { 119 | if (IsValid(Event)) 120 | { 121 | EditedEvent = Event; 122 | 123 | TSharedRef StandaloneDefaultLayout = 124 | FTabManager::NewLayout("Standalone_FMODEventEditor_Layout") 125 | ->AddArea(FTabManager::NewPrimaryArea() 126 | ->SetOrientation(Orient_Vertical) 127 | ->Split(FTabManager::NewStack()->AddTab(EventEditorTabId, ETabState::OpenedTab)->SetHideTabWell(true))); 128 | 129 | const bool bCreateDefaultStandaloneMenu = true; 130 | const bool bCreateDefaultToolbar = false; 131 | FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, FFMODEventEditor::FMODEventEditorAppIdentifier, StandaloneDefaultLayout, 132 | bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, Event); 133 | } 134 | } 135 | 136 | FName FFMODEventEditor::GetToolkitFName() const 137 | { 138 | return FName("FMODEventEditor"); 139 | } 140 | 141 | FText FFMODEventEditor::GetBaseToolkitName() const 142 | { 143 | return LOCTEXT("ToolkitName", "FMOD Event Editor"); 144 | } 145 | 146 | FString FFMODEventEditor::GetWorldCentricTabPrefix() const 147 | { 148 | return LOCTEXT("WorldCentricTabPrefix", "FMOD Event ").ToString(); 149 | } 150 | 151 | FLinearColor FFMODEventEditor::GetWorldCentricTabColorScale() const 152 | { 153 | return FLinearColor(0.0f, 0.0f, 0.5f, 0.5f); 154 | } 155 | 156 | void FFMODEventEditor::CreateInternalWidgets() 157 | { 158 | FMODEventEditorPanel = SNew(SFMODEventEditorPanel).FMODEventEditor(SharedThis(this)); 159 | } 160 | 161 | TSharedRef FFMODEventEditor::SpawnTab_EventEditor(const FSpawnTabArgs &Args) 162 | { 163 | check(Args.GetTabId().TabType == EventEditorTabId); 164 | 165 | CreateInternalWidgets(); 166 | 167 | return SAssignNew(OwnerTab, SDockTab) 168 | .Label(LOCTEXT("EventEditorTitle", "FMOD Event")) 169 | .TabColorScale(GetTabColorScale())[FMODEventEditorPanel.ToSharedRef()]; 170 | } 171 | 172 | void FFMODEventEditor::HandleBanksReloaded() 173 | { 174 | CurrentPreviewEventInstance = nullptr; 175 | 176 | CreateInternalWidgets(); 177 | 178 | if (OwnerTab.IsValid()) 179 | { 180 | OwnerTab->SetContent(FMODEventEditorPanel.ToSharedRef()); 181 | } 182 | } 183 | 184 | void FFMODEventEditor::HandleBeginPIE(bool bSimulating) 185 | { 186 | CurrentPreviewEventInstance = nullptr; 187 | } 188 | 189 | #undef LOCTEXT_NAMESPACE 190 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODEventEditor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "Toolkits/AssetEditorToolkit.h" 6 | #include "fmod_studio_common.h" 7 | 8 | namespace FMOD 9 | { 10 | namespace Studio 11 | { 12 | class EventDescription; 13 | class EventInstance; 14 | } 15 | } 16 | 17 | static bool operator==(const FMOD_STUDIO_PARAMETER_ID &a, const FMOD_STUDIO_PARAMETER_ID &b) 18 | { 19 | return (a.data1 == b.data1 && a.data2 == b.data2); 20 | } 21 | FORCEINLINE uint32 GetTypeHash(const FMOD_STUDIO_PARAMETER_ID& id) 22 | { 23 | return FCrc::MemCrc_DEPRECATED(&id, sizeof(FMOD_STUDIO_PARAMETER_ID)); 24 | } 25 | 26 | class FFMODEventEditor : public FAssetEditorToolkit 27 | { 28 | public: 29 | virtual void RegisterTabSpawners(const TSharedRef &NewTabManager) override; 30 | virtual void UnregisterTabSpawners(const TSharedRef &NewTabManager) override; 31 | 32 | /** 33 | * Edits the specified event 34 | * 35 | * @param Mode Asset editing mode for this editor (standalone or world-centric) 36 | * @param InitToolkitHost When Mode is WorldCentric, this is the level editor instance to spawn this editor within 37 | * @param Event The event to edit 38 | */ 39 | void InitFMODEventEditor(const EToolkitMode::Type Mode, const TSharedPtr &InitToolkitHost, class UFMODEvent *Event); 40 | 41 | /** Constructor */ 42 | FFMODEventEditor(); 43 | 44 | /** Destructor */ 45 | virtual ~FFMODEventEditor(); 46 | 47 | UFMODEvent *GetEditedEvent() const; 48 | FMOD::Studio::EventDescription *GetEventDescription() const; 49 | void PlayEvent(); 50 | void PauseEvent(); 51 | void StopEvent(); 52 | float GetParameterValue(FMOD_STUDIO_PARAMETER_ID Id); 53 | void SetParameterValue(FMOD_STUDIO_PARAMETER_ID ParameterId, float Value); 54 | void AddParameter(FMOD_STUDIO_PARAMETER_ID ParameterId, float Value); 55 | 56 | /** IToolkit interface */ 57 | virtual FName GetToolkitFName() const override; 58 | virtual FText GetBaseToolkitName() const override; 59 | virtual FString GetWorldCentricTabPrefix() const override; 60 | virtual FLinearColor GetWorldCentricTabColorScale() const override; 61 | 62 | private: 63 | TMap ParameterValues; 64 | FMOD::Studio::EventInstance *CurrentPreviewEventInstance; 65 | 66 | void HandlePreBanksReloaded(); 67 | void HandleBanksReloaded(); 68 | void HandleBeginPIE(bool bSimulating); 69 | 70 | /** Creates all internal widgets for the tabs to point at */ 71 | void CreateInternalWidgets(); 72 | 73 | /** Spawns the tab with the FMOD event inside */ 74 | TSharedRef SpawnTab_EventEditor(const FSpawnTabArgs &Args); 75 | 76 | TSharedPtr FMODEventEditorPanel; 77 | TSharedPtr OwnerTab; 78 | 79 | /** The tab id for the event editor tab */ 80 | static const FName EventEditorTabId; 81 | 82 | /** FMOD event editor app identifier string */ 83 | static const FName FMODEventEditorAppIdentifier; 84 | 85 | class UFMODEvent *EditedEvent; 86 | 87 | FDelegateHandle BeginPIEDelegateHandle; 88 | }; -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODGenerateAssetsCommandlet.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2 | 3 | #include "FMODGenerateAssetsCommandlet.h" 4 | 5 | #include "FMODSettings.h" 6 | #include "AssetRegistryModule.h" 7 | #include "Editor.h" 8 | #include "Editor/UnrealEd/Public/FileHelpers.h" 9 | #include "HAL/PlatformFilemanager.h" 10 | #include "../Classes/FMODAssetBuilder.h" 11 | 12 | DEFINE_LOG_CATEGORY_STATIC(LogFMODCommandlet, Log, All); 13 | 14 | static constexpr auto RebuildSwitch = TEXT("rebuild"); 15 | 16 | UFMODGenerateAssetsCommandlet::UFMODGenerateAssetsCommandlet(const FObjectInitializer& ObjectInitializer) 17 | : Super(ObjectInitializer) 18 | { 19 | } 20 | 21 | int32 UFMODGenerateAssetsCommandlet::Main(const FString& CommandLine) 22 | { 23 | int32 returnCode = 0; 24 | 25 | #if WITH_EDITOR 26 | 27 | FAssetRegistryModule& assetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); 28 | IAssetRegistry& AssetRegistry = assetRegistryModule.Get(); 29 | 30 | const UFMODSettings& Settings = *GetDefault(); 31 | 32 | TArray Tokens, Switches; 33 | TMap Params; 34 | ParseCommandLine(*CommandLine, Tokens, Switches, Params); 35 | 36 | // Rebuild switch 37 | if (Switches.Contains(RebuildSwitch)) 38 | { 39 | IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile(); 40 | 41 | /* 42 | Combine the ProjectContentDir + ContentBrowserPrefix to make a filesystem path 43 | to where the FMOD generated assets directories live e.g. 44 | ../../../../UnrealProjects/MyProject/Content/FMOD 45 | Should work for non-default values of ContentBrowserPrefix e.g. /Game/foo/bar/baz/ 46 | */ 47 | FString folderPath = Settings.ContentBrowserPrefix.TrimChar('/'); // /Game/FMOD/ -> Game/FMOD 48 | folderPath.Split(TEXT("/"), 0, &folderPath); // Game/FMOD -> FMOD 49 | folderPath = FPaths::ProjectContentDir() + folderPath + "/"; // FMOD -> ../../../../UnrealProjects/MyProject/Content/FMOD/ 50 | 51 | for (FString folder : Settings.GeneratedFolders) 52 | { 53 | FString FolderToDelete = folderPath + folder; 54 | bool removed = FileManager.DeleteDirectoryRecursively(*FolderToDelete); 55 | if (!removed) 56 | { 57 | UE_LOG(LogFMODCommandlet, Warning, TEXT("Unable to delete '%s'."), *FolderToDelete); 58 | } 59 | } 60 | } 61 | 62 | // Ensure AssetRegistry is up to date 63 | TArray InPaths; 64 | InPaths.Add(Settings.GetFullContentPath()); 65 | AssetRegistry.ScanPathsSynchronous(InPaths); 66 | while (AssetRegistry.IsLoadingAssets()) 67 | { 68 | AssetRegistry.Tick(1.0f); 69 | } 70 | 71 | FFMODAssetBuilder assetBuilder; 72 | if (!IsEngineExitRequested()) 73 | { 74 | assetBuilder.Create(); 75 | assetBuilder.ProcessBanks(); 76 | } 77 | #endif 78 | 79 | return returnCode; 80 | } -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODSettingsCustomization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2025. 2 | 3 | #include "FMODSettingsCustomization.h" 4 | 5 | #include "DetailCategoryBuilder.h" 6 | #include "DetailLayoutBuilder.h" 7 | #include "DetailWidgetRow.h" 8 | #include "FMODSettings.h" 9 | #include "IDetailPropertyRow.h" 10 | #include "Settings/ProjectPackagingSettings.h" 11 | #include "Styling/SlateColor.h" 12 | #include "Widgets/DeclarativeSyntaxSupport.h" 13 | #include "Widgets/SWidget.h" 14 | #include "Widgets/SCompoundWidget.h" 15 | #include "Widgets/SBoxPanel.h" 16 | #include "Widgets/Layout/SBorder.h" 17 | #include "Widgets/Layout/SWidgetSwitcher.h" 18 | #include "Widgets/Images/SImage.h" 19 | #include "Widgets/Text/STextBlock.h" 20 | #include "Widgets/Input/SButton.h" 21 | 22 | #define LOCTEXT_NAMESPACE "FMODSettings" 23 | 24 | class SSettingsMessage : public SCompoundWidget 25 | { 26 | SLATE_BEGIN_ARGS(SSettingsMessage) 27 | {} 28 | 29 | // Called when the Setup button is clicked 30 | SLATE_EVENT(FSimpleDelegate, OnSetupClicked) 31 | 32 | SLATE_END_ARGS() 33 | 34 | public: 35 | void Construct(const FArguments& InArgs) 36 | { 37 | TSharedRef SettingsOkayWidget = MakeRow( 38 | "SettingsEditor.GoodIcon", 39 | LOCTEXT("SettingsOkayText", "FMOD Settings are valid, run the Validate FMOD command to perform additional checking."), 40 | FText() 41 | ); 42 | 43 | TSharedRef NoContentDirWidget = MakeRow( 44 | "SettingsEditor.WarningIcon", 45 | LOCTEXT("NoContentDirText", "Bank Output Directory directory has not been set."), 46 | FText() 47 | ); 48 | 49 | TSharedRef PackagingSettingsBadWidget = MakeRow( 50 | "SettingsEditor.WarningIcon", 51 | LOCTEXT("PackagingSettingsBadText", 52 | "The packaging settings for copying the FMOD bank files to staging are not correct. It is recommended that:\n" 53 | " - The bank output directory for the Desktop platform (or the forced platform if set) is added to the \"Additional Non-Asset Directories To Copy\" list.\n" 54 | " - That no other directory containing FMOD banks or assets is added to either the \"Additional Non-Asset Directories To Copy\" list " 55 | "or the \"Additional Non-Asset Directories to Package\" list.\n" 56 | " - The Generated Assets are added to the \"Additional Asset Directories to Cook\" list." 57 | ), 58 | LOCTEXT("FixPackagingSettings", "Fix") 59 | ); 60 | 61 | ChildSlot 62 | [ 63 | SNew(SBorder) 64 | .BorderBackgroundColor(this, &SSettingsMessage::GetBorderColor) 65 | .BorderImage(FEditorStyle::GetBrush("ToolPanel.LightGroupBorder")) 66 | .Padding(8.0f) 67 | [ 68 | SNew(SWidgetSwitcher) 69 | .WidgetIndex(this, &SSettingsMessage::GetSetupStateAsInt) 70 | 71 | + SWidgetSwitcher::Slot() 72 | [ 73 | SettingsOkayWidget 74 | ] 75 | 76 | + SWidgetSwitcher::Slot() 77 | [ 78 | NoContentDirWidget 79 | ] 80 | 81 | + SWidgetSwitcher::Slot() 82 | [ 83 | PackagingSettingsBadWidget 84 | ] 85 | ] 86 | ]; 87 | 88 | UpdateState(); 89 | } 90 | 91 | void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) 92 | { 93 | UpdateState(); 94 | } 95 | 96 | private: 97 | FSlateColor GetBorderColor() const 98 | { 99 | if (SettingsState == UFMODSettings::Okay) 100 | { 101 | return FLinearColor::Green; 102 | } 103 | else 104 | { 105 | return FLinearColor(0.8f, 0, 0); 106 | } 107 | } 108 | 109 | TSharedRef MakeRow(FName IconName, FText Message, FText ButtonMessage) 110 | { 111 | TSharedRef Result = SNew(SHorizontalBox) 112 | 113 | // Status icon 114 | + SHorizontalBox::Slot().AutoWidth().VAlign(VAlign_Center)[SNew(SImage).Image(FEditorStyle::GetBrush(IconName))] 115 | 116 | // Notice 117 | + SHorizontalBox::Slot() 118 | .FillWidth(1.0f) 119 | .Padding(16.0f, 0.0f) 120 | .VAlign(VAlign_Center)[ 121 | SNew(STextBlock) 122 | .ColorAndOpacity(FLinearColor::White) 123 | .ShadowColorAndOpacity(FLinearColor::Black) 124 | .ShadowOffset(FVector2D::UnitVector) 125 | .AutoWrapText(true) 126 | .Text(Message) 127 | ]; 128 | 129 | if (!ButtonMessage.IsEmpty()) 130 | { 131 | Result->AddSlot() 132 | .AutoWidth() 133 | .VAlign(VAlign_Center) 134 | [ 135 | SNew(SButton) 136 | .OnClicked(this, &SSettingsMessage::OnButtonPressed) 137 | .Text(ButtonMessage) 138 | ]; 139 | } 140 | 141 | return Result; 142 | } 143 | 144 | FReply OnButtonPressed() 145 | { 146 | const UFMODSettings& Settings = *GetDefault(); 147 | UProjectPackagingSettings* PackagingSettings = Cast(UProjectPackagingSettings::StaticClass()->GetDefaultObject()); 148 | 149 | if (SettingsState == UFMODSettings::PackagingSettingsBad) 150 | { 151 | // Remove any bad entries 152 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysStageAsNonUFS.Num();) 153 | { 154 | if (PackagingSettings->DirectoriesToAlwaysStageAsNonUFS[i].Path.StartsWith(Settings.BankOutputDirectory.Path)) 155 | { 156 | PackagingSettings->DirectoriesToAlwaysStageAsNonUFS.RemoveAt(i); 157 | } 158 | else 159 | { 160 | ++i; 161 | } 162 | } 163 | 164 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysStageAsUFS.Num();) 165 | { 166 | if (PackagingSettings->DirectoriesToAlwaysStageAsUFS[i].Path.StartsWith(Settings.BankOutputDirectory.Path)) 167 | { 168 | PackagingSettings->DirectoriesToAlwaysStageAsUFS.RemoveAt(i); 169 | } 170 | else 171 | { 172 | ++i; 173 | } 174 | } 175 | 176 | for (int i = 0; i < PackagingSettings->DirectoriesToAlwaysCook.Num();) 177 | { 178 | if (PackagingSettings->DirectoriesToAlwaysCook[i].Path.StartsWith(Settings.GetFullContentPath())) 179 | { 180 | PackagingSettings->DirectoriesToAlwaysCook.RemoveAt(i); 181 | } 182 | else 183 | { 184 | ++i; 185 | } 186 | } 187 | 188 | // Add correct entry 189 | FDirectoryPath BankPath; 190 | BankPath.Path = Settings.GetDesktopBankPath(); 191 | PackagingSettings->DirectoriesToAlwaysStageAsNonUFS.Add(BankPath); 192 | FDirectoryPath generatedFolder; 193 | for (FString folder : Settings.GeneratedFolders) 194 | { 195 | generatedFolder.Path = Settings.GetFullContentPath() / folder; 196 | PackagingSettings->DirectoriesToAlwaysCook.Add(generatedFolder); 197 | } 198 | 199 | PackagingSettings->UpdateDefaultConfigFile(); 200 | } 201 | 202 | UpdateState(); 203 | return FReply::Handled(); 204 | } 205 | 206 | int32 GetSetupStateAsInt() const 207 | { 208 | return (int32)SettingsState; 209 | } 210 | 211 | void UpdateState() 212 | { 213 | const UFMODSettings& Settings = *GetDefault(); 214 | SettingsState = Settings.Check(); 215 | } 216 | 217 | private: 218 | UFMODSettings::EProblem SettingsState; 219 | }; 220 | 221 | TSharedRef FFMODSettingsCustomization::MakeInstance() 222 | { 223 | return MakeShareable(new FFMODSettingsCustomization); 224 | } 225 | 226 | FFMODSettingsCustomization::FFMODSettingsCustomization() 227 | { 228 | } 229 | 230 | void FFMODSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder &DetailLayout) 231 | { 232 | IDetailCategoryBuilder &PackagingCategory = DetailLayout.EditCategory(TEXT("Basic")); 233 | TSharedRef PlatformSetupMessage = SNew(SSettingsMessage); 234 | PackagingCategory.AddCustomRow(LOCTEXT("Warning", "Warning"), false).WholeRowWidget[PlatformSetupMessage]; 235 | } 236 | 237 | #undef LOCTEXT_NAMESPACE 238 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODSettingsCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Misc/Attribute.h" 7 | #include "Input/Reply.h" 8 | #include "IDetailCustomization.h" 9 | #include "PropertyHandle.h" 10 | 11 | class IDetailLayoutBuilder; 12 | 13 | class FFMODSettingsCustomization : public IDetailCustomization 14 | { 15 | public: 16 | // Makes a new instance of this detail layout class for a specific detail view requesting it 17 | static TSharedRef MakeInstance(); 18 | 19 | // IDetailCustomization interface 20 | virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; 21 | // End of IDetailCustomization interface 22 | 23 | private: 24 | FFMODSettingsCustomization(); 25 | }; 26 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODStudioEditorPrivatePCH.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | #pragma once 3 | 4 | #include "Runtime/Engine/Classes/Components/SceneComponent.h" 5 | #include "Runtime/Engine/Classes/Camera/CameraComponent.h" 6 | #include "Runtime/Engine/Classes/Curves/IntegralCurve.h" 7 | #include "Runtime/Engine/Classes/Curves/NameCurve.h" 8 | #include "Runtime/Engine/Classes/Curves/RichCurve.h" 9 | #include "Runtime/MovieScene/Public/MovieScene.h" 10 | #include "Runtime/MovieScene/Public/KeyParams.h" 11 | 12 | #include "Editor/Sequencer/Public/ISectionLayoutBuilder.h" 13 | #include "Editor/Sequencer/Public/ISequencerSection.h" 14 | #include "Editor/Sequencer/Public/MovieSceneTrackEditor.h" 15 | #include "Runtime/MovieScene/Public/MovieSceneCommonHelpers.h" 16 | #include "Runtime/MovieScene/Public/MovieSceneSection.h" 17 | #include "Editor/UnrealEd/Public/ScopedTransaction.h" 18 | 19 | DECLARE_LOG_CATEGORY_EXTERN(LogFMOD, Log, All); -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODStudioStyle.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODStudioStyle.h" 4 | #include "SlateCore/Public/Styling/SlateStyle.h" 5 | #include "EditorStyle/Public/Interfaces/IEditorStyleModule.h" 6 | 7 | #define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(Style.RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__) 8 | 9 | ////////////////////////////////////////////////////////////////////////// 10 | // FFMODStudioStyle 11 | 12 | void FFMODStudioStyle::Initialize() 13 | { 14 | FSlateStyleSet& Style = static_cast(FEditorStyle::Get()); 15 | 16 | Style.Set("ClassIcon.FMODAmbientSound", new IMAGE_BRUSH("Icons/AssetIcons/AmbientSound_16x", FVector2D(16.0f, 16.0f))); 17 | Style.Set("ClassThumbnail.FMODAmbientSound", new IMAGE_BRUSH("Icons/AssetIcons/AmbientSound_64x", FVector2D(64.0f, 64.0f))); 18 | Style.Set("ClassIcon.FMODAudioComponent", new IMAGE_BRUSH("Icons/ActorIcons/SoundActor_16x", FVector2D(16.0f, 16.0f))); 19 | Style.Set("ClassIcon.FMODAsset", new IMAGE_BRUSH("Icons/ActorIcons/SoundActor_16x", FVector2D(16.0f, 16.0f))); 20 | } 21 | 22 | ////////////////////////////////////////////////////////////////////////// 23 | 24 | #undef IMAGE_BRUSH 25 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/FMODStudioStyle.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | #include "EditorStyle/Public/EditorStyleSet.h" 5 | 6 | class FFMODStudioStyle : public FEditorStyle 7 | { 8 | public: 9 | static void Initialize(); 10 | }; 11 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/SFMODEventEditorPanel.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "FMODEventEditor.h" 6 | 7 | namespace FMOD 8 | { 9 | namespace Studio 10 | { 11 | class EventDescription; 12 | } 13 | } 14 | 15 | class SFMODEventEditorPanel : public SCompoundWidget 16 | { 17 | public: 18 | SLATE_BEGIN_ARGS(SFMODEventEditorPanel) {} 19 | SLATE_ARGUMENT(TWeakPtr, FMODEventEditor) 20 | SLATE_END_ARGS() 21 | 22 | ~SFMODEventEditorPanel(); 23 | 24 | /** SCompoundWidget interface */ 25 | void Construct(const FArguments &InArgs); 26 | 27 | private: 28 | TSharedRef ConstructToolbar(FMOD::Studio::EventDescription *EventDescription); 29 | TSharedRef ConstructInfo(FMOD::Studio::EventDescription *EventDescription); 30 | TSharedRef ConstructParameters(FMOD::Studio::EventDescription *EventDescription); 31 | TSharedRef ConstructUserProperties(FMOD::Studio::EventDescription *EventDescription); 32 | 33 | /** Editor that owns this panel */ 34 | TWeakPtr FMODEventEditorPtr; 35 | 36 | FReply OnClickedPlay(); 37 | FReply OnClickedStop(); 38 | FReply OnClickedPause(); 39 | 40 | TOptional GetParameterValue(FMOD_STUDIO_PARAMETER_ID ParameterId) const; 41 | void OnParameterValueChanged(float NewValue, FMOD_STUDIO_PARAMETER_ID ParameterId); 42 | }; 43 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODChannelEditors.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "Sequencer/FMODChannelEditors.h" 4 | #include "ISequencerChannelInterface.h" 5 | #include "Widgets/DeclarativeSyntaxSupport.h" 6 | #include "Widgets/SCompoundWidget.h" 7 | #include "MovieSceneTimeHelpers.h" 8 | #include "MovieSceneToolHelpers.h" 9 | #include "ScopedTransaction.h" 10 | #include "EditorWidgets/Public/SEnumCombobox.h" 11 | #include "EditorStyleSet.h" 12 | #include "Channels/MovieSceneChannelTraits.h" 13 | 14 | class SFMODEventControlKeyEditor : public SCompoundWidget 15 | { 16 | public: 17 | SLATE_BEGIN_ARGS(SFMODEventControlKeyEditor) {} 18 | SLATE_END_ARGS(); 19 | 20 | void Construct(const FArguments &InArgs, TMovieSceneChannelHandle InChannelHandle, 21 | TWeakObjectPtr InWeakSection, TWeakPtr InWeakSequencer, UEnum *InEnum) 22 | { 23 | ChannelHandle = InChannelHandle; 24 | WeakSection = InWeakSection; 25 | WeakSequencer = InWeakSequencer; 26 | 27 | ChildSlot[MovieSceneToolHelpers::MakeEnumComboBox(InEnum, 28 | TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFMODEventControlKeyEditor::OnGetCurrentValueAsInt)), 29 | SEnumComboBox::FOnEnumSelectionChanged::CreateSP(this, &SFMODEventControlKeyEditor::OnChangeKey))]; 30 | } 31 | 32 | private: 33 | int32 OnGetCurrentValueAsInt() const 34 | { 35 | using namespace UE::MovieScene; 36 | 37 | FFMODEventControlChannel *Channel = ChannelHandle.Get(); 38 | ISequencer *Sequencer = WeakSequencer.Pin().Get(); 39 | UMovieSceneSection *OwningSection = WeakSection.Get(); 40 | uint8 Result = 0; 41 | 42 | if (Channel && Sequencer && OwningSection) 43 | { 44 | const FFrameTime CurrentTime = UE::MovieScene::ClampToDiscreteRange(Sequencer->GetLocalTime().Time, OwningSection->GetRange()); 45 | EvaluateChannel(Channel, CurrentTime, Result); 46 | } 47 | 48 | return Result; 49 | } 50 | 51 | void SetValue(uint8 InValue) 52 | { 53 | using namespace UE::MovieScene; 54 | 55 | UMovieSceneSection *OwningSection = WeakSection.Get(); 56 | if (!OwningSection) 57 | { 58 | return; 59 | } 60 | 61 | OwningSection->SetFlags(RF_Transactional); 62 | 63 | FFMODEventControlChannel *Channel = ChannelHandle.Get(); 64 | ISequencer *Sequencer = WeakSequencer.Pin().Get(); 65 | 66 | if (!OwningSection->TryModify() || !Channel || !Sequencer) 67 | { 68 | return; 69 | } 70 | 71 | const FFrameNumber CurrentTime = Sequencer->GetLocalTime().Time.FloorToFrame(); 72 | const bool bAutoSetTrackDefaults = Sequencer->GetAutoSetTrackDefaults(); 73 | 74 | EMovieSceneKeyInterpolation Interpolation = Sequencer->GetKeyInterpolation(); 75 | 76 | TArray KeysAtCurrentTime; 77 | Channel->GetKeys(TRange(CurrentTime), nullptr, &KeysAtCurrentTime); 78 | 79 | if (KeysAtCurrentTime.Num() > 0) 80 | { 81 | AssignValue(Channel, KeysAtCurrentTime[0], InValue); 82 | } 83 | else 84 | { 85 | const bool bHasAnyKeys = Channel->GetNumKeys() != 0; 86 | 87 | if (bHasAnyKeys || bAutoSetTrackDefaults == false) 88 | { 89 | // When auto setting track defaults are disabled, add a key even when it's empty so that the changed 90 | // value is saved and is propagated to the property. 91 | AddKeyToChannel(Channel, CurrentTime, InValue, Interpolation); 92 | } 93 | 94 | if (bHasAnyKeys) 95 | { 96 | TRange KeyRange = TRange(CurrentTime); 97 | TRange SectionRange = OwningSection->GetRange(); 98 | 99 | if (!SectionRange.Contains(KeyRange)) 100 | { 101 | OwningSection->SetRange(TRange::Hull(KeyRange, SectionRange)); 102 | } 103 | } 104 | } 105 | 106 | // Always update the default value when auto-set default values is enabled so that the last changes 107 | // are always saved to the track. 108 | if (bAutoSetTrackDefaults) 109 | { 110 | SetChannelDefault(Channel, InValue); 111 | } 112 | } 113 | 114 | void OnChangeKey(int32 Selection, ESelectInfo::Type SelectionType) 115 | { 116 | FScopedTransaction Transaction(FText::FromString("Set FMOD Event Control Key Value")); 117 | SetValue(Selection); 118 | if (ISequencer *Sequencer = WeakSequencer.Pin().Get()) 119 | { 120 | Sequencer->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::TrackValueChangedRefreshImmediately); 121 | } 122 | } 123 | 124 | TMovieSceneChannelHandle ChannelHandle; 125 | TWeakObjectPtr WeakSection; 126 | TWeakPtr WeakSequencer; 127 | }; 128 | 129 | bool CanCreateKeyEditor(const FFMODEventControlChannel *Channel) 130 | { 131 | return true; 132 | } 133 | 134 | TSharedRef CreateKeyEditor(const TMovieSceneChannelHandle &Channel, UMovieSceneSection *Section, 135 | const FGuid &InObjectBindingID, TWeakPtr PropertyBindings, TWeakPtr InSequencer) 136 | { 137 | const FFMODEventControlChannel *RawChannel = Channel.Get(); 138 | 139 | if (!RawChannel) 140 | { 141 | return SNullWidget::NullWidget; 142 | } 143 | 144 | UEnum *Enum = RawChannel->GetEnum(); 145 | return SNew(SFMODEventControlKeyEditor, Channel, Section, InSequencer, Enum); 146 | } 147 | 148 | void DrawKeys(FFMODEventControlChannel *Channel, TArrayView InKeyHandles, const UMovieSceneSection* InOwner, TArrayView OutKeyDrawParams) 149 | { 150 | static const FName KeyLeftBrushName("Sequencer.KeyLeft"); 151 | static const FName KeyRightBrushName("Sequencer.KeyRight"); 152 | static const FName KeyDiamondBrushName("Sequencer.KeyDiamond"); 153 | 154 | const FSlateBrush *LeftKeyBrush = FEditorStyle::GetBrush(KeyLeftBrushName); 155 | const FSlateBrush *RightKeyBrush = FEditorStyle::GetBrush(KeyRightBrushName); 156 | const FSlateBrush *DiamondBrush = FEditorStyle::GetBrush(KeyDiamondBrushName); 157 | 158 | TMovieSceneChannelData ChannelData = Channel->GetData(); 159 | 160 | for (int32 Index = 0; Index < InKeyHandles.Num(); ++Index) 161 | { 162 | FKeyHandle Handle = InKeyHandles[Index]; 163 | 164 | FKeyDrawParams Params; 165 | Params.BorderBrush = Params.FillBrush = DiamondBrush; 166 | 167 | const int32 KeyIndex = ChannelData.GetIndex(Handle); 168 | if (KeyIndex != INDEX_NONE) 169 | { 170 | const EFMODEventControlKey Value = (EFMODEventControlKey)ChannelData.GetValues()[KeyIndex]; 171 | if (Value == EFMODEventControlKey::Play) 172 | { 173 | Params.BorderBrush = Params.FillBrush = LeftKeyBrush; 174 | Params.FillOffset = FVector2D(-1.0f, 1.0f); 175 | } 176 | else if (Value == EFMODEventControlKey::Stop) 177 | { 178 | Params.BorderBrush = Params.FillBrush = RightKeyBrush; 179 | Params.FillOffset = FVector2D(1.0f, 1.0f); 180 | } 181 | } 182 | 183 | OutKeyDrawParams[Index] = Params; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODChannelEditors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "KeyDrawParams.h" 4 | #include "Channels/MovieSceneChannelHandle.h" 5 | #include "Sequencer/FMODEventControlSection.h" 6 | 7 | /** Key editor overrides */ 8 | bool CanCreateKeyEditor(const FFMODEventControlChannel* Channel); 9 | 10 | TSharedRef CreateKeyEditor(const TMovieSceneChannelHandle& Channel, UMovieSceneSection* Section, 11 | const FGuid& InObjectBindingID, TWeakPtr PropertyBindings, TWeakPtr InSequencer); 12 | 13 | /** Key drawing overrides */ 14 | void DrawKeys(FFMODEventControlChannel *Channel, TArrayView InKeyHandles, const UMovieSceneSection* InOwner, TArrayView OutKeyDrawParams); 15 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODEventControlTrackEditor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventControlTrackEditor.h" 4 | #include "Rendering/DrawElements.h" 5 | #include "Framework/MultiBox/MultiBoxBuilder.h" 6 | #include "Curves/IntegralCurve.h" 7 | #include "SequencerSectionPainter.h" 8 | #include "EditorStyleSet.h" 9 | #include "Editor/UnrealEdEngine.h" 10 | #include "Sequencer/FMODEventControlSection.h" 11 | #include "Sequencer/FMODEventControlTrack.h" 12 | #include "ISectionLayoutBuilder.h" 13 | #include "FMODAmbientSound.h" 14 | #include "CommonMovieSceneTools.h" 15 | #include "Channels/MovieSceneChannelProxy.h" 16 | #include "Channels/MovieSceneChannelEditorData.h" 17 | 18 | #define LOCTEXT_NAMESPACE "FFMODEventControlTrackEditor" 19 | 20 | FFMODEventControlSection::FFMODEventControlSection(UMovieSceneSection &InSection, TSharedRef InOwningSequencer) 21 | : Section(InSection) 22 | , OwningSequencerPtr(InOwningSequencer) 23 | { 24 | } 25 | 26 | UMovieSceneSection *FFMODEventControlSection::GetSectionObject() 27 | { 28 | return &Section; 29 | } 30 | 31 | float FFMODEventControlSection::GetSectionHeight() const 32 | { 33 | static const float SectionHeight = 20.f; 34 | return SectionHeight; 35 | } 36 | 37 | int32 FFMODEventControlSection::OnPaintSection(FSequencerSectionPainter &InPainter) const 38 | { 39 | TSharedPtr OwningSequencer = OwningSequencerPtr.Pin(); 40 | 41 | if (!OwningSequencer.IsValid()) 42 | { 43 | return InPainter.LayerId + 1; 44 | } 45 | 46 | const ESlateDrawEffect DrawEffects = InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; 47 | const FTimeToPixel &TimeToPixelConverter = InPainter.GetTimeConverter(); 48 | 49 | FLinearColor TrackColor; 50 | 51 | // TODO: Set / clip stop time based on event length 52 | UFMODEventControlSection *ControlSection = Cast(&Section); 53 | if (IsValid(ControlSection)) 54 | { 55 | UFMODEventControlTrack *ParentTrack = Cast(ControlSection->GetOuter()); 56 | if (IsValid(ParentTrack)) 57 | { 58 | TrackColor = ParentTrack->GetColorTint(); 59 | } 60 | } 61 | 62 | // TODO: This should only draw the visible ranges. 63 | TArray> DrawRanges; 64 | TOptional CurrentRangeStart; 65 | 66 | if (ControlSection != nullptr) 67 | { 68 | TMovieSceneChannelData ChannelData = ControlSection->ControlKeys.GetData(); 69 | TArrayView Times = ChannelData.GetTimes(); 70 | TArrayView Values = ChannelData.GetValues(); 71 | 72 | for (int32 Index = 0; Index < Times.Num(); ++Index) 73 | { 74 | const double Time = Times[Index] / TimeToPixelConverter.GetTickResolution(); 75 | const EFMODEventControlKey Value = (EFMODEventControlKey)Values[Index]; 76 | 77 | if (Value == EFMODEventControlKey::Play) 78 | { 79 | if (CurrentRangeStart.IsSet() == false) 80 | { 81 | CurrentRangeStart = Time; 82 | } 83 | } 84 | if (Value == EFMODEventControlKey::Stop) 85 | { 86 | if (CurrentRangeStart.IsSet()) 87 | { 88 | DrawRanges.Add(TRange(CurrentRangeStart.GetValue(), Time)); 89 | CurrentRangeStart.Reset(); 90 | } 91 | } 92 | } 93 | } 94 | 95 | if (CurrentRangeStart.IsSet()) 96 | { 97 | DrawRanges.Add(TRange(CurrentRangeStart.GetValue(), OwningSequencer->GetViewRange().GetUpperBoundValue())); 98 | } 99 | 100 | for (const TRange &DrawRange : DrawRanges) 101 | { 102 | float XOffset = TimeToPixelConverter.SecondsToPixel(DrawRange.GetLowerBoundValue()); 103 | float XSize = TimeToPixelConverter.SecondsToPixel(DrawRange.GetUpperBoundValue()) - XOffset; 104 | FSlateDrawElement::MakeBox(InPainter.DrawElements, InPainter.LayerId, 105 | InPainter.SectionGeometry.ToPaintGeometry( 106 | FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2), 107 | FVector2D(XSize, SequencerSectionConstants::KeySize.Y)), 108 | FEditorStyle::GetBrush("Sequencer.Section.Background"), DrawEffects); 109 | FSlateDrawElement::MakeBox(InPainter.DrawElements, InPainter.LayerId, 110 | InPainter.SectionGeometry.ToPaintGeometry( 111 | FVector2D(XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2), 112 | FVector2D(XSize, SequencerSectionConstants::KeySize.Y)), 113 | FEditorStyle::GetBrush("Sequencer.Section.BackgroundTint"), DrawEffects, TrackColor); 114 | } 115 | 116 | return InPainter.LayerId + 1; 117 | } 118 | 119 | FFMODEventControlTrackEditor::FFMODEventControlTrackEditor(TSharedRef InSequencer) 120 | : FMovieSceneTrackEditor(InSequencer) 121 | { 122 | } 123 | 124 | TSharedRef FFMODEventControlTrackEditor::CreateTrackEditor(TSharedRef InSequencer) 125 | { 126 | return MakeShareable(new FFMODEventControlTrackEditor(InSequencer)); 127 | } 128 | 129 | bool FFMODEventControlTrackEditor::SupportsType(TSubclassOf Type) const 130 | { 131 | return Type == UFMODEventControlTrack::StaticClass(); 132 | } 133 | 134 | TSharedRef FFMODEventControlTrackEditor::MakeSectionInterface( 135 | UMovieSceneSection &SectionObject, UMovieSceneTrack &Track, FGuid ObjectBinding) 136 | { 137 | check(SupportsType(SectionObject.GetOuter()->GetClass())); 138 | const TSharedPtr OwningSequencer = GetSequencer(); 139 | return MakeShareable(new FFMODEventControlSection(SectionObject, OwningSequencer.ToSharedRef())); 140 | } 141 | 142 | void FFMODEventControlTrackEditor::BuildObjectBindingTrackMenu(FMenuBuilder &MenuBuilder, const TArray &ObjectBindings, const UClass *ObjectClass) 143 | { 144 | if (ObjectClass->IsChildOf(AFMODAmbientSound::StaticClass()) || ObjectClass->IsChildOf(UFMODAudioComponent::StaticClass())) 145 | { 146 | const TSharedPtr ParentSequencer = GetSequencer(); 147 | 148 | MenuBuilder.AddMenuEntry(LOCTEXT("AddFMODEventControlTrack", "FMOD Event Control Track"), 149 | LOCTEXT("FMODEventControlTooltip", "Adds a track for controlling FMOD event."), FSlateIcon(), 150 | FUIAction(FExecuteAction::CreateSP(this, &FFMODEventControlTrackEditor::AddControlKey, ObjectBindings))); 151 | } 152 | } 153 | 154 | void FFMODEventControlTrackEditor::AddControlKey(TArray ObjectGuids) 155 | { 156 | TSharedPtr SequencerPtr = GetSequencer(); 157 | for (FGuid ObjectGuid : ObjectGuids) 158 | { 159 | UObject *Object = SequencerPtr.IsValid() ? SequencerPtr->FindSpawnedObjectOrTemplate(ObjectGuid) : nullptr; 160 | 161 | if (Object) 162 | { 163 | AnimatablePropertyChanged(FOnKeyProperty::CreateRaw(this, &FFMODEventControlTrackEditor::AddKeyInternal, Object)); 164 | } 165 | } 166 | } 167 | 168 | FKeyPropertyResult FFMODEventControlTrackEditor::AddKeyInternal(FFrameNumber KeyTime, UObject *Object) 169 | { 170 | FKeyPropertyResult KeyPropertyResult; 171 | 172 | FFindOrCreateHandleResult HandleResult = FindOrCreateHandleToObject(Object); 173 | FGuid ObjectHandle = HandleResult.Handle; 174 | KeyPropertyResult.bHandleCreated |= HandleResult.bWasCreated; 175 | 176 | if (ObjectHandle.IsValid()) 177 | { 178 | FFindOrCreateTrackResult TrackResult = FindOrCreateTrackForObject(ObjectHandle, UFMODEventControlTrack::StaticClass()); 179 | UMovieSceneTrack *Track = TrackResult.Track; 180 | KeyPropertyResult.bTrackCreated |= TrackResult.bWasCreated; 181 | 182 | if (KeyPropertyResult.bTrackCreated && ensure(Track)) 183 | { 184 | UFMODEventControlTrack *EventTrack = Cast(Track); 185 | EventTrack->AddNewSection(KeyTime); 186 | EventTrack->SetDisplayName(LOCTEXT("TrackName", "FMOD Event")); 187 | KeyPropertyResult.bTrackModified = true; 188 | } 189 | } 190 | 191 | return KeyPropertyResult; 192 | } 193 | 194 | #undef LOCTEXT_NAMESPACE 195 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODEventControlTrackEditor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Misc/Guid.h" 7 | #include "Templates/SubclassOf.h" 8 | #include "Curves/KeyHandle.h" 9 | #include "ISequencer.h" 10 | #include "MovieSceneTrack.h" 11 | #include "ISequencerSection.h" 12 | #include "ISequencerTrackEditor.h" 13 | #include "MovieSceneTrackEditor.h" 14 | 15 | class FMenuBuilder; 16 | class FSequencerSectionPainter; 17 | 18 | /** FMOD Event control track */ 19 | class FFMODEventControlTrackEditor : public FMovieSceneTrackEditor 20 | { 21 | public: 22 | FFMODEventControlTrackEditor(TSharedRef InSequencer); 23 | 24 | static TSharedRef CreateTrackEditor(TSharedRef OwningSequencer); 25 | 26 | void AddControlKey(TArray ObjectGuids); 27 | 28 | // Begin ISequencerTrackEditor interface 29 | virtual void BuildObjectBindingTrackMenu(FMenuBuilder &MenuBuilder, const TArray &ObjectBindings, const UClass *ObjectClass) override; 30 | virtual TSharedRef MakeSectionInterface( 31 | UMovieSceneSection &SectionObject, UMovieSceneTrack &Track, FGuid ObjectBinding) override; 32 | virtual bool SupportsType(TSubclassOf Type) const override; 33 | // End ISequencerTrackEditor interface 34 | 35 | private: 36 | /** Delegate for AnimatablePropertyChanged in AddKey. */ 37 | virtual FKeyPropertyResult AddKeyInternal(FFrameNumber KeyTime, UObject *Object); 38 | }; 39 | 40 | /** Class for event control sections. */ 41 | class FFMODEventControlSection : public ISequencerSection, public TSharedFromThis 42 | { 43 | public: 44 | FFMODEventControlSection(UMovieSceneSection &InSection, TSharedRef InOwningSequencer); 45 | 46 | // Begin ISequencerSection interface 47 | virtual UMovieSceneSection *GetSectionObject() override; 48 | virtual float GetSectionHeight() const override; 49 | virtual int32 OnPaintSection(FSequencerSectionPainter &InPainter) const override; 50 | virtual bool SectionIsResizable() const override { return false; } 51 | // End ISequencerSection interface 52 | 53 | private: 54 | /** The section we are visualizing. */ 55 | UMovieSceneSection &Section; 56 | 57 | /** The sequencer that owns this section */ 58 | TWeakPtr OwningSequencerPtr; 59 | }; 60 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODEventParameterTrackEditor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODEventParameterTrackEditor.h" 4 | #include "FMODAmbientSound.h" 5 | #include "FMODEvent.h" 6 | #include "FMODStudioModule.h" 7 | #include "Framework/MultiBox/MultiBoxBuilder.h" 8 | #include "Sequencer/FMODEventParameterTrack.h" 9 | #include "Sections/MovieSceneParameterSection.h" 10 | #include "Sequencer/FMODParameterSection.h" 11 | #include "SequencerUtilities.h" 12 | #include "fmod_studio.hpp" 13 | 14 | #define LOCTEXT_NAMESPACE "FMODEeventParameterTrackEditor" 15 | 16 | FName FFMODEventParameterTrackEditor::TrackName("FMODEventParameter"); 17 | 18 | FFMODEventParameterTrackEditor::FFMODEventParameterTrackEditor(TSharedRef InSequencer) 19 | : FMovieSceneTrackEditor(InSequencer) 20 | { 21 | } 22 | 23 | TSharedRef FFMODEventParameterTrackEditor::CreateTrackEditor(TSharedRef OwningSequencer) 24 | { 25 | return MakeShareable(new FFMODEventParameterTrackEditor(OwningSequencer)); 26 | } 27 | 28 | TSharedRef FFMODEventParameterTrackEditor::MakeSectionInterface( 29 | UMovieSceneSection &SectionObject, UMovieSceneTrack &Track, FGuid ObjectBinding) 30 | { 31 | UMovieSceneParameterSection *ParameterSection = Cast(&SectionObject); 32 | checkf(ParameterSection != nullptr, TEXT("Unsupported section type.")); 33 | return MakeShareable(new FFMODParameterSection(*ParameterSection)); 34 | } 35 | 36 | TSharedPtr FFMODEventParameterTrackEditor::BuildOutlinerEditWidget( 37 | const FGuid &ObjectBinding, UMovieSceneTrack *Track, const FBuildEditWidgetParams &Params) 38 | { 39 | UFMODEventParameterTrack *EventParameterTrack = Cast(Track); 40 | 41 | // Create a container edit box 42 | return FSequencerUtilities::MakeAddButton(LOCTEXT("ParameterText", "Parameter"), 43 | FOnGetContent::CreateSP(this, &FFMODEventParameterTrackEditor::OnGetAddParameterMenuContent, ObjectBinding, EventParameterTrack), 44 | Params.NodeIsHovered, 45 | GetSequencer()); 46 | } 47 | 48 | void FFMODEventParameterTrackEditor::BuildObjectBindingTrackMenu(FMenuBuilder &MenuBuilder, const TArray &ObjectBindings, const UClass *ObjectClass) 49 | { 50 | if (ObjectClass->IsChildOf(AFMODAmbientSound::StaticClass()) || ObjectClass->IsChildOf(UFMODAudioComponent::StaticClass())) 51 | { 52 | const TSharedPtr ParentSequencer = GetSequencer(); 53 | 54 | MenuBuilder.AddMenuEntry(LOCTEXT("AddFMODParameterTrack", "FMOD Event Parameter Track"), 55 | LOCTEXT("AddFMODParameterTrackTooltip", "Adds a track for controlling FMOD event parameter values."), FSlateIcon(), 56 | FUIAction(FExecuteAction::CreateSP(this, &FFMODEventParameterTrackEditor::AddEventParameterTrack, ObjectBindings[0]), 57 | FCanExecuteAction::CreateSP(this, &FFMODEventParameterTrackEditor::CanAddEventParameterTrack, ObjectBindings[0]))); 58 | } 59 | } 60 | 61 | bool FFMODEventParameterTrackEditor::SupportsType(TSubclassOf Type) const 62 | { 63 | return Type == UFMODEventParameterTrack::StaticClass(); 64 | } 65 | 66 | TSharedRef FFMODEventParameterTrackEditor::OnGetAddParameterMenuContent(FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack) 67 | { 68 | TSharedPtr SequencerPtr = GetSequencer(); 69 | AFMODAmbientSound *Sound = SequencerPtr.IsValid() ? Cast(SequencerPtr->FindSpawnedObjectOrTemplate(ObjectBinding)) : nullptr; 70 | UFMODAudioComponent *AudioComponent; 71 | 72 | if (IsValid(Sound)) 73 | { 74 | AudioComponent = Sound->AudioComponent; 75 | } 76 | else 77 | { 78 | AudioComponent = SequencerPtr.IsValid() ? Cast(SequencerPtr->FindSpawnedObjectOrTemplate(ObjectBinding)) : nullptr; 79 | } 80 | return BuildParameterMenu(ObjectBinding, EventParameterTrack, AudioComponent); 81 | } 82 | 83 | TSharedRef FFMODEventParameterTrackEditor::BuildParameterMenu( 84 | FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack, UFMODAudioComponent *AudioComponent) 85 | { 86 | FMenuBuilder AddParameterMenuBuilder(true, nullptr); 87 | 88 | if (IsValid(AudioComponent) && AudioComponent->Event) 89 | { 90 | TArray ParameterNamesAndActions; 91 | TArray ParameterDescriptions; 92 | AudioComponent->Event->GetParameterDescriptions(ParameterDescriptions); 93 | 94 | for (FMOD_STUDIO_PARAMETER_DESCRIPTION &ParameterDescription : ParameterDescriptions) 95 | { 96 | FName ParameterName(ParameterDescription.name); 97 | FExecuteAction InitAction = 98 | FExecuteAction::CreateSP(this, &FFMODEventParameterTrackEditor::AddParameter, ObjectBinding, EventParameterTrack, ParameterName); 99 | FUIAction AddParameterMenuAction(InitAction); 100 | FParameterNameAndAction NameAndAction(ParameterName, AddParameterMenuAction); 101 | ParameterNamesAndActions.Add(NameAndAction); 102 | } 103 | 104 | // Sort and generate menu. 105 | ParameterNamesAndActions.Sort(); 106 | for (FParameterNameAndAction NameAndAction : ParameterNamesAndActions) 107 | { 108 | AddParameterMenuBuilder.AddMenuEntry(FText::FromName(NameAndAction.ParameterName), FText(), FSlateIcon(), NameAndAction.Action); 109 | } 110 | } 111 | return AddParameterMenuBuilder.MakeWidget(); 112 | } 113 | 114 | bool FFMODEventParameterTrackEditor::CanAddEventParameterTrack(FGuid ObjectBinding) 115 | { 116 | return GetSequencer()->GetFocusedMovieSceneSequence()->GetMovieScene()->FindTrack( 117 | UFMODEventParameterTrack::StaticClass(), ObjectBinding, TrackName) == nullptr; 118 | } 119 | 120 | void FFMODEventParameterTrackEditor::AddEventParameterTrack(FGuid ObjectBinding) 121 | { 122 | FindOrCreateTrackForObject(ObjectBinding, UFMODEventParameterTrack::StaticClass(), TrackName, true); 123 | GetSequencer()->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::MovieSceneStructureItemAdded); 124 | } 125 | 126 | void FFMODEventParameterTrackEditor::AddParameter(FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack, FName ParameterName) 127 | { 128 | UMovieSceneSequence *MovieSceneSequence = GetMovieSceneSequence(); 129 | FFrameNumber KeyTime = GetTimeForKey(); 130 | 131 | for (TWeakObjectPtr<> Object : GetSequencer()->FindObjectsInCurrentSequence(ObjectBinding)) 132 | { 133 | AFMODAmbientSound *Sound = Cast(Object.Get()); 134 | UFMODAudioComponent *AudioComponent = nullptr; 135 | 136 | if (IsValid(Sound)) 137 | { 138 | AudioComponent = Sound->AudioComponent; 139 | } 140 | else 141 | { 142 | AudioComponent = Cast(Object.Get()); 143 | } 144 | 145 | if (IsValid(AudioComponent)) 146 | { 147 | float Value = AudioComponent->GetParameter(ParameterName); 148 | const FScopedTransaction Transaction(LOCTEXT("AddEventParameter", "Add event parameter")); 149 | EventParameterTrack->Modify(); 150 | EventParameterTrack->AddParameterKey(ParameterName, KeyTime, Value); 151 | } 152 | } 153 | GetSequencer()->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::MovieSceneStructureItemAdded); 154 | } 155 | 156 | #undef LOCTEXT_NAMESPACE 157 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODEventParameterTrackEditor.h: -------------------------------------------------------------------------------- 1 | // Taken from ParticleParameterTrackEditor 2 | 3 | #pragma once 4 | #include "CoreMinimal.h" 5 | #include "Misc/Guid.h" 6 | #include "Templates/SubclassOf.h" 7 | #include "Widgets/SWidget.h" 8 | #include "ISequencer.h" 9 | #include "MovieSceneTrack.h" 10 | #include "ISequencerSection.h" 11 | #include "Framework/Commands/UIAction.h" 12 | #include "ISequencerTrackEditor.h" 13 | #include "MovieSceneTrackEditor.h" 14 | 15 | class FMenuBuilder; 16 | class UFMODEventParameterTrack; 17 | class UFMODAudioComponent; 18 | struct FMOD_STUDIO_PARAMETER_DESCRIPTION; 19 | 20 | /** 21 | * Track editor for material parameters. 22 | */ 23 | class FFMODEventParameterTrackEditor : public FMovieSceneTrackEditor 24 | { 25 | public: 26 | /** Constructor. */ 27 | FFMODEventParameterTrackEditor(TSharedRef InSequencer); 28 | 29 | /** Virtual destructor. */ 30 | virtual ~FFMODEventParameterTrackEditor() {} 31 | 32 | /** 33 | * Creates an instance of this class. Called by a sequencer. 34 | * 35 | * @param OwningSequencer The sequencer instance to be used by this tool. 36 | * @return The new instance of this class. 37 | */ 38 | static TSharedRef CreateTrackEditor(TSharedRef OwningSequencer); 39 | 40 | // ISequencerTrackEditor interface 41 | 42 | virtual TSharedPtr BuildOutlinerEditWidget( 43 | const FGuid &ObjectBinding, UMovieSceneTrack *Track, const FBuildEditWidgetParams &Params) override; 44 | virtual TSharedRef MakeSectionInterface( 45 | UMovieSceneSection &SectionObject, UMovieSceneTrack &Track, FGuid ObjectBinding) override; 46 | virtual bool SupportsType(TSubclassOf Type) const override; 47 | 48 | private: 49 | static FName TrackName; 50 | 51 | // Struct used for building the parameter menu. 52 | struct FParameterNameAndAction 53 | { 54 | FName ParameterName; 55 | FUIAction Action; 56 | 57 | FParameterNameAndAction(FName InParameterName, FUIAction InAction) 58 | { 59 | ParameterName = InParameterName; 60 | Action = InAction; 61 | } 62 | 63 | bool operator<(FParameterNameAndAction const &Other) const { return ParameterName.FastLess(Other.ParameterName); } 64 | }; 65 | 66 | void BuildObjectBindingTrackMenu(FMenuBuilder &MenuBuilder, const TArray &ObjectBindings, const UClass *ObjectClass); 67 | 68 | /** Provides the contents of the add parameter menu. */ 69 | TSharedRef OnGetAddParameterMenuContent(FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack); 70 | TSharedRef BuildParameterMenu(FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack, UFMODAudioComponent *AudioComponent); 71 | 72 | bool CanAddEventParameterTrack(FGuid ObjectBinding); 73 | void AddEventParameterTrack(FGuid ObjectBinding); 74 | 75 | /** Adds an event parameter and initial key to a track. */ 76 | void AddParameter(FGuid ObjectBinding, UFMODEventParameterTrack *EventParameterTrack, FName ParameterName); 77 | }; 78 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODParameterSection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #include "FMODParameterSection.h" 4 | #include "ISectionLayoutBuilder.h" 5 | #include "ScopedTransaction.h" 6 | #include "Sections/MovieSceneParameterSection.h" 7 | 8 | #define LOCTEXT_NAMESPACE "FMODParameterSection" 9 | 10 | bool FFMODParameterSection::RequestDeleteKeyArea(const TArray &KeyAreaNamePath) 11 | { 12 | if (KeyAreaNamePath.Num() == 1) 13 | { 14 | const FScopedTransaction Transaction(LOCTEXT("DeleteEventParameter", "Delete event parameter")); 15 | UMovieSceneParameterSection *ParameterSection = Cast(WeakSection.Get()); 16 | if (ParameterSection->TryModify()) 17 | { 18 | return ParameterSection->RemoveScalarParameter(KeyAreaNamePath[0]); 19 | } 20 | } 21 | 22 | return true; 23 | } 24 | 25 | #undef LOCTEXT_NAMESPACE 26 | -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Private/Sequencer/FMODParameterSection.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "ISequencerSection.h" 6 | 7 | class UMovieSceneSection; 8 | 9 | /** A movie scene section for Event parameters. */ 10 | class FFMODParameterSection : public FSequencerSection 11 | { 12 | public: 13 | FFMODParameterSection(UMovieSceneSection &InSectionObject) 14 | : FSequencerSection(InSectionObject) 15 | { 16 | } 17 | 18 | // Begin ISequencerSection interface 19 | virtual bool RequestDeleteKeyArea(const TArray &KeyAreaNamePath) override; 20 | // End ISequencerSection interface 21 | }; -------------------------------------------------------------------------------- /FMODStudio/Source/FMODStudioEditor/Public/FMODStudioEditorModule.h: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | #pragma once 4 | 5 | #include "Modules/ModuleManager.h" 6 | 7 | /** 8 | * The public interface to this module 9 | */ 10 | class IFMODStudioEditorModule : public IModuleInterface 11 | { 12 | 13 | public: 14 | /** 15 | * Singleton-like access to this module's interface. This is just for convenience! 16 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 17 | * 18 | * @return Returns singleton instance, loading the module on demand if needed 19 | */ 20 | static inline IFMODStudioEditorModule &Get() { return FModuleManager::LoadModuleChecked("FMODStudioEditor"); } 21 | 22 | /** 23 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 24 | * 25 | * @return True if the module is loaded and ready to use 26 | */ 27 | static inline bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("FMODStudioEditor"); } 28 | 29 | /** This event is fired after all banks were reloaded */ 30 | virtual FSimpleMulticastDelegate &BanksReloadedEvent() = 0; 31 | }; 32 | -------------------------------------------------------------------------------- /FMODStudioNiagara/Content/ENiagara_FMODParamType.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudioNiagara/Content/ENiagara_FMODParamType.uasset -------------------------------------------------------------------------------- /FMODStudioNiagara/Content/PlayFMODEvent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudioNiagara/Content/PlayFMODEvent.uasset -------------------------------------------------------------------------------- /FMODStudioNiagara/Content/PlayPersistentFMODEvent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudioNiagara/Content/PlayPersistentFMODEvent.uasset -------------------------------------------------------------------------------- /FMODStudioNiagara/Content/Templates/PlayFMODEventEmitter.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudioNiagara/Content/Templates/PlayFMODEventEmitter.uasset -------------------------------------------------------------------------------- /FMODStudioNiagara/Content/UpdatePersistentFMODEvent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmod/fmod-for-unreal/20d09ba9bd4a1cc50439aedb49ec28cc183a022c/FMODStudioNiagara/Content/UpdatePersistentFMODEvent.uasset -------------------------------------------------------------------------------- /FMODStudioNiagara/FMODStudioNiagara.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | 4 | "FriendlyName": "FMOD Studio Niagara Integration", 5 | "Version" : 20228, 6 | "VersionName" : "2.02.28", 7 | "CreatedBy": "Firelight Technologies", 8 | "CreatedByURL" : "http://fmod.com", 9 | "Description" : "FMOD Studio with Niagara Integration.", 10 | "Category": "Audio", 11 | 12 | "CanContainContent": true, 13 | "Installed": true, 14 | 15 | "Modules": [ 16 | { 17 | "Name": "FMODStudioNiagara", 18 | "Type": "Runtime", 19 | "LoadingPhase": "Default" 20 | } 21 | ], 22 | "Plugins": [ 23 | { 24 | "Name": "FMODStudio", 25 | "Enabled": true 26 | }, 27 | { 28 | "Name": "Niagara", 29 | "Enabled": true 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /FMODStudioNiagara/Source/FMODStudioNiagara/FMODStudioNiagara.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c), Firelight Technologies Pty, Ltd. 2012-2025. 2 | 3 | using UnrealBuildTool; 4 | using System; 5 | 6 | public class FMODStudioNiagara : ModuleRules 7 | { 8 | public FMODStudioNiagara(ReadOnlyTargetRules Target) : base(Target) 9 | { 10 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 11 | 12 | PublicDependencyModuleNames.AddRange( 13 | new[] 14 | { 15 | "Core" 16 | }); 17 | 18 | PrivateDependencyModuleNames.AddRange( 19 | new[] 20 | { 21 | "CoreUObject", 22 | "Engine", 23 | "Slate", 24 | "SlateCore", 25 | "Projects", 26 | "FMODStudio", 27 | 28 | // Data interface dependencies 29 | "Niagara", "NiagaraCore", "VectorVM", "RenderCore", "RHI", 30 | }); 31 | 32 | if (Target.bBuildEditor == true) 33 | { 34 | PrivateDependencyModuleNames.Add("UnrealEd"); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /FMODStudioNiagara/Source/FMODStudioNiagara/Private/FMODStudioNiagara.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "FMODStudioNiagara.h" 4 | #include "Misc/Paths.h" 5 | #include "Interfaces/IPluginManager.h" 6 | 7 | #define LOCTEXT_NAMESPACE "FFMODStudioNiagaraModule" 8 | 9 | void FFMODStudioNiagaraModule::StartupModule() 10 | { 11 | IPluginManager::Get().FindPlugin(TEXT("FMODStudioNiagara"))->GetBaseDir(); 12 | } 13 | 14 | void FFMODStudioNiagaraModule::ShutdownModule() 15 | { 16 | } 17 | 18 | #undef LOCTEXT_NAMESPACE 19 | 20 | IMPLEMENT_MODULE(FDefaultModuleImpl, FMODStudioNiagara) -------------------------------------------------------------------------------- /FMODStudioNiagara/Source/FMODStudioNiagara/Public/FMODNiagaraEventPlayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FMODEvent.h" 4 | #include "FMODAudioComponent.h" 5 | 6 | #include "NiagaraCommon.h" 7 | #include "NiagaraDataInterface.h" 8 | #include "NiagaraShared.h" 9 | #include "NiagaraSystem.h" 10 | 11 | #include "Sound/SoundAttenuation.h" 12 | 13 | #include "FMODStudioNiagara.h" 14 | #include "FMODNiagaraEventPlayer.generated.h" 15 | 16 | struct FEventParticleData 17 | { 18 | FVector Position; 19 | FRotator Rotation; 20 | }; 21 | 22 | struct FPersistentEventParticleData 23 | { 24 | int32 AudioHandle = 0; 25 | 26 | /** The update callback is executed in PerInstanceTickPostSimulate, which runs on the game thread */ 27 | TFunction UpdateCallback; 28 | }; 29 | 30 | struct FEventPlayerInterface_InstanceData 31 | { 32 | /** We use a lock-free queue here because multiple threads might try to push data to it at the same time. */ 33 | TQueue PlayAudioQueue; 34 | TQueue PersistentAudioActionQueue; 35 | FThreadSafeCounter HandleCount; 36 | 37 | TSortedMap> PersistentAudioMapping; 38 | 39 | TWeakObjectPtr EventToPlay; 40 | TArray ParameterNames; 41 | 42 | int32 MaxPlaysPerTick = 0; 43 | bool bStopWhenComponentIsDestroyed = true; 44 | 45 | #if WITH_EDITORONLY_DATA 46 | bool bOnlyActiveDuringGameplay = true; 47 | #endif 48 | }; 49 | 50 | /** This Data Interface can be used to play one-shot audio effects driven by particle data. */ 51 | UCLASS(EditInlineNew, Category = "Audio", meta = (DisplayName = "FMOD Event Player")) 52 | class FMODSTUDIONIAGARA_API UFMODNiagaraEventPlayer : public UNiagaraDataInterface 53 | { 54 | GENERATED_UCLASS_BODY() 55 | 56 | public: 57 | /** Reference to the audio asset to play */ 58 | UPROPERTY(EditAnywhere, Category = "Audio") 59 | UFMODEvent* EventToPlay; 60 | 61 | /** A set of parameter names that can be referenced via index when setting sound cue parameters on persistent audio */ 62 | UPROPERTY(VisibleAnywhere, NoClear, Category = "Parameters") 63 | TArray ParameterNames; 64 | 65 | UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Audio", meta = (InlineEditConditionToggle)) 66 | bool bLimitPlaysPerTick; 67 | 68 | /** This sets the max number of sounds played each tick. 69 | * If more particles try to play a sound in a given tick, then it will play sounds until the limit is reached and discard the rest. 70 | * The particles to discard when over the limit are *not* chosen in a deterministic way. */ 71 | UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Audio", meta = (EditCondition = "bLimitPlaysPerTick", ClampMin = "0", UIMin = "0")) 72 | int32 MaxPlaysPerTick; 73 | 74 | /** If false then it the audio component keeps playing after the niagara component was destroyed. Looping sounds are always stopped when the component is destroyed. */ 75 | UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Audio") 76 | bool bStopWhenComponentIsDestroyed = true; 77 | 78 | #if WITH_EDITORONLY_DATA 79 | /** If true then this data interface only processes sounds during active gameplay. This is useful when you are working in the preview window and the sounds annoy you. 80 | * Currently the FMOD Niagara integration will not play in Editor. 81 | */ 82 | UPROPERTY(VisibleAnywhere, AdvancedDisplay, Category = "Audio") 83 | bool bOnlyActiveDuringGameplay = true; 84 | #endif 85 | 86 | //UObject Interface 87 | virtual void PostInitProperties() override; 88 | //UObject Interface End 89 | 90 | //UNiagaraDataInterface Interface 91 | virtual void GetFunctions(TArray& OutFunctions) override; 92 | virtual void GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo, void* InstanceData, FVMExternalFunction& OutFunc) override; 93 | virtual bool InitPerInstanceData(void* PerInstanceData, FNiagaraSystemInstance* SystemInstance) override; 94 | virtual void DestroyPerInstanceData(void* PerInstanceData, FNiagaraSystemInstance* SystemInstance) override; 95 | virtual int32 PerInstanceDataSize() const override { return sizeof(FEventPlayerInterface_InstanceData); } 96 | virtual bool PerInstanceTick(void* PerInstanceData, FNiagaraSystemInstance* SystemInstance, float DeltaSeconds) override; 97 | virtual bool PerInstanceTickPostSimulate(void* PerInstanceData, FNiagaraSystemInstance* SystemInstance, float DeltaSeconds) override; 98 | virtual bool Equals(const UNiagaraDataInterface* Other) const override; 99 | virtual bool CanExecuteOnTarget(ENiagaraSimTarget Target) const override { return Target == ENiagaraSimTarget::CPUSim; } 100 | 101 | virtual bool HasPreSimulateTick() const override { return true; } 102 | virtual bool HasPostSimulateTick() const override { return true; } 103 | //UNiagaraDataInterface Interface 104 | 105 | virtual void PlayOneShotAudio(FVectorVMContext& Context); 106 | virtual void PlayPersistentAudio(FVectorVMContext& Context); 107 | virtual void SetParameterFloat(FVectorVMContext& Context); 108 | virtual void UpdateLocation(FVectorVMContext& Context); 109 | virtual void UpdateRotation(FVectorVMContext& Context); 110 | virtual void SetPausedState(FVectorVMContext& Context); 111 | 112 | #if WITH_EDITOR 113 | void PostEditChangeProperty(FPropertyChangedEvent& e); 114 | void CacheDefaultParameterValues(); 115 | bool ShouldCacheParameter(const FMOD_STUDIO_PARAMETER_DESCRIPTION& ParameterDescription); 116 | bool bDefaultParameterValuesCached; 117 | #endif 118 | 119 | protected: 120 | virtual bool CopyToInternal(UNiagaraDataInterface* Destination) const override; 121 | 122 | private: 123 | static const FName PlayAudioName; 124 | static const FName PlayPersistentAudioName; 125 | static const FName SetPersistentAudioLocationName; 126 | static const FName SetPersistentAudioRotationName; 127 | static const FName SetPersistentAudioFloatParamName; 128 | static const FName PausePersistentAudioName; 129 | }; -------------------------------------------------------------------------------- /FMODStudioNiagara/Source/FMODStudioNiagara/Public/FMODStudioNiagara.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | class FMODSTUDIONIAGARA_API FFMODStudioNiagaraModule : public IModuleInterface 9 | { 10 | public: 11 | 12 | /** IModuleInterface implementation */ 13 | virtual void StartupModule() override; 14 | virtual void ShutdownModule() override; 15 | }; 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FMOD For Unreal 2 | 3 | This repository contains the source code for the FMOD Studio Unreal integration, excluding any platforms that require a non-disclosure agreement (such as Xbox). Additionally, native binaries for all platforms have been removed and must be acquired from a built package. Developers can use this repository to track changes, report issues or submit modifications. 4 | 5 | * Packages which include binaries can be downloaded from the FMOD [download page](https://fmod.com/download#unrealintegration). 6 | * For getting started information, up-to-date documentation and compatibility details check the FMOD For Unreal [documentation site](https://fmod.com/docs/2.02/unreal). 7 | * Free support is available on the FMOD [forums](https://qa.fmod.com/c/ue4) for all users, paid / licensed support available by email. --------------------------------------------------------------------------------