Skip to content

Playing Sounds

An Audio Source component covers a sound that belongs to an entity. For a one-off, play it directly and get back a handle you can use to adjust or stop the voice while it runs.

The audio engine is process-global in both languages. C++ reaches it through the GAudioContext pointer; C# goes through World.Audio, with a static Sound shorthand for the current world.

#include "Audio/AudioGlobals.h"
CAudioStream* Shot = ...;
FAudioHandle Handle = GAudioContext->PlayAudio2D(Shot->GetAudioData());

GAudioContext is null before the audio device comes up and when audio is disabled, so null-check it outside the normal frame path. Every play call takes a TSharedPtr<FAudioData>, which the asset hands out through GetAudioData(); the bytes are kept alive for the life of the voice, so the asset can unload mid-playback.

A 2D sound plays at full volume regardless of position, use it for UI, music, and non-diegetic effects. A 3D sound is attenuated by distance from the listener, fading between MinDistance (full volume) and MaxDistance (silent).

// UI / music.
GAudioContext->PlayAudio2D(Music->GetAudioData(), 0.6f, 1.0f, /*bLooping*/ true);
// Positional gunshot that falls off between 2m and 40m.
GAudioContext->PlayAudioAtLocation(
Shot->GetAudioData(), Location, 1.0f, 1.0f, /*MinDistance*/ 2.0f, /*MaxDistance*/ 40.0f);

PlaySound2D and PlaySoundAtLocation are the same two calls against a loose file path instead of an asset.

Both languages have a parameter struct covering everything a voice can be configured with at start: bus, attenuation, cone, priority, fades, and delay. C++ calls it FAudioPlayParams and default-builds it; C# calls it FSoundPlayParams and starts from Default().

FAudioPlayParams Params;
Params.Bus = EAudioBus::Ambient;
Params.bSpatialized = true;
Params.Position = Location;
Params.bLooping = true;
Params.Priority = 40;
Params.FadeInSeconds = 1.5f;
Params.Attenuation.MaxDistance = 30.0f;
Params.Attenuation.Model = EAudioAttenuationModel::Linear;
FAudioHandle Wind = GAudioContext->PlayAudio(Loop->GetAudioData(), Params);
FieldC++Does
Volume, PitchsameMultipliers, 1 is unchanged.
LoopingbLoopingRestart on completion.
SpatializedbSpatializedAttenuate and pan by Position.
StartPausedbStartPausedCreate the voice without starting it.
Position, DirectionsameWorld position and cone forward axis.
BussameMix group.
Prioritysame0 to 255. Low priority voices are evicted first at the voice cap.
FadeInSecondssameRamp up from silence.
StartDelaySecondssameSchedule the voice to begin later.
UseOcclusionbUseOcclusionBuild the voice’s filter up front if you plan to occlude it.
AttenuationsameFalloff, cone, doppler. See Attenuation.

C++ operates on the FAudioHandle through the context. C# also returns a PlayingSound wrapper that carries its world, so it keeps working after the callback that created it returns. Every call is safe on a stale or invalid handle, it simply does nothing.

FAudioHandle Engine = GAudioContext->PlayAudioAtLocation(Loop->GetAudioData(), Location, 1.0f, 1.0f, 1.0f, 50.0f, true);
// Later, as the car revs and moves:
GAudioContext->SetPitch(Engine, 1.0f + Throttle);
GAudioContext->SetPosition(Engine, Location);
GAudioContext->SetVelocity(Engine, Velocity); // drives doppler
// When it stops:
GAudioContext->StopSound(Engine, EAudioStopMode::FadeOut, 0.5f);
C# memberC++Effect
Volume, Pitch, PanSetVolume, SetPitch, SetPanLive multipliers.
Position, VelocitySetPosition, SetVelocityMove a spatialized voice. Velocity drives doppler.
Looping, Paused, BusSetLooping, SetPaused, SetBusToggle looping, pause without losing position, move to another bus.
IsPlaying, StateIsPlaying, GetVoiceStateWhether the mixer still holds the voice.
PlaybackFrameGetPlaybackFrameCurrent position in PCM frames.
SetAttenuation(atten)sameReplace the whole 3D setup.
SetOcclusion(amount, lowPass, volume)sameMuffle by hand, 0 clear to 1 blocked.
FadeTo(volume, seconds)sameRamp to a new volume.
Stop(fadeOut, fadeSeconds)StopSound(handle, mode, seconds)Stop, optionally with a fade.

The C# AudioHandle carries Generation / Index to identify the voice, and IsValid is false if the sound failed to start (no data, audio disabled, or the voice cap was hit).

Components can occlude themselves automatically (see Occlusion). For voices you started yourself you supply the value, which is also how you get effects that aren’t occlusion at all.

// Muffle everything while the player is underwater.
GAudioContext->SetLowPassCutoff(Handle, 800.0f);
// Open it back up.
GAudioContext->SetLowPassCutoff(Handle, 0.0f);

SetOcclusion applies both a low-pass and a volume drop scaled by the amount, and expects a value you’ve already smoothed. Jumping it from 0 to 1 in one frame will be audible.