13

你好音频计算世界的好心人,

我有一组代表录音的样本。假设它在 44100Hz 时为 5 秒。我将如何以更高的音调回放这个?是否可以动态增加和减少音高?就像让音高慢慢增加到两倍的速度,然后再降下来。

换句话说,我想录制并播放它,就好像它被 dj '刮擦'

伪代码总是受欢迎的。我将用 C 来写这个。

谢谢,


编辑 1

请允许我澄清我的意图。我想将播放保持在 44100Hz,因此我需要在播放前操作样本。这也是因为我想将音高增加的音频与以正常速率运行的音频混合

以另一种方式表达,也许我需要以某种方式在相同数量的样本上缩小音频?这样播放时声音会更快吗?


编辑 2

另外,我想自己做这件事。请不要使用库(除非您觉得我可以通过代码挑选并找到有趣的东西)。


编辑 3

一段用 C 编写的示例代码,它接受 2 个参数(样本数组和音高因子),然后返回一个新音频数组,这太棒了!


PS我已经开始赏金不是因为我认为已经给出的答案是无效的。我只是认为获得有关该主题的更多反馈会很好。



赏金

老实说,我希望我可以将赏金分配给几个不同的答案,因为它们有很多我认为非常有帮助的。特别感谢 Daniel 向我传递了一些代码,以及 AShelly 和 Hotpaw2 提供了如此详细的回复。

最终,尽管我使用了datageist 引用的另一个 SO 问题的答案,因此该奖项归他所有。

再次感谢大家!

4

6 回答 6

11

看看 Nosredna 对这个(非常相似的)SO 问题的回答中的“大象”论文: 你如何对重新采样的音频数据进行双三次(或其他非线性)插值?

从第 37 页开始提供示例实现,作为参考,AShelly 的答案对应于线性插值(在同一页上)。稍加调整,论文中的任何其他公式都可以插入该框架。

要评估给定插值方法的质量(并了解使用“更便宜”方案的潜在问题),请查看此页面:

http://www.discodsp.com/highlife/aliasing/

对于比您可能想要处理的更多理论(使用源代码),这也是一个很好的参考:

https://ccrma.stanford.edu/~jos/resample/

于 2011-03-19T12:21:33.310 回答
8

一种方法是在原始波中保留一个浮点索引,并将插值样本混合到输出波中。

//Simulate scratching of `inwave`: 
// `rate` is the speedup/slowdown factor. 
// result mixed into `outwave`
// "Sample" is a typedef for the raw audio type.
void ScratchMix(Sample* outwave, Sample* inwave, float rate)
{
   float index = 0;
   while (index < inputLen)
   {
      int i = (int)index;          
      float frac = index-i;      //will be between 0 and 1
      Sample s1 = inwave[i];
      Sample s2 = inwave[i+1];
      *outwave++ += s1 + (s2-s1)*frac;   //do clipping here if needed
      index+=rate;
   }

}

如果您想rate即时更改,也可以这样做。

如果在 rate > 1 时这会产生嘈杂的伪影,请尝试用*outwave++ += s1 + (s2-s1)*frac;这种技术替换(来自这个问题

*outwave++ = InterpolateHermite4pt3oX(inwave+i-1,frac);

在哪里

public static float InterpolateHermite4pt3oX(Sample* x, float t)
{
    float c0 = x[1];
    float c1 = .5F * (x[2] - x[0]);
    float c2 = x[0] - (2.5F * x[1]) + (2 * x[2]) - (.5F * x[3]);
    float c3 = (.5F * (x[3] - x[0])) + (1.5F * (x[1] - x[2]));
    return (((((c3 * t) + c2) * t) + c1) * t) + c0;
}

在“Windows Startup.wav”上使用系数为 1.1 的线性插值技术的示例。原版在上面,加速版在下面:

它可能在数学上并不完美,但听起来应该,并且应该可以很好地满足 OP 的需求。

于 2011-03-01T20:48:22.333 回答
3

是的,有可能。

但这不是少量的伪代码。您要求的是时间音高修改算法,这是相当大且复杂的 DSP 代码量,以获得不错的结果。

这是来自 DSP Dimensions 的 Time Pitch 拉伸概述。你也可以谷歌搜索相位声码器算法。

添加:

如果您想“从头开始”,就像 DJ 可能在物理转盘上使用 LP 所做的那样,您不需要时间音高修改。刮擦会以相同的量改变音高和演奏速度(不是独立的,因为需要时间音高修改)。

并且生成的数组的长度不会相同,但会随着俯仰/速度的变化而变短或变长。

您可以更改音高,并以相同的比率使声音播放更快或更慢,只需使用适当过滤的插值对信号进行重新采样即可。只需通过所需速率变化的浮点加法来移动每个采样点,而不是 1.0,然后在该点过滤和插值数据。使用窗口 Sinc 插值内核进行插值,低通滤波器转换频率低于原始和插值局部采样率的较低值,将工作得相当好。在网上搜索“windowed Sinc interpolation”会返回很多合适的结果。

您需要一种包含低通滤波器的插值方法,否则您将听到可怕的混叠噪声。(如果您的原始声音文件已经被严重低通滤波了十倍或更长时间,则可能是例外情况。)

于 2011-03-02T00:51:18.610 回答
3

如果您希望轻松完成此操作,请参阅 AShelly 的建议[编辑:事实上,无论如何都要先尝试]。如果你需要好的质量,你基本上需要一个相位声码器

相位声码器的基本思想是找到声音所包含的频率,根据需要更改这些频率并重新合成声音。所以一个残酷的简化是:

  1. 运行 FFT
  2. 将所有频率改变一个因子
  3. 运行逆 FFT

如果您要自己实现这一点,您绝对应该阅读有关相位声码器工作原理的详尽说明。该算法确实需要比上面的三步简化更多的考虑。

当然,存在现成的实现,但是从我收集的问题来看,您想自己做这件事。

于 2011-03-24T11:47:35.737 回答
0

降低和提高音高就像以低于或高于 44.1kHz 的速率播放样本一样简单。这将产生更慢/更快的录音声音,但您需要添加真实录音的“粗糙度”。

于 2011-03-01T15:12:13.083 回答
0

有助于我重新采样,这与您需要从对面看的相同。

如果您找不到代码,请联系我,我为此提供了一个不错的 C 例程。

于 2011-03-01T19:46:00.803 回答