references/full.md
# Roblox Audio: Full Reference
> **Code in this reference is illustrative. Adapt to your game and verify in Studio before production use.**
## Legacy System (Sound Objects)
### Where to Place Sounds
| Location | Behavior | Use for |
|----------|----------|---------|
| Child of block/sphere/cylinder BasePart | Volumetric: emits from entire surface, volume changes with distance AND part size | Ambient zones, large area sounds |
| Child of Attachment, MeshPart, TrussPart, WedgePart | Point source: emits from single point, volume changes with distance | Footsteps, impacts, small objects |
| Within SoundService or Workspace | Global: same volume everywhere regardless of position | Background music, UI sounds |
### Basic Playback
```luau
-- Background music (global, in SoundService)
local SoundService = game:GetService("SoundService")
local bgMusic = Instance.new("Sound")
bgMusic.Name = "BackgroundMusic"
bgMusic.SoundId = "rbxassetid://1843463175"
bgMusic.Looped = true
bgMusic.Volume = 0.25
bgMusic.Parent = SoundService
bgMusic:Play()
```
```luau
-- Positional sound (3D, on a part)
local waterfall = Instance.new("Sound")
waterfall.SoundId = "rbxassetid://ASSET_ID"
waterfall.Looped = true
waterfall.Volume = 0.5
waterfall.RollOffMode = Enum.RollOffMode.InverseTapered
waterfall.RollOffMinDistance = 10 -- full volume within this range
waterfall.RollOffMaxDistance = 100 -- silent beyond this range
waterfall.Parent = workspace.WaterfallPart
waterfall:Play()
```
### RollOff Modes
| Mode | Behavior |
|------|----------|
| `Inverse` | Realistic falloff (1/distance). Drops quickly near source, slowly far away. |
| `Linear` | Linear falloff between min and max distance. |
| `InverseTapered` | Inverse near the source, tapers to silence at max. Most natural for games. |
| `LinearSquare` | Attempt at realistic with linear square curve. |
- `RollOffMinDistance`: distance (studs) where volume starts decreasing. Default 10.
- `RollOffMaxDistance`: distance where volume reaches zero. Default 10000 (effectively infinite).
### SoundGroups (Audio Mixer)
SoundGroups let you control volume of multiple sounds at once. Nest them for a mix tree.
```luau
-- Create mix hierarchy in SoundService
local master = Instance.new("SoundGroup")
master.Name = "Master"
master.Volume = 1
master.Parent = SoundService
local music = Instance.new("SoundGroup")
music.Name = "Music"
music.Volume = 0.5
music.Parent = master -- nested under Master
local sfx = Instance.new("SoundGroup")
sfx.Name = "SFX"
sfx.Volume = 0.8
sfx.Parent = master
-- Assign a sound to a group
bgMusic.SoundGroup = music
```
Adjusting `master.Volume` affects ALL nested groups. Players can control Music vs SFX independently.
### Dynamic Effects
Parent these to a Sound or SoundGroup to modify audio:
| Effect | What it does | Use for |
|--------|-------------|---------|
| `ReverbSoundEffect` | Simulates room reflections | Caves, large halls, bathrooms |
| `EqualizerSoundEffect` | Control volume of frequency bands | Muffled underwater, radio effect |
| `CompressorSoundEffect` | Reduces dynamic range | Consistent volume, ducking |
| `ChorusSoundEffect` | Thickens sound with copies | Ethereal voices, dream sequences |
| `DistortionSoundEffect` | Adds distortion/overdrive | Damaged radio, horror |
| `FlangeSoundEffect` | Sweeping comb filter | Sci-fi, psychedelic |
| `PitchShiftSoundEffect` | Changes pitch without speed | Chipmunk voice, deep voice |
| `TremoloSoundEffect` | Periodic volume modulation | Vibrato, pulsing |
```luau
-- Add reverb to all sounds in a cave zone
local caveGroup = Instance.new("SoundGroup")
caveGroup.Name = "Cave"
caveGroup.Parent = master
local reverb = Instance.new("ReverbSoundEffect")
reverb.DecayTime = 3.0
reverb.Density = 1.0
reverb.Diffusion = 1.0
reverb.WetLevel = -6 -- dB, how much reverb vs dry signal
reverb.Parent = caveGroup
```
### Ducking (Lower music when SFX plays)
Use CompressorSoundEffect with a SideChain:
```luau
-- Music ducks when SFX plays
local compressor = Instance.new("CompressorSoundEffect")
compressor.Threshold = -20
compressor.Ratio = 4
compressor.Attack = 0.01
compressor.Release = 0.2
compressor.SideChain = sfx -- SFX group triggers the compression
compressor.Parent = music -- Music group gets compressed
```
## New Modular System (Audio Objects)
The new system uses explicit wiring between audio components. Each object maps to a real-world audio device:
| Object | Real-world equivalent | Role |
|--------|----------------------|------|
| `AudioPlayer` | Media player / turntable | Produces audio from an asset |
| `AudioEmitter` | Speaker in 3D space | Emits audio positionally |
| `AudioListener` | Microphone | Picks up audio from 3D space |
| `AudioDeviceOutput` | Headphones/speakers | Plays to the real player |
| `AudioDeviceInput` | Physical microphone | Captures real player voice |
| `Wire` | Audio cable | Carries stream between objects |
| `AudioTextToSpeech` | TTS engine | Converts text to speech |
| `AudioEqualizer` | EQ pedal | Modifies frequency response |
| `AudioCompressor` | Compressor pedal | Controls dynamic range |
| `AudioReverb` | Reverb unit | Adds room reflections |
### 2D Audio (non-positional)
```
AudioPlayer → Wire → AudioDeviceOutput
```
```luau
-- In SoundService:
local player = Instance.new("AudioPlayer")
player.AssetId = "rbxassetid://MUSIC_ID"
player.Looping = true
player.Volume = 0.5
player.Parent = SoundService
local output = Instance.new("AudioDeviceOutput")
output.Parent = SoundService
local wire = Instance.new("Wire")
wire.SourceInstance = player
wire.TargetInstance = output
wire.Parent = SoundService
player:Play()
```
### 3D Audio (positional)
```
AudioPlayer → Wire → AudioEmitter (on Part)
AudioListener (on Camera/Character) → Wire → AudioDeviceOutput
```
```luau
-- On the part that emits sound:
local player = Instance.new("AudioPlayer")
player.AssetId = "rbxassetid://SFX_ID"
player.Parent = workspace.CampfirePart
local emitter = Instance.new("AudioEmitter")
emitter.Parent = workspace.CampfirePart
local wire = Instance.new("Wire")
wire.SourceInstance = player
wire.TargetInstance = emitter
wire.Parent = workspace.CampfirePart
-- Studio/plugin-only SoundService.DefaultListenerLocation controls whether
-- Roblox creates and wires the default AudioListener and AudioDeviceOutput.
-- For runtime custom placement, create and wire an explicit AudioListener.
player:Play()
```
`AudioEmitter.DistanceAttenuation` controls the volume-over-distance curve.
### Triggering Audio from Scripts
```luau
-- Basic trigger pattern
local audioPlayer = script.Parent -- AudioPlayer
local part = audioPlayer.Parent
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChildOfClass("Humanoid") then
audioPlayer:Play()
end
end)
```
## Patterns
### Preloading Critical Audio
```luau
local ContentProvider = game:GetService("ContentProvider")
local criticalSounds = {
Instance.new("Sound"), -- temp instances for preloading
Instance.new("Sound"),
}
criticalSounds[1].SoundId = "rbxassetid://HIT_SOUND"
criticalSounds[2].SoundId = "rbxassetid://JUMP_SOUND"
ContentProvider:PreloadAsync(criticalSounds)
-- Now these assets are cached and play instantly
```
### One-Shot SFX (auto-cleanup)
```luau
local function playSFX(parent: BasePart, soundId: string)
local sound = Instance.new("Sound")
sound.SoundId = soundId
sound.RollOffMode = Enum.RollOffMode.InverseTapered
sound.RollOffMinDistance = 10
sound.RollOffMaxDistance = 80
sound.Parent = parent
sound:Play()
sound.Ended:Once(function()
sound:Destroy()
end)
end
```
### Client-Side Playback
Play sounds on the client for zero-latency feedback. Server tells client WHAT to play:
```luau
-- Server
SFXRemote:FireClient(player, "hit", workspace.Enemy.HumanoidRootPart.Position)
-- Client
SFXRemote.OnClientEvent:Connect(function(sfxName: string, position: Vector3)
local part = Instance.new("Part")
part.Position = position
part.Anchored = true
part.Transparency = 1
part.CanCollide = false
part.Parent = workspace
playSFX(part, SFX_IDS[sfxName])
task.delay(3, function() part:Destroy() end)
end)
```
## Common Mistakes
- **Playing sounds on the server for feedback**: Server sounds have network latency. Play on client for responsive SFX. Server only for sounds ALL players must hear identically.
- **No RollOff configuration**: Default RollOffMaxDistance is 10000 studs (basically infinite). Set it explicitly or sounds bleed across the entire map.
- **Stacking rapid sounds**: Playing the same sound 10x in 0.1s creates ear-splitting overlap. Check `sound.IsPlaying` or use a cooldown.
- **Forgetting Looped = false on one-shots**: Default is false, but if you clone from a template that has Looped = true, your SFX plays forever.
- **Not destroying one-shot sounds**: Sounds parented to destroyed parts get GC'd, but sounds in SoundService accumulate. Always Destroy() after Ended.
- **Volume > 1**: Causes clipping/distortion. Keep ≤ 1. Use SoundGroup volume for amplification.
- **Using legacy system for voice chat integration**: The new AudioPlayer/Wire system is required for voice chat features (AudioDeviceInput, AudioSpeechToText).
- **No SoundGroup hierarchy**: Without groups, players can't independently control music vs SFX volume in settings.
## Review and regression checks
- Give subjective review candidates stable names or slots and freeze their source, pitch, speed, offset, and effects while comparing them. Record the selected settings before adding random variation.
- Listen to the actual requested cue and its in-game use. Successful loading, a filename, or measured loudness does not establish sound identity or acceptable feel. If listening is unavailable, keep that acceptance check explicitly unverified.
- Inspect a cropped cue's start, attack, peak, release, and tail. Use suitable fades or adjusted slice points where a hard boundary produces a click or abrupt cutoff; audition every derived cue at its actual playback settings. Do not apply one fade duration blindly to all recordings.
- Test each configured action slot and the full preview sequence: windup, charge, release, travel or near miss, impact, and kill where present. Confirm the correct cue plays in each slot and that previews use the intended nonspatial or spatial mix. A shared refactor must preserve deliberately distinct cosmetic overrides.
- Reproduce loudness complaints from the listener's actual position and event path. Check launch, passing near the listener, impact, and victim-local playback separately. Align the perceived attack and peak with the visual event; removing leading silence alone may leave a slow buildup.
- Validate an audio-review tool using known clips, including silence and a known signal, before trusting its descriptions. Use direct measurements for timing and perceptual review for identity/feel; record the tool's demonstrated limits and retain owner listening when needed. Do not infer capability from a model label or a successful request.
SKILL.md
---
name: roblox-audio
description: "Use when adding, changing, or fixing Roblox audio: playback, spatial sound, music, sound effects, SoundGroups, or dynamic effects."
when_to_use: "Also when a sound doesn't play, is too loud or quiet, overlaps or loops wrongly, volume settings, and auditing audio assets or mixes."
last_reviewed: 2026-10-14
sources:
- https://create.roblox.com/docs/reference/engine/classes/SoundService
- https://create.roblox.com/docs/audio/objects
- https://create.roblox.com/docs/audio/effects
- https://create.roblox.com/docs/sound/groups
- https://create.roblox.com/docs/sound/dynamic-effects
- original
- https://raw.githubusercontent.com/Roblox/creator-docs/main/content/en-us/reference/engine/classes/Sound.yaml
---
# Roblox Audio
## When to Load
Load when implementing audio playback, spatial/3D sound, background music, sound effects, audio mixing (SoundGroups), or dynamic effects. Covers both legacy Sound objects and the newer modular AudioPlayer/Wire system.
## Quick Reference
**Two Systems**: Legacy (`Sound`/`SoundGroup`/`SoundEffect`): simpler. New modular (`AudioPlayer`/`AudioEmitter`/`Wire`/`AudioDeviceOutput`): preferred for new projects, required for voice chat.
**Sound Placement**: BasePart child → volumetric. Attachment/MeshPart → point source. SoundService/Workspace → global (BGM/UI).
**Legacy Setup**:
```luau
local s = Instance.new("Sound")
s.SoundId = "rbxassetid://ID"; s.Looped = true; s.Volume = 0.25
s.RollOffMode = Enum.RollOffMode.InverseTapered
s.RollOffMinDistance = 10; s.RollOffMaxDistance = 100
s.Parent = SoundService; s:Play()
```
**SoundGroups** (mixer): Nest `SoundGroup` under Master for player-adjustable Music vs SFX volume. `bgMusic.SoundGroup = musicGroup`. Effects (`ReverbSoundEffect`, `EqualizerSoundEffect`, `CompressorSoundEffect`, etc.) parent to Sound/SoundGroup. Ducking: `CompressorSoundEffect` with `SideChain = sfxGroup` on music.
**New Modular**: 2D: `AudioPlayer → Wire → AudioDeviceOutput`. 3D: `AudioPlayer → Wire → AudioEmitter` (on Part). Studio/plugin-only `SoundService.DefaultListenerLocation` controls the default listener; wire an explicit `AudioListener` for runtime control.
**One-Shot SFX**:
```luau
local function playSFX(parent, id)
local s = Instance.new("Sound"); s.SoundId = id
s.RollOffMode = Enum.RollOffMode.InverseTapered
s.RollOffMinDistance = 10; s.RollOffMaxDistance = 80
s.Parent = parent; s:Play()
s.Ended:Once(function() s:Destroy() end)
end
```
**Preload**: `ContentProvider:PreloadAsync({sound1, sound2})`. **Client SFX**: `FireClient` → `OnClientEvent` creates invisible Part + `playSFX`.
**Pitfalls**: Server sounds have latency → play feedback on client. Default `RollOffMaxDistance`=10000 studs → set explicitly. Volume > 1 clips. Rapid-fire → check `IsPlaying`. Always `Destroy()` one-shots after `Ended`.
See `references/full.md` for detailed examples, effect table, and client-side patterns.