如何使用AS3对wav文件进行上采样?

时间:2009-12-16 22:06:29

标签: actionscript-3 audio wav

我试图在AS3中将8000hz,16位wav文件上采样到11025hz。在这一点上,我并不关心应用我知道最终需要的低通滤波器。

我一直referencing this wiki page

这是我到目前为止所做的:

  1. 计算最小公倍数为3528000
  2. 计算L为441
  3. 计算M为320
  4. 在样本之间添加了440个零
  5. 将每320个样本写入一个新的字节数组
  6. 然而,当我去玩新的wav时,它是难以区分的噪音。这是我的代码:

    const sourceRate:uint = 8000;
    const targetRate:uint = 11025;
    var lcm:uint = lcm(targetRate, sourceRate); // = 3528000
    var l:uint = lcm / sourceRate; // = 441
    var m:uint = lcm / targetRate; // = 320
    
    // upsample by factor of l
    var upsampleData:ByteArray = new ByteArray();
    upsampleData.endian = Endian.LITTLE_ENDIAN;
    
    // originalWavData is a ByteArray of the source wav data
    // fill is a ByteArray that contains 440 zeroes, written using writeShort(0x0)
    
    while(originalWavData.bytesAvailable > 1) {
        upsampleData.writeBytes(fill);
        upsampleData.writeShort(originalWavData.readShort());
    }
    
    // downsample by factor of m
    var downsampleData:ByteArray = new ByteArray();
    downsampleData.endian = Endian.LITTLE_ENDIAN;
    
    upsampleData.position = 0;
    
    for(var k:uint=0; k<upsampleData.length; k++) {
        upsampleData.position = k * m;
        if(upsampleData.bytesAvailable < 2) break;
        downsampleData.writeShort(upsampleData.readShort());
    }
    

    有人能告诉我我的代码中出错了吗?这是我的第一个问题帖子,所以如果我忘记了某些内容,或者需要提供更多信息,请告诉我。

    谢谢!

    更新

    我愚弄了Aric的答案,现在使用以下代码成功进行上采样:

    /**
     * Generates a ByteArray containing numSamples of
     * data using linear interpolation between points
     * y0 and y1.
     */
    function interpolate(y0:int, y1:int, numSamples:uint):ByteArray {
        var b:ByteArray = new ByteArray();
        b.endian = Endian.LITTLE_ENDIAN;
        var m:Number = Math.round((y1-y0)/numSamples);
        for(var i:uint=0; i<numSamples; i++) {
            var n:int = m * i + y0;
            b.writeShort(n);
        }
        b.position = 0;
        return 0;
    }
    
    // upsample by factor of l
    var n1:int = 0;
    while(originalWavData.bytesAvailable > 1) {
        var sample:int = originalWavData.readShort();
        upsampleData.writeBytes(interpolate(n1, sample, (l-1)));
        n1 = sample;
    }
    
    // downsample by factor of m
    while(upsampleData.bytesAvailable > 1) {
        downsampleData.writeShort(upsampleData.readShort());
        upsampleData.position += ((m-1)*2);
    }
    

    关于这个解决方案需要注意几点:我正在对音频验证码进行上采样,因此音质并不是非常重要。此外,第一个样本只是静音,所以我不需要计算第一个样本左边的值。这就是n1最初等于0的原因。另外,不是在我的缩减示例中将生成的样本平均在一起,我只是抓住了每个Mth样本,它听起来很合适。

    我确信有1000种更好的方法可以做到这一点,但是对于我需要的东西,它是有效的。再次感谢Aric的回答。

1 个答案:

答案 0 :(得分:5)

您想要进行上采样的特定原因吗?上采样不会为您提供更好的音频,只需将手机对话录制到CD上就可以获得“CD质量”的音频。

如果你确实想要上传,那么正如Lasse所提到的,不要只是插入零。您需要插入样本所经过的内容,如维基百科所指出的,上采样到3528000赫兹,然后下采样回到11025赫兹。

对于上采样,一种方法是在每个点之间使用线算法。假设8 kHz录音中的前三个样本是:[15,25,33]。

要将这三个样本上采样到3528000 Hz,您需要输出(441 * 3 = 1323)个样本。第220个样本应为15,第661个样本应为25,第1102个样本应为33.在点之间画一条直线,你将获得一个不错的上采样。

一旦你这样做,你需要将1323个样本抽样到大约4个样本。第一个应该是样本160-480的平均值,第二个是平均值481-800,第三个是平均值801-1160,第四个是平均值1161-1480。当然,您缺少样本1324-1480,您可以使用原始数据中的样本#4生成样本。

至少应该让你接近。但在你这样做之前,问问自己是否真的需要上传。除非你使用的是一些只采用某些格式的怪异软件,否则最好只给它提供你拥有的数据。