声音播放延迟错误

时间:2013-02-09 21:14:00

标签: actionscript-3 flex media

我正在使用Flex + AS3编写简单的节拍器组件。我希望它播放'tick1'声音,例如,每500毫秒后,每第4次播放另一个声音'tick2'。但实际上声音之间的延迟并不相同 - 有时候会更小,有时会更大一些。我在最新的Chrome上测试它。

这是我的代码:

//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);
}

1 个答案:

答案 0 :(得分:2)

我认为有两个主要原因:

  1. 众所周知,Flash Player中的Timer对象不准确,其火灾之间的延迟会发生波动。
  2. Sound.play()方法在声音实际开始播放之前也引入了一些延迟,理论上这种延迟可能会波动。在Chrome中使用的PPAPI版本的Flash Player中,延迟尤其明显。
  3. 有几种解决方案。我建议其中一个:

    1. 使用整个节拍器循环的预先组合的声音(tick1-pause1-tick2-pause2),然后使用Sound.play()方法的第二个参数循环它;
    2. 使用动态声音生成。
    3. 第二种选择更灵活,但更难实施。基本上,您需要创建Sound对象的新实例,订阅它的SAMPLE_DATA事件并调用它的play()方法。在处理程序中,您将检查event.position / 44.1,它将以ms为单位为您提供声音生成的当前位置。然后,如果您决定播放tick1或tick2声音的时间,您将调用tickN.extract(event.data, ...),其中tickN是tick1或tick2 Sound对象,否则请写入静音。

      您可以阅读有关动态声音生成的更多信息here

      另请注意,当您致电Sound.play()时,它会返回SoundChannel个对象,该对象具有position属性。这是一个正在播放的声音的毫秒位置(未生成)此刻,它是准确的。因此,使用此属性,您可以提出第三种方法:创建Sound对象并在动态声音生成解决方案中设置SAMPLE_DATA处理程序,但将静默(零)写入{句柄内的{1}}对象一直存在。这是获得声道而不实际播放声音所必需的。然后,使用具有最小可能延迟(1毫秒)的高帧速率(60 FPS)和event.data。每次Timer触发时,请检查Timer以确定是否该时间播放嘀嗒声,如果是,请按照您在示例中所做的那样播放。这种方法很可能解决soundChannel.position不准确的问题,但它无法处理由Timer方法引起的延迟。