Уменьшить битрейт в 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 в размере по сравнению с первоначально произведенным файлом.