我正在编写一些以不同速度播放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));
}
这样可以正常工作,但只有当我降低播放频率(即减慢播放频率)时才会听起来不错。如果我在播放时提高音高,这种方法往往会产生高频伪像,可能是因为样本信息丢失。
我知道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;
}
在这些函数中,x1是您尝试估计的点之前的样本值,x2是您的点之后的样本值。 x0左边是x1,x3右边是x2。 t从0到1,是您估计的点与x1点之间的距离。
Hermite方法似乎工作得很好,似乎有点降低噪音。更重要的是,当波浪加速时似乎听起来更好。
答案 0 :(得分:15)
我最喜欢的音频插值资源(尤其是重采样应用程序)是Olli Niemitalo's "Elephant" paper。
我已经使用了其中的一些并且它们听起来很棒(比直立立方解决方案好得多,相对嘈杂)。有样条形式,Hermite形式,Watte,抛物线等。它们是从音频的角度讨论的。这不仅仅是典型的朴素多项式拟合。
包含代码!
要决定使用哪个,您可能希望从第60页的表开始,该表将算法分组为运算符复杂度(乘法次数和添加次数)。然后选择最佳的信噪比解决方案 - 用耳朵作为指导,做出最终选择。 注意:一般来说,更高 SNR越好。
答案 1 :(得分: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;
}
其中x1和x2是插值的样本,x0是x1的左邻居,x3是x2的右邻居。 t为[0,1],表示x1和x2之间的插值位置。
答案 2 :(得分:3)
老实说,立方插值对音频而言通常不比线性好得多。改进线性插值的一个简单建议是使用抗混叠滤波器(在插值之前或之后,取决于您是缩短信号还是延长信号)。另一种选择(虽然计算成本更高)是sinc-interpolation,可以用非常高的质量来完成。
我们发布了一些简单的LGPL重采样代码,可以将这两个代码作为WDL的一部分来执行(参见resample.h)。
答案 3 :(得分:1)
您正在寻找polynomial interpolation。我们的想法是在您想要插入的点周围选择一些已知数据点,使用数据点计算插值多项式,然后找出多项式的值和插值点。
还有其他方法。如果您可以忍受数学,请查看signal reconstruction,或谷歌搜索“信号插值”。