使用 Matt Diamond 的记录器.js在 javascript 中编码 8 位 wav

Encoding 8 bit wav in javascript using Matt Diamond's recorder.js

本文关键字:编码 wav javascript Diamond Matt 记录器 js 使用      更新时间:2023-09-26

我做了一个javascript录音机,可以记录音频文件并存储在服务器上。为此,我使用了此示例中的代码:https://webaudiodemos.appspot.com/AudioRecorder/index.html。

它记录了 16 位 wav 文件,并且在 chrome 和 Firefox 中都能完美运行。但是,我需要它来记录 8 位 wav 文件。

我在录音机.js中进行了以下更改:

1)我更改了encodeWav函数,以便在wav文件的标头中有信息,它是一个8位文件,而不是16位文件:

function encodeWAV(samples, mono){
  var buffer = new ArrayBuffer(44 + samples.length * 2);
  var view = new DataView(buffer);
  /* RIFF identifier */
  writeString(view, 0, 'RIFF');
  /* file length */
  view.setUint32(4, 32 + samples.length * 2, true);
  /* RIFF type */
  writeString(view, 8, 'WAVE');
  /* format chunk identifier */
  writeString(view, 12, 'fmt ');
  /* format chunk length */
  view.setUint32(16, 16, true);
  /* sample format (raw) */
  view.setUint16(20, 1, true);
  /* channel count */
  view.setUint16(22, mono?1:2, true);
  /* sample rate */
  view.setUint32(24, sampleRate, true);
  /* byte rate (sample rate * block align) */
  view.setUint32(28, sampleRate * 4, true);
  /* block align (channel count * bytes per sample) */
  view.setUint16(32, 4, true);
  /* bits per sample */
  view.setUint16(34, 8, true);
  /* data chunk identifier */
  writeString(view, 36, 'data');
  /* data chunk length */
  view.setUint32(40, samples.length * 2, true);
  floatTo8BitPCM(view, 44, samples);
  return view;
}

2)我做了一个函数floatTo8BitPCM来替换floatTo16BitPCM,它看起来像这样:

function floatTo8BitPCM(output, offset, input){
  for (var i = 0; i < input.length; i++, offset++){
    var s = Math.max(-1, Math.min(1, input[i]));
    output.setInt8(offset, (s * 128) + 128);
  }
}

当我录制声音时,它总是在chrome中工作,但有时只能在Firefox中工作。而且,生成的文件比应有的长两倍。前半部分是我录制的,后半部分是沉默的。

我尝试将缓冲区大小设置为 44 + sample.length 而不是 44 + sample.length * 2,并将文件长度设置为 32 + sample.length

而不是 32 + sample.length * 2。

编辑:另外,当我减小文件大小和缓冲区大小时,当我在iTunes中播放它时,文件保持了2倍

的时间,但是当我在浏览器中播放它时,它缩短了2倍,我只听到了它的前半部分。

8

位的样本大小就是8位。它嵌入在块对齐、字节速率和每个样本的位数中。如果您同时支持单声道和立体声,您还需要更加注意通道数。

int bytesPerSample = 1;
int channelCount = mono ? 2 : 1;
int blockAlign =  bytesPerSample * channelCount;
int bitsPerSample = bytesPerSample * 8;
var buffer = new ArrayBuffer(44 + samples.length*blockAlign);
...
/* channel count */
view.setUint16(22, channelCount, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, sampleRate*blockAlign, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, blockAlign, true);
/* bits per sample */
view.setUint16(34, bitsPerSample, true);
...
/* data chunk length */
view.setUint32(40, samples.length*blockAlign, true);

作为旁注,从浮点数到字节的转换可能会溢出。 考虑到在最大浮点样本值可以是 1.0 时,您的公式将转换为 256,这太大了。

 1.0 * 128 + 128 = 256 
-1.0 * 128 + 128 = 0

您需要在以下选项之一之间进行选择。我不知道是否有正确的标准定义:

 1.0 * 127 + 128 = 255
-1.0 * 127 + 128 = 1
 1.0 * 127 + 127 = 254
-1.0 * 127 + 127 = 0