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 var recording = false, 69 currCallback; 70 71 this.node.onaudioprocess = function(e){ 72 if (!recording) return; 73 worker.postMessage({ 74 command: 'record', 75 buffer: [ 76 e.inputBuffer.getChannelData(0), 77 e.inputBuffer.getChannelData(1) 78 ] 79 }); 80 } 81 82 this.configure = function(cfg){ 83 for (var prop in cfg){ 84 if (cfg.hasOwnProperty(prop)){ 85 config[prop] = cfg[prop]; 86 } 87 } 88 } 89 90 this.record = function(){ 91 recording = true; 92 } 93 94 this.stop = function(){ 95 recording = false; 96 } 97 98 this.clear = function(){ 99 worker.postMessage({ command: 'clear' }); 100 } 101 102 this.getBuffers = function(cb) { 103 currCallback = cb || config.callback; 104 worker.postMessage({ command: 'getBuffers' }) 105 } 106 107 this.exportWAV = function(cb, type){ 108 currCallback = cb || config.callback; 109 type = type || config.type || 'audio/wav'; 110 if (!currCallback) throw new Error('Callback not set'); 111 worker.postMessage({ 112 command: 'exportWAV', 113 type: type 114 }); 115 } 116 117 this.exportMonoWAV = function(cb, type){ 118 currCallback = cb || config.callback; 119 type = type || config.type || 'audio/wav'; 120 if (!currCallback) throw new Error('Callback not set'); 121 worker.postMessage({ 122 command: 'exportMonoWAV', 123 type: type 124 }); 125 } 126 127 worker.onmessage = function(e){ 128 var blob = e.data; 129 currCallback(blob); 130 } 131 132 source.connect(this.node); 133 this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggered in chrome. 134 }; 135 136 Recorder.forceDownload = function(blob, filename){ 137 var url = (window.URL || window.webkitURL).createObjectURL(blob); 138 var link = window.document.createElement('a'); 139 link.href = url; 140 link.download = filename || 'output.wav'; 141 var click = document.createEvent("Event"); 142 click.initEvent("click", true, true); 143 link.dispatchEvent(click); 144 } 145 146 window.Recorder = Recorder; 147 })(window); 148