flash - 录制音频有效,播放方式太快

标签 flash actionscript-3 audio audio-recording playback

我正在使用以下函数录制来自麦克风的音频输入:

    private function handleSampleData(p_sampleEvent:SampleDataEvent) :void
    {
        var data :Number;
        while (p_sampleEvent.data.bytesAvailable)
        {
            data = p_sampleEvent.data.readFloat();
            _buffer.writeFloat(data);
            _buffer.writeFloat(data);
        }
    }

这似乎有效。完成录制后,我将录制的数据复制到另一个缓冲区,如下所示:

            _buffer.position = 0;
            _lastRecord = new ByteArray();
            while (_buffer.bytesAvailable)
            {
                _lastRecord.writeFloat(_buffer.readFloat());
            }
            _lastRecord.position = 0;

然后,我在新创建的声音上使用 play() 并使用此函数将 _lastRecord 缓冲区提供给它:

    public function handlePlaybackSampleData(p_sampleEvent:SampleDataEvent) :void 
    {
        // Read data until either MAX_SAMPLES or all available samples are reached.
        var i:int = 0;
        var data :Number = 0;
        while( i < 8192 )
        {
            if( _lastRecord.bytesAvailable )
            {
                data = _lastRecord.readFloat();
                p_sampleEvent.data.writeFloat(data);
                i++;
                continue;
            }
            else 
            {
                break;
            }
        }
    }

虽然它基本上可以工作,但播放的声音太快了。 我从一个例子中获取了大部分代码,在这个例子中它工作得很好。我发现我的代码和这个代码之间没有更多重要区别:http://labs.makemachine.net/2011/04/record-visualize-save-microphone-input/

不过,音频出来的速度太快了。如果我通过添加更多“_buffer.writeFloat(data);”将更多数据放入_buffer,它会变得更好,当我有 12 行时,它就是所需的速度。但即便如此,也只有当我碰到我的麦克风时才有用。如果我真的说话,这似乎也不够。

但这是怎么回事呢?为什么在我从中获取该代码的示例中,只有 2 行代码就足够了?有没有办法确定我在录制时需要向缓冲区写入多少数据?

最佳答案

FlashPlayer 中麦克风的默认采样率为 8 kHz 单声道 - 或者,如果不可用,则为第一个可用的 11.025 kHz、22.05 kHz 或 44.1 kHz。音频输出始终为 44.1 kHz 立体声。这意味着,您获得的样本太少:44.1/8 ~= 5.5。

您可以通过将录音采样率设置为 44.1 kHz 来解决此问题:

microphone.rate = 44; // Yes, the API doesn't want the decimals

您也可以将费率保持在例如22 或 11,然后在录制时将额外的重复样本写入缓冲区(简单的“上采样”)——即,如果以 22 kHz 录制,则写入 4 个 float ,而不是 2 个,如果以 11 kHz 录制,则写入 8 个 float 。

另一件需要注意的事情是输出样本不是单个 float ,而是两个 - 每个 channel 一个。因此,麦克风将为您提供 8192 个单声道样本,您 - 就像您应该的那样 - 通过将每个样本写入两次来将其应用于两个 channel 。您现在有 8192 个“立体声”样本。

但是,当您写入输出时,您最多写入 8192 个 float (i) - 对应于 4096 个立体声样本。另一半 - 我从你的代码和你的结果中假设 - 被扔掉了。

最后,您得到的是 8192 个样本的前半部分,其采样率比回放采样率低大约 5.5 倍。这意味着声音播放速度会快 2*5.5 = 11 倍。

确保将所有样本写入输出,并以 44.1 kHz(或如上所述的上采样)记录,并且它应该以正确的速度播放。

旁注,event.data.writeBytes 复制缓冲区的速度可能很多(假设 - 尚未实际检查):

_lastRecord = new ByteArray();
_lastRecord.writeBytes(_buffer, 0, _buffer.bytesAvailable);

编写示例数据也是如此:

public function handlePlaybackSampleData(p_sampleEvent:SampleDataEvent) :void 
{
   // Maximum amount of samples we're allowed to write: 8192
   // Copying bytes here, rather than floats, so:
   // 8192 samples * 2 channels * 4 bytes per float = 65536:
   var bytesToCopy:int = Math.min(_lastRecord.bytesAvailable, 65536);

   // Using _lastRecord.position since some of it may have been written on the
   // last call to handlePlaybackSampleData if it had more than 8192 samples:
   p_sampleEvent.data.writeBytes(
      _lastRecord, 
      _lastRecord.position, 
      bytesToCopy
   );
}

关于flash - 录制音频有效,播放方式太快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9380499/

相关文章:

actionscript-3 - AS3 - 如何停止功能?

C++ 在控制台应用程序中播放视频音频

javascript - 有没有办法使用pdf.js为pdf渲染编写javascript事件

java - 如何触发 intent 以启动 flv 或 swf 到 Flash Player 10.1?

flash - 如何使用 FFMPEG 最好地转换 Flash 兼容的 mp4 文件?

actionscript-3 - 如何计算转发次数

flash - 在Flash播放器中再现(几种)同时声音的最佳方法

html - 用于 html 的 Flash 解析器

php - sox的音频水印在php中不起作用

播放完成后iOS背景音频停止