Flash 10中的Actionscript声音播放精度

时间:2009-03-30 21:40:29

标签: flash actionscript-3 audio

我们有一台需要Flash 10的AS3播放器(克服9和播放偏移的旧问题)来处理音频剪辑。但是,当我选择开始和结束点进行播放时,很多时候播放的内容与Audacity中播放的内容不匹配。以下是我的测试mp3的一些细节(来自ffmpeg的结果)。

libavutil     49.10. 0 / 49.10. 0
libavcodec    52. 0. 0 / 52. 0. 0
libavformat   52.22. 1 / 52.22. 1
libavdevice   52. 1. 0 / 52. 1. 0
libswscale     0. 6. 1 /  0. 6. 1
libpostproc   51. 2. 0 / 51. 2. 0
built on Sep 24 2008 15:49:57, gcc: 4.2.4 (TDM-1 for MinGW)
Input #0, mp3, from 'reagan_challenger.mp3':
Duration: 00:00:14.62, start: 0.000000, bitrate: 127 kb/s
Stream #0.0: Audio: mp3, 44100 Hz, stereo, s16, 128 kb/s

原始网址:http://ericmalone.net/test_media/reagan_challenger.mp3

剪切网址:http://ericmalone.net/test_media/reagan_clipped.wav

使用ffmpeg在后端创建剪辑以从4017ms - 7400ms获取剪辑:

ffmpeg -i reagan_challenger.mp3 -ss 4.017 -t 3.383 reagan_clipped.wav

我还使用Audacity将文件剪切到略微不准确的位置4.017676秒 - http://ericmalone.net/test_media/reagan_challenger_from_audacity.wav时的7.401333秒

这是通过http://ericmalone.net/test_media/SoundExample.swf

下面显示的代码播放的剪辑部分

请注意, challenger 一词在Flash播放中完成,但在Audacity和基于ffmpeg的剪辑中都被截断。

我们在闪存中停止音频播放的方法是相当标准的。我已将声音位提取到测试类。这是相关代码

package {
    import flash.display.Sprite;
    import flash.events.*;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;
    import flash.text.TextField;
    import flash.utils.Timer;

    public class SoundExample extends Sprite {
        private var url:String = "http://www.ericmalone.net/test_media/reagan_challenger.mp3";
        private var soundFactory:Sound;
        private var song:SoundChannel;

        private var clipStart:int = 4017;
        private var clipEnd:int = 7400;

        private var timer:Timer;
        private var timerInterval:uint = 20;

        private var textField:TextField;

        public function SoundExample() {
            var request:URLRequest = new URLRequest(url);
            soundFactory = new Sound();
            soundFactory.addEventListener(Event.COMPLETE, completeHandler);
            soundFactory.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            soundFactory.load(request);

            textField = new TextField();
            textField.wordWrap = true;
            textField.width = 500;
            addChild(textField);
        }

        private function completeHandler(event:Event):void {
            output("file completely loaded and playing");
            timer = new Timer(timerInterval);
            timer.addEventListener(TimerEvent.TIMER, onTimer);
            song = soundFactory.play(clipStart);
            timer.start();
        }

        private function ioErrorHandler(event:Event):void {
            output("ioErrorHandler: " + event);
        }

        private function onTimer(event:TimerEvent):void
        {
            //stop playback if position is greater than clip end 
            //or if there's less duration left than difference of the timer and current position
            if((song.position >= clipEnd || clipEnd - song.position < timerInterval))
            {
                timer.stop();
                song.stop();
                output("Ending playback at " + song.position + " to be as close to " + clipEnd + " as possible");

            }
        }

        private function output(str):void
        {
            textField.text = str;
            trace(str); 
        }
    }
}

所以问题是,是否有更好的方法可以在闪存中获得更准确的播放效果?它取决于编解码器/采样率/等吗?

1 个答案:

答案 0 :(得分:2)

不直接关于正确的mp3编码,但可以帮助......

您必须知道Timer类具有一定的精度余量。

你的例子中的测试对我来说听起来不错(中间没有点击)我接近0.2%接近期望的结果,这是完全可以接受的IMO。

关于代码,我想提供一个细节,给出你的例子中的以下条件:

clipEnd - song.position < timerInterval

想象一下以下场景:

  • 计时器以20毫秒的间隔运行,从0到7400
  • 倒数第二个蜱落在7381上升1ms
  • 声音停止在99.74%

如果条件没有取消,我猜它会停在7401(100.01%)

也许你应该尝试类似的东西(小心,盲目编码):

if(song.position >= clipEnd || (clipEnd - song.position < (song.position + timerInterval) - clipEnd))
{
    // Stop Timer
} 

延迟将取决于您执行的代码,计算机等。但我建议使用不同的间隔值来保持接近最佳“均匀度”。

另外,请确保您没有其他方法来延迟执行计时器事件。 为此,您应该将此Timer部分隔离开以对其进行基准测试(同时删除声音)。