Преобразование аудио Float32 в Int16 в javascript - PullRequest
0 голосов
/ 13 июля 2020

Я пытаюсь создать фильтр шумоподавления в WebRt c, используя мою C библиотеку, скомпилированную в wasm и вызываемую из Javascript.

Я могу записать звук pcm с помощью WebAudioApi и обработать фрейм с помощью wasm.

Моя библиотека принимает ввод только в int16.

Вот мой код: Я пробовал 2 метода

Метод 1:

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 ]. Таким образом, аудиоданные не передаются.

Метод 2:


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 было бы здорово.

1 Ответ

2 голосов
/ 13 июля 2020

Не уверен, что вы имеете в виду под «сохранить байты», но преобразование из float32 в int16 обязательно приведет к потере информации. Но не должно быть настолько сильного искажения. В конце концов, компакт-диски имеют всего 16 бит.

Для простоты я бы преобразовал float в int16, зафиксировав значение float до [-1, 1], как вы это сделали, а затем просто умножив на 32768 и взяв целую часть. Это дает 16-битное целое число со знаком.

To go В противном случае просто разделите значение int16 на 32768 (опять же, это предполагает, что вы подписали 16-битные числа.)

...