RealtimeStyleTransferRuntime/Source/LyraGame/Audio/LyraAudioMixEffectsSubsyste...

360 lines
12 KiB
C++
Raw Normal View History

2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Audio/LyraAudioMixEffectsSubsystem.h"
2022-09-13 07:18:28 +00:00
#include "AudioMixerBlueprintLibrary.h"
2022-05-23 18:41:30 +00:00
#include "AudioModulationStatics.h"
2022-09-13 07:18:28 +00:00
#include "Containers/EnumAsByte.h"
#include "Delegates/Delegate.h"
#include "Engine/GameInstance.h"
#include "Engine/World.h"
#include "HAL/Platform.h"
#include "LoadingScreenManager.h"
2022-05-23 18:41:30 +00:00
#include "LyraAudioSettings.h"
2022-09-13 07:18:28 +00:00
#include "Misc/AssertionMacros.h"
2022-05-23 18:41:30 +00:00
#include "Settings/LyraSettingsLocal.h"
2022-09-13 07:18:28 +00:00
#include "Sound/SoundEffectSubmix.h"
#include "Sound/SoundSubmix.h"
#include "SoundControlBus.h"
#include "SoundControlBusMix.h"
#include "Templates/Casts.h"
#include "UObject/Object.h"
#include "UObject/SoftObjectPath.h"
#include "UObject/SoftObjectPtr.h"
class FSubsystemCollectionBase;
2022-05-23 18:41:30 +00:00
void ULyraAudioMixEffectsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
}
void ULyraAudioMixEffectsSubsystem::Deinitialize()
{
if (ULoadingScreenManager* LoadingScreenManager = UGameInstance::GetSubsystem<ULoadingScreenManager>(GetWorld()->GetGameInstance()))
{
LoadingScreenManager->OnLoadingScreenVisibilityChangedDelegate().RemoveAll(this);
ApplyOrRemoveLoadingScreenMix(false);
}
Super::Deinitialize();
}
bool ULyraAudioMixEffectsSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
bool bShouldCreateSubsystem = Super::ShouldCreateSubsystem(Outer);
if (Outer)
{
if (UWorld* World = Outer->GetWorld())
{
bShouldCreateSubsystem = DoesSupportWorldType(World->WorldType) && bShouldCreateSubsystem;
}
}
return bShouldCreateSubsystem;
}
void ULyraAudioMixEffectsSubsystem::PostInitialize()
{
if (const ULyraAudioSettings* LyraAudioSettings = GetDefault<ULyraAudioSettings>())
{
if (UObject* ObjPath = LyraAudioSettings->DefaultControlBusMix.TryLoad())
{
if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
{
DefaultBaseMix = SoundControlBusMix;
}
else
{
ensureMsgf(SoundControlBusMix, TEXT("Default Control Bus Mix reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->LoadingScreenControlBusMix.TryLoad())
{
if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
{
LoadingScreenMix = SoundControlBusMix;
}
else
{
ensureMsgf(SoundControlBusMix, TEXT("Loading Screen Control Bus Mix reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->UserSettingsControlBusMix.TryLoad())
{
if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
{
UserMix = SoundControlBusMix;
}
else
{
ensureMsgf(SoundControlBusMix, TEXT("User Control Bus Mix reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->OverallVolumeControlBus.TryLoad())
{
if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
{
OverallControlBus = SoundControlBus;
}
else
{
ensureMsgf(SoundControlBus, TEXT("Overall Control Bus reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->MusicVolumeControlBus.TryLoad())
{
if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
{
MusicControlBus = SoundControlBus;
}
else
{
ensureMsgf(SoundControlBus, TEXT("Music Control Bus reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->SoundFXVolumeControlBus.TryLoad())
{
if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
{
SoundFXControlBus = SoundControlBus;
}
else
{
ensureMsgf(SoundControlBus, TEXT("SoundFX Control Bus reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->DialogueVolumeControlBus.TryLoad())
{
if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
{
DialogueControlBus = SoundControlBus;
}
else
{
ensureMsgf(SoundControlBus, TEXT("Dialogue Control Bus reference missing from Lyra Audio Settings."));
}
}
if (UObject* ObjPath = LyraAudioSettings->VoiceChatVolumeControlBus.TryLoad())
{
if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
{
VoiceChatControlBus = SoundControlBus;
}
else
{
ensureMsgf(SoundControlBus, TEXT("VoiceChat Control Bus reference missing from Lyra Audio Settings."));
}
}
// Load HDR Submix Effect Chain
for (const FLyraSubmixEffectChainMap& SoftSubmixEffectChain : LyraAudioSettings->HDRAudioSubmixEffectChain)
{
FLyraAudioSubmixEffectsChain NewEffectChain;
if (UObject* SubmixObjPath = SoftSubmixEffectChain.Submix.LoadSynchronous())
{
if (USoundSubmix* Submix = Cast<USoundSubmix>(SubmixObjPath))
{
NewEffectChain.Submix = Submix;
TArray<USoundEffectSubmixPreset*> NewPresetChain;
for (const TSoftObjectPtr<USoundEffectSubmixPreset>& SoftEffect : SoftSubmixEffectChain.SubmixEffectChain)
{
if (UObject* EffectObjPath = SoftEffect.LoadSynchronous())
{
if (USoundEffectSubmixPreset* SubmixPreset = Cast<USoundEffectSubmixPreset>(EffectObjPath))
{
NewPresetChain.Add(SubmixPreset);
}
}
}
NewEffectChain.SubmixEffectChain.Append(NewPresetChain);
}
}
HDRSubmixEffectChain.Add(NewEffectChain);
}
// Load LDR Submix Effect Chain
for (const FLyraSubmixEffectChainMap& SoftSubmixEffectChain : LyraAudioSettings->LDRAudioSubmixEffectChain)
{
FLyraAudioSubmixEffectsChain NewEffectChain;
if (UObject* SubmixObjPath = SoftSubmixEffectChain.Submix.LoadSynchronous())
{
if (USoundSubmix* Submix = Cast<USoundSubmix>(SubmixObjPath))
{
NewEffectChain.Submix = Submix;
TArray<USoundEffectSubmixPreset*> NewPresetChain;
for (const TSoftObjectPtr<USoundEffectSubmixPreset>& SoftEffect : SoftSubmixEffectChain.SubmixEffectChain)
{
if (UObject* EffectObjPath = SoftEffect.LoadSynchronous())
{
if (USoundEffectSubmixPreset* SubmixPreset = Cast<USoundEffectSubmixPreset>(EffectObjPath))
{
NewPresetChain.Add(SubmixPreset);
}
}
}
NewEffectChain.SubmixEffectChain.Append(NewPresetChain);
}
}
LDRSubmixEffectChain.Add(NewEffectChain);
}
}
// Register with the loading screen manager
if (ULoadingScreenManager* LoadingScreenManager = UGameInstance::GetSubsystem<ULoadingScreenManager>(GetWorld()->GetGameInstance()))
{
LoadingScreenManager->OnLoadingScreenVisibilityChangedDelegate().AddUObject(this, &ThisClass::OnLoadingScreenStatusChanged);
ApplyOrRemoveLoadingScreenMix(LoadingScreenManager->GetLoadingScreenDisplayStatus());
}
}
void ULyraAudioMixEffectsSubsystem::OnWorldBeginPlay(UWorld& InWorld)
{
if (const UWorld* World = InWorld.GetWorld())
{
// Activate the default base mix
if (DefaultBaseMix)
{
UAudioModulationStatics::ActivateBusMix(World, DefaultBaseMix);
}
// Retrieve the user settings
if (const ULyraSettingsLocal* LyraSettingsLocal = GetDefault<ULyraSettingsLocal>())
{
// Activate the User Mix
if (UserMix)
{
UAudioModulationStatics::ActivateBusMix(World, UserMix);
if (OverallControlBus && MusicControlBus && SoundFXControlBus && DialogueControlBus && VoiceChatControlBus)
{
const FSoundControlBusMixStage OverallControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, OverallControlBus, LyraSettingsLocal->GetOverallVolume());
const FSoundControlBusMixStage MusicControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, MusicControlBus, LyraSettingsLocal->GetMusicVolume());
const FSoundControlBusMixStage SoundFXControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, SoundFXControlBus, LyraSettingsLocal->GetSoundFXVolume());
const FSoundControlBusMixStage DialogueControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, DialogueControlBus, LyraSettingsLocal->GetDialogueVolume());
const FSoundControlBusMixStage VoiceChatControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, VoiceChatControlBus, LyraSettingsLocal->GetVoiceChatVolume());
TArray<FSoundControlBusMixStage> ControlBusMixStageArray;
ControlBusMixStageArray.Add(OverallControlBusMixStage);
ControlBusMixStageArray.Add(MusicControlBusMixStage);
ControlBusMixStageArray.Add(SoundFXControlBusMixStage);
ControlBusMixStageArray.Add(DialogueControlBusMixStage);
ControlBusMixStageArray.Add(VoiceChatControlBusMixStage);
UAudioModulationStatics::UpdateMix(World, UserMix, ControlBusMixStageArray);
}
}
ApplyDynamicRangeEffectsChains(LyraSettingsLocal->IsHDRAudioModeEnabled());
}
}
}
void ULyraAudioMixEffectsSubsystem::ApplyDynamicRangeEffectsChains(bool bHDRAudio)
{
TArray<FLyraAudioSubmixEffectsChain> AudioSubmixEffectsChainToApply;
TArray<FLyraAudioSubmixEffectsChain> AudioSubmixEffectsChainToClear;
// If HDR Audio is selected, then we clear out any existing LDR Submix Effect Chain Overrides
// otherwise the reverse is the case.
if (bHDRAudio)
{
AudioSubmixEffectsChainToApply.Append(HDRSubmixEffectChain);
AudioSubmixEffectsChainToClear.Append(LDRSubmixEffectChain);
}
else
{
AudioSubmixEffectsChainToApply.Append(LDRSubmixEffectChain);
AudioSubmixEffectsChainToClear.Append(HDRSubmixEffectChain);
}
// We want to collect just the submixes we need to actually clear, otherwise they'll be overridden by the new settings
TArray<USoundSubmix*> SubmixesLeftToClear;
// We want to get the submixes that are not being overridden by the new effect chains, so we can clear those out separately
for (const FLyraAudioSubmixEffectsChain& EffectChainToClear : AudioSubmixEffectsChainToClear)
{
bool bAddToList = true;
for (const FLyraAudioSubmixEffectsChain& SubmixEffectChain : AudioSubmixEffectsChainToApply)
{
if (SubmixEffectChain.Submix == EffectChainToClear.Submix)
{
bAddToList = false;
break;
}
}
if (bAddToList)
{
SubmixesLeftToClear.Add(EffectChainToClear.Submix);
}
}
// Override submixes
for (const FLyraAudioSubmixEffectsChain& SubmixEffectChain : AudioSubmixEffectsChainToApply)
{
if (SubmixEffectChain.Submix)
{
UAudioMixerBlueprintLibrary::SetSubmixEffectChainOverride(GetWorld(), SubmixEffectChain.Submix, SubmixEffectChain.SubmixEffectChain, 0.1f);
}
}
// Clear remaining submixes
for (USoundSubmix* Submix : SubmixesLeftToClear)
{
UAudioMixerBlueprintLibrary::ClearSubmixEffectChainOverride(GetWorld(), Submix, 0.1f);
}
}
void ULyraAudioMixEffectsSubsystem::OnLoadingScreenStatusChanged(bool bShowingLoadingScreen)
{
ApplyOrRemoveLoadingScreenMix(bShowingLoadingScreen);
}
void ULyraAudioMixEffectsSubsystem::ApplyOrRemoveLoadingScreenMix(bool bWantsLoadingScreenMix)
{
UWorld* World = GetWorld();
if (bAppliedLoadingScreenMix != bWantsLoadingScreenMix && LoadingScreenMix && World)
{
if (bWantsLoadingScreenMix)
{
// Apply the mix
UAudioModulationStatics::ActivateBusMix(World, LoadingScreenMix);
}
else
{
// Remove the mix
UAudioModulationStatics::DeactivateBusMix(World, LoadingScreenMix);
}
bAppliedLoadingScreenMix = bWantsLoadingScreenMix;
}
}
bool ULyraAudioMixEffectsSubsystem::DoesSupportWorldType(const EWorldType::Type World) const
{
// We only need this subsystem on Game worlds (PIE included)
return (World == EWorldType::Game || World == EWorldType::PIE);
}