SFXSpace and SFXEmitter

SFXSpace and SFXEmitter are scene audio objects.

Class Purpose
SFXSpace Defines a 3D ambient audio zone/volume.
SFXEmitter Places a positional or non-positional sound source in the level.

Use SFXSpace for area-based ambience changes, such as tunnels, interiors, caves, forests, or reverb/ambience zones.

Use SFXEmitter for actual sound playback at a point in the world, such as machinery hums, waterfalls, birds, sirens, loops, one-shots, or local environmental sounds.


SFXSpace

SFXSpace is a 3D volume that defines an ambient sound zone.

It is usually used to change the listener’s ambience when the listener enters or overlaps the volume. For example:

  • Interior room ambience
  • Tunnel reverb/ambience
  • Cave ambience
  • Forest ambience
  • Underpass ambience
  • Industrial area ambience
  • Local environmental sound zones

SFXSpace is a scene object with position, rotation, and scale. Its default object scale is:

[10, 10, 10]

Its local object box is a unit cube from -0.5 to 0.5, so the final zone size is controlled by scale.


Basic SFXSpace example

{
  "class": "SFXSpace",
  "name": "tunnel_audio_space",
  "position": [120, 45, 8],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [40, 12, 8],
  "soundAmbience": "TunnelAmbience"
}

This creates a box-shaped audio zone centered at [120, 45, 8].


SFXSpace fields

SFXSpace inherits most of its useful fields from its scene object and ambient sound mixin behavior.

Field Type Description
class string Must be "SFXSpace".
name string Scene object name.
position array[3] Center position of the audio volume.
rotationMatrix array[9] Orientation of the audio volume.
scale array[3] Size of the SFXSpace volume.
soundAmbience object/datablock name Ambience assigned to the space, where supported by the ambient sound object implementation.

Shape and scale

SFXSpace is box-based.

Example:

"scale": [30, 20, 6]

This produces a volume approximately:

30 meters wide
20 meters long
6 meters tall

Use scale to fit the zone around the area where the ambience should apply.


Editor visibility

SFXSpace rendering is disabled by default:

getStaticClassRep()->mIsRenderEnabled = false;

This means SFXSpaces are not normally visible as rendered objects. They are primarily editor/helper volumes.

The editor solid color can come from the assigned ambience:

getSoundAmbience()->getEditorColor()

If no ambience is assigned, it uses the default parent editor color.


Common SFXSpace uses

Tunnel ambience

{
  "class": "SFXSpace",
  "name": "tunnel_reverb_space",
  "position": [0, 200, 10],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [16, 120, 10],
  "soundAmbience": "Ambience_Tunnel"
}

Garage/interior ambience

{
  "class": "SFXSpace",
  "name": "garage_audio_space",
  "position": [50, -20, 4],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [25, 18, 8],
  "soundAmbience": "Ambience_Garage"
}

Forest zone ambience

{
  "class": "SFXSpace",
  "name": "forest_audio_zone",
  "position": [-300, 120, 20],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [180, 160, 60],
  "soundAmbience": "Ambience_Forest"
}

SFXEmitter

SFXEmitter is an invisible 3D scene object that emits sound.

It can play:

  • An existing SFXTrack
  • A directly assigned sound file
  • A 3D positional sound
  • A non-positional sound
  • Looping or non-looping audio
  • Streaming or buffered audio, depending on settings

For level ambience, a LevelInfo ambience setup or SFXSpace may be simpler. Use SFXEmitter when the sound has a specific location or needs explicit playback behavior.


Basic SFXEmitter example

{
  "class": "SFXEmitter",
  "name": "waterfall_emitter",
  "position": [100, 250, 15],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "track": "WaterfallLoop",
  "playOnAdd": true,
  "useTrackDescriptionOnly": true
}

This emitter plays the WaterfallLoop track when the level loads.


File-based SFXEmitter example

{
  "class": "SFXEmitter",
  "name": "generator_hum",
  "position": [20, 15, 2],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "fileName": "/levels/example/art/sound/generator_loop.ogg",
  "playOnAdd": true,
  "is3D": true,
  "isLooping": true,
  "isStreaming": false,
  "volume": 0.8,
  "pitch": 1,
  "referenceDistance": 5,
  "maxDistance": 60,
  "fadeInTime": 0.5,
  "fadeOutTime": 1.0
}

