AS3 在循环中使用 Sound.extract 来分析声音文件

发布于 2024-12-01 19:17:51 字数 1181 浏览 0 评论 0原文

从这个 AS3 代码中,我预计有 500 行包含“2048”的跟踪输出。但我只得到一些包含“2048”的行。其余的跟踪打印一个“0”,这表明 extract() 方法没有返回任何数据。

为什么会这样呢?我想使用特定数量的步骤迭代声音文件,以在相应位置提取 2048 字节的声音。一次提取整个声音文件会使 flashplayer 冻结几秒钟,因此对我来说不是一个好的解决方案。

只要 steps 小于 samplesInSound/2048,就可以发现此行为。越接近该值,与包含 2048 的行相比,打印包含“0”的行就越多。

var sound:Sound = new Sound();
sound.load(new URLRequest("soundfile.mp3"));
sound.addEventListener(Event.COMPLETE, soundLoaded);

function soundLoaded(e:Event){
    var samplesInSound:Number = sound.length*44.1;
    var steps:int = 500;
    var byteArray:ByteArray = new ByteArray();
    for(var i=0; i<samplesInSound; i += Math.floor(samplesInSound/steps)){
        var extracted = sound.extract(byteArray, 2048, i);
        trace(i + ": " + extracted);
    }
}

我的想法是,声音文件的提取部分在提取后会从声音文件的其余部分中删除(例如 Actionscript 3 - Sound.extract 方法清空声音对象数据),所以我尝试了另一个 for 循环:

for(var i=0; i<samplesInSound - steps * 2048; i += Math.floor(samplesInSound/steps) - 2048)

但这也没有成功。

谁能帮我解决这个问题吗?

From this AS3 code I expect 500 lines of trace outputs that contain "2048". But instead I get only some lines containing "2048". The rest of the traces print a "0" which shows me that the extract() method did not return any data.

Why is this the case? I would like to iterate through the soundfile with a specific amount of steps to extract 2048 bytes of the sound at the respective position. Extracting the entire soundfile at once would freeze the flashplayer for seconds and is therefore not a good solution for me

This behaviour can be found as long steps is smaller than samplesInSound/2048. The closer it comes to that value, the more lines with a "0" are printed compared to those with a 2048 in it.

var sound:Sound = new Sound();
sound.load(new URLRequest("soundfile.mp3"));
sound.addEventListener(Event.COMPLETE, soundLoaded);

function soundLoaded(e:Event){
    var samplesInSound:Number = sound.length*44.1;
    var steps:int = 500;
    var byteArray:ByteArray = new ByteArray();
    for(var i=0; i<samplesInSound; i += Math.floor(samplesInSound/steps)){
        var extracted = sound.extract(byteArray, 2048, i);
        trace(i + ": " + extracted);
    }
}

I had the idea that the extracted part of the soundfile is cut out of the rest of the soundfile after extracting it (like at Actionscript 3 - Sound.extract method empties sound object data), so I tried out another for loop:

for(var i=0; i<samplesInSound - steps * 2048; i += Math.floor(samplesInSound/steps) - 2048)

but this didn't work out either.

Can anyone help me with this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

醉生梦死 2024-12-08 19:17:51

我没有足够的声誉来评论你的问题,所以我会写下这个带有免责声明的答案,如果它不能解决你的问题,请告诉我。

每次调用 sound.extract 都会从上一次调用 sound.extract 完成的位置提取内容,因此您不需要每次都使用 startPosition 参数。这就是为什么你会得到奇怪的结果,对 sound.extract 的调用已经在声音中前进了:

sound.extract(byteArray, 2048) // advances 2048 samples into the sound
sound.extract(byteArray, 2048) // we are 2048 samples in, grab another 2048
sound.extract(byteArray, 2048) // we are 4096 samples in, grab another 2048, etc.

更重要的是,你现在的方式实际上并不能阻止 Flash 播放器在长声音上冻结,因为你无论如何,这一切都在一个循环中完成。在循环中抓取 500 * 2048 (1,024,000) 个步骤并不比使用 sound.extract(byteArray, 1024000) 一次抓取所有步骤更好。如果有什么不同的话,那就是速度变慢了。您需要在调用 sound.extract 之间给 Flash 时间“呼吸”。

这是一个可能的解决方案:

class SoundLoader
{
    public var sound:Sound;
    public var byteArray:ByteArray;
    public var samplesInSound:int;

    public function SoundLoader(sound:Sound)
    {
        this.sound = sound;
        samplesInSound = sound.length * 44.1;
        byteArray = new ByteArray();
    }

    // Returns "true" if the sound has finished extracting.
    public function extract(samplesToExtract:int):Boolean
    {
        var extracted:int = sound.extract(byteArray, samplesToExtract);

        return extracted < samplesToExtract;
    }
}

function soundLoaded(e:Event)
{
    soundLoader = new SoundLoader(sound);

    // 2048 is very low, you'll need to experiment with how much you can load at once without Flash hiccupping.

    if (soundLoader.extract(2048))
    {
        // A very short sound! soundLoader.byteArray contains the extracted sound, ready to use.
    }
    else
    {
        // add a timer that calls soundLoader.extract(2048) again.
        // keep repeating the timer until soundLoader.extract returns 'true' - then you can use soundLoader.byteArray.
        // the timer allows Flash to do other things inbetween, which avoids it freezing up.
    }
}

I don't have enough reputation to comment on your question, so I'll write this answer with a disclaimer, let me know if it doesn't solve your problem.

Every call to sound.extract will just extract from where the previous call to sound.extract finished up, so you don't need to use the startPosition argument every time. That's why you were getting strange results, the call to sound.extract was already advancing through the sound:

sound.extract(byteArray, 2048) // advances 2048 samples into the sound
sound.extract(byteArray, 2048) // we are 2048 samples in, grab another 2048
sound.extract(byteArray, 2048) // we are 4096 samples in, grab another 2048, etc.

More importantly, the way you have it at the moment doesn't actually stop the Flash player freezing on a long sound, because you're doing it all in one loop anyway. Grabbing 500 * 2048 (1,024,000) steps in a loop is no better than just grabbing them all at once with sound.extract(byteArray, 1024000). If anything, it's slower. You need to give Flash time to 'breathe' inbetween the calls to sound.extract.

Here's a possible solution:

class SoundLoader
{
    public var sound:Sound;
    public var byteArray:ByteArray;
    public var samplesInSound:int;

    public function SoundLoader(sound:Sound)
    {
        this.sound = sound;
        samplesInSound = sound.length * 44.1;
        byteArray = new ByteArray();
    }

    // Returns "true" if the sound has finished extracting.
    public function extract(samplesToExtract:int):Boolean
    {
        var extracted:int = sound.extract(byteArray, samplesToExtract);

        return extracted < samplesToExtract;
    }
}

function soundLoaded(e:Event)
{
    soundLoader = new SoundLoader(sound);

    // 2048 is very low, you'll need to experiment with how much you can load at once without Flash hiccupping.

    if (soundLoader.extract(2048))
    {
        // A very short sound! soundLoader.byteArray contains the extracted sound, ready to use.
    }
    else
    {
        // add a timer that calls soundLoader.extract(2048) again.
        // keep repeating the timer until soundLoader.extract returns 'true' - then you can use soundLoader.byteArray.
        // the timer allows Flash to do other things inbetween, which avoids it freezing up.
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文