Actionscript 3 声音播放延迟错误
我正在使用Flex+AS3编写简单的节拍器组件。例如,我希望它在每500毫秒后播放“滴答声1”,每第4次播放另一个声音“滴答声2”。但实际上声音之间的延迟是不相等的——有时更小,有时更大。我正在最新的Chrome上测试它 这是我的代码: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
//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);
}
我认为主要有两个原因:
定时器
对象不准确,两次点火之间的延迟波动Sound.play()
方法也会在声音真正开始播放之前引入一些延迟,理论上这种延迟可能会波动。这种延迟在Chrome中使用的PPAPI版本的Flash Player中尤为明显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更好,因为更大的块大小会带来更好的性能(和更高的延迟,但它只在基于实时用户输入生成声音的应用程序中起作用)。