SFXEmitter media fields

Field Type Description
track SFXTrack name Existing track/event/profile to play. Takes precedence over fileName.
fileName string path Sound file to play directly. Used when track is not assigned.

Use either track or fileName.

If both are assigned:

track wins

SFXEmitter sound fields

Field Type Description
playOnAdd bool Starts playback automatically when the emitter is added/loaded.
useTrackDescriptionOnly bool If true, emitter fields do not override the assigned track description.
isLooping bool Whether fileName playback loops. Ignored when track is assigned.
isStreaming bool Whether fileName uses streamed playback. Ignored when track is assigned.
sourceGroup SFXSource name Optional source/channel/group to parent the sound under.
volume number Playback volume multiplier.
pitch number Pitch multiplier. 1 is normal pitch.
fadeInTime number Fade-in time in seconds.
fadeOutTime number Fade-out time in seconds.

SFXEmitter 3D sound fields

Field Type Description
is3D bool Whether fileName is played as positional 3D sound. Ignored when track is assigned.
referenceDistance number Distance where attenuation begins.
maxDistance number Distance where attenuation reaches its far limit. Also used for emitter bounds/editor scale.
scatterDistance array[3] Random offset bounds for initial 3D sound position.
coneInsideAngle integer Inner directional cone angle in degrees.
coneOutsideAngle integer Outer directional cone angle in degrees.
coneOutsideVolume number Volume multiplier outside the outer cone.
rangeSphereColor color[4] Editor visualization color for range sphere.

Default SFXEmitter behavior

The constructor initializes emitters with these defaults:

Setting Default
playOnAdd true
is3D true
isLooping true
isStreaming false
fadeInTime -1
fadeOutTime -1

The default object box is:

[-1, -1, -1] to [1, 1, 1]

On add/update, the emitter scale is set from maxDistance:

scale = [maxDistance, maxDistance, maxDistance]

Using track vs fileName

Using track

Use track when the audio setup already exists as a datablock/event/profile.

{
  "class": "SFXEmitter",
  "name": "factory_loop",
  "position": [0, 0, 3],
  "track": "FactoryMachineryLoop",
  "playOnAdd": true,
  "useTrackDescriptionOnly": true
}

Advantages:

  • Centralized audio setup
  • Reusable sound definitions
  • Good for FMOD events or configured SFX tracks
  • Description settings can be shared across emitters

Using fileName

Use fileName for simple level-local sounds without creating a separate track.

{
  "class": "SFXEmitter",
  "name": "buzzing_light",
  "position": [5, 10, 3],
  "fileName": "/levels/example/art/sound/light_buzz.ogg",
  "playOnAdd": true,
  "is3D": true,
  "isLooping": true,
  "volume": 0.5,
  "referenceDistance": 1,
  "maxDistance": 12
}

Advantages:

  • Quick setup
  • Good for simple placed sounds
  • Does not require a separate track datablock

useTrackDescriptionOnly

"useTrackDescriptionOnly": true

When enabled, the emitter uses the track’s sound description and ignores most local emitter sound fields.

This is useful when a track is already authored with correct:

  • 3D/2D behavior
  • Looping
  • Distance attenuation
  • Cone settings
  • Volume/pitch/fade behavior

Only playOnAdd and track remain relevant on the emitter.

If the assigned track does not allow description overrides, the emitter also uses the track description.

3D attenuation

For 3D sounds, distance behavior is controlled primarily by:

"referenceDistance": 5,
"maxDistance": 60
Field Meaning
referenceDistance Near distance where the sound is at full or reference volume.
maxDistance Far distance used for attenuation and editor visualization.

Example:

{
  "referenceDistance": 3,
  "maxDistance": 40
}

Use smaller values for quiet/local sounds, larger values for loud environmental sounds.


Emitter scale and maxDistance

In the editor, scaling an SFXEmitter changes maxDistance.

The implementation averages the scale axes:

maxDistance = (scale.x + scale.y + scale.z) / 3

Then it clamps to at least referenceDistance.

