GMS 2.3+ When using custom audio groups, how can I hook into the in-IDE volume slider on my sound resources?

TheDaywalkr

Member
Basically, when using audiogroup_default, the volume sliders present on sounds in the resource editor affects the volume of that specific sound.

This is SUPER handy, especially with the built-in sound mixer, for getting sound levels right across the game.

However, I'm leveraging audio groups, of course, to control specific groups of sounds. I've noticed, though, that when a sound is set to one of my custom audio groups, that every sound in that audio group is always played at the audio group's gain setting. Dragging the gain of the sound in the IDE does nothing.

Is there any way to hook into the same logic that seems to be being used for the default audio group, to allow my sounds to use the IDE's built-in sound mixing tools? I really don't want to do it manually, either through exporting sounds with gain reduction, or through code.
 
Click Tools > Sound Mixer. Choose the audiogroup you want to mix and you can adjust the volume of individual sounds within that group, and that will be the default volume for that sound index in-game.

Beware though, if you want to have the option to adjust volume levels in-game properly, you're going to have to go about things in a very roundabout way. As a runway you can use for take-off, I'll point out the function audio_sound_get_gain(sound_index). Normally, when you play with volumes, you save the return of audio_play_sound() into a variable (lets call it my_sound) and use the audio_sound_get_gain(my_sound) function to get the volume. I've noticed that this has issues when used in conjunction with in-game sound options. For instance, if you set the volume of a variable like this audio_sound_gain(my_sound_var,global.music_volume,0) or whatever your in-game controller variable is for generic volume, it will remove the audiogroup volume and replace it with global.music_volume. You have to pull the gain of the sound first, using audio_sound_get_gain(). However, if you use the variable you have saved, my_sound in audio_sound_get_gain(), it will return the wrong gain if you have previously set the gain (as in, if you can't adjust the volume more than once for the same sound variable using audio_sound_gain(my_sound,audio_sound_get_gain(my_sound)*global.music_volume,0) otherwise it will get progressively quieter. I have a script that deals with this by pulling the true audiogroup gain for that specific sound, applying my in-game sounds settings and then returning what the true gain should be automatically:
Code:
///@function        get_gain(sound_id,type);
///@description        Returns the correct gain from the settings for the provided sound ID
///@param {id}        sound_id    The name of the sound
///@param {macro}    type        MSC or SFX

#macro SFX 0 // The sound is a sound effect
#macro MSC 1 // The sound is music

var _snd = argument0;
var _type = argument1;
var _multi = 0;
var _index = audio_get_name(_snd);
var _id = asset_get_index(_index);
switch (_type) {
    case SFX:
        _multi = global.sfx_volume;
    break;
    case MSC:
        _multi = global.music_volume;
    break;
}

return (audio_sound_get_gain(_id)*_multi*global.master_volume);
This script returns the true gain of the supplied ID, whether it is an actual sound resource ID or a saved variable ID. There are a number of oddities you'll have to deal with like this when working with audio in GMS. At least, as far as I'm aware, maybe I'm just completely oblivious.
 

TheDaywalkr

Member
Ah hah, that makes a lot of sense.

It would be rad if the mixer controls just kinda... implicitly did this multiplication for you when you play_sound from a specific audio group, lol. It feels like that oughta be implemented at some point (when sounds play in an audio group, play with their respective volume to the current gain of the audio group).

Just for clarifcation:

I can adjust things in the sound mixer, and the sounds will have that gain applied to them, as sounds. However, currently, what's happening is my audio group, that has a gain set by some global variable, is overriding the gain of the sound.

So what _I_ need to do, is develop a system (like what you gave me), where when I play a sound, I need to first calculate that sound's _actual_ gain from the current volume settings, and then set the gain of the sound (not the group) to play at that gain?
 
Yeah, that's what I've had to do. I think GM just expects you to have all sounds already mixed at correct volumes before importing which, ya know, is doable but cumbersome. The only method I've found when working with audiogroups is what I described above, ignore audiogroup volume, adjust volume for each song/sound with the Sound Mixer tool, then in-game grab the direct gain from the sound and apply your multipliers to it (and don't apply gain to the sound indices themselves, only variables holding the sounds, I'm pretty sure that applying to the sound index directly will destroy the process).
 

Yal

šŸ§ *penguin noises*
GMC Elder
I have a system I keep reusing in every game where I have convenience scripts for BGM and sound effect calls... essentially they only differ in that they adjust volume using different global variables. If you want your game to only have separate BGM and SFX volume sliders, maybe this could be an option? (To be precise, the BGM script always plays the sound resource looping, will store the result in a global "current BGM" variable, stopping the prior if it's a different piece of music, and will play at a higher priority so the music won't stop if I hit the max number of audio channels)

So the idea is that rather than using audio_play_sound, you'd use your sfx script which plays the sound, gets its gain, adjusts it with the SFX volume factor, and then returns the sound.


Side note, I usually keep a special version of the sfx script which adjusts the pitch using a second argument; adding a random factor of 5-10% higher/lower speed can make repetitive sounds like sword swings at least not sound like it's the exact same sound effect every time, and it's a much more pleasant experience to listen to.
 
@Yal So if you're storing each piece of BGM in the same variable, how do you deal with fading songs in and out if you need to? I've had to set up two variables (and I would like more, but it's too cumbersome to properly maintain), with one being "title music" and one being "in-game music" so that I can fade between the two (and then stop the faded one once it's gain has reached 0). If I use just a single variable, I lose access to the gain of the faded one and therefore can't stop it once it hits 0, creating essentially a song memory leak.
 
Simple: I don't need to :p I just instantly cut the current song and start the next one.
On that thought, I just had an epiphany about a relatively simple way of handling it. The names of my variables got in the way of my own thought process when trying to work out a way to achieve this. Instead of having title_music and game_music holding the two songs respectively, I should just have current_song and previous_song. When current_song needs to fade out and a new song needs to fade in, simply stop the previous_song audio (to catch any events where you might have a situation in which songs might play in rapid succession), make previous_song = current_song, then set current_song to the new song and fade it in, then fade out previous_song and stop it when the gain has hit 0. Simple and it will never not stop a song playing before losing access to it's ID. It's not perfect, as I said, rapid cycling between songs will result in hard cuts to the previous song, but it should be pretty good in most other situations.
 
  • Like
Reactions: Yal
Top