我使用重新采样算法预计浮含有输入样品中的范围-1.0到1.0阵列。 音频数据是16位 PCM与采样率22kHz的 。
我想从下采样到22kHz的8kHz的音频,如何表示在字节数组的样品作为浮点数> = -1和<= 1并返回到字节数组?
我使用重新采样算法预计浮含有输入样品中的范围-1.0到1.0阵列。 音频数据是16位 PCM与采样率22kHz的 。
我想从下采样到22kHz的8kHz的音频,如何表示在字节数组的样品作为浮点数> = -1和<= 1并返回到字节数组?
你问两个问题:
如何从下采样的22kHz到8kHz的?
如何从浮[-1,1]转换为16位int和回?
请注意,这个问题已被更新,以表明#1是照顾其他地方,但我会离开的情况下我的回答的那部分它可以帮助别人。
一个评论者暗示,这可能与FFT来解决。 这是不正确的(在采样中的一个步骤是过滤我提到为什么不使用FFT用于过滤在这里,如果你有兴趣: http://blog.bjornroche.com/2012/08/when-to-not-use -fft.html )。
重新采样信号的一种非常好的方式是用多相滤波器 。 然而,这是相当复杂的,甚至有人在信号处理经验。 您有其他几个选项:
这听起来像你已经与第一种方法,这是伟大的了。
一个快速和肮脏的解决方案不会听起来不错,但因为你会下降到8千赫,我猜音质不是你的首要任务。 一个快速和肮脏的方法是:
这种技术应该比语音应用足够好了。 但是,我还没有尝试过,所以我不肯定知道,所以我强烈建议使用别人的库。
如果你真的想实现自己的高品质的采样率转换,比如多相滤波器,你应该研究它,然后问你的任何问题上https://dsp.stackexchange.com/ ,不在这里。
这是已经开始通过c.fogelklou,但让我美化。
要下手,16位整数的范围为-32768至32767(通常是16位音频签署)。 由Int转换为浮动你这样做:
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的,我认为我们已经确定,并非如此,所以这个答案是罚款。
然而,为了完整,我必须补充一点:如果你试图让事情绝对纯净,要记住,这种转换引入失真。 为什么? 因为从浮点数转换为INT当误差与信号相关。 事实证明,这个错误的相关性是可怕的,你其实可以听到它,即使它是非常小的。 (幸好它足够小,对于像语音和低动态范围的音乐也没多大关系)为了消除这种错误,你必须使用一些所谓的抖动在转换从float到int。 再次,如果这是你关心的东西,研究它,并要求对相关的,具体问题https://dsp.stackexchange.com/ ,不在这里。
您可能也有兴趣从我的数字音频节目,其中有关于这一主题幻灯片的基础知识讲的幻灯片,但它基本上是说同样的事(甚至比我刚才说的少): HTTP://博客.bjornroche.com / 2011/11 /载玻片从-基本面的-audio.html
16位PCM具有范围 - 32768〜32767。因此,通过(1.0F / 32768.0f)乘以每个PCM样本的在float一个新的数组,并传递到您的重采样。
让我们再回到漂浮重采样后,乘以32768.0,饱和(夹任何范围之外 - 32768〜32767),圆形(或抖动作为比约恩提到),然后转换回短。
测试代码,显示前进和后退转换使用乘以无位误差:
// 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;
}