roblox-audio — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited roblox-audio (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Official sources:
Sound)AudioPlayer, AudioEmitter, AudioListener, AudioDeviceOutput, AudioDeviceInput, AudioTextToSpeech, AudioSpeechToText, Wire, AudioEqualizer, AudioCompressor, AudioReverb, AudioChorus, AudioDistortion, AudioEcho, AudioFlanger, AudioPitchShifter, AudioTremolo, AudioFader, AudioAnalyzerRoblox recommends audio objects over Sound, SoundGroup, and SoundEffect. New work should use the graph; legacy code can keep using Sound where the graph offers no advantage.
Cross-reference:
Modular instances that mirror real-world audio devices. Each object produces, consumes, modifies, or carries an audio stream. You wire them together with Wire instances (SourceInstance → TargetInstance).
| Object | Role | Real-world analog |
|---|---|---|
AudioPlayer | Produces a stream from an audio asset ID | A audio file player |
AudioEmitter | Emits a stream into the 3D environment (parent position = emission point) | A speaker in the world |
AudioListener | Picks up streams from the environment (parent = camera or character) | A microphone in the world |
AudioDeviceOutput | Plays a stream to the player's physical speaker/headphones | The player's hardware output |
AudioDeviceInput | Captures audio from the player's physical microphone | The player's hardware mic |
AudioTextToSpeech | Converts text to audio with an artificial voice | A TTS engine |
AudioSpeechToText | Converts spoken audio to text | A transcription engine |
Wire | Carries a stream from SourceInstance to TargetInstance | An audio cable |
Effects (all "modify" category): AudioEqualizer, AudioCompressor, AudioReverb, AudioChorus, AudioDistortion, AudioEcho, AudioFlanger, AudioPitchShifter, AudioTremolo, AudioFader, AudioAnalyzer. See references/audio-effects.md.
Sound system (still works, discouraged)Sound parented to a BasePart or Attachment emits from that position with built-in Doppler and distance rolloff (RollOffMode, RollOffMaxDistance, RollOffMinDistance, EmitterSize). A "global" Sound (not parented to a part/attachment) plays at constant volume everywhere. SoundGroup controls group volume and effects; SoundEffect subclasses (EqualizerSoundEffect, ReverbSoundEffect, etc.) apply per-group effects. SoundService exposes global properties (AmbientReverb, DistanceFactor, DopplerScale, RespectFilteringEnabled) that affect Sound playback.
SoundService.AmbientReverb and the Doppler/distance properties affect only legacy `Sound`, not the audio graph. The graph has its own effect objects and per-emitter DistanceAttenuation curves.
Sound is acceptable and simpler. Don't rewrite working legacy code just to migrate.AudioEmitter.DistanceAttenuation).AudioTextToSpeech / AudioSpeechToText).VoiceChatService (separate from in-experience audio; uses AudioDeviceInput under the hood when UseAudioApi is enabled).SoundService.AcousticSimulationEnabled = true and per-instance AcousticSimulationEnabled on emitters/listeners.Sound is fine.See references/audio-graph-vs-sound.md for a side-by-side property map and migration notes.
Same volume everywhere. Requires: AudioPlayer → Wire → AudioDeviceOutput, all parented under SoundService.
--!strict
local SoundService = game:GetService("SoundService")
local player = Instance.new("AudioPlayer")
player.AssetId = "rbxassetid://YOUR_AUDIO_ID"
player.Looping = true
player.Volume = 1
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()Volume changes with the listener's distance to the emitter. Requires six objects: AudioPlayer → Wire → AudioEmitter (parented to the 3D part), and AudioListener → Wire → AudioDeviceOutput (under SoundService). Set SoundService.ListenerLocation to Character or Camera (the engine auto-creates the AudioDeviceOutput under SoundService at runtime when you do).
--!strict
local SoundService = game:GetService("SoundService")
SoundService.ListenerLocation = Enum.ListenerLocation.Camera -- or Character
-- On the 3D part that should emit audio:
local part = workspace:WaitForChild("NoisyPart")
local player = Instance.new("AudioPlayer")
player.AssetId = "rbxassetid://YOUR_AUDIO_ID"
player.Looping = true
player.Parent = part
local emitter = Instance.new("AudioEmitter")
-- Custom curve: DistanceAttenuation is a NumberSequence (x = distance studs, y = volume 0..1).
-- This curve is only used when DistanceAttenuationMode == Custom (the default).
emitter.DistanceAttenuation = NumberSequence.new({
NumberSequenceKeypoint.new(0, 1), -- full volume at 0 studs
NumberSequenceKeypoint.new(50, 0.5), -- half volume at 50 studs
NumberSequenceKeypoint.new(70, 0), -- silent at 70 studs
})
-- Preset alternative (no custom curve needed):
-- emitter.DistanceAttenuationMode = Enum.DistanceAttenuationMode.Inverse
-- emitter.DistanceAttenuationBounds = NumberRange.new(4, 10000) -- [min,max] for the preset rolloff
emitter.Parent = part
local wire = Instance.new("Wire")
wire.SourceInstance = player
wire.TargetInstance = emitter
wire.Parent = part
player:Play()The emitter's parent position determines where audio emits from. AudioEmitter ignores its own orientation; rotate the parent part/attachment to steer emission.
Distance model: AudioEmitter.DistanceAttenuationMode selects the rolloff formula (Custom by default; uses your DistanceAttenuation curve; other presets use DistanceAttenuationBounds which defaults to [4, 10000] and ignore the custom curve). GetDistanceAttenuation() always returns the custom curve even when a preset is active. Don't assume it reflects the audible rolloff unless Mode == Custom. SetDistanceAttenuation(curve) only affects playback when Mode == Custom. Angle attenuation is set via SetAngleAttenuation({[angle]=volume}) (0–180° → 0–1); use for directional sources (e.g. avatar voice projects forward).
Acoustic simulation (occlusion/diffraction/reverb): Enable SoundService.AcousticSimulationEnabled and AcousticSimulationEnabled on both the emitter and listener. The current reference no longer exposes the separate per-instance OcclusionEnabled, DiffractionEnabled, and ReverbEnabled toggles; do not generate calls to them. Use emitter:GetAudibilityFor(listener) or listener:GetAudibilityFor(emitter) for combined distance and angle attenuation (0–1).
SoundService.ListenerLocation (a ListenerLocation enum) controls where the AudioListener is auto-created:
Humanoid.RootPart).workspace.CurrentCamera.When set to Character or Camera, the engine auto-creates an AudioDeviceOutput under SoundService at runtime. The AudioListener picks up audio from AudioEmitters based on distance and the emitter's DistanceAttenuation curve.
local audio = script.Parent :: AudioPlayer
someEvent:Connect(function()
audio:Play()
end)AudioPlayer:Play(atTime?), :Stop(atTime?). When atTime is supplied the action is scheduled against SoundService:GetMixerTime() for sample-accurate, framerate-independent timing (rhythm games / beat sync). :Cancel(actionId) cancels a future-scheduled Play/Stop (returns true if cancelled). :Pause(), :SeekTime(...), :GetWaveform(timeRange) (samples volume without playing; useful for waveform visualization vs live AudioAnalyzer). AudioPlayer.TimeVolume is tweenable. See references/audio-effects.md for tweening volume and effect parameters.
Preload prominent audio assets before they're needed (loading screen, round start) to avoid first-play hitches on lower-end devices:
--!strict
local ContentProvider = game:GetService("ContentProvider")
local audioPlayer = workspace:WaitForChild("MusicPlayer") :: AudioPlayer
ContentProvider:PreloadAsync({ audioPlayer })For the legacy Sound system, preload the Sound instance the same way.
SoundService.AcousticSimulationEnabled) adds per-emitter occlusion/diffraction/reverb cost; disable on low-end clients or when not needed.Profile audio with the MicroProfiler (audio appears under worker threads) and the Developer Console Memory tab.
AudioPlayer, Sound, and effects is client-side. Each client plays its own audio. The server does not mix audio for clients.AudioPlayer state (playing/paused/stopped) replicates from server to clients if the instance is in a replicated location, but per-client volume/effects are local. For one-shot SFX, prefer client-authoritative emission: server signals "this event happened" via RemoteEvent, each affected client plays the sound locally. This avoids replicating per-burst timing and respects each client's quality settings (same pattern as VFX; see roblox-vfx skill).AudioPlayer lives in ReplicatedStorage or SoundService and the server calls :Play()), but be aware each client still renders locally and may drift.VoiceChatService for spatial voice. Access control: SetUserIdAccessList(userIds) + AccessType (Allow = only listed users hear the input, Deny = all except listed; default Deny), GetUserIdAccessList() returns the allow/deny list.AudioTextToSpeech converts text (≤300 chars per request) to audio with an artificial voice. The available VoiceId values are 1–11 (English variants), 101–102 (Spanish), 201–202 (German), 301–302 (Italian), 401–402 (French), 501–502 (Mandarin Chinese), 601–602 (Hindi), 701–702 (Japanese), 801–802 (Arabic), 901–902 (Korean), and 1001–1002 (Portuguese); odd IDs are male and even IDs are female for the locale-specific pairs. Wire it like an AudioPlayer: for 2D, AudioTextToSpeech → Wire → AudioDeviceOutput; for 3D, AudioTextToSpeech → Wire → AudioEmitter (plus the listener→output wire). Set Text, VoiceId, Volume on the AudioTextToSpeech. :WaitForSpeechReady() yields until AssetFetchStatus is Success (or Failure). All text must comply with Roblox Community Standards and Terms of Use.
Audio analysis: AudioAnalyzer window is controlled by AudioWindowSize. Small (lowest latency, low frequency resolution), Medium (balanced), Large (highest resolution, more latency).
Use cases: accessibility (reading UI text aloud), NPC voiceover without recorded audio, dynamic announcements.
AudioSpeechToText converts speech captured by AudioDeviceInput into text. Requires VoiceChatService.UseAudioApi = Enabled. Wire: AudioDeviceInput → Wire → AudioSpeechToText. Set audioDeviceInput.Player = Players.LocalPlayer at runtime to target the local player's mic. Roblox auto-detects the spoken language (17 supported: Arabic, Chinese Simplified/Traditional, English, French, German, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Spanish, Russian, Turkish, Thai, Vietnamese).
To use STT without broadcasting voice to other players, disable VoiceChatService.EnableDefaultVoice. All audio for AudioSpeechToText must comply with Community Standards and Terms of Use.
Looping = true (graph) or Looped = true (legacy). For finite loops N times, use the DidLoop event (legacy Sound) or count plays on the graph.AudioPlayer.Volume (graph) or Sound.Volume (legacy). AudioFader is the graph-native way to control multiple streams' volume at once.AudioFader or SoundGroup so you can mute music independently and apply ducking (SFX ducks music via AudioCompressor sidechain).AudioEmitter); if it's UI/global, use 2D (AudioDeviceOutput direct).AudioPlayer/Sound instances for frequent one-shots rather than creating/destroying per shot.Sound/SoundGroup/SoundEffect for new work when the graph is the recommended path.AudioEmitter to SoundService (it must be parented to a 3D part/attachment for 3D audio).Wire (audio won't flow from player to output/emitter).SoundService.AmbientReverb to affect the audio graph (it only affects legacy Sound).DistanceAttenuation as a single number instead of a NumberSequence (it's a curve, not a scalar).scripts/AudioBus.lua: a small music/SFX bus helper using AudioFader to control group volume and duck music when SFX play. Adapt for your mix.Sound for simple/legacy.AudioFader or SoundGroup.DistanceAttenuation per emitter.<!-- catalog:references:start -->
<!-- catalog:references:end -->
Acoustic API references: https://create.roblox.com/docs/reference/engine/classes/AudioEmitter and https://create.roblox.com/docs/reference/engine/classes/AudioListener.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.