Audio playback delay is not correct

I am writing a simple metronome component using Flex + AS3. I want it to play the "tick1" sound after, for example, every 500 milliseconds, and play a different "tick2" sound every fourth time. But in reality, the delay between sounds is not equivalent - sometimes less, sometimes more. I am testing it on the latest Chrome.

Here's my code:

//Somewhere here button bound to the 'toggle' function

import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.media.SoundTransform;
import flash.media.SoundChannel;

private var bpm:Number = 120; //2 bit per second, delay=500ms
private var period:Number = 4;
private var timer:Timer = new Timer(bpm, period);

[Embed(source='sounds/1.mp3')]
private var tickSound1Class:Class;
private var tickSound1:Sound;

[Embed(source='sounds/2.mp3')]
private var tickSound2Class:Class;
private var tickSound2:Sound;

private var trans:SoundTransform = new SoundTransform(1);

private function init():void {
    ....

    tickSound1 = new tickSound1Class() as Sound;
    tickSound2 = new tickSound2Class() as Sound;

    update();


    timer.addEventListener(TimerEvent.TIMER, onTimerEvent);

    ....
}

private function update():void {
    timer.delay = 1000 * 60/bpm;
    timer.repeatCount = 0;
}

private function toggle():void {
    if (timer.running) {
        timer.reset();
        startStopButton.label = "Start";
    } else {
        update();
        timer.start();
        startStopButton.label = "Stop";
    }
}

private function onTimerEvent(event:TimerEvent):void {
    var t:Timer = event.currentTarget as Timer;

    if (t.currentCount % period == 0)
        tickSound1.play(0, 0, trans);
    else
        tickSound2.play(0, 0, trans);
}

      

+3


source to share


1 answer


I think there are two main reasons:

  • The object Timer

    in Flash Player is known to be imprecise, the delay between them fluctuates.
  • Sound.play()

    also introduces some delay before the sound starts playing, and in theory this delay can fluctuate. The lag is especially noticeable in the PPAPI version of Flash Player used in Chrome.

There are several solutions. I would suggest one of these:

  • Use the pre-assembled sound of the entire metronome loop (tick1-pause1-tick2-pause2) and simply loop it using the second argument of the method Sound.play()

    ;
  • use dynamic sound generation.


The second option is more flexible, but more difficult to implement. Basically you need to create a new instance of the object Sound

, subscribe to it SAMPLE_DATA

and call it play()

. In the handler you check event.position / 44.1

which will give you the current sound generation position in ms. Then, if you decide that the time to play tick1 or tick2 sounds, you name tickN.extract(event.data, ...)

, where tickN

is the tick1 or tick2 object, Sound

or else record the silence.

Learn more about dynamic sound generation here .

Also note that when called, Sound.play()

it returns an object SoundChannel

that has a property position

. This is the position in ms of the sound that is being played (not generated) at the moment, and that's for sure. So using this property you can come up with a third approach: create an object Sound

and set up a handler SAMPLE_DATA

like in the dynamic sound generation solution, but write silence (zeros) to the object event.data

inside the handler all the time. This is necessary to obtain an audio channel without sound reproduction. Then use the maximum frame rate (60 FPS) and Timer

the lowest possible latency (1ms). Every time it fires Timer

checksoundChannel.position

to determine if it's time to play the tick sound, and if so, just play as in your example. This approach will probably solve the inaccuracy problem Timer

, but it cannot handle the delay caused by the method tickSound.play()

.

+2


source







All Articles