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

Audio 如何对重新采样的音频数据进行双三次(或其他非线性)插值?,audio,signal-processing,interpolation,resampling,bicubic,Audio,Signal Processing,Interpolation,Resampling,Bicubic,我正在编写一些代码,以不同的速度播放WAV文件,这样波形要么较慢且音调较低,要么较快且音调较高。我目前正在使用简单的线性插值,如下所示: int newlength = (int)Math.Round(rawdata.Length * lengthMultiplier); float[] output = new float[newlength]; for (int i = 0; i < newlength; i++

我正在编写一些代码,以不同的速度播放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));
            }
在这些函数中,x1是您试图估计的点之前的样本值,x2是您的点之后的样本值。x0是x1的左边,x3是x2的右边。t从0到1,是您估计的点与x1点之间的距离

Hermite方法似乎工作得很好,似乎在某种程度上降低了噪音。更重要的是,当波浪加速时,它听起来似乎更好。

你正在寻找的。其思想是,在要插值的点周围拾取许多已知数据点,使用这些数据点计算插值多项式,然后找出多项式和插值点的值

还有其他方法。如果你能接受数学,看看,或者谷歌搜索“信号插值”


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

我最喜欢的音频插值资源(尤其是在重采样应用程序中)是

我用过两个这样的方法,它们听起来很棒(比一个相对嘈杂的三次方解要好得多)。有样条形式、厄米形式、瓦特形式、抛物线形式等,它们是从音频的角度进行讨论的。这不仅仅是典型的朴素多项式拟合

和代码包括在内


要决定使用哪种算法,您可能需要从第60页的表开始,该表将算法分为运算符复杂度(多少次乘法和多少次加法)。然后从最好的信噪比解决方案中进行选择——以您的耳朵为向导进行最终选择。注:一般情况下,信噪比越高越好

老实说,对于音频来说,三次插值通常并不比线性插值好多少。改进线性插值的一个简单建议是使用抗锯齿滤波器(在插值之前或之后,取决于是缩短信号还是延长信号)。另一种选择(尽管计算成本更高)是sinc插值,它可以以非常高的质量完成


我们发布了一些简单的LGPL重采样代码,可以同时完成这两项工作(参见resample.h)。

对2D信号(即图像)不就是双三次的吗?你肯定是指1D(即音频)信号的立方?不过我可能错了…@Goz:1D音频可能只是“立方体”(我不知道)。我的部分问题是,我看到的所有代码示例都是用于2D图形的,我只需要一个D。@MusiGenesis,是的,你不想使用图形解决方案。耳朵很挑剔。您希望使用一种能够提供较大信噪比的解决方案。请看下面我的答案。我刚刚重读了一遍,注意到你准备悬赏。老兄,我为什么回答得这么快?我还没找到答案,所以赏金可能还是会来的。我可能会把我的整个代表都放上去。我能忍受数学,但主要是我在寻找代码样本(最好是C#或C)。我喜欢。我将尝试一下。注意:由于三次插值使用4个样本(2个样本在它们的两个最近邻之间进行插值),因此必须弄清楚如何处理波形数据的第一个插值间隔和最后一个插值间隔。通常,人们只是在左右两侧发明幻影样本。没问题。我上面的例子使用了右边的一个幻影样本。好吧,它可以工作,但不幸的是,它听起来比线性插值更糟糕。线性插值似乎会产生更多的一般低电平嘶嘶声,而这个立方公式往往会产生高音调的响声。如果你用频谱分析仪查看处理过的样本,你会发现嘶嘶声是一种噪声地板。这种振铃可能是由于立方体中增加了一些频率,这些频率在振幅上进行了调制。这又是一个很好的链接。我现在正在深入研究。我刚刚根据另一个答案实现了三次插值,听起来很糟糕。如果你在信噪比超过60的情况下使用其中任何一个,你应该听不到伪影。如果你这样做了,你很可能在实现上犯了一个错误。不要低估了你可以轻易搞乱哪一点是哪一点,你的“中间”值是多少。我第一次尝试就失败了。你甚至可能弄乱了立方体。它有助于绘制输入和输出的各个部分。:-)哈,就像我从来没有犯过错误一样!另外,请原谅我在这里的密度,但链接文章推荐这些插值器用于过采样数据,但我正在处理不能过采样的预录WAV文件(除非我误解了这个术语?)。作者说过采样是留给读者的,所以我可能需要在这里问另一个问题。当你加速时,任何靠近奈奎斯特的频率都会对你产生影响。在加速之前,你必须先做低通,否则你会切断属于那里的声音,而不仅仅是那些折叠起来的声音(这可能就是为什么你会变得缺乏亮度)。假设您有一个想在44100玩的示例。你有一个想以双倍速度玩的示例。将低通截止设置为11025,进行滤波,然后加速。你不希望任何频率超过奈奎斯特。是的,我同意。我最终回到了直线插值,因为与线性插值相比,这种改进基本上是难以察觉的。
    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;
    }
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;
}