addWavHeader.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /**
  2. * 将pcm音频添加头部信息转换为wav音频
  3. * @ date: 2019年10月17日
  4. * @ param ArrayBuffer samples Uint8Array || Uint16Array || Uint32Array
  5. * @ param int sampleRateTmp 采样率(8000 - ???)
  6. * @ param int sampleBits 采样精度(8 || 16 || 32)和samples对应
  7. * @ param int channelCount 声道(单声道1,双声道2)
  8. * @ return: ArrayBuffer
  9. */
  10. function addWavHeader(samples, sampleRateTmp, sampleBits, channelCount){
  11. var dataLength = samples.byteLength;
  12. var buffer = new ArrayBuffer(44 + dataLength);
  13. var view = new DataView(buffer);
  14. function writeString(view, offset, string) {
  15. for (var i = 0; i < string.length; i++) {
  16. view.setUint8(offset + i, string.charCodeAt(i));
  17. }
  18. }
  19. var offset = 0;
  20. /* 资源交换文件标识符 */
  21. writeString(view, offset, 'RIFF'); offset += 4;
  22. /* 下个地址开始到文件尾总字节数,即文件大小-8 */
  23. view.setUint32(offset, /*32*/ 36 + dataLength, true); offset += 4;
  24. /* WAV文件标志 */
  25. writeString(view, offset, 'WAVE'); offset += 4;
  26. /* 波形格式标志 */
  27. writeString(view, offset, 'fmt '); offset += 4;
  28. /* 过滤字节,一般为 0x10 = 16 */
  29. view.setUint32(offset, 16, true); offset += 4;
  30. /* 格式类别 (PCM形式采样数据) */
  31. view.setUint16(offset, 1, true); offset += 2;
  32. /* 通道数 */
  33. view.setUint16(offset, channelCount, true); offset += 2;
  34. /* 采样率,每秒样本数,表示每个通道的播放速度 */
  35. view.setUint32(offset, sampleRateTmp, true); offset += 4;
  36. /* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
  37. view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
  38. /* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
  39. view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
  40. /* 每样本数据位数 */
  41. view.setUint16(offset, sampleBits, true); offset += 2;
  42. /* 数据标识符 */
  43. writeString(view, offset, 'data'); offset += 4;
  44. /* 采样数据总数,即数据总大小-44 */
  45. view.setUint32(offset, dataLength, true); offset += 4;
  46. function floatTo32BitPCM(output, offset, input) {
  47. input = new Int32Array(input);
  48. for (var i = 0; i < input.length; i++, offset += 4) {
  49. // output.setFloat32(offset, (input[i]), true);
  50. output.setInt32(offset, input[i], true);
  51. }
  52. }
  53. function floatTo16BitPCM(output, offset, input) {
  54. input = new Int16Array(input);
  55. for (var i = 0; i < input.length; i++, offset += 2) {
  56. output.setInt16(offset, (input[i]), true);
  57. }
  58. }
  59. function floatTo8BitPCM(output, offset, input) {
  60. input = new Int8Array(input);
  61. for (var i = 0; i < input.length; i++, offset++) {
  62. output.setInt8(offset, input[i], true);
  63. }
  64. }
  65. if (sampleBits == 16) {
  66. floatTo16BitPCM(view, 44, samples);
  67. } else if (sampleBits == 8) {
  68. floatTo8BitPCM(view, 44, samples);
  69. } else {
  70. floatTo32BitPCM(view, 44, samples);
  71. }
  72. return view.buffer;
  73. }