Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Actionscript 3 声音播放延迟错误_Actionscript 3_Apache Flex_Media - Fatal编程技术网

Actionscript 3 声音播放延迟错误

Actionscript 3 声音播放延迟错误,actionscript-3,apache-flex,media,Actionscript 3,Apache Flex,Media,我正在使用Flex+AS3编写简单的节拍器组件。例如,我希望它在每500毫秒后播放“滴答声1”,每第4次播放另一个声音“滴答声2”。但实际上声音之间的延迟是不相等的——有时更小,有时更大。我正在最新的Chrome上测试它 这是我的代码: //Somewhere here button bound to the 'toggle' function import flash.utils.Timer; import flash.events.TimerEvent; import flash.medi

我正在使用Flex+AS3编写简单的节拍器组件。例如,我希望它在每500毫秒后播放“滴答声1”,每第4次播放另一个声音“滴答声2”。但实际上声音之间的延迟是不相等的——有时更小,有时更大。我正在最新的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);
}

我认为主要有两个原因:

  • 众所周知,Flash播放器中的
    定时器
    对象不准确,两次点火之间的延迟波动
  • Sound.play()
    方法也会在声音真正开始播放之前引入一些延迟,理论上这种延迟可能会波动。这种延迟在Chrome中使用的PPAPI版本的Flash Player中尤为明显
  • 有几种解决方案。我建议采取以下措施之一:

  • 使用整个节拍器周期的预合成声音(tick1-pause1-tick2-pause2),只需使用
    sound.play()的第二个参数进行循环即可
    
  • 使用动态声音生成
  • 第二种选择更灵活,但更难实施。基本上,您需要创建一个
    Sound
    对象的新实例,订阅它的
    SAMPLE\u DATA
    事件并调用它的
    play()
    方法。在处理程序中,您将检查
    event.position/44.1
    ,它将以毫秒为单位给出声音生成的当前位置。然后,如果您决定播放滴答声1或滴答声2,您将调用
    tickN.extract(event.data,…)
    ,其中
    tickN
    是滴答声1或滴答声2
    对象,或者用其他方式写下沉默

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


    另外,请注意,当调用
    Sound.play()
    时,它返回一个
    SoundChannel
    对象,该对象具有
    position
    属性。它是当前正在播放(未生成)的声音的位置,以毫秒为单位,并且是准确的。因此,使用此属性,您可以提出第三种方法:创建一个
    Sound
    对象,并像动态声音生成解决方案中那样设置一个
    SAMPLE\u DATA
    处理程序,但始终将静默(零)写入处理程序中的
    event.DATA
    对象。这是在不实际播放声音的情况下获得声道所必需的。然后,使用高帧速率(60 FPS)和
    定时器
    ,尽可能减少延迟(1 ms)。每次启动
    定时器
    时,请检查
    soundChannel.position
    以确定是否是播放滴答声的时间,如果是,只需像示例中那样播放滴答声即可。这种方法可能会解决
    计时器
    不准确的问题,但无法解决
    滴答声.play()
    方法造成的延迟。

    谢谢。我决定使用第二种方法。它需要一些时间来研究如何采样和取消采样声音,但这似乎是最好的解决方案,因为我不想使用服务器端预生成的声音。欢迎:)请注意,在单个采样数据事件中可以传递2048个采样(约50毫秒)和8192个采样(约190毫秒),因此,在某些情况下,您需要在几个连续事件中记录滴答声,原因是当前event.position可能早于下一个滴答声,但(event.position+2048)可能晚于下一个滴答声。您将编写A=(tickTime*44.1-event.position)静默样本,然后B=(2048-A)从开头开始的滴答声样本。然后,在下一个样本数据事件中,C=(tickSound.length*44.1-B)滴答声样本从不是第二个样本开始,再次是D=(2048-C)静默样本(1个静默样本=2个零浮动)。使用这种方法,您可以选择任何大小的声音块,不一定是2048个样本。只需将上一条评论中的2048替换为2048到8192个示例之间的任何大小:)使用大于2048的smth更好,因为更大的块大小会带来更好的性能(和更高的延迟,但它只在基于实时用户输入生成声音的应用程序中起作用)。