wav.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. wav编码器+编码引擎
  3. https://github.com/xiangyuecn/Recorder
  4. 当然最佳推荐使用mp3、wav格式,代码也是优先照顾这两种格式
  5. 浏览器支持情况
  6. https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
  7. 编码原理:给pcm数据加上一个44字节的wav头即成wav文件;pcm数据就是Recorder中的buffers原始数据(重新采样),16位时为LE小端模式(Little Endian),实质上是未经过任何编码处理
  8. 注意:其他wav编码器可能不是44字节的头,要从任意wav文件中提取pcm数据,请参考:assets/runtime-codes/fragment.decode.wav.js
  9. */
  10. (function(factory){
  11. var browser=typeof window=="object" && !!window.document;
  12. var win=browser?window:Object; //非浏览器环境,Recorder挂载在Object下面
  13. var rec=win.Recorder,ni=rec.i18n;
  14. factory(rec,ni,ni.$T,browser);
  15. }(function(Recorder,i18n,$T,isBrowser){
  16. "use strict";
  17. Recorder.prototype.enc_wav={
  18. stable:true,fast:true
  19. ,getTestMsg:function(){
  20. return $T("gPSE::支持位数8位、16位(填在比特率里面),采样率取值无限制;此编码器仅在pcm数据前加了一个44字节的wav头,编码出来的16位wav文件去掉开头的44字节即可得到pcm(注:其他wav编码器可能不是44字节)");
  21. }
  22. };
  23. var NormalizeSet=function(set){
  24. var bS=set.bitRate,b=bS==8?8:16;
  25. if(bS!=b) Recorder.CLog($T("wyw9::WAV Info: 不支持{1}位,已更新成{2}位",0,bS,b),3);
  26. set.bitRate=b;
  27. };
  28. Recorder.prototype.wav=function(res,True,False){
  29. var This=this,set=This.set;
  30. NormalizeSet(set);
  31. var size=res.length,sampleRate=set.sampleRate,bitRate=set.bitRate;
  32. var dataLength=size*(bitRate/8);
  33. //生成wav头
  34. var header=Recorder.wav_header(1,1,sampleRate,bitRate,dataLength);
  35. var offset=header.length;
  36. var bytes=new Uint8Array(offset+dataLength);
  37. bytes.set(header);
  38. // 写入采样数据
  39. if(bitRate==8) {
  40. for(var i=0;i<size;i++) {
  41. //16转8据说是雷霄骅的 https://blog.csdn.net/sevennight1989/article/details/85376149 细节比blqw的按比例的算法清晰点
  42. var val=(res[i]>>8)+128;
  43. bytes[offset++]=val;
  44. };
  45. }else{
  46. bytes=new Int16Array(bytes.buffer);//长度一定是偶数
  47. bytes.set(res,offset/2);
  48. };
  49. True(bytes.buffer,"audio/wav");
  50. };
  51. /**
  52. 根据参数生成wav文件头,返回Uint8Array(format=1时固定返回44字节,其他返回46字节)
  53. format: 1 (raw pcm) 2 (ADPCM) 3 (IEEE Float) 6 (g711a) 7 (g711u)
  54. numCh: 声道数
  55. dataLength: wav中的音频数据二进制长度
  56. **/
  57. Recorder.wav_header=function(format,numCh,sampleRate,bitRate,dataLength){
  58. //文件头 http://soundfile.sapp.org/doc/WaveFormat/ https://www.jianshu.com/p/63d7aa88582b https://github.com/mattdiamond/Recorderjs https://www.cnblogs.com/blqw/p/3782420.html https://www.cnblogs.com/xiaoqi/p/6993912.html
  59. var extSize=format==1?0:2;
  60. var buffer=new ArrayBuffer(44+extSize);
  61. var data=new DataView(buffer);
  62. var offset=0;
  63. var writeString=function(str){
  64. for (var i=0;i<str.length;i++,offset++) {
  65. data.setUint8(offset,str.charCodeAt(i));
  66. };
  67. };
  68. var write16=function(v){
  69. data.setUint16(offset,v,true);
  70. offset+=2;
  71. };
  72. var write32=function(v){
  73. data.setUint32(offset,v,true);
  74. offset+=4;
  75. };
  76. /* RIFF identifier */
  77. writeString('RIFF');
  78. /* RIFF chunk length */
  79. write32(36+extSize+dataLength);
  80. /* RIFF type */
  81. writeString('WAVE');
  82. /* format chunk identifier */
  83. writeString('fmt ');
  84. /* format chunk length */
  85. write32(16+extSize);
  86. /* audio format */
  87. write16(format);
  88. /* channel count */
  89. write16(numCh);
  90. /* sample rate */
  91. write32(sampleRate);
  92. /* byte rate (sample rate * block align) */
  93. write32(sampleRate*(numCh*bitRate/8));// *1 声道
  94. /* block align (channel count * bytes per sample) */
  95. write16(numCh*bitRate/8);// *1 声道
  96. /* bits per sample */
  97. write16(bitRate);
  98. if(format!=1){// ExtraParamSize 0
  99. write16(0);
  100. }
  101. /* data chunk identifier */
  102. writeString('data');
  103. /* data chunk length */
  104. write32(dataLength);
  105. return new Uint8Array(buffer);
  106. };
  107. }));