MasterSubmix

MasterSubmix

#Overview

name: MasterSubmix

The value of this variable can be defined or overridden in .ini config files. 2 .ini config files referencing this setting variable.

It is referenced in 11 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of MasterSubmix is to serve as the default submix through which all sounds are routed to and ultimately outputs to the audio hardware. It is a crucial component of the audio system in Unreal Engine 5.

This setting variable is primarily used by the audio system in Unreal Engine 5. It is referenced in various audio-related modules and plugins, including:

  1. AudioInsights plugin
  2. MediaIOCore plugin
  3. MovieRenderPipelineCore plugin
  4. AudioEditor module
  5. AudioMixer module
  6. Engine module

The value of this variable is set in the Audio Settings of the project. It is defined as a FSoftObjectPath in the UAudioSettings class, which allows for lazy loading of the submix asset.

MasterSubmix interacts with other audio-related variables and systems, such as:

  1. BaseDefaultSubmix: Another submix setting used for implicit submix sends.
  2. Audio device and mixer device objects.
  3. Submix analyzers and listeners.

Developers should be aware of the following when using this variable:

  1. The MasterSubmix cannot be set to a submix that has a parent submix. It must be a top-level submix.
  2. Changing the MasterSubmix may require a restart of the engine or project.
  3. It’s used for initializing the audio system and setting up submix hierarchies.

Best practices when using this variable include:

  1. Ensure the MasterSubmix is properly set in the project’s Audio Settings.
  2. Avoid frequently changing the MasterSubmix during runtime, as it may have significant impact on the audio system.
  3. When creating custom audio systems or plugins, reference the MasterSubmix through the audio settings rather than hard-coding it.
  4. Be cautious when modifying the MasterSubmix, as it affects the entire audio output of the game or application.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:1598, section: [/Script/Engine.AudioSettings]

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:251, section: [/Script/Engine.AudioSettings]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/AudioInsights/Source/AudioInsights/Private/Views/OutputMeterDashboardViewFactory.cpp:44

Scope (from outer to inner):

file
namespace    UE::Audio::Insights
function     TSharedRef<SWidget> FOutputMeterDashboardViewFactory::MakeWidget

