你如何对重新采样的音频数据进行双三次(或其他非线性)插值?

Mus*_*sis 16 audio interpolation signal-processing resampling bicubic

我正在编写一些以不同速度播放WAV文件的代码,因此波浪要么慢,要么低音,要么更快,音高更高.我目前正在使用简单的线性插值,如下所示:

            int newlength = (int)Math.Round(rawdata.Length * lengthMultiplier);
            float[] output = new float[newlength];

            for (int i = 0; i < newlength; i++)
            {
                float realPos = i / lengthMultiplier;
                int iLow = (int)realPos;
                int iHigh = iLow + 1;
                float remainder = realPos - (float)iLow;

                float lowval = 0;
                float highval = 0;
                if ((iLow >= 0) && (iLow < rawdata.Length))
                {
                    lowval = rawdata[iLow];
                }
                if ((iHigh >= 0) && (iHigh < rawdata.Length))
                {
                    highval = rawdata[iHigh];
                }

                output[i] = (highval * remainder) + (lowval * (1 - remainder));
            }
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,但只有当我降低播放频率(即减慢播放频率)时才会听起来不错.如果我在回放时提高音高,这种方法往往会产生高频伪像,可能是因为样本信息丢失.

我知道bicubic和其他插值方法重新采样不仅仅使用我的代码示例中的两个最接近的样本值,但我找不到任何好的代码示例(最好是C#)我可以插入来替换我的线性插值方法.

有谁知道任何好的例子,或者任何人都可以写一个简单的双三次插值方法?如果必须的话,我会给予此奖励.:)

更新:这里有一些插值方法的C#实现(感谢Donnie DeBoer的第一个和nosredna的第二个):

    public static float InterpolateCubic(float x0, float x1, float x2, float x3, float t)
    {
        float a0, a1, a2, a3;
        a0 = x3 - x2 - x0 + x1;
        a1 = x0 - x1 - a0;
        a2 = x2 - x0;
        a3 = x1;
        return (a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3);
    }

    public static float InterpolateHermite4pt3oX(float x0, float x1, float x2, float x3, float t)
    {
        float c0 = x1;
        float c1 = .5F * (x2 - x0);
        float c2 = x0 - (2.5F * x1) + (2 * x2) - (.5F * x3);
        float c3 = (.5F * (x3 - x0)) + (1.5F * (x1 - x2));
        return (((((c3 * t) + c2) * t) + c1) * t) + c0;
    }
Run Code Online (Sandbox Code Playgroud)

在这些函数中,x1是您尝试估计的点之前的样本值,x2是您的点之后的样本值.x0左边是x1,x3右边是x2.t从0到1,是您估计的点与x1点之间的距离.

Hermite方法看起来效果很好,似乎可以减少噪音.更重要的是,当波浪加速时似乎听起来更好.

Nos*_*dna 15

我最喜欢的音频插值资源(尤其是重采样应用程序)是Olli Niemitalo的"大象"论文.

我已经使用了其中的一些并且它们听起来很棒(比直立立方解决方案好得多,相对嘈杂).有样条形式,Hermite形式,Watte,抛物线等.从音频的角度讨论它们.这不仅仅是典型的朴素多项式拟合.

代码包括在内!

要决定使用哪个,您可能希望从第60页的表开始,该表将算法分​​组为运算符复杂度(乘法次数和添加次数).然后选择最佳的信噪比解决方案 - 用耳朵作为指导,做出最终选择.注意:一般来说,SNR 越高越好.

  • 如果您使用SNR超过60的任何一个,您将无法听到伪影.如果你这样做,你可能犯了一个错误.并且不要低估你可以轻松搞砸哪个点和你的"中间"值是什么.我搞砸了第一次尝试.你甚至可能搞乱了立方体.它有助于绘制输入和输出的部分.:-) (2认同)
  • 另外,请原谅我的密度,但链接的文章推荐这些内插器用于过采样数据,但我正在研究预先录制的WAV文件,这些文件不能过采样(除非我误解了这个术语?).作者说,过采样是留给读者的,所以也许我需要在这里提出另一个问题. (2认同)

Don*_*oer 7

double InterpCubic(double x0, double x1, double x2, double x3, double t)
{
   double a0, a1, a2, a3;

   a0 = x3 - x2 - x0 + x1;
   a1 = x0 - x1 - a0;
   a2 = x2 - x0;
   a3 = x1;

   return a0*(t^3) + a1*(t^2) + a2*t + a3;
}
Run Code Online (Sandbox Code Playgroud)

其中x1和x2是在其间插入的样本,x0是x1的左邻居,x3是x2的右邻居.t为[0,1],表示x1和x2之间的插值位置.