我使用的重采样算法期望 float 数组,其中包含 -1.0到1.0 范围内的输入样本。音频数据为 16位 PCM,采样率为 22khz 。
我想将音频从22khz下采样到8khz,如何将字节数组中的样本表示为浮点数> = -1和并返回字节数组?
最佳答案
您问两个问题:
请注意,该问题已更新,以指示#1已在其他地方处理,但是我将保留我的回答的这一部分,以防其他人受到帮助。
1.如何将采样率从22kHz下调至8kHz?
一个评论者暗示这可以通过FFT解决。这是不正确的(重新采样的第一步是过滤。如果您感兴趣,我在这里提到为什么不使用FFT进行过滤:http://blog.bjornroche.com/2012/08/when-to-not-use-fft.html)。
对信号重新采样的一种非常好的方法是使用polyphase filter。但是,即使对于有信号处理经验的人来说,这也相当复杂。您还有其他几种选择:
听起来您已经采用第一种方法,这很棒。
快速而肮脏的解决方案听起来不那么理想,但是由于您将频率降至8 kHz,因此我认为音质不是您的首要任务。一种快速而肮脏的选择是:
对于语音应用来说,这种技术应该已经足够好了。但是,我还没有尝试过,所以我不确定,因此我强烈建议您使用其他人的库。
如果您真的想实现自己的高质量采样率转换(例如多相滤波器),则应该对其进行研究,然后再对https://dsp.stackexchange.com/提出任何问题,而不是此处。
2.如何从float [-1,1]转换为16位int并返回?
这已经由c.fogelklou开始,但是让我修饰一下。
首先,16位整数的范围是-32768到32767(通常对16位音频进行签名)。要将int转换为float,请执行以下操作:
float f;
int16 i = ...;
f = ((float) i) / (float) 32768
if( f > 1 ) f = 1;
if( f < -1 ) f = -1;
通常,您不需要执行额外的“边界”操作(实际上,如果确实使用的是16位整数,则不需要这样做),但是如果您出于某些原因拥有一些> 16位整数,就可以使用它。要转换回来,请执行以下操作:
float f = ...;
int16 i;
f = f * 32768 ;
if( f > 32767 ) f = 32767;
if( f < -32768 ) f = -32768;
i = (int16) f;
在这种情况下,通常有必要注意超出范围的值,尤其是大于32767的值。您可能会提示说,这会导致f = 1产生一些失真。有关此问题的一些(不完整的)讨论,请参见this blog post。这不仅仅是“足以胜任政府工作”。换句话说,除非您担心最终的声音质量,否则它将正常工作。由于您将达到8kHz,因此我认为事实并非如此,因此此答案很好。
但是,为了完整起见,我必须添加一点:如果您要使事情绝对原始,请记住,这种转换会导致失真。为什么?因为从float转换为int时的误差与信号相关。事实证明,该错误的相关性非常糟糕,即使它很小,您实际上也可以听到。 (幸运的是,它足够小,对于语音和低动态范围的音乐来说,无关紧要)。要消除此错误,必须在从float到int的转换中使用dither。同样,如果您对此很在意,请进行研究并在https://dsp.stackexchange.com/上询问相关的特定问题,而不是在此处。
您可能也对我在数字音频编程基础上的幻灯片中的幻灯片感兴趣,该幻灯片也有关于此主题的幻灯片,尽管它基本上说的是同一件事(甚至比我刚才说的要少):http://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html