Уменьшить битрейт в WAV-файле, созданном с помощью recorderjs
Я пытаюсь использовать recorderjs на сайте App engine, где пользователи загружают короткие аудиозаписи (скажем, от 1 до дюжины секунд). Я заметил, что файлы WAV, которые я загружаю, намного больше, чем я ожидал. Например, я только что создал запись, которая длится примерно 9 секунд, а загруженный blob-это 1736769 байт, что составляет > 1,5 мегабайта.
вопрос:
Как изменить код recorderjs (или мой собственный код-возможно, я использование recorderjs неправильно), так что мои звуковые капли имеют более низкий битрейт? Я бы хотел, чтобы 10-секундная запись была безопасно под 1 MB.
Я предполагаю, что мне нужно будет изменить функцию encodeWAV в здесь, или, может быть, exportWAV, но я не уверен, как. Имеет ли смысл просто отбросить все остальные элементы перемежаемого буфера в exportWAV? Есть ли более разумный способ сделать это? Как битрейт экспортируемого WAV зависит от свойств моего компьютера (например, частота дискретизации моей звуковой карты)?
Я могу добавить некоторые детали в свой собственный код, если это может быть полезно.
Edit: если вы хотите увидеть живой пример, установите Google chrome beta и попробуйте на этой странице. На моем компьютере длина записи 5-10 секунд превышает 1 МБ.
большое спасибо,
Эдриан
3 ответов
вы можете попробовать пару вещей. Во-первых, я думаю, что вы на что-то о "отбрасывании каждого другого элемента чередующегося буфера" (преобразование звука в моно).
для этого вы можете выбрать, чтобы сохранить левый или правый канал. Вы можете изменить функцию "interleave" на:
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, поэтому я не знаю, что это внутренняя работа), строка 113/114 в recorderWorker, вероятно, может быть изменена на 1.
Я предполагаю, что вам может сойти с рук просто изменение двух мест, упомянутых здесь (функция interleave и место, где установлено количество каналов [строка 114]) потому что: interleave и encodeWAV вызываются только через функцию exportWAV, поэтому не касаясь того, как исходный работник был звукозаписывающим (и он записывал стерео), надеюсь, не сломает его. В этом случае мы будем вносить изменения только в аудио, которое было сохранено.
в моем случае Chrome записывает аудио на 96 кГц и Firefox на 44,1 кГц, что делает огромный WAV и файлы. Я реализовал функцию downsampling внутри 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);
}
я использую тот же код рекордера, и мне нужно было снизить скорость передачи данных. Мое решение создает моно-файл 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 в размере по сравнению с первоначально произведенным файлом.