Skip to main content
Inspiring
March 8, 2019
Answered

Help With Volume Slider

  • March 8, 2019
  • 1 reply
  • 2184 views

So I was following a tutorial to add a volume slider to my flash project - and all went well until the point of actually making the slider control the volume.

Unfortunately the video only showed how to use the slider to control the opacity of a symbol, rather than the volume of sound.

So I'm hoping someone can help me finish it~

This is the code I have for the slider's .as file, which is working fine;

package  {

import flash.display.MovieClip;

import flash.events.MouseEvent;

import flash.geom.Rectangle;

public class SFXSlider extends MovieClip {

  var myRect:Rectangle = new Rectangle(0, 0, 60, 0)

  public function SFXSlider() {

   // constructor code

 

   SFXKnobInst1.addEventListener(MouseEvent.MOUSE_DOWN, startMove);

   stage.addEventListener(MouseEvent.MOUSE_UP, stopMove);

 

  }

  private function startMove (e:MouseEvent){

   SFXKnobInst1.startDrag(false, myRect);

  }

  private function stopMove (e:MouseEvent){

   SFXKnobInst1.stopDrag();

  }

}

}

SFXSlider = Name of slider

SFXKnobInst1 = Name of control knob instance

So as I said before, I need to make it control the volume now. However, this is just one of two visually identical sliders to control two different types of sound (one for sound effects, one for music) - so I also need know how define all sound effects as a separate 'type' of sound to the music, and have the two sliders control each separately. (The music slider/knob will be same names only with MUS instead of SFX in the names)

Please keep in mind i'm a newbie and clueless about coding Also, here's the tutorial I was following incase needed for some reason: Creating a Custom Slider With startDrag() Method in Flash Using AS3 - YouTube

Please & Thanks~

This topic has been closed for replies.
Correct answer JoãoCésar17023019

Hi.

Here is a sample of how you can achieve this.

If you are going to use OOP, try to let things the more generic, modular, and dynamic as possible.

In this demo, I created a class for a generic slider that has the only purpose of returning a number from 0 to 1. I called this returned value ratio.

The Audio class has methods to play and stop sounds and also to change their volume. The methods are static which means you don't need to create an instance of the Audio class to use them. You only have to write Audio.play(...), for example.

Also, you can separate your sounds in different channels by assigning an id to them. In my case, i used "bgm" and "sfx".

In the FLA, I added click events to the buttons to play a BGM and a SFX that live in the Library.

The slider class can inform the ratio value everytime it changes through a callback function called update that is a property of the callBacks object. Just call the Audio.volume method inside of the update function using the returned ratio value as an argument.

It's hard to explain OOP concepts. I hope it all makes some sense.

Please let me know if you have any questions.

AS3 code:

FLA

import flash.events.MouseEvent;

var bgmIsPlaying:Boolean = false;

function toggleBGM(e:MouseEvent):void

{

    if (bgmIsPlaying)

        Audio.stop("bgm");      

    else

        Audio.play(new ActiveBGM(), "bgm", bgmSlider.ratio);

  

    bgmIsPlaying = !bgmIsPlaying;

}

function playSFX(e:MouseEvent):void

{

    Audio.play(new LaserSFX(), "sfx", sfxSlider.ratio);

}

bgmButton.addEventListener(MouseEvent.CLICK, toggleBGM);

sfxButton.addEventListener(MouseEvent.CLICK, playSFX);

bgmSlider.callBacks.update = function(ratio):void

{

    Audio.volume("bgm", ratio);

};

sfxSlider.callBacks.update = function(ratio):void

{

    Audio.volume("sfx", ratio);

};

Audio.as

package

{

    import flash.media.SoundChannel;

    import flash.media.SoundTransform;   

    public class Audio

    {

        public static var channels:Object = {};

       

        public static function play(sound:*, channel:String, volume:Number = 1):void

        {

            var soundTransform:SoundTransform = new SoundTransform();

           

            if (!channels[channel])

                channels[channel] = new SoundChannel();

           

            channels[channel] = sound.play();

            soundTransform.volume = volume;

            channels[channel].soundTransform = soundTransform;

        }

       

        public static function stop(channel:String):void

        {

            if (channels[channel])

                channels[channel].stop();

        }

       

        public static function volume(channel:String, volume:Number):void

        {

            if (channels[channel])

            {

                var soundTransform:SoundTransform = new SoundTransform();               

                soundTransform.volume = volume;

                channels[channel].soundTransform = soundTransform;

            }

        }

    }

}

