Ran*_*med 24 java floating-point android signal-processing
我使用的重采样算法需要包含-1.0到1.0范围内的输入样本的float数组.音频数据是16位 PCM,采样率为22khz.
我想将音频从22khz下采样到8khz,如何将字节数组中的样本表示为浮点数> = -1且<= 1并返回字节数组?
Bjo*_*che 51
你问两个问题:
如何从22kHz下采样到8kHz?
如何从float [-1,1]转换为16位int和back?
请注意,问题已经更新,表明#1在其他地方得到了处理,但我会留下我的答案的一部分,以防它帮助其他人.
一位意见提供者暗示这可以通过FFT解决.这是不正确的(重新采样的一步是过滤.我提到为什么不在这里使用FFT进行过滤,如果你感兴趣的话:http://blog.bjornroche.com/2012/08/when-to-not-use -fft.html).
重采样信号的一种非常好的方法是使用多相滤波器.然而,即使对于有信号处理经验的人来说,这也非常复杂.您还有其他几种选择:
听起来你已经采用了第一种方法,这很棒.
一个快速而肮脏的解决方案听起来不会那么好,但是由于你的音频低至8 kHz,我猜测音质不是你的首要任务.一个快速而肮脏的选择是:
这种技术应该足以满足语音应用的需求.但是,我没有尝试过,所以我不确定,所以我强烈建议使用其他人的库.
如果您真的想要实现自己的高质量采样率转换,例如多相滤波器,您应该对其进行研究,然后在https://dsp.stackexchange.com/上提出您的问题,而不是在这里.
这是由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;
Run Code Online (Sandbox Code Playgroud)
你通常不需要做那些额外的"边界",(事实上,如果你真的使用的是16位整数,你就不会这样做),但是如果出于某种原因你有一些> 16位整数的情况就会存在.
要转换回来,请执行以下操作:
float f = ...;
int16 i;
f = f * 32768 ;
if( f > 32767 ) f = 32767;
if( f < -32768 ) f = -32768;
i = (int16) f;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,通常需要注意超出范围的值,尤其是大于32767的值.您可能会抱怨这会为f = 1引入一些失真.这个问题引起了激烈的争论.有关此问题的一些(不完整)讨论,请参阅此博客文章.
这不仅仅是"对政府工作而言足够好".换句话说,除非您关注最终的音质,否则它将正常工作.由于你要达到8kHz,我认为我们已经确定并非如此,所以这个答案很好.
但是,为了完整起见,我必须补充一点:如果你想保持绝对原始的东西,请记住这种转换会引入失真.为什么?因为从float转换为int时的错误与信号相关.事实证明,该错误的相关性非常糟糕,你可以实际听到它,即使它非常小.(幸运的是,它足够小,对于像语音和低动态范围音乐这样的事情并不重要)为了消除这个错误,你必须在从float到int的转换中使用一个叫做dither的东西.再说一遍,如果这是你关心的事情,请研究它并在https://dsp.stackexchange.com/上询问相关的具体问题,而不是在这里.
您可能也会对我关于数字音频编程基础知识的幻灯片感兴趣,该演示文稿有一个关于此主题的幻灯片,虽然它基本上说同样的事情(甚至可能比我刚才说的还要少):http:// blog .bjornroche.com/2011/11 /载玻片从-基本面的-audio.html
c.f*_*lou 12
16位PCM具有范围 - 32768〜32767.因此,通过(1.0F/32768.0f)乘以每个PCM样本的在float一个新的数组,并传递到您的重采样.
重新采样后重新浮动,乘以32768.0,饱和(剪切范围之外的任何东西 - 32768到32767),圆形(或Björn提到的抖动)然后再回到短路.
使用没有位错误的乘法显示向前和向后转换的测试代码:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23224 次 |
| 最近记录: |