使用WebAudioApi在Javascript中对音频PCM数据进行上采样



对于一个项目,我正在通过Java服务器上的WebSockets检索实时音频流。在服务器上,我以8位带符号字节值的形式(两个字节组成一个样本)处理16Bit/8000hz/mono中的样本。然而,在浏览器上,支持的最低采样率是22050赫兹。因此,我的想法是"简单地"将现有的8000赫兹增加到32000赫兹,这是受支持的,在我看来是一个简单的计算。

到目前为止,我已经尝试过线性上采样和余弦插值,但两者都不起作用。除了听起来真的失真之外,第一个还添加了一些咔嗒声。我可能在Chrome中的WebAudioAPI也有问题,但至少声音正在播放,几乎无法识别它应该是什么。所以我想没有编解码器或endianes问题。

以下是当接收到带有声音数据的二进制数据包时执行的完整代码。为了简单起见,我一直在创建新的缓冲区和缓冲源(是的,对性能没有好处)。data是一个ArrayBuffer。首先,我将采样转换为Float,然后进行上采样。

//endianess-aware buffer view
var bufferView=new DataView(data),
//the audio buffer to set for output
buffer=_audioContext.createBuffer(1,640,32000),
//reference to underlying buffer array
buf=buffer.getChannelData(0),
floatBuffer8000=new Float32Array(160);

//16Bit => Float
for(var i=0,j=null;i<160;i++){
j=bufferView.getInt16(i*2,false);
floatBuffer8000[i]=(j>0)?j/32767:j/-32767;
}   
//convert 8000 => 32000
var point1,point2,point3,point4,mu=0.2,mu2=(1-Math.cos(mu*Math.PI))/2;
for(var i=0,j=0;i<160;i++){
//index for dst buffer
j=i*4;
//the points to interpolate between
point1=floatBuffer8000[i];
point2=(i<159)?floatBuffer8000[i+1]:point1;
point3=(i<158)?floatBuffer8000[i+2]:point1;
point4=(i<157)?floatBuffer8000[i+3]:point1;

//interpolate
point2=(point1*(1-mu2)+point2*mu2);
point3=(point2*(1-mu2)+point3*mu2);
point4=(point3*(1-mu2)+point4*mu2);
//put data into buffer
buf[j]=point1;
buf[j+1]=point2;
buf[j+2]=point3;
buf[j+3]=point4;
}
//playback
var node=_audioContext.createBufferSource(0);
node.buffer=buffer;
node.connect(_audioContext.destination);
node.noteOn(_audioContext.currentTime);

终于找到了解决方案。从16Bit到Float的转换是错误的,它只需要是

floatBuffer8000[i]=j/32767.0;

此外,向API提供大量的小样本也不能很好地工作,因此您需要缓冲一些样本并一起播放它们。

最新更新