3D Sound System - Realistic frequency dampening

Before we begin:

This system was designed by @sidnad10. He reached out to me with this presentation:

He asked me if I could try creating it, and I quickly accepted.

For those who don’t want to read the presentation, the tl;dr:

In real life, your ears dampen the higher frequencies of sounds behind you, around 7k Hz. Headphones only simulate left and right, so we need to do a bit of extra work for real 3D sound emulation.

The product

I spent a couple hours creating a simple-to-use module that accomplishes this effect by playing with the HighGain of an EqualizerSoundEffect.
By using the equalizer, we can automate the dampening based on direction of sound. This way, it can be differentiated, and therefore emulate what happens with real sound.
Using a touch of angular math, we determine the relative position to the Camera, and adjust the HighGain accordingly.

Demo:

It may be subtle, but for games in which locating objects via sound is vital (like a tactical shooter), it can be game changing.

Module

Usage is super simple, with just a single function.

local SoundSystem3D = require(script.SoundSystem3D)

local Sound = SoundSystem3D:Create(ID, Target, Looped)

:Create() returns an Attachment with a Sound in it. (I use Attachments because they are more efficient than Parts or so I’ve read )
image

ID can be:

  • A string of numbers
  • A string of the whole Id (“rbxassetid://” included)

Target can be:

  • CFrame (will create a sound that stays at that CFrame)
  • Vector3 (will create a sound that stays at that Vector3)
  • Instance with a Position property (will create a sound that follows the Instance)

Looped can be:

  • A boolean (defaults to false)
    Note: If Looped is false, it will automatically delete the Attachment once the Sound has played

Because this must be run from the client, you should use RemoteEvents to tell the client when and where to play sounds.



If you have any issues, comments, or anything at all, please reply below!




Enjoying my work? I love to create and share with the community, for free.

If you’d like to help fund my work, consider sponsoring me on GitHub or donating on BuyMeACoffee!

279 Likes

I made something similar to this a while ago but done it by having 4 points around the player playing the same sound with multiple different effects applied to them to give the illusion of 3D sound.

6 Likes

That’s really innovative! I’d imagine this way is more efficient, as it only uses one.

6 Likes

I’ve implemented this in my game for practically all of my sounds and the listening experience with a headset or headphones is much nicer. Much appreciated!

7 Likes

You’re unbelievable. You just keep surprising me with these amazing, innovative, helpful inventions and then when that’s over, you share it with the developer community. Your exploits of the platform are just so cool. I never even thought of such a system or using any of the tools this way.

Great work you have there, chief.

9 Likes

This was one of the best boatbomber’s project. Really innovated. Hopefully Roblox will officially release this thing in the future.

7 Likes

Not to burst your bubble, but the engine is already capable of handling this.

Attached is a sample file of a sound rotating around the origin with Rolloff settings in SoundService set to exaggerate the effect. (Careful the sound may be a bit loud on some audio devices)
EngineAttenuation.rbxl (15.5 KB)

What does your module do that isn’t already being done passively by Roblox?

7 Likes

… I was told it didn’t. Wow. Thanks for letting me know!

Regardless, I suppose this could still be used to quickly and easily handle sound creation at specific positions?

Edit:

4 Likes

Funny. In any case this sounds like it was a fun exercise

6 Likes

It was! I did this to procrastinate my actual work cuz I got stuck on a bug and didn’t want to deal with it anymore :stuck_out_tongue_closed_eyes:

5 Likes

I’m not sure why, but boatbomber’s seems more realistic and accurate. It could just be because the sound in his place is playing more frequently.

2 Likes

Upon further testing with @sidnad10, we have determined that Rolloff handles based on distance, not angle relative to the camera LookVector. It simply makes sounds quieter the farther away they are. The fact that you think it is “behind” you is simply your brain interpreting it’s path to predict that it’s circling “around” you. This module is made to actually simulate how your ears interpret directional sounds.

You can prove this by having the object switch between a few studs in front and a few studs behind at random intervals. Close your eyes, and you’ll find yourself unable to tell when it is switching. Here, feel free to try it.
BlindTest.rbxl (18.7 KB)

Whereas the same test, but using the module, shows clear difference between front and back.
BlindTestModule.rbxl (20.2 KB)

This module is useful!

7 Likes

Yup! This reply explains why:

3 Likes

Update:

After more testing, I’ve found that doing

Emitter.Sound.EqualizerSoundEffect.HighGain = -(-25 * cos(acos(dot(cf(Camera.CFrame.Position,v3(Camera.CFrame.LookVector.X,Camera.CFrame.Position.Y,Camera.CFrame.LookVector.Z)).LookVector.Unit,v3(Emitter.WorldPosition.Unit.X,Camera.CFrame.Position.Y,Emitter.WorldPosition.Unit.Z)))/pi * (pi / 2)) + 25)

for the HighGain calculation provides a much nicer and more realistic result.

The original edition had it dampen linearly, which meant that the sides were half-dampened.
This is an inSine ease, so it dampens more behind you than to the sides.

Files have been updated with this, and I recommend anyone who has already implemented this to insert the new file. API hasn’t changed, so you can just replace the module without any issues.

6 Likes

I can’t hear the difference between BlindTest vs BlindTestModule and your game vs EngineAttenuation. Do you have any other examples that might be clearer?

3 Likes

I suppose if you replace the SoundID with the ID of a sound with more high frequencies in it, the reduction of high frequency would be more apparent.

2 Likes

It would be kind of cool to see roll off used with this!

2 Likes

I would suggest also adding an function to attach an audio to this, so it can support all audios rather than just audios created by the script. I am going to modify the code to fit my use by doing this and if people are interested, I can link it here.

3 Likes

I’d love for you to share your changes!

1 Like

Here’s the code I used (Posted directly after :Create() function)

function SoundSystem:Attach(sound)
	local Equalizer	= sound:FindFirstChildOfClass("EqualizerSoundEffect") or newInst("EqualizerSoundEffect")
	Equalizer.LowGain	= 0
	Equalizer.MidGain	= 0
	Equalizer.HighGain	= 0
	Equalizer.Parent = sound
	local tbl = {Sound = sound}
	CurrentObjects[tbl]	= true
	spawn(function()
		repeat wait() until not sound:IsDescendantOf(workspace)
		
		CurrentObjects[tbl] = nil
	end)
end

Edit: I would like to add that this has not been tested, and will be pending testing until I have properly incorporated my Vehicle Physics into the file with this.

1 Like