以编程方式增加音频样本数组的音高

时间:2011-03-01 15:00:52

标签: audio signal-processing pitch

音响计算世界的好心人,

我有一系列样本可以呈现录音。让我们说它在44100Hz时是5秒。如何以更高的音高回放?是否可以动态增加和减少音高?就像让音高慢慢增加到速度加倍然后再下降。

换句话说,我想录制并播放它,好像被d.j“刮伤”一样。

永远欢迎伪代码。我将在C中写这篇文章。

谢谢,


编辑1

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

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


编辑2

另外,我想自己这样做。请不要图书馆(除非你觉得我可以选择代码并找到有趣的东西)。


编辑3

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


PS我已经开始对此表示赏心,不是因为我认为已经给出的答案无效。我只是觉得在这个问题上获得更多反馈会很好。



获奖者

老实说,我希望我可以将赏金分配给几个不同的答案,因为我认为这些答案非常有用。特别感谢丹尼尔传递给我一些代码,而AShelly和Hotpaw2则提供了如此详细的回复。

最终虽然我使用了由datageist引用的another SO question的答案,因此该奖项归他所有。

再次感谢大家!

6 个答案:

答案 0 :(得分:10)

看看Nosredna对此(非常相似)SO问题的答案中的“大象”论文: How do you do bicubic (or other non-linear) interpolation of re-sampled audio data?

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

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

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

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

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

答案 1 :(得分: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,也可以这样做。

如果这会在比率&gt;时产生嘈杂的伪影。 1,尝试使用此技术(from this question

替换*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的需要......

答案 2 :(得分:3)

是的,有可能。

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

<击>

这是一个Time Pitch stretching overview from DSP Dimensions。您还可以使用Google进行阶段声码器算法。

增加:

如果您想要“刮擦”,就像DJ可能会对物理转盘上的LP一样,您不需要时间间距修改。划痕会改变音高和播放速度相同的量(不是独立的,需要时间间距修改)。

结果阵列的长度不会相同,但是由于音高/速度变化不会更短或更长。

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

您需要一种包含低通滤波器的插值方法,否则您将听到可怕的混叠噪声。 (例外情况可能是您的原始声音文件已经过低于采样率十倍或更多的低通滤波。)

答案 3 :(得分:3)

如果您希望轻松完成此操作,请参阅AShelly的建议 [编辑:事实上,无论如何首先尝试] 。如果您需要高质量,则基本上需要phase vocoder

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

  1. 运行FFT
  2. 按因子更改所有频率
  3. 运行逆FFT
  4. 如果您打算自己实施,请务必阅读a thorough explanation of how a phase vocoder works。该算法确实需要比上述三步简化更多的考虑因素。

    当然,ready-made实施exist,但从我收集的问题中你想自己做。

答案 4 :(得分:0)

减小和增加音高就像以比44.1kHz更低或更高的速率播放样本一样简单。这将产生较慢/较快的录音,但您需要添加真实记录的“刮擦”。

答案 5 :(得分:0)

This帮助我重新取样,这是你需要从对面看的同样的东西。

如果你找不到代码,请ping我,我有一个很好的C例程。