How to stop the same sound playing multiple times at once

OVERVIEW

Picture this, you have a collectable item, which spawns in your world, like a coin, and it can spawn in great numbers in a pile, say 30 at once. The player collects them all at once and there is a sound that plays when each one is collected. The problem is those 30 sound files play all at once and it is quite distracting, loud and obnoxious. This kind of situation might happen for any of your sounds and this solution will limit them so they all don’t play at once.

SETUP

How it works is you need an object that is persistent and always in your game, personally I use a persistent object called o_game. In it’s create event, you create an enum for every sound you want to limit, then you set how many of that sound is allowed at once, and you can also set a time that the sound can play before before defining as finished, as some sounds have a fade out trail, so this caters for that. 

//CREATE EVENT
enum sound_limits {
	COIN,	
	TOTAL
}

//how many sounds we allow at once
global.sound_limits[sound_limits.COIN] = array_create(3, noone);

//how long (secs) until we can remove this and allow another sound, set to 0 if not needed
global.sound_limits_time[sound_limits.COIN] = 0.2;

Then you use this function to play the sound.  Note that gain and pitch_arr  are optional values. If you are not sure where to create this, just create it in a script called play_sound_limited.

function play_sound_limited(_snd, _priority, _loop, _enum, _gain, _pitch_arr) {
	///@desc		plays the passed sound if there is no sound playing
	///@arg	snd		real	sound file
	///@arg	priority	real	sound priority, 100 is prioritiezed over 1, i.e the higher the number the higher the priority
	///@arg	loop		bool	loop the sound?
	///@arg	enum		real	enum value from sound_limits enum array
	///@arg	[gain]		array	set sounds gain value 0 - 1
	///@arg	[pitch_arr]	array	min, max values [0.8, 1.2]
	
	var _size = array_length(global.sound_limits[_enum]);
	for (var i = 0; i < _size; ++i) {
		if global.sound_limits[_enum][i] == noone {
			var _id = audio_play_sound(_snd, _priority, _loop, _gain);
			if _id >= 0 {
				if _pitch_arr != undefined {
					audio_sound_pitch(_id, random_range(_pitch_arr[0], _pitch_arr[1]));
				}
				global.sound_limits[_enum][i] = _id;
				return _id;
			}
		}
	}
	return -1;
}

Then in the step event of o_game we use this to check if there is a sound in the sound_limits array and if it’s finished playing or has past the set time, it’s then removed from the array.

//STEP EVENT
//sound limit checks
for (var j = 0; j < sound_limits.TOTAL; ++j) {
	var _size = array_length(global.sound_limits[j]);
	for (var i = 0; i < _size; ++i) {
		if global.sound_limits[j][i] != noone {
			var _snd = global.sound_limits[j][i];
			var _playing = audio_is_playing(_snd);
			if !_playing or (_playing and global.sound_limits_time[j] > 0 and audio_sound_get_track_position(_snd) > global.sound_limits_time[j]) {
				global.sound_limits[j][i] = noone;
			}
		}
	}
}

Lastly when you want to play the sound you can call the function with this line :

play_sound_limited(snd_coin_collect, 15, false, sound_limits.COIN, , [0.8, 1.2]);

Hope this helps. Any questions, just let me know.

Cheers,

Peter

Share