Slider.as

package

{

    import flash.display.Sprite;

    import flash.events.Event;

    import flash.events.MouseEvent;

    import flash.geom.Rectangle;

    public class Slider extends Sprite

    {

        public var ratio:Number;

        public var callBacks:Object = {};

       

        public function Slider()

        {

            if (stage)

                start(null);

            else

                addEventListener(Event.ADDED_TO_STAGE, start);

        }

       

        public function start(e:Event):void

        {

            ratio = getRatio();

           

            removeEventListener(Event.ADDED_TO_STAGE, start);

            addEventListener(MouseEvent.MOUSE_DOWN, _startMovingButton);

        }

       

        public function getRatio():Number

        {

            return button.x / (rec.width - button.width);

        }

       

        private function _startMovingButton(e:MouseEvent):void

        {

            stage.addEventListener(MouseEvent.MOUSE_MOVE, _moveButton);

            stage.addEventListener(MouseEvent.MOUSE_UP, _stopMovingButton);

        }

       

        private function _moveButton(e:MouseEvent):void

        {

            button.x = mouseX;

           

            if (button.x < 0)

                button.x = 0;

            else if (button.x > rec.width - button.width)

                button.x = rec.width - button.width;

           

            ratio = getRatio();

           

            if (callBacks.update)

                callBacks.update(ratio);

        }

       

        private function _stopMovingButton(e:MouseEvent):void

        {

            stage.removeEventListener(MouseEvent.MOUSE_MOVE, _moveButton);

            stage.removeEventListener(MouseEvent.MOUSE_UP, _stopMovingButton);

        }       

    }

}

FLA download:

animate_cc_as3_volume_slider.zip - Google Drive

Regards,

JC

1 reply

JoãoCésar17023019
JoãoCésar17023019Correct answer
Inspiring
March 9, 2019

Hi.

Here is a sample of how you can achieve this.

If you are going to use OOP, try to let things the more generic, modular, and dynamic as possible.

In this demo, I created a class for a generic slider that has the only purpose of returning a number from 0 to 1. I called this returned value ratio.

The Audio class has methods to play and stop sounds and also to change their volume. The methods are static which means you don't need to create an instance of the Audio class to use them. You only have to write Audio.play(...), for example.

Also, you can separate your sounds in different channels by assigning an id to them. In my case, i used "bgm" and "sfx".

In the FLA, I added click events to the buttons to play a BGM and a SFX that live in the Library.

The slider class can inform the ratio value everytime it changes through a callback function called update that is a property of the callBacks object. Just call the Audio.volume method inside of the update function using the returned ratio value as an argument.

It's hard to explain OOP concepts. I hope it all makes some sense.

Please let me know if you have any questions.

AS3 code:

FLA

import flash.events.MouseEvent;

var bgmIsPlaying:Boolean = false;

function toggleBGM(e:MouseEvent):void

{

    if (bgmIsPlaying)

        Audio.stop("bgm");      

    else

        Audio.play(new ActiveBGM(), "bgm", bgmSlider.ratio);

  

    bgmIsPlaying = !bgmIsPlaying;

}

function playSFX(e:MouseEvent):void

{

    Audio.play(new LaserSFX(), "sfx", sfxSlider.ratio);

}

bgmButton.addEventListener(MouseEvent.CLICK, toggleBGM);

sfxButton.addEventListener(MouseEvent.CLICK, playSFX);

bgmSlider.callBacks.update = function(ratio):void

{

    Audio.volume("bgm", ratio);

};

sfxSlider.callBacks.update = function(ratio):void

{

    Audio.volume("sfx", ratio);

};

Audio.as

package

{

    import flash.media.SoundChannel;

    import flash.media.SoundTransform;   

    public class Audio

    {

        public static var channels:Object = {};

       

        public static function play(sound:*, channel:String, volume:Number = 1):void

        {

            var soundTransform:SoundTransform = new SoundTransform();

           

            if (!channels[channel])

                channels[channel] = new SoundChannel();

           

            channels[channel] = sound.play();

            soundTransform.volume = volume;

            channels[channel].soundTransform = soundTransform;

        }

       

        public static function stop(channel:String):void

        {

            if (channels[channel])

                channels[channel].stop();

        }

       

        public static function volume(channel:String, volume:Number):void

        {

            if (channels[channel])

            {

                var soundTransform:SoundTransform = new SoundTransform();               

                soundTransform.volume = volume;

                channels[channel].soundTransform = soundTransform;

            }

        }

    }

}

