Effective audio management

Hi,

For certain GUI interactions like when the player hovers over a button, I create a new AudioPlayer instance and a Wire to play a hover sound. This happens frequently as players navigate the interface, so potentially a large number of audio instances could be created in a short amount of time.

I do destroy the AudioPlayer and its Wire immediately after the sound finishes playing, but I’m still wondering:

  • Is there a memory/performance impact when frequently creating and destroying lots of AudioPlayer and Wire instances?
  • Would it be more efficient to pool or reuse audio - players instead of creating new ones each time?

If anyone knows the best practices with the new Audio API for frequent SFX like UI interactions, I’d really appreciate the advice.

Thanks

1 Like

Creating a pool would most definitely be the most performant option, since creating and destroying instances is expensive when done very frequently and in large quantities

The drawbacks of using a pool is that, if you don’t reserve enough AudioPlayers, then sound effects won’t play until at least one of the players is available again. If you reserve too much, then you’ll be wasting memory. Technically, you should only need to create one AudioPlayer per unique sound effect, and use it whenever you need to play the sound effect

I don’t see the point to create and destroy sounds for GUI interactions, since the client is the only player who will hear them. You can simply store them in the SoundService and play them from there.

You generally use such method only for sounds in 3D space that need to be hear by everyone, to avoid having multiple same sounds stored across multiple models within the Workspace or in ReplicatedStorage.

1 Like

@Crygen54
I have a predefined module that stores all of my sound asset references like this:

return {
    UI_Hover = { id = "rbxassetid://1848354536" },
}

For frequently used sounds such as UI hovers and clicks, I’m considering adding a property (e.g. cache = true) to each entry. If set, the system will preload and store a reusable AudioPlayer instance for that sound.

Instead of creating a new AudioPlayer every time the sound is needed, I would simply call :Play() on the already cached instance.

I’m wondering if this was what you were saying.

2 Likes

That would most certainly be the preferable option for performance, and using a module to link the sound effect id to the ui element and the appropriate AudioPlayer, is a pretty good way of doing it too :slight_smile::+1:

Yeah, making a reusable AudioPlayer would be much better for performances.
I’m just wondering, is there a specific reason why you use this module + AudioPlayer method over the basic one (bellow)?

local SoundService = game:GetService("SoundService")
local UIHoverSound = SoundService:WaitForChild("UIHover", 60)--Sound Instance

UIButton.MouseHoverEnter:Connect(function()
    UIHoverSound:Play()
end)

I use the module because in my opinion it helps me better keep track of all the sounds I have, it also gives me the ability to preload them all on join so there is no delays when playing for the first time.

I use the AudioPlayer because it gives me better control over audio in my game and I heard it was overall just better than the legacy sound system.

1 Like

Alright, thank you for the clarification!