Source code excerpt:

			AudioSettings.IsValid())
		{
			MainSubmix = Cast<USoundSubmix>(AudioSettings->MasterSubmix.ResolveObject());

			if (MainSubmix)
			{
				OutputMeterSubmixAnalyzer = MakeShared<FAudioMeterSubmixAnalyzer>(MainSubmix);

				FDashboardFactory::OnActiveAudioDeviceChanged.AddSP(this, &FOutputMeterDashboardViewFactory::HandleOnActiveAudioDeviceChanged);

#Loc: <Workspace>/Engine/Plugins/AudioInsights/Source/AudioInsights/Private/Views/OutputOscilloscopeDashboardViewFactory.cpp:42

Scope (from outer to inner):

file
namespace    UE::Audio::Insights
function     TSharedRef<SWidget> FOutputOscilloscopeDashboardViewFactory::MakeWidget

Source code excerpt:

			AudioSettings.IsValid())
		{
			MainSubmix = Cast<USoundSubmix>(AudioSettings->MasterSubmix.ResolveObject());

			if (MainSubmix)
			{
				OutputOscilloscopeAnalyzer = MakeShared<FAudioOscilloscopeAnalyzer>(MainSubmix);

				FDashboardFactory::OnActiveAudioDeviceChanged.AddSP(this, &FOutputOscilloscopeDashboardViewFactory::HandleOnActiveAudioDeviceChanged);

#Loc: <Workspace>/Engine/Plugins/Media/MediaIOFramework/Source/MediaIOCore/Private/MediaIOCoreAudioOutput.cpp:168

Scope (from outer to inner):

file
function     void FMediaIOAudioCapture::RegisterBufferListener

Source code excerpt:

		NumChannels = MixerDevice->GetDeviceOutputChannels();
		SampleRate = MixerDevice->GetSampleRate();
		PrimarySubmixName = *GetDefault<UAudioSettings>()->MasterSubmix.GetAssetName();
		AudioDevice->RegisterSubmixBufferListener(AsShared(), AudioDevice->GetMainSubmixObject());
	}
}

const FString& FMediaIOAudioCapture::GetListenerName() const
{

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/Graph/MovieGraphDefaultAudioRenderer.cpp:22

Scope (from outer to inner):

file
function     void UMovieGraphDefaultAudioRenderer::StartAudioRecording

Source code excerpt:

	if (Audio::FMixerDevice* MixerDevice = UE::MovieGraph::Audio::GetAudioMixerDeviceFromWorldContext(this))
	{
		const TWeakPtr<Audio::FMixerSubmix> MasterSubmix = MixerDevice->GetMasterSubmix();
		if (MasterSubmix.Pin())
		{
			AudioState.ActiveSubmixes.Add(MasterSubmix);
		}

		for (TWeakPtr<Audio::FMixerSubmix>& WeakSubmix : AudioState.ActiveSubmixes)
		{
			constexpr float ExpectedDuration = 30.f;
			WeakSubmix.Pin()->OnStartRecordingOutput(ExpectedDuration);

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/MoviePipelineAudioRendering.cpp:76

Scope (from outer to inner):

file
function     void UMoviePipeline::StartAudioRecording

Source code excerpt:

	if (MixerDevice)
	{
		TWeakPtr<Audio::FMixerSubmix, ESPMode::ThreadSafe> MasterSubmix = MixerDevice->GetMasterSubmix();
		if (MasterSubmix.Pin())
		{
			AudioState.ActiveSubmixes.Add(MasterSubmix);
		}

		for (TWeakPtr<Audio::FMixerSubmix, ESPMode::ThreadSafe> WeakSubmix : AudioState.ActiveSubmixes)
		{
			const float ExpectedDuration = 30.f;
			WeakSubmix.Pin()->OnStartRecordingOutput(ExpectedDuration);

#Loc: <Workspace>/Engine/Source/Editor/AudioEditor/Private/SoundSubmixGraphSchema.cpp:125

Scope (from outer to inner):

file
function     bool USoundSubmixGraphSchema::ConnectionCausesLoop

Source code excerpt:

	if (const UAudioSettings* Settings = GetDefault<UAudioSettings>())
	{
		if (USoundSubmix* MasterSubmix = Cast<USoundSubmix>(Settings->MasterSubmix.TryLoad()))
		{
			if (OutputNode->SoundSubmix == MasterSubmix)
			{
				return true;
			}

			if (SubmixUtils::FindInGraph(MasterSubmix, OutputNode->SoundSubmix, false))
			{
				return true;
			}
		}
	}

#Loc: <Workspace>/Engine/Source/Runtime/AudioMixer/Private/AudioMixerDevice.cpp:1164

Scope (from outer to inner):

file
namespace    Audio
function     void FMixerDevice::InitSoundSubmixes

Source code excerpt:


			// 1. Load or reload all sound submixes/instances
			LoadRequiredSubmix(ERequiredSubmixes::Main, TEXT("MasterSubmixDefault"), false /* DefaultMuteWhenBackgrounded */, AudioSettings->MasterSubmix);

			// BaseDefaultSubmix is an optional master submix type set by project settings
			if (AudioSettings->BaseDefaultSubmix.IsValid())
			{
				LoadRequiredSubmix(ERequiredSubmixes::BaseDefault, TEXT("BaseDefault"), false /* DefaultMuteWhenBackgrounded */, AudioSettings->BaseDefaultSubmix);
			}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Sound/AudioSettings.h:154

Scope (from outer to inner):

file
class        class UAudioSettings : public UDeveloperSettings

Source code excerpt:

	/** The default submix through which all sounds are routed to. The root submix that outputs to audio hardware. */
	UPROPERTY(config, EditAnywhere, Category="Mix", meta=(AllowedClasses="/Script/Engine.SoundSubmix"))
	FSoftObjectPath MasterSubmix;

	/** The default submix to use for implicit submix sends (i.e. if the base submix send is null or if a submix parent is null) */
	UPROPERTY(config, EditAnywhere, Category = "Mix", meta = (AllowedClasses = "/Script/Engine.SoundSubmix"), AdvancedDisplay)
	FSoftObjectPath BaseDefaultSubmix;

	/** The submix through which all sounds set to use reverb are routed */

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp:48

Scope (from outer to inner):

file
function     void UAudioSettings::PreEditChange

Source code excerpt:


	// Cache master submix in case user tries to set to submix that isn't a top-level submix
	CachedMasterSubmix = MasterSubmix;

	// Cache at least the first entry in case someone tries to clear the array
	CachedQualityLevels = QualityLevels;
}

void UAudioSettings::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp:64

Scope (from outer to inner):

file
function     void UAudioSettings::PostEditChangeChainProperty

Source code excerpt:

		LoadDefaultObjects();

		if (PropertyName == GET_MEMBER_NAME_CHECKED(UAudioSettings, MasterSubmix))
		{
			if (USoundSubmix* NewSubmix = Cast<USoundSubmix>(MasterSubmix.TryLoad()))
			{
				if (NewSubmix->ParentSubmix)
				{
					FNotificationInfo Info(LOCTEXT("AudioSettings_InvalidMasterSubmix", "'Master Submix' cannot be set to submix with parent."));
					Info.bFireAndForget = true;
					Info.ExpireDuration = 2.0f;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp:76

Scope (from outer to inner):

file
function     void UAudioSettings::PostEditChangeChainProperty

Source code excerpt:

					FSlateNotificationManager::Get().AddNotification(Info);

					MasterSubmix = CachedMasterSubmix;
				}
			}

			bPromptRestartRequired = true;
		}
		else if (PropertyName == GET_MEMBER_NAME_CHECKED(UAudioSettings, BaseDefaultSubmix))