The final object scale is forced to:

[maxDistance, maxDistance, maxDistance]

This means emitters behave as spherical range objects rather than arbitrary box-shaped audio objects.


Directional sound cones

SFXEmitter supports directional 3D cone settings.

"coneInsideAngle": 90,
"coneOutsideAngle": 180,
"coneOutsideVolume": 0.25
Field Description
coneInsideAngle Full-volume cone angle.
coneOutsideAngle Outer transition cone angle.
coneOutsideVolume Volume outside the outer cone.

Use cones for directional sounds such as:

  • Speakers
  • Sirens
  • Vents
  • Machinery exhaust
  • Waterfalls facing a direction
  • Loudspeakers or PA systems

If both cone angles are near 360, the sound is effectively omnidirectional.


Directional emitter example

{
  "class": "SFXEmitter",
  "name": "speaker_emitter",
  "position": [10, 0, 3],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "fileName": "/levels/example/art/sound/speaker_loop.ogg",
  "playOnAdd": true,
  "is3D": true,
  "isLooping": true,
  "volume": 1,
  "referenceDistance": 4,
  "maxDistance": 80,
  "coneInsideAngle": 60,
  "coneOutsideAngle": 140,
  "coneOutsideVolume": 0.15
}

The emitter’s transform orientation matters for cone direction.


Playback lifecycle

When an SFXEmitter is added:

  1. The emitter validates its sound description.
  2. It creates or updates its internal SFXSource.
  3. It applies transform and velocity to the source.
  4. It sets volume, pitch, fade times, distance, and cone settings where allowed.
  5. If playOnAdd is true, playback starts.

When removed, the emitter deletes its internal source.


Manual playback

SFXEmitter supports manual playback methods:

play()
stop()

Legacy console methods exist:

emitter.play();
emitter.stop();

Lua bindings also expose emitter behavior.


Lua API

SFXEmitter is exposed to Lua as a SceneObject subclass.

Creating an emitter

local emitter = SFXEmitter()

The object is owned by C++ once registered/added through normal engine object workflows.


Static variables

Lua name Type Description
SFXEmitter.renderEmitters bool Enables emitter debug rendering.
SFXEmitter.renderFarEmitters bool Forces far emitters to render in editor debug view.

Example:

SFXEmitter.renderEmitters = true
SFXEmitter.renderFarEmitters = true

Lua methods

Method Description
setVolumePitchCT(volume, pitch, color, texture) Sets volume, pitch, and color/texture parameters on the source.
setPosition(position) Sets emitter position.
setVelocity(velocity) Sets emitter velocity.

Example:

emitter:setPosition(Point3F(10, 20, 3))
emitter:setVelocity(Point3F(0, 0, 0))
emitter:setVolumePitchCT(0.8, 1.0, 0.2, 0.5)

setVolumePitchCT only affects the emitter if its internal SFXSource exists.


Editor visualization

SFXEmitter renders debug visuals only while editing the mission.

It can show:

  • Max range sphere
  • Reference/min distance sphere
  • Forward/up orientation arrows
  • Directional cone visualization
  • Color changes based on playing/stopped and in-range/out-of-range state

The range sphere color is controlled by:

"rangeSphereColor": [0.8, 0, 0, 0.3]

The emitter only renders debug visuals if:

  • The world editor is active, and
  • The emitter is selected or SFXEmitter.renderEmitters is true, and
  • The sound is 3D

Common examples

Waterfall loop

{
  "class": "SFXEmitter",
  "name": "waterfall_sound",
  "position": [300, 120, 18],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "fileName": "/levels/example/art/sound/waterfall_loop.ogg",
  "playOnAdd": true,
  "is3D": true,
  "isLooping": true,
  "isStreaming": true,
  "volume": 1,
  "pitch": 1,
  "referenceDistance": 10,
  "maxDistance": 120,
  "fadeInTime": 1,
  "fadeOutTime": 2
}

Small electrical hum

{
  "class": "SFXEmitter",
  "name": "electrical_box_hum",
  "position": [12, 8, 1.5],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "fileName": "/levels/example/art/sound/electrical_hum.ogg",
  "playOnAdd": true,
  "is3D": true,
  "isLooping": true,
  "isStreaming": false,
  "volume": 0.45,
  "pitch": 1,
  "referenceDistance": 1,
  "maxDistance": 15
}

