5

我正在尝试将信号(声音样本)从一个采样率重新采样到更高的采样率。不幸的是,它需要某种过滤器,因为似乎会出现一些“混叠”,而且我不熟悉过滤器。这是我想出的:

int i, j, a, b, z;

a = 44100;
b = 8363;

// upsample by a
for(i = z = 0; i < samplen; i++)
    for(j = 0; j < a; j++)
        cbuf[z++] = sampdata[i];

// some filter goes here???

// downsample by b
for(j = i = 0; i < z; i += b)
    buf[j++] = cbuf[i];

新样本与原始样本非常相似,但有一些噪音。你能告诉我我需要添加什么过滤器,最好是一些与该过滤器相关的代码?

原声:http ://www.mediafire.com/? 9gnga1in52d6t4x 重新采样的声音:http ://www.mediafire.com/?x34h7ggk8n9k8z1

4

7 回答 7

12

除非采样率(源和目标)都远高于数据中的最高频率,否则不要使用线性插值。这是一个非常差的低通滤波器。

您想要的是一个内插低通滤波器,其阻带开始低于您正在处理的两个采样率中较低的一半。实现这一点的常用方法是使用 IIR 滤波器进行上采样/下采样,以及使用多相 FIR 滤波器。如果您不需要实时性能并且不想上采样/下采样,则窗口式 Sinc 插值器也适用于此。这是Basic 中的 Windowed Sinc 插值低通滤波器,转换为 C 应该很简单。

如果您想使用 IIR 滤波,这里是双二阶 IIR 滤波器的规范食谱

如果您想要音频重采样理论的最佳解释,请访问斯坦福 CCRMA 的重采样页面

于 2010-12-09T05:18:29.043 回答
10

您是否考虑过为此使用专门的库,例如libsamplerate

它非常便携,并且是由知道如何正确执行此类操作的人开发的。即使您不直接使用它,您也可能会发现它实现的算法非常有趣。

于 2010-12-09T00:15:48.023 回答
2

一些评论,虽然我只是猜测你的实际意图:

  • 您正在以原始采样率的44100 倍进行上采样。例如,如果您的输入为 10kHz,则中间cbuf[]频率为 441MHz,这对于大多数音频分析来说有点高。假设您想要cbuf[]44100Hz,那么您只需要44100/OrigSampleRatecbuf[]每个样本中创建样本sampdata[]
  • z在上采样循环中增加了两次。这导致所有奇数元素cbuf[]都具有其原始值。我相信这最终会导致最终buf[]出现无效的奇数元素,这可能是您噪音的来源。如果您没有使用至少两倍的所需元素数量创建它,那么 cbuf 中也存在潜在的缓冲区溢出。
  • 正如史蒂夫所提到的,线性插值通常是最简单的,可以在上采样时产生良好的结果。如果需要,可以进行更复杂的上采样(多项式、样条等)。同样,在下采样时,您可能希望对样本进行平均而不是截断。
于 2010-12-09T00:16:45.513 回答
1

我遇到过的最好的重采样代码:http: //shibatch.sourceforge.net/

获取源代码,并尝试从中学习一些东西。它处于令人讨厌的状态,但该重采样器的结果远远高于其他一切。

于 2012-04-04T09:01:06.577 回答
0

直接使用 FFMpeg 和 avcodec。这是一个很好的例子,展示了如何做到这一点:

http://tdistler.com/projects/audio-resampling-with-ffmpeg

于 2011-04-13T20:20:59.757 回答
0

在重新采样到较低的采样率之前,您必须对原始采样率进行低于 1/2 倍的低通滤波,否则您将引入失真伪影。对于超过采样率 1/2 的频率,频谱将自行折叠。因此,如果您想从 44100 重新采样到 11025,您必须在 11025 或 5500 Hz 的 1/2 处过滤 44100 低通滤波器,因为再现的忠实度会随着较低的带宽而降低,最好使用最大幅度(如 -10Db 的幅度)来执行此操作。对于带符号的 16 位,该值类似于 10^(-10/20)*2^(16-1) 或 10362 +/- 用于最大幅度。确切的算法可以在网上找到,因为这些旧的和基本的想法不应该有知识产权。在没有舍入双精度浮点数的情况下进行所有计算之后,然后将结果四舍五入到其正确的整数值,并在时间尺度上准确插值一组与另一组相交的位置。它需要相当大的想象力和记忆力以及以前的经验,然后将您带入数学家物理程序员的领域。:-O :-)

于 2014-10-01T04:47:27.287 回答
0

线性插值在这里工作得很好。问题在于作者的代码,它不是线性插值 - 它只是采用最接近的值,根本没有任何插值。

这是源采样率 = 5 和目标采样率 = 6 的线性插值示例

src val:    5    10   5    0    5    (this is our audio data, 5 samples)
src idx:    0    1    2    3    4    (source positions for 5 samples)

dst idx:    0   1   2   3   4   5    (destination positions for 6 samples)
dst val:    ?   ?   ?   ?   ?   ?

首先让我们计算比例因子:

scaleCF = srcSampleRate / dstSampleRate             = 0.83333334

让我们看看 dst[2] 对于 dst index 2,我们需要从 src[1] 和从 src[2] 中提取一部分让我们找到最近的源索引及其贡献系数:

idxD = (double)idx * cf;  = 0.833333334 * 2         = 1.6666668

a = (int)idxD = (int)(1.6666668)                    = 1
b = a + 1                                           = 2


bCF = idxD - a = 1.6666668 - 1                      = 0.6666668
aCF = 1.0 - bCF = 1.0 - 0.6666668                   = 0.3333332

res = (float)(aCF * Data[a] + bCF * Data[b])
    = 0.3333332 * 10 + 0.6666668 * 5                = 6.6666666

所以我们在位置 2 的目标值将是 6.6666666 算法可用于下采样/上采样。可能不是最有效的解决方案,也不是最准确的,仍然很容易实现并且效果很好。

于 2021-10-23T17:12:47.413 回答