首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用getChannelData API从WebAudio方法获取麦克风PCM数据不起作用

使用getChannelData API从WebAudio方法获取麦克风PCM数据不起作用
EN

Stack Overflow用户
提问于 2019-12-09 16:22:47
回答 1查看 1.6K关注 0票数 3

我正在尝试使用Web从麦克风中获取原始PCM样本。经过一番研究,我似乎应该得到“包含与信道关联的PCM数据的Float32Array”了。这个流程对我有用,但是当我尝试把PCM样本放到WAV文件中时,我会得到随机噪声,而不是我在麦克风录音时说的话。下面是使用AudioBuffer.getChannelData()获取PCM数据的代码片段,您可以直接粘贴到浏览器控制台中:

代码语言:javascript
运行
复制
let recLength = 0;
let recBuffers = [];

let bufferLen = 4096;
let numChannels = 1;
let mimeType = 'audio/wav';

window.AudioContext = window.AudioContext || window.webkitAudioContext;
let audio_context = new AudioContext();

let audio_stream;

navigator.mediaDevices.getUserMedia({audio: true}).then(function (stream)
{
    audio_stream = stream;
});

// wait a sec or two

let source = audio_context.createMediaStreamSource(audio_stream);
let context = source.context;
let sampleRate = context.sampleRate; // you will need to know this number for creating a WAV file.

let node = (context.createScriptProcessor || context.createJavaScriptNode).call(context, bufferLen, numChannels, numChannels);

node.onaudioprocess = function(e)
{
    const inputBuffer = e.inputBuffer.getChannelData(0);

    recBuffers.push(inputBuffer);
    recLength += inputBuffer.length;
};

source.connect(node);
node.connect(context.destination);

// wait 10 seconds or so, while speaking into microphone

node.disconnect();

function mergeBuffers()
{
    let result = new Float32Array(recLength);
    let offset = 0;
    for (let i = 0; i < recBuffers.length; i++) {
        result.set(recBuffers[i], offset);
        offset += recBuffers[i].length;
    }
    return result;
}

let mergedBuffer = mergeBuffers();

let normalBuffer = [];
for (let i = 0; i < mergedBuffer.length; i++)
{
    normalBuffer.push(mergedBuffer[i]);
}

JSON.stringify(normalBuffer);

现在,如果我复制最后一行的字符串输出,并将其传递给任何生成WAV文件的库,则输出WAV文件只是随机噪声。如果您想自己复制这一点,我将使用这个NodeJS库编写WAV文件:

代码语言:javascript
运行
复制
let arr = [1,2,3]; // replace this array with the string output of normalBuffer from above

samples = [[]];
for (let i = 0; i < arr.length; i++)
{
    samples[0].push(arr[i]);
}

const fs = require("fs");
const WaveFile = require("wavefile");

let wav = new WaveFile();
wav.fromScratch(1, 44100, "32f", samples); // the sampling rate (second parameter) could be different on your machine, but you can print it out in the code snippet above to find out
fs.writeFileSync("test.wav", wav.toBuffer());

我也尝试过将样本转换成未签名的16位Ints,但我仍然有同样的问题,我尝试将样本乘以一些常量,以防录音的音量太低,但也没有效果。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-10 03:13:40

问题(至少在Chrome中)是,ScriptProcessorNode一直在重复使用相同的底层音频缓冲区。这意味着您的Float32Array数组中的每个recBuffers都指向相同的内存。您可以通过复制数据来避免这种情况。

台词..。

代码语言:javascript
运行
复制
const inputBuffer = e.inputBuffer.getChannelData(0);

..。变成..。

代码语言:javascript
运行
复制
const inputBuffer = new Float32Array(bufferLen);

e.inputBuffer.copyFromChannel(inputBuffer, 0);

请记住,这在Safari中是行不通的,因为它还没有copyFromChannel方法。需要手动复制缓冲区。

如果您只想记录wav文件,那么重用像可扩展媒体记录器这样的现有库可能会更容易。但我想您只创建了一个wav文件来调试这个问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59252870

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档