Hello everyone! In this post I would like to make tutorial on how to store sounds and music correctly. What prompted me to do it is that new developers basically store sounds and musics in the workspace, and most of them are not used often. It is bad…
(Sorry if in this post is bad grammar)
So, you probably get a question “why shouldn’t I store them in workspace?”
– A long sound can take a lot of client memory usage. If the client memory usage will be very big it can make your game unplayable and unoptimized for some devices. A better way to avoid this is to store them in ServerStorage. When you need to use one of them you just copy in the Workspace and use it. When you don’t need it or it was used already you remove it.
If you would like to see how much memory does sounds take in total you can look in dev. console > Memory (See screenshot).
Next step you need to scroll down till you find “Place memory” and in it find “Sounds” (See video).
If you saw that in your game has more than 50 MB of sounds usage then this post is for you. Please make sure you know the basics of scripting to use this tutorial.
How removing long sounds/musics from the Workspace will help to lower client memory usage?
– Watch the video:
So, below you will see steps how to store sounds and musics proper, and manage them:
Step 1. Transfering sounds.
If your sounds and musics are store to play as a background sound or music then you need to create any folder in ServerStorage with the name “SoundStorage” and transfer them to this folder. If you have a background sound that is always looping (like ambience effect, etc) then you don’t need to transfer it.
You can also sort your sounds like on the screenshot (optional).
ServerStorage - a good storage where you can store tools, sounds, etc. Local scripts can’t get access to the storage because it is only server-sided storage, so any attempt will lead to an error.
Step 2. Creating a folder and module
Create a folder in the Workspace and name it “LoadedSounds”.
Create a module in the ServerScriptService and name it “SoundManager”.
Step 3. Setting up the module
3) Make the module to be empty and put this code in the module that was created by me:
local ServerStorage = game:GetService("ServerStorage")
local Debris = game:GetService("Debris")
local SoundStorage = ServerStorage.SoundStorage
local SoundStorageDescendants = SoundStorage:GetDescendants()
local LoadedSounds = workspace.LoadedSounds
local module = {}
local CurrentUsedSounds = {}
local function LoadSound(SoundName,Parent)
Parent = Parent or LoadedSounds
for _,Child in pairs(SoundStorageDescendants) do
if Child.Name == SoundName then
if not Parent:FindFirstChild(SoundName) then
local S = Child:Clone()
S.Parent = Parent
table.insert(CurrentUsedSounds,S)
return S
else
warn("The sound '" .. SoundName .. "' is already in use.")
return
end
end
end
warn("No sound with the name '" .. SoundName .. "' has been founded in " .. Parent:GetFullName() .. ".")
end
function module:FindAudioInLoaded(SoundName,NeedPlay) -- Finds a sound in "LoadedStorage" and returns the info about sound.
if NeedPlay == true then
local S = LoadedSounds:FindFirstChild(SoundName)
if S then
S:Play()
end
return S
end
return LoadedSounds:FindFirstChild(SoundName)
end
function module:PreloadAudio(SoundName,Parent) -- Preloads a sound
local Sound = LoadSound(SoundName,Parent)
if Sound==nil then return end
return Sound
end
function module:PlayAudio(SoundName,Parent) -- Play a sound
local Sound = LoadSound(SoundName,Parent)
if Sound==nil then return end
Sound:Play()
return Sound
end
function module:DestroyAudio(Sound,TimeOfLife) -- Destroys a sound
TimeOfLife = TimeOfLife or 0
if typeof(Sound) == "Instance" then
table.remove(CurrentUsedSounds,CurrentUsedSounds[Sound])
Debris:AddItem(Sound,TimeOfLife)
else
local RealSound = module:FindSoundInLoaded(Sound)
if RealSound then
table.remove(CurrentUsedSounds,CurrentUsedSounds[RealSound])
Debris:AddItem(RealSound,TimeOfLife)
else
warn("No sound with the name '" .. Sound .. "' has been founded in " .. LoadedSounds:GetFullName() .. ".")
end
end
end
function module:RemoveAllAudiosInLoaded() -- If your game is regenerating in some moment then this function is for your game.
for _,v in pairs(LoadedSounds:GetChildren()) do
v:Destroy()
end
for _,v in pairs(CurrentUsedSounds) do
if v~=nil then
v:Destroy()
end
end
table.clear(CurrentUsedSounds)
end
return module
Step 4. How to use it
After setting up the module here is 5 functions in the module that you can use for sounds managing:
1 - FIndAudioInLoaded
2 - PreloadAudio
3 - PlayAudio
4 - DestroyAudio
5 - RemoveAllAudiosInLoaded
“FindAudioInLoaded” function is find out a sound in “LoadedSounds” folder in Workspace by the name and returns the data about the sound. Here is an example how to use this:
local Module = require(game.ServerScriptService.SoundManager)
local Sound = Module:FindAudioInLoaded("AnySound")
task.wait(3)
Sound:Play()
If you need to play it instantly and you don’t need to set it you can add in the “FindAudioInLoaded” function the second argument “true”:
local Module = require(game.ServerScriptService.SoundManager)
Module:FindAudioInLoaded("AnySound",true)
“PreloadAudio” function is find out a sound in “LoadedSounds” folder in Workspace and copy the sound to the folder. If you need to play it instantly you can use “PlayAudio” function. Both of functions are returning the data of the sound. Here is examples how to use them:
local Module = require(game.ServerScriptService.SoundManager)
local Sound = Module:PreloadAudio("AnySound")
task.wait(3)
Sound:Play()
local Module = require(game.ServerScriptService.SoundManager)
Module:PlayAudio("AnySound")
By default the parent of the sound sets to “LoadedSounds” folder in Workspace. If you need to play/preload it in a certain part just add in the function the second argument a parent in which you need to play it:
local Module = require(game.ServerScriptService.SoundManager)
local Sound = Module:PreloadAudio("AnySound",workspace.Part)
task.wait(3)
Sound:Play()
local Module = require(game.ServerScriptService.SoundManager)
Module:PlayAudio("AnySound",workspace.Part)
“DestroyAudio” function is find out a sound in “LoadedSounds” folder and destroy it. Here is an example how to use it:
local Module = require(game.ServerScriptService.SoundManager)
local Sound = Module:PreloadAudio("AnySound")
task.wait(3)
Sound:Play()
task.wait(3)
Module:DestroyAudio(Sound)
if you need to delay audio remove without needing to add “task.wait(3)” you can add the life time before it removes in the second argument of “DestroyAudio” function:
local Module = require(game.ServerScriptService.SoundManager)
local Sound = Module:PreloadAudio("AnySound")
task.wait(3)
Sound:Play()
Module:DestroyAudio(Sound,3)
You can also remove the sound by its name but make sure the sound is located in the “LoadedSounds” folder.
“RemoveAllAudiosInLoaded” function is remove every sound that was created but wasn’t removed by the module. This function can be used in the map regeneration, etc.
Now you know how to use the module. Just remind: don’t left any sound in the “LoadedSounds” folder in Workspace or in any part if it won’t be used during a period. After playing just remove it and when you need to use the sound again you can just add it back. Whatever any sound will adds to Workspace the sound memory usage will raising. But when they will remove from the Workspace the sound memory usage will droping also.
Module features:
– This module won’t let copy a sound in that place where it is already exists unless it will be removed.
Recommendations:
– It is recommend to store sounds in the Workspace that are less than 10-15s of the length because their weight are so small? Well, this is on your decision. I recommend to not store sounds in the workspace with the length of more than 1 minute.
– if you have a background sounds in which looping is turned on you need to store them in the Workspace because copying from the ServerStorage to Workspace does not make sense.
I think, this tutorial will help games that have a lot of sounds in the workspace. If you have any question or I did anything wrong, feel free to say it below.