Playing sounds

Playing a loaded sound can be as simple as calling the Sound.play() method for a Sound object, as follows:

var snd:Sound = new Sound(new URLRequest("smallSound.mp3"));
snd.play();

Warning: When targeting HTML and JavaScript, web browsers may ignore attempts to play sounds until after the user has interacted with the page—such as clicking, tapping, or pressing keys. See MDN: Autoplay guide for media and Web Audio APIs for more details.

When playing back sounds using OpenFL, you can perform the following operations:

  • Play a sound from a specific starting position

  • Pause a sound and resume playback from the same position later

  • Know exactly when a sound finishes playing

  • Track the playback progress of a sound

  • Change volume or panning while a sound plays

To perform these operations during playback, use the SoundChannel and SoundTransform classes.

The SoundChannel class controls the playback of a single sound. The SoundChannel.position property can be thought of as a playhead, indicating the current point in the sound data that's being played.

When an application calls the Sound.play() method, a new instance of the SoundChannel class is created to control the playback.

Your application can play a sound from a specific starting position by passing that position, in terms of milliseconds, as the startTime parameter of the Sound.play() method. It can also specify a fixed number of times to repeat the sound in rapid succession by passing a numeric value in the loops parameter of the Sound.play() method.

When the Sound.play() method is called with both a startTime parameter and a loops parameter, the sound is played back repeatedly from the same starting point each time, as shown in the following code:

var snd:Sound = new Sound(new URLRequest("repeatingSound.mp3"));
snd.play(1000, 3);

In this example, the sound is played from a point one second after the start of the sound, three times in succession.

Pausing and resuming a sound

If your application plays long sounds, like songs or podcasts, you probably want to let users pause and resume the playback of those sounds. A sound cannot literally be paused during playback in OpenFL; it can only be stopped. However, a sound can be played starting from any point. You can record the position of the sound at the time it was stopped, and then replay the sound starting at that position later.

For example, let's say your code loads and plays a sound file like this:

var snd:Sound = new Sound(new URLRequest("bigSound.mp3"));
var channel:SoundChannel = snd.play();

While the sound plays, the SoundChannel.position property indicates the point in the sound file that is currently being played. Your application can store the position value before stopping the sound from playing, as follows:

var pausePosition = channel.position;
channel.stop();

To resume playing the sound, pass the previously stored position value to restart the sound from the same point it stopped at before.

channel = snd.play(pausePosition);

Monitoring playback

Your application might want to know when a sound stops playing so it can start playing another sound, or clean up some resources used during the previous playback. The SoundChannel class dispatches an Event.SOUND_COMPLETE event when its sound finishes playing. Your application can listen for this event and take appropriate action, as shown below:

import openfl.display.Sprite;
import openfl.events.Event;
import openfl.media.Sound;
import openfl.media.SoundChannel;
import openfl.net.URLRequest;

class SoundCompleteEventExample extends Sprite {
    public function new() {
        super();

        var snd:Sound = new Sound();
        var req:URLRequest = new URLRequest("smallSound.mp3");
        snd.load(req);

        var channel:SoundChannel = snd.play();
        channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
    }

    function onPlaybackComplete(event:Event):Void {
        trace("The sound has finished playing.");
    }
}

The SoundChannel class does not dispatch progress events during playback. To report on playback progress, your application can set up its own timing mechanism and track the position of the sound playhead.

To calculate what percentage of a sound has been played, you can divide the value of the SoundChannel.position property by the length of the sound data that's being played:

var playbackPercent = 100.0 * (channel.position / snd.length);

However, this code only reports accurate playback percentages if the sound data was fully loaded before playback began. The Sound.length property shows the size of the sound data that is currently loaded, not the eventual size of the entire sound file. To track the playback progress of a streaming sound that is still loading, your application should estimate the eventual size of the full sound file and use that value in its calculations. You can estimate the eventual length of the sound data using the bytesLoaded and bytesTotal properties of the Sound object, as follows:

var estimatedLength = Math.ceil(snd.length / (snd.bytesLoaded / snd.bytesTotal));
var playbackPercent = 100.0 * (channel.position / estimatedLength);

The following code loads a larger sound file and uses the Event.ENTER_FRAME event as its timing mechanism for showing playback progress. It periodically reports on the playback percentage, which is calculated as the current position value divided by the total length of the sound data:

import openfl.media.SoundChannel;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.media.Sound;
import openfl.net.URLRequest;

class SoundProgressEventExample extends Sprite {
    private var snd:Sound;
    private var channel:SoundChannel;

    public function new() {
        super();

        snd = new Sound();
        var req:URLRequest = new URLRequest("bigSound.mp3");
        snd.load(req);

        channel = snd.play();
        addEventListener(Event.ENTER_FRAME, onEnterFrame);
        channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
    }

    function onEnterFrame(event:Event):Void {
        var estimatedLength:Int = Math.ceil(snd.length / (snd.bytesLoaded / snd.bytesTotal));
        var playbackPercent:Int = Math.round(100 * (channel.position / estimatedLength));
        trace("Sound playback is " + playbackPercent + "% complete.");
    }

    function onPlaybackComplete(event:Event):Void {
        trace("The sound has finished playing.");
        removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
}

After the sound data starts loading, this code calls the snd.play() method and stores the resulting SoundChannel object in the channel variable. Then it adds an event listener to the main application for the Event.ENTER_FRAME event and another event listener to the SoundChannel object for the Event.SOUND_COMPLETE event that occurs when playback is complete.

Each time the application reaches a new frame in its animation, the onEnterFrame() method is called. The onEnterFrame() method estimates the total length of the sound file based on the amount of data that has already been loaded, and then it calculates and displays the current playback percentage.

When the entire sound has been played, the onPlaybackComplete() method executes, removing the event listener for the Event.ENTER_FRAME event so that it doesn't try to display progress updates after playback is done.

The Event.ENTER_FRAME event can be dispatched many times per second. In some cases, you won't want to display playback progress that frequently. In those cases, your application can set up its own timing mechanism using the openfl.utils.Timer class.

Stopping streaming sounds

There is a quirk in the playback process for sounds that are streaming—that is, for sounds that are still loading while they are being played. When your application calls the SoundChannel.stop() method on a SoundChannel instance that is playing back a streaming sound, the sound playback stops for one frame, and then on the next frame, it restarts from the beginning of the sound. This occurs because the sound loading process is still underway. To stop both the loading and the playback of a streaming sound, call the Sound.close() method.

results matching ""

    No results matching ""