1(function(window) { 2 //å ¼å®¹ 3 window.URL = window.URL || window.webkitURL; 4 navigator.getUserMedia = 5 navigator.getUserMedia || 6 navigator.webkitGetUserMedia || 7 navigator.mozGetUserMedia || 8 navigator.msGetUserMedia; 9 10 var HZRecorder = function(stream, config) { 11 config = config || {}; 12 config.sampleBits = config.sampleBits || 8; //éæ ·æ°ä½ 8, 16 13 config.sampleRate = config.sampleRate || 44100 / 6; //éæ ·ç(1/6 44100) 14 15 var context = new (window.webkitAudioContext || window.AudioContext)(); 16 var audioInput = context.createMediaStreamSource(stream); 17 var createScript = 18 context.createScriptProcessor || context.createJavaScriptNode; 19 var recorder = createScript.apply(context, [4096, 1, 1]); 20 21 var audioData = { 22 size: 0, //å½é³æä»¶é¿åº¦ 23 buffer: [], //å½é³ç¼å 24 inputSampleRate: context.sampleRate, //è¾å ¥éæ ·ç 25 inputSampleBits: 16, //è¾å ¥éæ ·æ°ä½ 8, 16 26 outputSampleRate: config.sampleRate, //è¾åºéæ ·ç 27 oututSampleBits: config.sampleBits, //è¾åºéæ ·æ°ä½ 8, 16 28 input: function(data) { 29 this.buffer.push(new Float32Array(data)); 30 this.size += data.length; 31 }, 32 compress: function() { 33 //åå¹¶å缩 34 //åå¹¶ 35 var data = new Float32Array(this.size); 36 var offset = 0; 37 for (var i = 0; i < this.buffer.length; i++) { 38 data.set(this.buffer[i], offset); 39 offset += this.buffer[i].length; 40 } 41 //å缩 42 var compression = parseInt( 43 this.inputSampleRate / this.outputSampleRate 44 ); 45 var length = data.length / compression; 46 var result = new Float32Array(length); 47 var index = 0, 48 j = 0; 49 while (index < length) { 50 result[index] = data[j]; 51 j += compression; 52 index++; 53 } 54 return result; 55 }, 56 encodeWAV: function() { 57 var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate); 58 var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits); 59 var bytes = this.compress(); 60 var dataLength = bytes.length * (sampleBits / 8); 61 var buffer = new ArrayBuffer(44 + dataLength); 62 var data = new DataView(buffer); 63 64 var channelCount = 1; //å声é 65 var offset = 0; 66 67 var writeString = function(str) { 68 for (var i = 0; i < str.length; i++) { 69 data.setUint8(offset + i, str.charCodeAt(i)); 70 } 71 }; 72 73 // èµæºäº¤æ¢æä»¶æ è¯ç¬¦ 74 writeString("RIFF"); 75 offset += 4; 76 // ä¸ä¸ªå°åå¼å§å°æä»¶å°¾æ»åèæ°,峿件大å°-8 77 data.setUint32(offset, 36 + dataLength, true); 78 offset += 4; 79 // WAVæä»¶æ å¿ 80 writeString("WAVE"); 81 offset += 4; 82 // æ³¢å½¢æ ¼å¼æ å¿ 83 writeString("fmt "); 84 offset += 4; 85 // è¿æ»¤åè,ä¸è¬ä¸º 0x10 = 16 86 data.setUint32(offset, 16, true); 87 offset += 4; 88 // æ ¼å¼ç±»å« (PCMå½¢å¼éæ ·æ°æ®) 89 data.setUint16(offset, 1, true); 90 offset += 2; 91 // ééæ° 92 data.setUint16(offset, channelCount, true); 93 offset += 2; 94 // éæ ·ç,æ¯ç§æ ·æ¬æ°,表示æ¯ä¸ªééçææ¾é度 95 data.setUint32(offset, sampleRate, true); 96 offset += 4; 97 // æ³¢å½¢æ°æ®ä¼ è¾ç (æ¯ç§å¹³ååèæ°) å声éÃæ¯ç§æ°æ®ä½æ°Ãæ¯æ ·æ¬æ°æ®ä½/8 98 data.setUint32( 99 offset, 100 channelCount * sampleRate * (sampleBits / 8), 101 true 102 ); 103 offset += 4; 104 // å¿«æ°æ®è°æ´æ° éæ ·ä¸æ¬¡å ç¨åèæ° å声éÃæ¯æ ·æ¬çæ°æ®ä½æ°/8 105 data.setUint16(offset, channelCount * (sampleBits / 8), true); 106 offset += 2; 107 // æ¯æ ·æ¬æ°æ®ä½æ° 108 data.setUint16(offset, sampleBits, true); 109 offset += 2; 110 // æ°æ®æ è¯ç¬¦ 111 writeString("data"); 112 offset += 4; 113 // éæ ·æ°æ®æ»æ°,峿°æ®æ»å¤§å°-44 114 data.setUint32(offset, dataLength, true); 115 offset += 4; 116 // åå ¥éæ ·æ°æ® 117 if (sampleBits === 8) { 118 for (var i = 0; i < bytes.length; i++, offset++) { 119 var s = Math.max(-1, Math.min(1, bytes[i])); 120 var val = s < 0 ? s * 0x8000 : s * 0x7fff; 121 val = parseInt(255 / (65535 / (val + 32768))); 122 data.setInt8(offset, val, true); 123 } 124 } else { 125 for (var i = 0; i < bytes.length; i++, offset += 2) { 126 var s = Math.max(-1, Math.min(1, bytes[i])); 127 data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true); 128 } 129 } 130 131 return new Blob([data], { type: "audio/wav" }); 132 } 133 }; 134 135 //å¼å§å½é³ 136 this.start = function() { 137 audioInput.connect(recorder); 138 recorder.connect(context.destination); 139 }; 140 141 //忢 142 this.stop = function() { 143 recorder.disconnect(); 144 }; 145 146 //è·åé³é¢æä»¶ 147 this.getBlob = function() { 148 this.stop(); 149 return audioData.encodeWAV(); 150 }; 151 152 //åæ¾ 153 this.play = function(audio) { 154 audio.src = window.URL.createObjectURL(this.getBlob()); 155 }; 156 157 //ä¸ä¼ 158 this.upload = function(url, callback) { 159 var fd = new FormData(); 160 fd.append("audioData", this.getBlob()); 161 var xhr = new XMLHttpRequest(); 162 if (callback) { 163 xhr.upload.addEventListener( 164 "progress", 165 function(e) { 166 callback("uploading", e); 167 }, 168 false 169 ); 170 xhr.addEventListener( 171 "load", 172 function(e) { 173 callback("ok", e); 174 }, 175 false 176 ); 177 xhr.addEventListener( 178 "error", 179 function(e) { 180 callback("error", e); 181 }, 182 false 183 ); 184 xhr.addEventListener( 185 "abort", 186 function(e) { 187 callback("cancel", e); 188 }, 189 false 190 ); 191 } 192 xhr.open("POST", url); 193 xhr.send(fd); 194 }; 195 196 //é³é¢éé 197 recorder.onaudioprocess = function(e) { 198 audioData.input(e.inputBuffer.getChannelData(0)); 199 //record(e.inputBuffer.getChannelData(0)); 200 }; 201 }; 202 //æåºå¼å¸¸ 203 HZRecorder.throwError = function(message) { 204 alert(message); 205 throw new (function() { 206 this.toString = function() { 207 return message; 208 }; 209 })(); 210 }; 211 //æ¯å¦æ¯æå½é³ 212 HZRecorder.canRecording = navigator.getUserMedia != null; 213 //è·åå½é³æº 214 HZRecorder.get = function(callback, config) { 215 if (callback) { 216 if (navigator.getUserMedia) { 217 navigator.getUserMedia( 218 { audio: true }, //åªå¯ç¨é³é¢ 219 function(stream) { 220 var rec = new HZRecorder(stream, config); 221 callback(rec); 222 }, 223 function(error) {
224 switch (error.code || error.name) { 225 case "PERMISSION_DENIED": 226 case "PermissionDeniedError": 227 HZRecorder.throwError("ç¨æ·æç»æä¾ä¿¡æ¯ã"); 228 break; 229 case "NOT_SUPPORTED_ERROR": 230 case "NotSupportedError": 231 HZRecorder.throwError("æµè§å¨ä¸æ¯æç¡¬ä»¶è®¾å¤ã"); 232 break; 233 case "MANDATORY_UNSATISFIED_ERROR": 234 case "MandatoryUnsatisfiedError": 235 HZRecorder.throwError("æ æ³åç°æå®ç硬件设å¤ã"); 236 break; 237 default: 238 HZRecorder.throwError( 239 "æ æ³æå¼éº¦å é£ãå¼å¸¸ä¿¡æ¯:" + (error.code || error.name) 240 ); 241 break; 242 } 243 } 244 ); 245 } else { 246 HZRecorder.throwErr("å½åæµè§å¨ä¸æ¯æå½é³åè½ã"); 247 return; 248 } 249 } 250 }; 251 252 window.HZRecorder = HZRecorder; 253})(window);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.