Slider.as

package

{

    import flash.display.Sprite;

    import flash.events.Event;

    import flash.events.MouseEvent;

    import flash.geom.Rectangle;

    public class Slider extends Sprite

    {

        public var ratio:Number;

        public var callBacks:Object = {};

       

        public function Slider()

        {

            if (stage)

                start(null);

            else

                addEventListener(Event.ADDED_TO_STAGE, start);

        }

       

        public function start(e:Event):void

        {

            ratio = getRatio();

           

            removeEventListener(Event.ADDED_TO_STAGE, start);

            addEventListener(MouseEvent.MOUSE_DOWN, _startMovingButton);

        }

       

        public function getRatio():Number

        {

            return button.x / (rec.width - button.width);

        }

       

        private function _startMovingButton(e:MouseEvent):void

        {

            stage.addEventListener(MouseEvent.MOUSE_MOVE, _moveButton);

            stage.addEventListener(MouseEvent.MOUSE_UP, _stopMovingButton);

        }

       

        private function _moveButton(e:MouseEvent):void

        {

            button.x = mouseX;

           

            if (button.x < 0)

                button.x = 0;

            else if (button.x > rec.width - button.width)

                button.x = rec.width - button.width;

           

            ratio = getRatio();

           

            if (callBacks.update)

                callBacks.update(ratio);

        }

       

        private function _stopMovingButton(e:MouseEvent):void

        {

            stage.removeEventListener(MouseEvent.MOUSE_MOVE, _moveButton);

            stage.removeEventListener(MouseEvent.MOUSE_UP, _stopMovingButton);

        }       

    }

}

FLA download:

animate_cc_as3_volume_slider.zip - Google Drive

Regards,

JC

Inspiring
March 9, 2019

Oh, thank you for the reply~

I'm having trouble figuring out how to apply all of this to my own project with the custom slider I have made already, though.

See, I don't want any play/pause buttons, as the music will always be playing by default and the SFX is triggered on different frames throughout the flash.

For example, I have variations of this code on different frames to trigger the different SFX sounds on those frames;

var soundsA:Array=['sound1','sound2','sound3','sound4'];

var S=Class(getDefinitionByName(soundsA[Math.floor(4*Math.random())]));

var s=new S();

s.play();

The music on the other hand is just sat in the timeline using the sound section of the properties panel.

Is it possible to get this to work with what I have already? I was hoping it would be as simple as categorizing different types of sounds together in classes then having my slider adjust the volume of those classes, without any kind of play/pause or other user input involved~

Inspiring
March 12, 2019

Don't give up. Take your time. No need to understand everything now.

Just focus on the FLA code. Run some tests, Google your doubts. Coding requires patience, trial and error, research and often frustration. This is how the things are.

But again, if you don't mind, share your file and I'll be happy to take a look at it.

Regards,

JC


Ok, I've finally got it working for the SFX <3

There's a couple more things I need to do now though;

First - I need to know how to add the possibility of no sound playing at all randomly, and a way to adjust the chance of each sound (or no sound) playing in a way that still works with your sliders. For example, this is what I was using before without volume sliders;

var probA:Array = [.2,.2,.2,.4];

var soundsA:Array=['sound1','sound2','sound3','no sound'];

var i:int = indexF(Math.random());

if(SoundsA!='no sound'){

var S=Class(getDefinitionByName(soundsA));

var s=new S();

s.play();

}

function indexF(r:Number):int{

var s:Number=0;

for(var i:int=0;i<probA.length;i++){

s+=probA;

if(r<s){

return i;

}

}

}

Second -  I want the BGM/Music set up in a certain way - Is there a way to specifically code the same functions you get from the default Properties>Sound>Sync options (Event, Stop, Start, Stream, Loop, Repeat, etc.) so that I can trigger them on certain frames and still have them respond to the BGM volume slider? Or perhaps simply leave them to be controlled by the timeline without coding as is, and just have them classed as "bgm" so the slider affects them?

(The reason for this is I actually have 2 music files, an 'Intro' and a 'Main' file - the intro starts on frame 2 and loops in the first scene (frames 3-62), then stops and switches to the main theme after the user clicks a button to continue on, and this file then loops uninterrupted and indefinitely throughout the rest of the flash from scene 2 (frames 63-92) onwards)