The Unreal audio pipeline: a sound asset (USoundBase subclass) is activated either
as a fire-and-forget one-shot or via a UAudioComponent for ongoing control. 3D
sounds are positioned and faded using a USoundAttenuation asset. Mixing is handled
through sound classes, submixes, and concurrency objects. MetaSounds are the
modern, node-based, parameter-driven replacement for SoundCues.
When to use this skill
- Playing SFX (gunshots, footsteps, impacts), music, or UI sounds from C++.
- Attaching a looping or positional sound to an actor (engine hum, ambience).
- 3D spatialization and distance falloff configuration.
- Mixing: volume groups, ducking music under dialogue, limiting voice counts.
- Procedural/parameterized audio (footsteps that vary, adaptive music) via MetaSounds.
- Beat-synchronized audio events with the Quartz clock system.
- Building or modifying MetaSound graphs at runtime via the Builder API.
Sound asset types
| Asset | Class | Best for |
|---|---|---|
| Imported PCM clip | USoundWave |
Raw audio; compose variation in a cue or MetaSound |
| Legacy node graph | USoundCue |
Simple randomization / modulation over waves |
| Modern graph with typed I/O | UMetaSoundSource |
Procedural, parameter-driven, DSP-composable audio |
| Abstract base | USoundBase |
The type accepted by all play functions |
Prefer MetaSounds for new dynamic audio. SoundCues remain fully supported and are
simpler for lightweight randomization. USoundWave is never played directly in gameplay
code — it is the leaf asset referenced inside cues or MetaSound graphs.
Playing sounds from C++
#include "Kismet/GameplayStatics.h"
#include "Components/AudioComponent.h"
// 2D (UI, music) — fire-and-forget, no spatialization:
UGameplayStatics::PlaySound2D(this, UISound);
// 3D at a world position — fire-and-forget:
UGameplayStatics::PlaySoundAtLocation(this, ExplosionSound, HitLocation,
FRotator::ZeroRotator, 1.f, 1.f, 0.f, AttenuationAsset);
// 3D attached to a component — returns controllable UAudioComponent:
UAudioComponent* AC = UGameplayStatics::SpawnSoundAttached(
EngineLoop, VehicleMesh, NAME_None);
AC->FadeIn(0.5f);
// Stop or adjust later:
AC->SetFloatParameter(TEXT("RPM"), 4200.f); // MetaSound input
AC->FadeOut(0.3f, 0.f);
PlaySound* functions are fire-and-forget. Use SpawnSound* or a
UAudioComponent placed on the actor when you need to stop, fade, change
parameters, or react to OnAudioFinished. Store the component in a
UPROPERTY() member so GC cannot collect it while it is playing (see
memory-and-gc).
Audio component placed on an actor
// Header — owned audio component, UPROPERTY keeps it alive:
UPROPERTY(VisibleAnywhere)
TObjectPtr<UAudioComponent> EngineAudio;
// Constructor:
EngineAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("EngineAudio"));
EngineAudio->SetupAttachment(RootComponent);
EngineAudio->bAutoActivate = false; // start silent; Play() from BeginPlay
// BeginPlay:
EngineAudio->SetSound(EngineLoopAsset);
EngineAudio->Play();
See references/audiocomponent-and-playback.md
for the full UAudioComponent API, delegates, and playback state machine.
3D spatialization & attenuation
A USoundAttenuation asset bundles: distance model and falloff radius,
spatialization algorithm (panning or HRTF plugin), occlusion, reverb send,
air absorption, and priority attenuation. Assign it on the sound asset itself
(AttenuationSettings on USoundBase) or override it per-call by passing it
to PlaySoundAtLocation / SpawnSoundAttached.
A sound without an attenuation asset plays as flat 2D regardless of where the audio component is in the world. The inner radius defines a constant-volume zone; falloff begins at the inner radius and reaches zero at the falloff distance.
See references/attenuation-and-spatialization.md
for the full FSoundAttenuationSettings fields, distance models, HRTF, and
Audio Gameplay Volumes.
Mixing: classes, submixes, concurrency
| Tool | Purpose |
|---|---|
Sound Class (USoundClass) |
Group sounds (SFX / Music / Voice) for shared volume, pitch, and property settings |
Sound Mix (USoundMix) |
Push temporary class adjustments — duck Music when a Voice plays |
Submix (USoundSubmix) |
DSP bus: apply effects (reverb, EQ, compression), meter, record audio |
Concurrency (USoundConcurrency) |
Cap simultaneous voices in a group; choose a steal rule when limit is hit |
A sound routes to its sound class's submix by default. Submix sends let a
sound copy signal to additional buses (e.g. a reverb or analysis bus) without
leaving the main chain. Audio Buses (UAudioBus) are an alternative bus type
that route before or after source effects, useful for sidechaining.
See references/mixing-classes-submixes-concurrency.md for concurrency steal rules, submix effect chains, audio bus sends, and dynamic mixing from C++.
MetaSound parameters at runtime
MetaSound Sources expose typed inputs (float, int32, bool, trigger, wave) declared in the graph. Drive them from the owning audio component:
// Set before or during playback:
AC->SetFloatParameter(TEXT("Intensity"), 0.8f);
AC->SetBoolParameter(TEXT("IsUnderwater"), true);
AC->SetIntParameter(TEXT("FootSurface"), 2);
// Trigger a one-shot event inside the graph (stateless pulse):
AC->SetTriggerParameter(TEXT("OnImpact"));
// Swap the wave asset a graph node is playing:
AC->SetWaveParameter(TEXT("ImpactWave"), GroundHitWave);
Input names are case-sensitive FName values that must exactly match the
graph's Input node names. A mismatch produces no error and no effect. The
parameter interface is declared in
Runtime/Engine/Public/Audio/SoundParameterControllerInterface.h.
MetaSounds also expose outputs (e.g., a float metering value). Read them
through UMetasoundGeneratorHandle obtained from UMetaSoundSource:: GetGeneratorForAudioComponent — available only while the sound is playing.
See references/metasound-parameters-and-builder.md for the Builder API, output watching, and runtime graph authoring.
Quartz: beat-quantized playback
Quartz provides a game-thread musical clock (UQuartzClockHandle) that
fires events on beat/bar boundaries. Use it to start sounds precisely on the
beat without drifting audio timers:
// Obtain the clock subsystem and create or find a named clock:
UQuartzSubsystem* Quartz = UQuartzSubsystem::Get(GetWorld());
UQuartzClockHandle* Clock = Quartz->CreateNewClock(this, TEXT("MusicClock"),
FQuartzClockSettings{});
// Schedule a sound to start on the next bar boundary:
FQuartzQuantizationBoundary Boundary;
Boundary.Quantization = EQuartzCommandQuantization::Bar;
Boundary.BoundaryType = EQuarztQuantizationBoundaryType::FromNow;
AC->PlayQuantized(GetWorld(), Clock, Boundary, {});
The Quartz subsystem (UQuartzSubsystem) lives in the Audio Mixer module.
UAudioComponent::PlayQuantized is declared in AudioComponent.h:521.
Triggering from gameplay & animation
Footstep, impact, and weapon sounds should be triggered from Anim Notifies
(see animation-system) or gameplay events, not manual timers. This keeps
audio in sync at any play rate or time dilation. For high-frequency impacts use
concurrency to avoid voice spam — limit simultaneous instances and choose an
appropriate steal rule.
Gotchas
- Fire-and-forget when you needed control —
PlaySound*returns nothing; useSpawnSound*or a component to stop, fade, or change parameters later. - No attenuation asset → 3D sound plays as 2D, no falloff.
- Parameter name mismatch on MetaSounds → silent no-op, no log warning.
- No concurrency limits → voice spam and clipping under heavy action.
- Audio component not in a
UPROPERTY→ GC'd while playing, sound stops. SetWaveParametercalled on a SoundCue → no effect; wave params target MetaSound wave inputs (or legacy SoundCue wave params — different systems).bDisableParameterUpdatesWhilePlayingset on the component → parameter calls are queued but not forwarded to the active sound.- Importing non-WAV → import PCM WAV only; build variation inside MetaSound or SoundCue graphs rather than baking it into the file.
- Virtualization —
EVirtualizationModeonUSoundBasecontrols whether looping sounds silently continue (PlayWhenSilent), restart, or drop when evicted. Default isDisabled; forgotten virtualization config is a common cause of music "disappearing" under heavy load.
Version notes
- MetaSounds were introduced in UE5.0; the Builder API (Beta) expanded
significantly in 5.4–5.5; output watching via
UMetasoundGeneratorHandlewas stabilised in 5.4. EVirtualizationMode::SeekRestartis experimental as of UE 5.6–5.8 (SoundBase.h:76).FAudioComponentParam(old named-parameter struct) was deprecated in UE 5.0; useFAudioParameter/SetFloatParameteretc. instead.OnGeneratorInstanceCreated/OnGeneratorInstanceDestroyedonUMetaSoundSourcedeprecated in 5.6; useOnGeneratorInstanceInfoCreated/OnGeneratorInstanceInfoDestroyed(MetasoundSource.h:338–344).
References & source material
Engine source (UE 5.8):
Runtime/Engine/Classes/Components/AudioComponent.h—UAudioComponent:167;Play:517,Stop:583,FadeIn:500,FadeOut:511,SetFloatParameter:548,SetBoolParameter:534,SetIntParameter:541,SetWaveParameter:622,OnAudioFinished:456,GetPlayState:605,SetSubmixSend:644.Runtime/Engine/Public/Audio/SoundParameterControllerInterface.h—ISoundParameterControllerInterface:24,SetTriggerParameter:32.Runtime/Engine/Classes/Sound/SoundBase.h—USoundBase:108,SoundClassObject:117,AttenuationSettings:222,ConcurrencySet:188,VirtualizationMode:170,EVirtualizationMode:57.Runtime/Engine/Classes/Sound/SoundWave.h—USoundWave:421 (extendsUSoundBase; leaf asset for raw PCM audio).Runtime/Engine/Classes/Sound/SoundCue.h—USoundCue:90 (legacy node graph overUSoundWaveassets).Runtime/Engine/Classes/Sound/SoundAttenuation.h—USoundAttenuation:453,FSoundAttenuationSettings:148.Runtime/Engine/Classes/Sound/SoundClass.h—USoundClass,FSoundClassProperties:54.Runtime/Engine/Classes/Sound/SoundSubmix.h—USoundSubmix, submix effects.Runtime/Engine/Classes/Sound/SoundConcurrency.h—FSoundConcurrencySettings:74,EMaxConcurrentResolutionRule:31.Runtime/Engine/Classes/Sound/AudioBus.h—UAudioBus,EAudioBusChannels:13.Runtime/Engine/Classes/Kismet/GameplayStatics.h—PlaySound2D:680,SpawnSound2D:699,PlaySoundAtLocation:732,SpawnSoundAtLocation:754,SpawnSoundAttached:778.Plugins/Runtime/Metasound/Source/MetasoundEngine/Public/MetasoundSource.h—UMetaSoundSource:89,GetGeneratorForAudioComponent:326,OnGeneratorInstanceInfoCreated:343.Plugins/Runtime/Metasound/Source/MetasoundEngine/Public/MetasoundBuilderSubsystem.h—UMetaSoundBuilderSubsystem,UMetaSoundSourceBuilder:71.
Official docs (UE 5.8):
- Working with Audio — https://dev.epicgames.com/documentation/unreal-engine/working-with-audio-in-unreal-engine
- MetaSounds — https://dev.epicgames.com/documentation/unreal-engine/metasounds-in-unreal-engine
- MetaSound Builder API — https://dev.epicgames.com/documentation/unreal-engine/metasound-builder-api-in-unreal-engine
- Spatialization and Sound Attenuation — https://dev.epicgames.com/documentation/unreal-engine/spatialization-and-sound-attenuation-in-unreal-engine
- Audio Mixing — https://dev.epicgames.com/documentation/unreal-engine/audio-mixing-in-unreal-engine
- Submixes — https://dev.epicgames.com/documentation/unreal-engine/submixes-in-unreal-engine
Deep-dive references in this skill:
- references/audiocomponent-and-playback.md —
full
UAudioComponentAPI, playback state machine, delegates, and Quartz. - references/attenuation-and-spatialization.md —
FSoundAttenuationSettingsfields, distance models, HRTF, Audio Gameplay Volumes. - references/mixing-classes-submixes-concurrency.md — concurrency steal rules, submix effect chains, audio bus sends, dynamic mixing.
- references/metasound-parameters-and-builder.md — runtime parameter API, output watching, MetaSound Builder API.