Audio Source GC
-
- Prole
- Posts: 3
- Joined: Wed Jan 03, 2024 8:25 pm
Audio Source GC
Hello! I’m adding sounds and doing this by creating persistent decoder and sound data instances - and then each time I want to play a sound/sfx I create a new source and call play. I’m wondering if a) this is a recommended/conventional way of playing sfx and b) if I need to explicitly call Object:release() to free up the source or will it automatically be garbage collected if nothing in Lua is referencing it?
Re: Audio Source GC
You should not create a new source every time you call play. If the thing you are assigning it to is being reused, it should GC just fine, but you're tanking your performance doing that and that could cause other problems like if the source is already playing when you recreate it. You will be using a ton of CPU and IO just re-reading the same files every frame, or however often you are calling this if you doing it on every frame. There is no need to release manually.
But if you are only doing this based on user input you should be fine - especially if say you don't know in advance what audio file is being worked with. But if you're talking about a finite set, you can load them all in advance and reference them.
Are you making some sort of music editor or music player something? That would be a use case for creating a new source on play, but I'd still want to assign it to something unique that gets cleaned up later when it's no longer used - and so long as it isn't referenced, it will get released.
Here's an example of how I load music in Endless Dark:
Then, when going to play it, I have a single global variable that determines what music should be playing, and I ensure all others are stopped:
I have similar code for SFX that happens on every frame. For sounds that are short, I don't bother checking if they should continue to play - but instead I have a curated list of sounds that should stop playing if some condition is lost, and I call their stop on every frame, e.g.:
I only ever create the audio source once, on load, and I reference the table that contains those sounds. I can iterate thousands of sounds on every frame with basically no performance hit at all. I don't bother to even check if a given sound is playing and shouldn't, I just spam stop on every frame for those that shouldn't be currently playing. It's not the most efficient in the world, but it's efficient enough, and scales easily. If I was trying to make a music player, I would instead track what is currently playing, then stop that, and move on to the next, and unload the old track once the new one was finished loading.
But if you are only doing this based on user input you should be fine - especially if say you don't know in advance what audio file is being worked with. But if you're talking about a finite set, you can load them all in advance and reference them.
Are you making some sort of music editor or music player something? That would be a use case for creating a new source on play, but I'd still want to assign it to something unique that gets cleaned up later when it's no longer used - and so long as it isn't referenced, it will get released.
Here's an example of how I load music in Endless Dark:
Code: Select all
local muslist = love.filesystem.getDirectoryItems( audiopath .. "mus" )
if (muslist) then
if (type(muslist) == "table") then
for k,v in ipairs(muslist) do
local fn = string.upper(v:gsub("%.+.*", ""))
if ((string.match(v, ".ogg")) or (string.match(v, ".wav"))) then -- only load audio files
audio.mus[fn] = love.audio.newSource(audiopath .. "mus/" .. v, "stream")
end
end
end
end
Code: Select all
function f_ed_change_music(id)
if not(id) then return false end
if not(type(id) == "string") then return false end
if not(audio) then return false end
local key = "mus"
if not(audio[key]) then return false end
if not(type(audio) == "table") then return false end
if not(audio[key][id]) then return false end
for k,v in pairs(audio[key]) do
if (k ~= id) then
love.audio.stop ( audio[key][k] )
end
end
for k,v in pairs(audio[key]) do
if (k ~= id) then
love.audio.stop ( audio[key][k] )
end
end
f_ed_set_audio(key,id,"play")
end
I have similar code for SFX that happens on every frame. For sounds that are short, I don't bother checking if they should continue to play - but instead I have a curated list of sounds that should stop playing if some condition is lost, and I call their stop on every frame, e.g.:
Code: Select all
else -- if the sound is especially long (>a second or two), consider stopping it here
f_ed_set_audio("sfx","GENERICACTION","stop")
f_ed_set_audio("sfx","TAPPING1","stop")
f_ed_set_audio("sfx","TAPPING2","stop")
I only ever create the audio source once, on load, and I reference the table that contains those sounds. I can iterate thousands of sounds on every frame with basically no performance hit at all. I don't bother to even check if a given sound is playing and shouldn't, I just spam stop on every frame for those that shouldn't be currently playing. It's not the most efficient in the world, but it's efficient enough, and scales easily. If I was trying to make a music player, I would instead track what is currently playing, then stop that, and move on to the next, and unload the old track once the new one was finished loading.
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
Re: Audio Source GC
This is indeed good to know. No performance hits and you tested it on multiple systems? If I understand correctly, you just basically play each sound and stop it on every frame based on delta time and then continue playing again on next? Doesn't it sound choppy?
My boat driving game demo: https://dusoft.itch.io/captain-bradley- ... itius-demo
Re: Audio Source GC
Not quite- the way the audio system I wrote works like this
1) On load, read all audio files into a global table and create a new audio source for them with the filename as the key
2) In-game, when an event wants to play a sound, like SFX, tell that source to play
3) Every frame, see what music and environmental sound should be playing. Set that source to play.
4) Every frame, have a curated list of SFX, and then all music/environmental sounds that shouldn't be playing, and set them to stop.
This works great on Windows or Linux. No choppiness or other issues. Very low overhead - I wrote a profiler in-game and the audio subsystem is less than 0.25% of the CPU time spent.
1) On load, read all audio files into a global table and create a new audio source for them with the filename as the key
2) In-game, when an event wants to play a sound, like SFX, tell that source to play
3) Every frame, see what music and environmental sound should be playing. Set that source to play.
4) Every frame, have a curated list of SFX, and then all music/environmental sounds that shouldn't be playing, and set them to stop.
This works great on Windows or Linux. No choppiness or other issues. Very low overhead - I wrote a profiler in-game and the audio subsystem is less than 0.25% of the CPU time spent.
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
Re: Audio Source GC
Here's a short clip with audio showing off a bit of what I mean: https://i.imgur.com/FeDrNOz.mp4
There you can hear the background music (checking if it should play on every cycle), the environmental sounds (the creaking metal, etc), also checking every frame, the 1-time sounds (when I sabotage something), and the "Check on every frame" sounds, like the wrench sound when I am repairing something. It all works very smoothly.
There you can hear the background music (checking if it should play on every cycle), the environmental sounds (the creaking metal, etc), also checking every frame, the 1-time sounds (when I sabotage something), and the "Check on every frame" sounds, like the wrench sound when I am repairing something. It all works very smoothly.
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
- zorg
- Party member
- Posts: 3468
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Audio Source GC
I will add to this that while short sound effect sounds being loaded into RAM is fine, music files can be quite large (even streamed ones, since the non-decoded file does get loaded into ram in its entirety... a thing that can be toggled from löve 12.0 onwards), so keeping all tracks in there might not be a good idea, depending on how many bgm pieces you have, how long they are, and how much memory usage you want your game to have needlessly.
You can also call :clone on Sources, which can be useful if you want your sound effects, if called faster than they would have ended, to not get cut off by you just restarting one of each... although bookkeeping might turn a bit more complicated.
By the way, that iterating over all sound effects in a table bit... that is performant until you have like tens of thousands of sound samples; linearly going over that table is going to eat some processing power, so that could be done way smarter... and that includes just letting the sounds play out completely, and not stopping them every frame, testing lots of conditions.
You can also call :clone on Sources, which can be useful if you want your sound effects, if called faster than they would have ended, to not get cut off by you just restarting one of each... although bookkeeping might turn a bit more complicated.
By the way, that iterating over all sound effects in a table bit... that is performant until you have like tens of thousands of sound samples; linearly going over that table is going to eat some processing power, so that could be done way smarter... and that includes just letting the sounds play out completely, and not stopping them every frame, testing lots of conditions.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: Audio Source GC
How much memory does decoded music use?
I load about 40 soundtracks - the game at present uses about 1G of RAM, and almost all of that is image data. Actually it used to be a lot more when I was using tiles, but now on load I render all the tiles, then convert the tiles to an image, and only display the image, that saved a lot of RAM. I did not know about the BGM staying in memory even if streamed, though.
I load about 40 soundtracks - the game at present uses about 1G of RAM, and almost all of that is image data. Actually it used to be a lot more when I was using tiles, but now on load I render all the tiles, then convert the tiles to an image, and only display the image, that saved a lot of RAM. I did not know about the BGM staying in memory even if streamed, though.
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
- zorg
- Party member
- Posts: 3468
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Audio Source GC
Streamed music that gets loaded in currently takes up as much space as it does on disk, so if your music is in mp3 or ogg files, then they'll take up less than if they'd be in flac or wav. (assuming an average of 10 MB per track, for 40 tracks, that's 400 megabytes)
Static sources completely decode the files into memory on creation, so it'd be equivalent to however large a wav file would be, considering those (usually) directly store all samplepoints at whatever sampling rate the file has.
Static sources completely decode the files into memory on creation, so it'd be equivalent to however large a wav file would be, considering those (usually) directly store all samplepoints at whatever sampling rate the file has.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
-
- Prole
- Posts: 3
- Joined: Wed Jan 03, 2024 8:25 pm
Re: Audio Source GC
Thanks for the replies/info! The reason I was creating multiple sources was so that I could have the same sfx overlapping. What I mean is, if I have a single source and play it - and then play it again next frame, it won’t do anything (because it’s already playing). If I create a new source each time, I can hear the sound playing twice.
-
- Prole
- Posts: 3
- Joined: Wed Jan 03, 2024 8:25 pm
Re: Audio Source GC
Thanks, clone sounds like it might be what I want/need. For those cloned sources, do you still need to call :release on each one?
Who is online
Users browsing this forum: No registered users and 15 guests