首页 > 解决方案 > javascript中的音频Float32到Int16转换

问题描述

我正在尝试使用编译成 wasm 并从 Javascript 调用的 C 库在 WebRtc 中创建噪声消除过滤器。

我能够使用 WebAudioApi 捕获 pcm 音频并使用 wasm 处理帧。

我的库只接受 int16 中的输入。

这是我的代码:我尝试了 2 种方法

方法一:

navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
var audiocontext;
var audiosource;
var audiopreprocessnode;

 audiocontext = new (window.AudioContext || window.webkitAudioContext)();
 audiosource = audiocontext.createMediaStreamSource(stream);
 audioPreprocessNode = audioCtx.createScriptProcessor(2048,1,1);

 audiosource.connect(audioPreprocessNode);
 audioPreprocessNode.connect(audioCtx.destination);
 
 audioPreprocessNode.onaudioprocess = function(e) {
 
 var input = new Int16Array(e.inputbuffer.getChannelData(0));
 
 console.log(input.length); // prints 4096

 var denoised_array = Module["_denoise"](input);

 var output = new Float32Array(denoised_array);
 
 console.log(output.length);  // prints 2048
 
 e.outputBuffer.getChannelData(0).set(output); 
 
 
 }
   
}

该方法的优点是它保留了字节数,因此不会有数据丢失

但是当我将它转换回 Float32Array 时,浮点值超出了音频缓冲区限制值 [-1,1]。所以没有音频数据被推送。

方法二:


function floatTo16Bit(inputArray){
    var output = new Int16Array(2048);
    for (var i = 0; i < inputArray.length; i++){
        var s = Math.max(-1, Math.min(1, inputArray[i]));
        output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
    }
    return output;
}
function int16ToFloat32(inputArray) {
    var output = new Float32Array(2048);
    for (var i = 0; i < 2048; i++) {
        var int = inputArray[i];
        var float = (int >= 0x8000) ? -(0x10000 - int) / 0x8000 : int / 0x7FFF;
        output[i] = float;
    }
    return output;
}

navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
var audiocontext;
var audiosource;
var audiopreprocessnode;

 audiocontext = new (window.AudioContext || window.webkitAudioContext)();
 audiosource = audiocontext.createMediaStreamSource(stream);
 audioPreprocessNode = audioCtx.createScriptProcessor(2048,1,1);

 audiosource.connect(audioPreprocessNode);
 audioPreprocessNode.connect(audioCtx.destination);
 
 audioPreprocessNode.onaudioprocess = function(e) {
 
 var input = floatTo16Bit(e.inputbuffer.getChannelData(0));
 
 console.log(input.length); // prints 2048

 var denoised_array = Module["_denoise"](input);

 var output = int16ToFloat32(denoised_array);
 
 console.log(output.length);  // prints 2048
 
 e.outputBuffer.getChannelData(0).set(output); 
 
 
 }
   
}

这种方法的优点是它转换回范围 [-1,1] 内的值。

但是由于字节丢失,音频质量(失真)受到很大影响。

无论如何都可以保留字节并有效地转换 float32 - int16 并返回。

Anyhelp 将是巨大的。

标签: floating-pointweb-audio-apiwebassemblyaudio-processingavaudiopcmbuffer

解决方案


不确定“保留字节”是什么意思,但从 float32 到 int16 的转换必然会丢失信息。但它不应该有太大的失真。毕竟,CD 只有 16 位。

为简单起见,我将通过将浮点数限制为 [-1, 1] 将浮点数转换为 int16,就像您所做的那样,然后乘以 32768 并取整数部分。这给出了一个有符号的 16 位整数。

反之,只需将 int16 值除以 32768。(再次假设您已签署 16 位数字。)


推荐阅读