如何将字节数组中的pcm样本转换为-1.0到1.0之间的浮点数并返回?

我使用的重采样algorithm期望float数组包含范围从-1.0到1.0的input样本。 audio数据是采样率为22khz的 16位 PCM。

我想将audio从22khz下采样到8khz,如何将字节数组中的采样表示为浮点> = -1和<= 1并返回字节数组?

Solutions Collecting From Web of "如何将字节数组中的pcm样本转换为-1.0到1.0之间的浮点数并返回?"

你问两个问题:

  1. 如何从22kHz下采样到8kHz?

  2. 如何将float [-1,1]转换为16位int并返回?

请注意,这个问题已经更新,表明#1是在其他地方照顾,但我会留下我的答案的一部分,以防万一它帮助别人。

1.如何从22kHz下采样到8kHz?

一位评论者暗示,这可以通过FFT来解决。 这是不正确的(重新采样的一个步骤是过滤,我提到了为什么不在这里使用FFT进行过滤,以防您有兴趣: http : //blog.bjornroche.com/2012/08/when-to-not-use -fft.html )。

重采样信号的一个很好的方法是使用多相滤波器 。 然而,这是相当复杂的,即使对于有信号处理经验的人也是如此。 您还有其他几个select:

  • 使用实现高质量重采样的库,如libsamplerate
  • 做一些快速和肮脏的事情

这听起来像你已经走了第一个方法,这是伟大的。

一个快速和肮脏的解决scheme听起来不会很好,但是因为你正在下降到8千赫兹,我猜音质不是你的首要任务。 一个快速和肮脏的select是:

  • 对信号应用低通滤波器。 尽量摆脱4 kHz以上的audio。 你可以使用这里描述的filter(尽pipe理想情况下你想要的东西比那些filter更陡峭,但至less比没有更好)。
  • 从原始信号中select每2.75个样本,以产生新的重采样信号。 当您需要非整数样本时,请使用线性插值。 如果你需要线性插值的帮助,请在这里尝试。

这种技术对于语音应用程序来说应该足够好了。 但是,我没有尝试过,所以我不确定,所以我强烈build议使用别人的库。

如果您真的想要实现自己的高质量采样率转换(如多相滤波器),则应该研究它,然后询问您在https://dsp.stackexchange.com/上提出的任何问题,而不是在这里&#x3002;

2.如何将float [-1,1]转换为16位int并返回?

这是由c.fogelklou已经开始,但让我美化。

首先,16位整数的范围是-32768到32767(通常是16位audio被签名)。 要从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带来一些失真。这个问题引起了热烈的争论。 有关这方面的一些(不完整)讨论,请参阅此博客文章 。

这不仅仅是“政府工作够好”。 换句话说,除非您关心最终的音质,否则它将会正常工作。 既然你要8kHz,我认为我们已经确定,情况并非如此,所以这个答案是好的。

但是,为了完整起见,我必须补充一点:如果你想保持绝对原始的东西,请记住,这种转换引入了失真。 为什么? 因为从float转换为int时的错误与信号相关。 事实certificate,这个错误的相关性是可怕的,你可以真正听到它,即使它很小。 (幸运的是它足够小,对于语音和低dynamic范围音乐这样的事情并不重要)为了消除这个错误,你必须在从float到int的转换中使用所谓的抖动 。 再一次,如果这是你关心的,研究它,并在https://dsp.stackexchange.com/上提出相关的具体问题,而不是在这里&#x3002;

虽然它基本上说的是相同的东西(甚至可能比我刚才所说的还要less),但是您也可能对我的谈话中关于数字audio节目的基础知识的幻灯片感兴趣,该幻灯片在这个主题上有一个幻灯片: http:// blog .bjornroche.com / 2011/11 /载玻片从-基本面的-audio.html

16位PCM的范围是32768到32767.因此,将你的每个PCM采样乘以(1.0f / 32768.0f)到一个新的浮点数组中,并将其传递给你的resample。

在重采样之后回到浮动状态,乘以32768.0,饱和(夹住32768到32767范围以外的任何东西),圆形(或者像Björn提到的抖动),然后回缩。

testing代码显示转换正向和反向使用乘法没有位错误:

 // PcmConvertTest.cpp : Defines the entry point for the console application. // #include <assert.h> #include <string.h> #include <stdint.h> #define SZ 65536 #define MAX(x,y) ((x)>(y)) ? (x) : (y) #define MIN(x,y) ((x)<(y)) ? (x) : (y) int main(int argc, char* argv[]) { int16_t *pIntBuf1 = new int16_t[SZ]; int16_t *pIntBuf2 = new int16_t[SZ]; float *pFloatBuf = new float[SZ]; // Create an initial short buffer for testing for( int i = 0; i < SZ; i++) { pIntBuf1[i] = (int16_t)(-32768 + i); } // Convert the buffer to floats. (before resampling) const float div = (1.0f/32768.0f); for( int i = 0; i < SZ; i++) { pFloatBuf[i] = div * (float)pIntBuf1[i]; } // Convert back to shorts const float mul = (32768.0f); for( int i = 0; i < SZ; i++) { int32_t tmp = (int32_t)(mul * pFloatBuf[i]); tmp = MAX( tmp, -32768 ); // CLIP < 32768 tmp = MIN( tmp, 32767 ); // CLIP > 32767 pIntBuf2[i] = tmp; } // Check that the conversion went int16_t to float and back to int for every PCM value without any errors. assert( 0 == memcmp( pIntBuf1, pIntBuf2, sizeof(int16_t) * SZ) ); delete pIntBuf1; delete pIntBuf2; delete pFloatBuf; return 0; }