1 /* 2 * License (MIT) 3 * 4 * modifications: 5 * 6 * Copyright (C) 2013 DFKI GmbH 7 * Deutsches Forschungszentrum fuer Kuenstliche Intelligenz 8 * German Research Center for Artificial Intelligence 9 * http://www.dfki.de 10 * 11 * based on 12 * Copyright (C) 2013 Matt Diamond (MIT License) 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a 15 * copy of this software and associated documentation files (the 16 * "Software"), to deal in the Software without restriction, including 17 * without limitation the rights to use, copy, modify, merge, publish, 18 * distribute, sublicense, and/or sell copies of the Software, and to 19 * permit persons to whom the Software is furnished to do so, subject to 20 * the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be included 23 * in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 28 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 29 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 30 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 31 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 */ 33 34 35 (function(window){ 36 37 var WORKER_PATH = 'mmirf/workers/recorderWorker.js'; 38 39 var Recorder = function(source, cfg){ 40 var config = cfg || {}; 41 var bufferLen = config.bufferLen || 4096; 42 // this.context = source.context; 43 // this.createScriptProcessor = function(contextObj, bufferSize, numberOfInputChannels, numberOfOutputChannels){ 44 // if(contextObj.createJavaScriptNode){ 45 // return contextObj.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels); 46 // } 47 // else if(contextObj.createScriptProcessor){ 48 // return contextObj.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels); 49 // } 50 // else { 51 // throw Error('Could not create script-processor for AudioContext: context provides no function for generating processor!'); 52 // } 53 // }; 54 // this.node = this.createScriptProcessor(this.context, bufferLen, 2, 2); 55 // if(!this.context.createScriptProcessor){ 56 // this.node = this.context.createJavaScriptNode(bufferLen, 2, 2); 57 // } 58 // else { 59 // this.node = this.context.createScriptProcessor(bufferLen, 2, 2); 60 // } 61 var worker = new Worker(config.workerPath || WORKER_PATH); 62 // worker.postMessage({ 63 // command: 'init', 64 // config: { 65 // sampleRate: this.context.sampleRate 66 // } 67 // }); 68 this.processor = worker;///////////TODO MOD 69 70 var recording = false, 71 currCallback; 72 73 var dataListener;//TODO MOD 74 75 var doRecordAudio = function(e){ 76 if (!recording) return; 77 worker.postMessage({ 78 command: 'record', 79 buffer: [ 80 e.inputBuffer.getChannelData(0), 81 e.inputBuffer.getChannelData(1) 82 ] 83 }); 84 } 85 86 this._initSource = function(inputSource){ 87 88 this.context = inputSource.context; 89 90 //if we already had another input-source before, we need to clean up first: 91 if(this.node){ 92 this.node.disconnect(); 93 } 94 95 if(!this.context.createScriptProcessor){ 96 this.node = this.context.createJavaScriptNode(bufferLen, 2, 2); 97 } 98 else { 99 this.node = this.context.createScriptProcessor(bufferLen, 2, 2); 100 } 101 102 this.node.onaudioprocess = doRecordAudio; 103 104 worker.postMessage({ 105 command: 'init', 106 config: { 107 sampleRate: this.context.sampleRate 108 } 109 }); 110 111 inputSource.connect(this.node); 112 this.node.connect(this.context.destination); 113 } 114 115 this.configure = function(cfg){ 116 for (var prop in cfg){ 117 if (cfg.hasOwnProperty(prop)){ 118 config[prop] = cfg[prop]; 119 } 120 } 121 } 122 123 this.record = function(){ 124 recording = true; 125 } 126 127 this.stop = function(){ 128 recording = false; 129 } 130 131 this.clear = function(){ 132 worker.postMessage({ command: 'clear' }); 133 } 134 135 this.getBuffers = function(cb, isListener) {//TODO MOD additional parameter 136 //TODO MOD start 137 if(isListener === true){ 138 dataListener = cb; 139 worker.postMessage({ command: 'getBuffers', id: 'listener' }); 140 } 141 else {//TODO MOD end 142 currCallback = cb || config.callback; 143 worker.postMessage({ command: 'getBuffers' }) 144 } 145 } 146 147 this.exportWAV = function(cb, type){ 148 currCallback = cb || config.callback; 149 type = type || config.type || 'audio/wav'; 150 if (!currCallback) throw new Error('Callback not set'); 151 worker.postMessage({ 152 command: 'exportWAV', 153 type: type 154 }); 155 } 156 157 this.exportMonoWAV = function(cb, type){ 158 currCallback = cb || config.callback; 159 type = type || config.type || 'audio/wav'; 160 if (!currCallback) throw new Error('Callback not set'); 161 worker.postMessage({ 162 command: 'exportMonoWAV', 163 type: type 164 }); 165 } 166 167 var selfRef = this;///////////TODO MOD 168 worker.onmessage = function(e){ 169 170 var blob = e.data; 171 ///////////TODO MOD start 172 if(blob.buffers){ 173 var id = blob.id; 174 blob = blob.buffers; 175 if(id && id === 'listener' && dataListener){ 176 dataListener(blob); 177 } 178 return; 179 } 180 ///////////TODO MOD end 181 182 ///////////TODO MOD start 183 var result = true; 184 if(selfRef.beforeonmessage){ 185 result = selfRef.beforeonmessage(e); 186 } 187 if(typeof result !== 'undefined' && !result){ 188 return; 189 } 190 ///////////TODO MOD end 191 192 currCallback(blob); 193 194 } 195 196 // source.connect(this.node); 197 // this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggered in chrome. 198 199 this._initSource(source); 200 }; 201 202 Recorder.forceDownload = function(blob, filename){ 203 var url = (window.URL || window.webkitURL).createObjectURL(blob); 204 var link = window.document.createElement('a'); 205 link.href = url; 206 link.download = filename || 'output.wav'; 207 // var click = document.createEvent("Event");click.initEvent("click", true, true); 208 //MOD NOTE: FireFox requires a MouseEvent (in Chrome a simple Event would do the trick) 209 var click = document.createEvent("MouseEvent"); 210 click.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 211 link.dispatchEvent(click); 212 } 213 214 window.Recorder = Recorder; 215 })(window); 216