Decrease bitrate on WAV file created with recorderjs

♀尐吖头ヾ 提交于 2019-11-27 12:14:06

You could try a couple of things. First off, I think you're on to something about "dropping every other element of the interleaved buffer" (converting the sound to mono).

For that you could choose to keep the left or the right channel. You could change the "interleave" function to be:

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

If you wanted to keep both channels, but "pan" them both center (to the single mono channel), you could do something like:

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;
}

That being said, there are potentially a lot of other placed you would have to change the encoded audio from being denoted as stereo to mono. However, my guess is (and I haven't used recorder.js, so I don't know it's inner workings), line 113/114 in the recorderWorker could probably changed to 1.

My guess is that you could get away with just changing the two places mentioned here (the interleave function, and the place where channel-count is set [line 114]) because: interleave and encodeWAV are only called through the exportWAV function, so not touching how the original worker has been recorder audio (and it's been recording stereo) hopefully won't break it. We would in that case only be making changes to the audio that was stored.

In my case Chrome records audio at 96kHz and Firefox at 44.1kHz, that makes huge WAV files. I implemented a downsampling function inside recorderWorker.js where you can select the sample ratio you want, like 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;
}

and i call it when exporting the wav file:

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);
}
Super Class

I'm using the same recorder code and I needed to lower the bit rate. My solution produces a 11025Hz mono file. it's not very elegant so I'll be glad if someone has corrections for me.

First I change sample rate in the init function to be 11025 instead of the audio context's bit rate (this is the non elegant part since the context might not be 44100Hz).

I replace the interleave function content with this

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;

This takes only the left channel and turns every 4 buffer samples into 1 in the result so it takes up less memory. if the bit rate is changed by the same ratio (divided by 4 e.g. 11025), the file will sound the same but will be much smaller.

I also changed the channel count in encodeWAV to one

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

The recording will be 1/8 in size compared to originally produced file.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!