Added Queues and BGM/BGS looping
I wanted to create functionality to specify a number of tracks on my game to loop through as background music. I could do it externally in my own game, but I felt this functionality might be useful to other people.
Unfortunately due to the nature of the code and using the index of the children nodes, this was impossible to do with the current codebase. So I had to refactor things quite a bit. In the process I simplified the workflow and switched to some more simplified code.
- I removed the index-based arrays
- To discover playing tracks, I just check the existing children in runtime.
- I class-named the Sounds.gd as
SoundManagerAudioStreamPlayer
. This avoids having to check if the node has a script. - I renamed
sound_name
tosound_path
and added a newsound_name
which stores the key the developer has given to this file inAudio_Files_Dictionary
. This makes it more obvious what the variable stores. - Instead of having to keep track of children index, I am now using the
sound.gd
class directly. I have extended it to store more properties - Removed redundant
self.
pointers. - Added extra function
get_all_playing_streams()
which returns an Array ofSoundManagerAudioStreamPlayer
currently playing - Added extra function
find_audiostream()
which returns aSoundManagerAudioStreamPlayer
which has thatsound_name
ofsound_path
- Added extra function
get_sound_name_from_path()
which returns theAudio_Files_Dictionary
key which matches the sound_path provided - Added more static typing
On top of those I added 2 extra features
- You can now queue sounds, and they will be played after the current sound ends, in a FIFO order.
- Added functions
queue_bgm
andqueue_bgs
which handle this for these two types. I don't expect anyone will want to queue SE/ME types. - Queuing a sound when there's nothing in the queue already,will automatically start playing it.
- Added function
clear_queue()
to empty the specified sound_type queue
- Added functions
- Can now loop queues. A queue marked for looping will put any finished sound to the back of the queue.
- Added function
toggle_queue_repeat()
which accepts a sound_type argument as string
- Added function
PS: This includes the mp3 support, you you can skip that merge
Merge request reports
Activity
mentioned in merge request !19 (closed)
added 1 commit
- 36c9f079 - Added queue_directory, queue_filelist, and stop_all
Some more improvements:
- Added function
queue_directory()
- Added function
queue_filelist()
- Added function
stop_all()
- extracted code from
preload_audio_files_from_path
and converted it into static funcget_sound_files_in_dir()
which can be used by externally from the SoundManager - converted
is_import_file()
andis_audio_file
into static funcs as they don't have any dependency on the SoundManager instance.
- Added function
added 1 commit
- 868b4572 - fix for get_sound_files_in_dir to work with exports
And some more features
- Added functions
fade_in_bgm()
andfade_out_bgm()
to graceful start/end music - Added function
crossfade_queue()
which will crossfade the current playing song, with the next one in the queue -
queue_filelist()
andqueue_directory()
now accept a boolean to initiate a crossfade
These allow a game to gracefully change the looping background music between scenes gracefully.
Edited by Divided by Zer0- Added functions
Welp this is a lot of stuff haha Very impressive! I've actually wanted to add the queue feature for a while, but I read somewhere that in some new version of the engine they were adding AudioStreamPlaylists and I was waiting to see how they worked and what they were. But I'm more and more convinced they're going to pop up directly in Godot 4, so, yea, no reason not to make a self-made system at this point. I will have to review your code and test it before approving the merge (although I assume you're already testing it, but you know, just to be sure) so it'll take some more time. Still good job, though!
added 1 commit
- 7a581842 - fix(sound) Fix logic error in find_audiostream()
Ok, sorry for the wait (I had a really busy week). I took a quick look at the code and I like the new features, even though I feel like there's still room for improvement. But I'm not sure how atm, it's just a hunch. Switching to actually testing it, I started messing around with the official demo just to make sure the basic features weren't broken in the process. Unfortunately, I'm already finding a bug. If you try to play an audio (no preload, no preinstantiation, no queues, just playing an audio) then you stop it and you try to play it again, the engine throws this error.
Related to the methodprepare_sound
. It appears to only happen when you manually stop a sound: testing with a sound effect letting it naturally stop by itself didn't throw the same error.Edited by Celeste PriviteraLemme take a look. That reminds me, this project could really benefit from some unit testing. Not very optimal to be manually testing the features like that. Would you be OK with me adding the GUT add-on to your demo project? I can then develop some starting tests and you can keep adding to them
That reminds me, this project could really benefit from some unit testing. Not very optimal to be manually testing the features like that. Would you be OK with me adding the GUT add-on to your demo project?
I usually go with prints because I find them more convenient, but I understand where you're coming from with this proposal. If you want to try, yes, it could be a good idea.
I pulled the new version and tested again and it now works! Tomorrow (it's already evening here), I'll take a proper look at the changes and new additions!