Bird ambience point

{
  "class": "SFXEmitter",
  "name": "birds_tree_01",
  "position": [-40, 125, 12],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "track": "BirdsTreeLoop",
  "playOnAdd": true,
  "useTrackDescriptionOnly": true
}

Non-positional level sound

{
  "class": "SFXEmitter",
  "name": "global_alarm_loop",
  "fileName": "/levels/example/art/sound/alarm_loop.ogg",
  "playOnAdd": true,
  "is3D": false,
  "isLooping": true,
  "isStreaming": true,
  "volume": 0.7,
  "pitch": 1
}
For general background ambience, prefer LevelInfo ambience or SFXSpace when possible. Use non-3D SFXEmitters when explicit placed playback control is needed.

SFXSpace vs SFXEmitter

Need Use
Change ambience/reverb when entering an area SFXSpace
Place a looping sound at a position SFXEmitter
Play a machine hum from an object SFXEmitter
Define tunnel/cave/room audio zone SFXSpace
Directional speaker/siren/waterfall sound SFXEmitter
Global ambient audio for whole level LevelInfo ambience or non-3D emitter depending on use case

Best practices

SFXSpace

  • Use spaces for areas, not point sounds.
  • Match the volume scale to the real physical area.
  • Use clear names such as tunnel_audio_space or garage_reverb_space.
  • Avoid many overlapping spaces unless the intended blend/priority behavior is well understood.
  • Use ambience editor colors to make audio zones easier to identify.

SFXEmitter

  • Prefer track for reusable or FMOD-authored sounds.
  • Use fileName for simple local sound files.
  • Keep maxDistance as small as practical.
  • Use isStreaming for long audio files or ambience loops.
  • Use non-streaming playback for short sounds.
  • Use useTrackDescriptionOnly when the track is already authored correctly.
  • Use directional cones for speakers, sirens, vents, or other directional sources.
  • Avoid too many long-range looping emitters in one area.
  • Use fade times to avoid abrupt starts/stops.

Common issues

SFXEmitter does not play

Possible causes:

  • playOnAdd is false.
  • track points to a missing track.
  • fileName path is invalid.
  • Both track and fileName are empty.
  • Audio device/system is not initialized.
  • The sound is 3D and listener is outside maxDistance.
  • Volume is 0.
  • Source group/channel volume is muted.

fileName is ignored

If track is assigned, it takes precedence.

Remove track if you want to use:

"fileName": "/path/to/sound.ogg"

Emitter settings do not affect the sound

If using a track, check:

"useTrackDescriptionOnly": true

When enabled, local emitter fields such as volume, pitch, 3D distance, and cone settings are ignored in favor of the track description.

Also, some tracks may not allow their descriptions to be overridden.


Sound is not positional

Check:

"is3D": true

If using track, the track’s own SFXDescription controls whether the sound is 3D.


Sound fades out too early

Increase:

"maxDistance": 100

or check the track’s distance settings if track is used.


Directional cone points the wrong way

The cone follows the emitter transform orientation.

Rotate the emitter so its forward direction points where the sound should project.


SFXSpace has no audible effect

Possible causes:

  • No ambience assigned.
  • Listener is outside the volume.
  • The volume scale is too small or placed incorrectly.
  • Environment raycast/reverb behavior or ambience blending settings override or disable space behavior.
  • Another audio space or ambience has priority depending on the audio setup.

Summary

SFXSpace and SFXEmitter serve different audio placement roles.

  • SFXSpace defines an ambient audio zone volume.
  • SFXEmitter creates and controls a sound source in the scene.

Use SFXSpace for area ambience and reverb-style zones. Use SFXEmitter for actual sound playback from a point or orientation in the world. For reusable or FMOD-authored sounds, assign a track; for simple local sounds, use fileName.

For level-wide ambience, see LevelInfo .

Last modified: July 23, 2026

Any further questions?

Join our discord
Our documentation is currently incomplete and undergoing active development. If you have any questions or feedback, please visit this forum thread.