How To Create an Audio Manager in Unreal Engine

Si prefieres leer una versión en Español, da click en este botón =>

Unreal Engine Version: 5.2.1

This blog post shows you how to create an audio manager using a Game Instance Subsystem in Unreal Engine.

The only way to create and set a Game Instance Subsystem is through native C++ code, so unfortunately, there is no way to create this manager using only Blueprint. Despite this, all the functionality built on this Audio Manager should be easily accessible and extendable through visual scripting.

Important:

Please consider that this guide does not intend to teach creative sound design. Instead, it exclusively focuses on game audio's implementation and programming aspects.


Download the project here:

IMPORTANT!

〰️

IMPORTANT! 〰️

Prerequisites:

  • Create an empty C++ first-person or third-person project called “MyUEProject.”

IMPORTANT!

〰️

IMPORTANT! 〰️

 

The Gameplay Framework

“The Gameplay Framework in Unreal Engine provides multiple classes and components to serve as building blocks for your projects”

Epic Games

Discussing all the classes and functionality of the gameplay framework is outside of the scope of this blog post. I will focus on the Game Instance and the Game Instance Subsystem for our current purpose. If you would like to learn more about the Gameplay Framework, I recommend you watch these videos from Epic Online Learning and also read the official documentation:

Begin Play | Programming

Begin Play | Gameplay

Game Instance and Game Instance Subsystem:

Here are some essential facts about the Game Instance:

  • It spawns before the rest of the Gameplay Framework classes and the world

  • It’s destroyed after all the classes are destroyed when the game is closed

  • It persists during world loading, creation, and destruction

  • It’s globally accessible across the project

  • Only one instance exists per game session (Singleton behavior)

So, this is a big manager class, and it would work great if we added our audio management functionality here. Despite this, if every discipline on your game development team would do this, the Game Instance would be a massive class with thousands of lines of code. Not a good idea!

Unreal Engine provides a “module” or “component” for the Game Instance called Game Instance Subsystem to solve this issue.

A Game Instance Subsystem provides the same functionality and behaves as the Game Instance but lets us modularize our code so it’s easier to maintain and scale.

When the Game Instance initializes, it immediately initializes all its subsystems afterward. So we can be sure that our new manager will be ready when the game starts.

Audio Subsystem - Audio Manager

To create a Game Instance Subsystem, add a new C++ class derived from UGameInstanceSubsystem called “MyAudioSubsystem.”

A .h and .cpp file will be created in the source folder.

 
 

BP_MyAudioSubsystem

For this Audio Manager to be helpful to us Audio Designers, it is essential to create a blueprint (.uasset) representation of it so we can assign the assets that this manager will use.

Some examples of assets you might want to include are global states or parameters, physical surface mappings, mix buses, music events, and audio instances requiring persistence across the whole game loop.

Inside the UCLASS macro, add the Blueprintable specifier. This allows the creation of a Blueprint version of this subsystem. The Abstract specifier defines that the C++ version of the audio subsystem is only an archetype, which means that the data added to the blueprint version will be used.

After re-compiling the code, create a new blueprint class derived from UMyAudioSubsystem called BP_MyAudioSubsystem

 
 
 
 
 
 

Blueprint Subsystem Initializer

Unfortunately, the blueprint (.uasset) versions of the Game Instance Subsystem are not loaded by the world by default, so an additional step is required to make them work properly.

This is one way to do it:

  • Create a new C++ class derived from UDeveloperSettings called MyBlueprintSubsystemInitializer. An .h and .cpp file will be created in the source folder.

 
 
  • Make this class save its members inside the DefaultGame.ini. To achieve this, include the config = Game and DefaultConfig specifiers. Create an array of UGameInstanceSubsystems so new and different types of subsystems can be added later. Inside this .h file, create a new GameInstanceSubsystem class and use its Initialize() function to initialize your new Blueprint subsystems.

MyBlueprintSubsystemInitializer.h

MyBlueprintSubsystemInitializer.cpp

DefaultGame.ini and Project Settings

After compiling your code, click Edit -> Project Settings and look for the Game section. A new sub-section called “Blueprint Subsystems” is displayed. Assign your BP_MyAudioSubsystem to the array.

To verify that your subsystem has been assigned to the DefaultGame.ini, go to your project’s folder in your IDE or file explorer and open the “Config” folder.

Path: MyUEProject/Config

And now your Audio Manager is ready for any data and functions you need to implement. The sky is the limit!

Implementation

In this section, I demonstrate how to add data and call and extend functions on our new subsystem.

  • Add an FString variable and two functions, BlueprintImplementableFunction() and BlueprintExtendableFunction(), with a UObject* argument that serves as a World Context Object. Using the UFUNCTION macros with the BlueprintImplementableEvent and BlueprintNativeEvent specifiers allows designers to implement these functions in Blueprint without touching code.

MyAudioSubsystem.h:

MyAudioSubsystem.cpp:

  • Compile the code and open the BP_MyAudioSubsystem. Fill up the FString “MyTestString” field.

  • Implement both BlueprintImplementableFunction() and BlueprintExtendableFunction() in the Blueprint Graph.

How To Use?

As stated before, the benefit of a Game Instance Subsystem is that it is globally accessible. I used the Level Blueprint to test the new functions for these examples.

To call the subsystem, right-click on the graph and type MyAudioSubsystem.

Drag from this new node and call its functions on BeginPlay()

On Screen Debug Text

On Screen Debug Text

Finally, here is how to access the subsystem in C++ from any actor class:

THE END

〰️〰️〰️

THE END 〰️〰️〰️

Previous
Previous

2D Audio Listener for Music and UI in Unreal Engine and Wwise

Next
Next

Vertical Re-Mixing in Unreal Engine with Metasounds + Quartz (Part 2/2)