我正在写一些代码,播放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));
}
这工作得很好,但它往往OK音响只有当我降低了播放的频率(即慢下来)。 如果我提高对再现的音高,这种方法倾向于产生大概是因为样本信息的丢失的高频假象。
我知道双三次和其他插值方法重新取样使用不仅仅是最近的两个样本值作为我的代码例子更多,但我找不到任何好的代码样本(C#最好),我可以插入到这里取代我的直线内插法。
有谁知道任何很好的例子,或任何人都可以写一个简单的双三次插值方法? 如果我有,我会赏金这一点。 :)
更新 :这里有几个插值方法(感谢甄子丹德波尔的第一个和nosredna第二)C#实现的:
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的。 吨从0到1,并且你估计点和点X1之间的距离。
埃尔米特方法似乎工作得很好,似乎在一定程度上降低了噪音。 更重要的是它似乎更好的声音时,波加快。