PageSourceSearch

https://curatti.com/wp-content/plugins/universal-voice-search/js/r…/uvs.audio-recorder.js?ver=1790366516

js curatti.com collected 2026-09-25 20:02:52 UTC 8,049 bytes, 226 lines download raw bytes

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.