SoundSystem of ISS and panning sounds in FlashPunk

For ISS I created a class that would handle each and every sound. The main purpose was to add a panning system which would play the sound 2D, by evaluating the source of the sound. If e.g. an enemy alien died at the left of the stage the sound would be higher from the left speaker than the right. As I noticed in ISS that was not obvious in the user but instictively the user new where the particular sound was coming from. In ISS where the player shoots consecutively, and aliens die one by one in a particular small time, this isn’t very helpful for the user but again, its a nice addition :).

EDIT: SoundSystem now has a repository with bug fixes. Find it here.

So without further ado, here’s the code:

package
{
	import net.flashpunk.FP;
	import net.flashpunk.Sfx;
	import net.flashpunk.tweens.sound.Fader;
	/**
	 * ...
	 * @author Konstantinos Egarhos
	 */
	public class SoundSystem
	{
		private static var mute:Boolean;
		private static var volume:Number; // From 0 to 1.
		private static var snd:Sfx;
		private static var fader:Fader;

		// Gets-Sets
		public static function get muteG():Boolean
		{
			return mute;
		}

		/**
		 * Constructor of a static class.
		 */
		public function SoundSystem()
		{

		}

		/**
		 * Sets mute to false, and volume to 0.7.
		 */
		public static function reset():void
		{
			mute = false;
			volume = 0.7;
			setVolume();
			fader = new Fader(resetVolume);
		}

		/**
		 * Resets volume.
		 */
		public static function resetVolume():void
		{
			FP.volume = volume;
		}

		/**
		 * Adds the fader(in case the world is changed).
		 */
		public static function addFader():void
		{
			FP.world.addTween(fader);
		}

		/**
		 * Sets the volume, or if it's muted it zeroes it.
		 */
		public static function setVolume():void
		{
			if (mute)
			{
				FP.volume = 0;
			}else
			{
				FP.volume = volume;
			}
		}

		/**
		 * Returns the pan value according to the entity x position in the stage.
		 * @param	xPos The x position where the sound is comming.
		 * @return The pan value.
		 */
		public static function panSound(xPos:Number):Number
		{
			if (xPos > FP.halfWidth)
			{
				xPos -= FP.halfWidth;
				return xPos / FP.halfWidth;
			}else if(xPos < FP.halfWidth)
			{
				return (xPos/FP.halfWidth)-1;
			}else
			{
				return 0;
			}
		}

		/**
		 * Plays sounds.
		 * @param	snd The sound you want to hear.
		 * @param	xPos The source of the sound in the x axis for panning.
		 */
 		public static function play(snd:Sfx, xPos:Number = 320):void
		{
			if (!mute)
			{
				snd.play(volume, panSound(xPos));
			}
		}

		/**
		 * Loops sounds.
		 * @param	snd The sound you want to hear.
		 * @param	xPos The source of the sound in the x axis for panning.
		 */
		public static function loop(snd:Sfx, xPos:Number = 320):void
		{
			if (!mute)
			{
				snd.loop(volume, panSound(xPos));
			}
		}

		/**
		 * Pauses the sound from playing.
		 * @param	snd The sound you want to pause.
		 */
		public static function pause(snd:Sfx):void
		{
			snd.stop();
		}

		/**
		 * Mutes or unmutes the sounds.
		 */
		public static function reverseMute():void
		{
			if (mute)
			{
				mute = false;
			}else
			{
				mute = true;
			}
			setVolume();
		}

		/**
		 * Increases/decreases gradually to targetVolume all the sounds.
		 * @param	targetVolume The volume to be set.
		 * @param	time The duration the change will take.
		 */
		public static function fadeOut(targetVolume:Number, time:Number):void
		{
			fader.fadeTo(targetVolume, time);
		}

	}

}

The class is considered as “static”. Of course no such thing exists in actionscript but its easier to describe it that way. Every function is static in order to be called from other parts of the code with ease. e.g.

SoundSystem.reset(); // Initializes. Just once in your code.
SoundSystem.play(soundExplosion, this.centerX); // where this.centerX is the enemies position

The function panSound() is called from every other function except from the one that plays the background sound. It’s rather simple, though I’m a little proud for that little masterpiece :D. The pan value can be a float number from -1(left) to +1(right). So in the function we have to first find if the sound source is past the center or not, and that’s what the if-else if-else do. The division of a value to its full returns a value from 0 to 1, and that’s saficient for the first if which takes place if the source is in the right hand of the stage. As for the left this was rather tricky but simple. We take the same result but subtract it with 1, in order to have the exact same result in its minus form!

As for the reverseMute() function its here for the settings only. The user can choose to mute or unmute the sound, and by this function it is done.

You’ll have to call addFader() in each world initialization if you want to fade the sound in that world. Careful here, if you forget it probably you won’t have the result you want, and the sound will still play without giving you an error.

The only thing you have to care about this class is the default value of the xPos. Your game maybe will have different dimensions than mine, so though its a very rare occation to be exactly in the middle, you probably won’t want to miss that.

Posted on 14 October, 2011, in Actionscript 3, FlashPunk, ISS, Programming and tagged , , , , , , , , . Bookmark the permalink. 1 Comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: