12

我正在尝试在用户上传短录音(例如,1 到 12 秒长)的应用引擎网站上使用recorderjs 。我注意到我上传的 WAV 文件比我预期的要大得多。例如,我刚刚创建了一个持续大约 9 秒的记录,上传的 blob 为 1736769 字节,即 > 1.5 兆字节。

问题:

如何修改 recorderjs 代码(或我自己的代码——也许我错误地使用了 recorderjs)以使我的音频 blob 具有较低的比特率?我希望 10 秒的录音安全地低于 1 MB。

我的猜测是我需要在这里修改 encodeWAV 函数,或者可能是 exportWAV,但我不确定如何。在 exportWAV 中删除交错缓冲区的所有其他元素是否有意义?有没有更智能的方法来做到这一点?导出的 WAV 的比特率如何取决于我的计算机的属性(例如我的声卡的采样率)?

如果可能有帮助,我可以在我自己的代码中添加一些细节。

编辑:如果您想查看实时示例,请安装 google chrome beta 并尝试此页面。在我的电脑上,5-10 秒长的录音超过 1 MB。

非常感谢,

阿德里安

4

3 回答 3

22

在我的例子中,Chrome 以 96kHz 录制音频,Firefox 以 44.1kHz 录制音频,这会产生巨大的WAV文件。我在 recorderWorker.js 中实现了一个下采样功能,您可以在其中选择所需的采样率,例如 16000。

function downsampleBuffer(buffer, rate) {
    if (rate == sampleRate) {
        return buffer;
    }
    if (rate > sampleRate) {
        throw "downsampling rate show be smaller than original sample rate";
    }
    var sampleRateRatio = sampleRate / rate;
    var newLength = Math.round(buffer.length / sampleRateRatio);
    var result = new Float32Array(newLength);
    var offsetResult = 0;
    var offsetBuffer = 0;
    while (offsetResult < result.length) {
        var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
        var accum = 0, count = 0;
        for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
            accum += buffer[i];
            count++;
        }
        result[offsetResult] = accum / count;
        offsetResult++;
        offsetBuffer = nextOffsetBuffer;
    }
    return result;
}

我在导出 wav 文件时调用它:

function exportWAV(rate, type) {
    var bufferL = mergeBuffers(recBuffersL, recLength);
    var bufferR = mergeBuffers(recBuffersR, recLength);
    var interleaved = interleave(bufferL, bufferR);
    var downsampledBuffer = downsampleBuffer(interleaved, rate);
    var dataview = encodeWAV(rate, downsampledBuffer, false);
    var audioBlob = new Blob([ dataview ], {
        type : type
    });

    this.postMessage(audioBlob);
}
于 2014-10-07T21:04:00.737 回答
4

你可以尝试几件事。首先,我认为您正在讨论“删除交错缓冲区的所有其他元素”(将声音转换为单声道)。

为此,您可以选择保留左声道或右声道。您可以将“交错”功能更改为:

function interleave(inputL, inputR){
  return inputL; // or inputR
}

如果您想保留两个通道,但“平移”它们都居中(到单个单声道),您可以执行以下操作:

function interleave(inputL, inputR){
  var result = new Float32Array(inputL.length);
  for (var i = 0; i < inputL.length; ++i)
    result[i] = 0.5 * (inputL[i] + inputR[i]);
  return result;
}

话虽如此,可能还有很多其他地方您必须将编码音频从表示为立体声更改为单声道。但是,我的猜测是(而且我没有使用 recorder.js,所以我不知道它的内部工作原理),recorderWorker 中的第 113/114 行可能会更改为 1。

我的猜测是,您只需更改此处提到的两个位置(interleave 函数和设置通道计数的位置 [第 114 行])就可以逃脱,因为: interleave 和 encodeWAV 仅通过 exportWAV 函数调用,所以不是触摸原始工作人员如何录制音频(并且它一直在录制立体声)希望不会破坏它。在这种情况下,我们只会对存储的音频进行更改。

于 2013-05-01T14:48:37.650 回答
3

我正在使用相同的记录器代码,我需要降低比特率。我的解决方案生成一个 11025Hz 的单声道文件。它不是很优雅,所以如果有人对我进行更正,我会很高兴。

首先,我将函数中的采样率更改init为 11025,而不是音频上下文的比特率(这是不优雅的部分,因为上下文可能不是 44100Hz)。

interleave用这个替换功能内容

var length = inputL.length / 4;
var result = new Float32Array(length);

var index = 0,
  inputIndex = 0;

while (index < length) {
    result[index++] = 0.25 * (inputL[inputIndex++] + inputL[inputIndex++] +
                              inputL[inputIndex++] + inputL[inputIndex++]);
}

return result;

这仅占用左通道,并将结果中的每 4 个缓冲区样本转换为 1,因此占用的内存更少。如果比特率以相同的比率(除以 4,例如 11025)更改,则文件听起来相同,但会小得多。

我还将频道计数更改encodeWAV为一个

/* channel count */
 view.setUint16(22, 1, true);

与最初制作的文件相比,录音的大小将是 1/8。

于 2013-07-20T17:33:38.433 回答