使用Matt Diamond的recorder.js

时间:2016-03-06 14:48:41

标签: javascript audio

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

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

我在recorderworker.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倍,我听到的只是第一次一半。

1 个答案:

答案 0 :(得分:1)

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

作为旁注,您从float到byte的转换可能会溢出。考虑到最大浮点样本值可以是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