1// ***************************************************************************************************** 2// ******* speak2web UNIVERSAL VOICE SEARCH *********** 3// ******* Get your subscription at *********** 4// ******* https://speak2web.com/plugin#plans *********** 5// ******* Need support? https://speak2web.com/support *********** 6// ******* Licensed GPLv2+ *********** 7//****************************************************************************************************** 8 9 10(function (window) { 11 var WORKER_PATH = uvsWorkerPath; 12 13 var Recorder = function (source, cfg) { 14 var config = cfg || {}; 15 var bufferLen = config.bufferLen || 4096; 16 this.context = source.context; 17 18 // Create AnalyserNode to get real time frequencies 19 var uvsAnalyserNode = source.context.createAnalyser(); 20 source.connect(uvsAnalyserNode); 21 uvsAnalyserNode.fftSize = 2048; 22 23 let lastLowFilterValue = null; 24 let lowFilterValue = null; 25 let minFilterValue = null; 26 let maxFilterValue = null; 27 let reachedHigh = false; 28 let highFreqCount = 0; 29 let lowFreqCount = 0; 30 31 if (!this.context.createScriptProcessor) { 32 this.node = this.context.createJavaScriptNode(bufferLen, 2, 2); 33 } else { 34 this.node = this.context.createScriptProcessor(bufferLen, 2, 2); 35 } 36 37 var worker = new Worker(config.workerPath || WORKER_PATH); 38 worker.postMessage({ command: 'init', config: { sampleRate: this.context.sampleRate }}); 39 40 var recording = false, 41 currCallback; 42 43 // A reducer function to get sum of array elements/set 44 function uvsAdd(accumulator, a) { return accumulator + a; } 45 46 // A function to calculate low pass filter value 47 function uvsLowPassFilter (lastFilterValue, rawFreqValue){ 48 if(lastFilterValue == null) { return rawFreqValue; } 49 50 let x = (lastFilterValue * 4 + rawFreqValue) / 5; 51 return x; 52 } 53 54 // A click handler to dispatch click on mic button being used to record an audio. 55 function uvsMicButtonClickHandler() { 56 try { 57 if (typeof(uvsMicButtonElInCtx) != 'undefined' && uvsMicButtonElInCtx !== null) { 58 var uvsMicClassList = uvsMicButtonElInCtx.className || ''; 59 60 if (uvsMicClassList.indexOf('listening') != -1) uvsMicButtonElInCtx.click(); 61 } 62 } catch (err) { 63 console.log('uvs Error: Unable to reset Mic button.') 64 } 65 } 66 67 this.node.onaudioprocess = function (e) { 68 if (!recording) { return; } 69 70 var uvsAudioData = new Uint8Array(uvsAnalyserNode.frequencyBinCount); 71 uvsAnalyserNode.getByteFrequencyData(uvsAudioData); 72 73 //FIRST WE NEED TO ADD UP ALL FREQUENCIES TO GET THE TOTAL VOLUME 74 var currentVol = 0; 75 76 for (let i = 0; i < uvsAudioData.length; i++) { 77 currentVol = currentVol + uvsAudioData[i]; 78 } 79 80 lowFilterValue = uvsLowPassFilter(lowFilterValue, currentVol); 81 lowFilterValue = parseInt(lowFilterValue); 82 83 // Hold on minimum filter value 84 if (minFilterValue == null) { 85 minFilterValue = lowFilterValue; 86 } else if (lowFilterValue < minFilterValue) { 87 minFilterValue = lowFilterValue; 88 } 89 90 // Hold on maximum filter value 91 if (maxFilterValue == null) { 92 maxFilterValue = lowFilterValue; 93 } else if (lowFilterValue > maxFilterValue) { 94 maxFilterValue = lowFilterValue; 95 96 if (maxFilterValue > 2 * minFilterValue) { reachedHigh = true; } 97 } 98 99 // Count consectuive count's up and down 100 if ((lastLowFilterValue + 10) < lowFilterValue) { 101 lowFreqCount = 0; 102 highFreqCount = highFreqCount + 1; 103 } 104 105 if ((lastLowFilterValue - 10) > lowFilterValue) { 106 highFreqCount = 0; 107 lowFreqCount = lowFreqCount + 1; 108 } 109 110 lastLowFilterValue = lowFilterValue; 111
112 // End mic recording 113 if (lowFreqCount > 17 && reachedHigh ) { uvsMicButtonClickHandler(); } 114 115 worker.postMessage({ 116 command: 'record', 117 buffer: [ 118 e.inputBuffer.getChannelData(0), 119 e.inputBuffer.getChannelData(1) 120 ] 121 }); 122 } 123 124 this.configure = function (cfg) { 125 for (var prop in cfg) { 126 if (cfg.hasOwnProperty(prop)) { 127 config[prop] = cfg[prop]; 128 } 129 } 130 } 131 132 this.record = function (micButtonEl = null) { 133 recording = true; 134 uvsMicButtonElInCtx = micButtonEl; 135 } 136 137 this.stop = function () { 138 recording = false; 139 lastLowFilterValue = null; 140 highFreqCount = 0; 141 lowFreqCount = 0; 142 lowFilterValue = null; 143 minFilterValue = null; 144 maxFilterValue = null; 145 reachedHigh = false; 146 } 147 148 this.clear = function () { 149 uvsMicButtonInCtx = null; 150 worker.postMessage({ command: 'clear' }); 151 } 152 153 this.getBuffers = function (cb) { 154 // alert("getBuffers"); 155 currCallback = cb || config.callback; 156 worker.postMessage({ command: 'getBuffers' }) 157 } 158 159 this.exportWAV = function (cb, type) { 160 currCallback = cb || config.callback; 161 type = type || config.type || 'audio/wav'; 162 163 if (!currCallback) throw new Error('Callback not set'); 164 165 worker.postMessage({ 166 command: 'exportWAV', 167 type: type 168 }); 169 } 170 171 this.exportMonoWAV = function (cb, type) { 172 currCallback = cb || config.callback; 173 type = type || config.type || 'audio/wav'; 174 175 if (!currCallback) throw new Error('Callback not set'); 176 177 worker.postMessage({ 178 command: 'exportMonoWAV', 179 type: type 180 }); 181 } 182 183 this.convertBlobToBase64 = function(blobObj) { 184 return new Promise(function(resolve, reject){ 185 if (!(typeof blobObj != 'undefined' && !!blobObj && blobObj instanceof Blob)) { 186 reject(null); 187 return; 188 } 189 190 let reader = new FileReader(); 191 reader.readAsDataURL(blobObj); 192 193 reader.onload = function() { 194 let base64data = reader.result; 195 196 if (typeof base64data != 'undefined' && !!base64data && base64data.indexOf(',') !== -1) { 197 resolve(base64data.split(',')[1]); 198 } else { 199 reject(null); 200 } 201 } 202 203 reader.onerror = function(event) { 204 reader.abort(); 205 }; 206 207 reader.onabort = function() { 208 reject(null); 209 } 210 }); 211 } 212 213 worker.onmessage = function (e) { 214 var blob = e.data; 215 currCallback(blob); 216 } 217 218 uvsAnalyserNode.connect(this.node); 219 220 // if the script node is not connected to an output the "onaudioprocess" event is not triggered in chrome. 221 this.node.connect(this.context.destination); 222 }; 223 224 window.Recorder = Recorder; 225})(window); 226
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.