I'm trying to use recorderjs on an app engine site where users upload short audio recordings (say, 1 to a dozen seconds long). I've noticed that the WAV files I'm uploading are much larger than I expected. For example, I just created a recording that lasts roughly 9 seconds, and the uploaded blob is 1736769 bytes, which is > 1.5 megabytes.
Question:
How do I modify the recorderjs code (or my own code -- maybe I'm using recorderjs incorrectly) so that my audio blobs have a lower bitrate? I'd like a 10 second recording to be safely under 1 MB.
My guess is that I would need to modify the encodeWAV function in here, or maybe exportWAV, but I'm not sure how. Would it make sense to just drop every other element of the interleaved buffer in exportWAV? Is there a more intelligent way to do it? How does the bitrate of the exported WAV depend on properties of my computer (e.g. the sampling rate of my soundcard)?
I can add some details on my own code if it might be helpful.
Edit: if you'd like to see a live example, install google chrome beta and try this page. On my computer, a recording 5-10 seconds long is over 1 MB.
Many thanks,
Adrian
Hit the gear icon right next to the audio file. Select the Audio section and choose WAV. Click on Settings again and choose the new bitrate for your WAV file. Click on Create to finalize the settings made.
WAV Audio BitrateHigh-quality WAV files have an audio bitrate exactly the same as CDs at 1,411 kbps at 16 bit.
Just select the file type you want from the "Format" menu and select "Options" to change the bit rate. Preset bit rate mode provides four bit rates that are selected for you. Choose a low bit rate to lower the bit rate of the audio.
WAV files are also uncompressed, meaning that the data is stored as-is in full original format that doesn't require decoding.
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);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With