{"version":3,"sources":["webpack:///./node_modules/vmsg/vmsg.es5.js"],"names":[],"mappings":";;;;;;AAAA,oDAAa;;AAEb;AACA;AACA,CAAC;AACD;AACA;;AAEA,iDAAiD,0CAA0C,0DAA0D,EAAE;;AAEvJ,2CAA2C,gBAAgB,kBAAkB,OAAO,2BAA2B,wDAAwD,gCAAgC,uDAAuD,2DAA2D,EAAE;;AAE3T,6DAA6D,sEAAsE,8DAA8D,oBAAoB;;AAErN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL,GAAG;;;AAGH;AACA;AACA;AACA;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;;AAGA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,GAAG;;;AAGH;AACA;AACA;AACA,+CAA+C,EAAE;AACjD;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;;AAEA,wEAAwE;;AAExE;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,GAAG;;AAEH;AACA,CAAC;;AAED;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA,qBAAqB,OAAO;AAC5B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;;AAEH;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB;AACA,WAAW,QAAQ;AACnB;AACA,WAAW,QAAQ;AACnB,YAAY,eAAe;AAC3B;;AAEA;AACA;AACA;AACA;AACA,oCAAoC;AACpC,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2DAA2D;AAC3D,oBAAoB;AACpB;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC;;AAExC,iBAAiB,aAAa;AAC9B;;AAEA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;;AAEA;AACA,GAAG;;;AAGH,uBAAuB,YAAY;AACnC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC;;AAEnC,iBAAiB,aAAa;AAC9B;AACA,oCAAoC;AACpC;AACA,GAAG;;;AAGH,uBAAuB,YAAY;AACnC;AACA;;AAEA;AACA;;AAEA;AACA,yBAAyB;;AAEzB;AACA;AACA;AACA,uBAAuB;;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;;AAEnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;;AAEzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;;AAE3B;AACA;AACA;AACA;AACA;AACA,uBAAuB;;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA","file":"vmsg.1c26a7a8c12e990197ea.js","sourcesContent":["\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.record = record;\nexports.default = exports.Form = exports.Recorder = void 0;\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n/* eslint-disable */\nfunction pad2(n) {\n n |= 0;\n return n < 10 ? \"0\".concat(n) : \"\".concat(Math.min(n, 99));\n}\n\nfunction inlineWorker() {\n // TODO(Kagami): Cache compiled module in IndexedDB? It works in FF\n // and Edge, see: https://github.com/mdn/webassembly-examples/issues/4\n // Though gzipped WASM module currently weights ~70kb so it should be\n // perfectly cached by the browser itself.\n function fetchAndInstantiate(url, imports) {\n if (!WebAssembly.instantiateStreaming) return fetchAndInstantiateFallback(url, imports);\n var req = fetch(url, {\n credentials: \"same-origin\"\n });\n return WebAssembly.instantiateStreaming(req, imports).catch(function (err) {\n // https://github.com/Kagami/vmsg/issues/11\n if (err.message && err.message.indexOf(\"Argument 0 must be provided and must be a Response\") > 0) {\n return fetchAndInstantiateFallback(url, imports);\n } else {\n throw err;\n }\n });\n }\n\n function fetchAndInstantiateFallback(url, imports) {\n return new Promise(function (resolve, reject) {\n var req = new XMLHttpRequest();\n req.open(\"GET\", url);\n req.responseType = \"arraybuffer\";\n\n req.onload = function () {\n resolve(WebAssembly.instantiate(req.response, imports));\n };\n\n req.onerror = reject;\n req.send();\n });\n } // Must be in sync with emcc settings!\n\n\n var TOTAL_STACK = 5 * 1024 * 1024;\n var TOTAL_MEMORY = 16 * 1024 * 1024;\n var WASM_PAGE_SIZE = 64 * 1024;\n var memory = null;\n var dynamicTop = TOTAL_STACK; // TODO(Kagami): Grow memory?\n\n function sbrk(increment) {\n var oldDynamicTop = dynamicTop;\n dynamicTop += increment;\n return oldDynamicTop;\n } // TODO(Kagami): LAME calls exit(-1) on internal error. Would be nice\n // to provide custom DEBUGF/ERRORF for easier debugging. Currenty\n // those functions do nothing.\n\n\n function exit(status) {\n postMessage({\n type: \"internal-error\",\n data: status\n });\n }\n\n var FFI = null;\n var ref = null;\n var pcm_l = null;\n\n function vmsg_init(rate) {\n ref = FFI.vmsg_init(rate);\n if (!ref) return false;\n var pcm_l_ref = new Uint32Array(memory.buffer, ref, 1)[0];\n pcm_l = new Float32Array(memory.buffer, pcm_l_ref);\n return true;\n }\n\n function vmsg_encode(data) {\n pcm_l.set(data);\n return FFI.vmsg_encode(ref, data.length) >= 0;\n }\n\n function vmsg_flush() {\n if (FFI.vmsg_flush(ref) < 0) return null;\n var mp3_ref = new Uint32Array(memory.buffer, ref + 4, 1)[0];\n var size = new Uint32Array(memory.buffer, ref + 8, 1)[0];\n var mp3 = new Uint8Array(memory.buffer, mp3_ref, size);\n var blob = new Blob([mp3], {\n type: \"audio/mpeg\"\n });\n FFI.vmsg_free(ref);\n ref = null;\n pcm_l = null;\n return blob;\n } // https://github.com/brion/min-wasm-fail\n\n\n function testSafariWebAssemblyBug() {\n var bin = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127, 3, 2, 1, 0, 5, 3, 1, 0, 1, 7, 8, 1, 4, 116, 101, 115, 116, 0, 0, 10, 16, 1, 14, 0, 32, 0, 65, 1, 54, 2, 0, 32, 0, 40, 2, 0, 11]);\n var mod = new WebAssembly.Module(bin);\n var inst = new WebAssembly.Instance(mod, {}); // test storing to and loading from a non-zero location via a parameter.\n // Safari on iOS 11.2.5 returns 0 unexpectedly at non-zero locations\n\n return inst.exports.test(4) !== 0;\n }\n\n onmessage = function onmessage(e) {\n var msg = e.data;\n\n switch (msg.type) {\n case \"init\":\n var _msg$data = msg.data,\n wasmURL = _msg$data.wasmURL,\n shimURL = _msg$data.shimURL;\n Promise.resolve().then(function () {\n if (self.WebAssembly && !testSafariWebAssemblyBug()) {\n delete self.WebAssembly;\n }\n\n if (!self.WebAssembly) {\n importScripts(shimURL);\n }\n\n memory = new WebAssembly.Memory({\n initial: TOTAL_MEMORY / WASM_PAGE_SIZE,\n maximum: TOTAL_MEMORY / WASM_PAGE_SIZE\n });\n return {\n memory: memory,\n pow: Math.pow,\n exit: exit,\n powf: Math.pow,\n exp: Math.exp,\n sqrtf: Math.sqrt,\n cos: Math.cos,\n log: Math.log,\n sin: Math.sin,\n sbrk: sbrk\n };\n }).then(function (Runtime) {\n return fetchAndInstantiate(wasmURL, {\n env: Runtime\n });\n }).then(function (wasm) {\n FFI = wasm.instance.exports;\n postMessage({\n type: \"init\",\n data: null\n });\n }).catch(function (err) {\n postMessage({\n type: \"init-error\",\n data: err.toString()\n });\n });\n break;\n\n case \"start\":\n if (!vmsg_init(msg.data)) return postMessage({\n type: \"error\",\n data: \"vmsg_init\"\n });\n break;\n\n case \"data\":\n if (!vmsg_encode(msg.data)) return postMessage({\n type: \"error\",\n data: \"vmsg_encode\"\n });\n break;\n\n case \"stop\":\n var blob = vmsg_flush();\n if (!blob) return postMessage({\n type: \"error\",\n data: \"vmsg_flush\"\n });\n postMessage({\n type: \"stop\",\n data: blob\n });\n break;\n }\n };\n}\n\nvar Recorder =\n/*#__PURE__*/\nfunction () {\n function Recorder() {\n var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var onStop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n\n _classCallCheck(this, Recorder);\n\n // Can't use relative URL in blob worker, see:\n // https://stackoverflow.com/a/22582695\n this.wasmURL = new URL(opts.wasmURL || \"/static/js/vmsg.wasm\", location).href;\n this.shimURL = new URL(opts.shimURL || \"/static/js/wasm-polyfill.js\", location).href;\n this.onStop = onStop;\n this.pitch = opts.pitch || 0;\n this.stream = null;\n this.audioCtx = null;\n this.gainNode = null;\n this.pitchFX = null;\n this.encNode = null;\n this.worker = null;\n this.workerURL = null;\n this.blob = null;\n this.blobURL = null;\n this.resolve = null;\n this.reject = null;\n Object.seal(this);\n }\n\n _createClass(Recorder, [{\n key: \"close\",\n value: function close() {\n if (this.encNode) this.encNode.disconnect();\n if (this.encNode) this.encNode.onaudioprocess = null;\n if (this.stream) this.stopTracks();\n if (this.audioCtx) this.audioCtx.close();\n if (this.worker) this.worker.terminate();\n if (this.workerURL) URL.revokeObjectURL(this.workerURL);\n if (this.blobURL) URL.revokeObjectURL(this.blobURL);\n } // Without pitch shift:\n // [sourceNode] -> [gainNode] -> [encNode] -> [audioCtx.destination]\n // |\n // -> [worker]\n // With pitch shift:\n // [sourceNode] -> [gainNode] -> [pitchFX] -> [encNode] -> [audioCtx.destination]\n // |\n // -> [worker]\n\n }, {\n key: \"initAudio\",\n value: function initAudio() {\n var _this = this;\n\n var getUserMedia = navigator.mediaDevices && navigator.mediaDevices.getUserMedia ? function (constraints) {\n return navigator.mediaDevices.getUserMedia(constraints);\n } : function (constraints) {\n var oldGetUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;\n\n if (!oldGetUserMedia) {\n return Promise.reject(new Error(\"getUserMedia is not implemented in this browser\"));\n }\n\n return new Promise(function (resolve, reject) {\n oldGetUserMedia.call(navigator, constraints, resolve, reject);\n });\n };\n return getUserMedia({\n audio: true\n }).then(function (stream) {\n _this.stream = stream;\n var audioCtx = _this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();\n var sourceNode = audioCtx.createMediaStreamSource(stream);\n var gainNode = _this.gainNode = (audioCtx.createGain || audioCtx.createGainNode).call(audioCtx);\n gainNode.gain.value = 1;\n sourceNode.connect(gainNode);\n var pitchFX = _this.pitchFX = new Jungle(audioCtx);\n pitchFX.setPitchOffset(_this.pitch);\n var encNode = _this.encNode = (audioCtx.createScriptProcessor || audioCtx.createJavaScriptNode).call(audioCtx, 0, 1, 1);\n pitchFX.output.connect(encNode);\n gainNode.connect(_this.pitch === 0 ? encNode : pitchFX.input);\n });\n }\n }, {\n key: \"initWorker\",\n value: function initWorker() {\n var _this2 = this;\n\n if (!this.stream) throw new Error(\"missing audio initialization\"); // https://stackoverflow.com/a/19201292\n\n var blob = new Blob([\"(\", inlineWorker.toString(), \")()\"], {\n type: \"application/javascript\"\n });\n var workerURL = this.workerURL = URL.createObjectURL(blob);\n var worker = this.worker = new Worker(workerURL);\n var wasmURL = this.wasmURL,\n shimURL = this.shimURL;\n worker.postMessage({\n type: \"init\",\n data: {\n wasmURL: wasmURL,\n shimURL: shimURL\n }\n });\n return new Promise(function (resolve, reject) {\n worker.onmessage = function (e) {\n var msg = e.data;\n\n switch (msg.type) {\n case \"init\":\n resolve();\n break;\n\n case \"init-error\":\n reject(new Error(msg.data));\n break;\n // TODO(Kagami): Error handling.\n\n case \"error\":\n case \"internal-error\":\n console.error(\"Worker error:\", msg.data);\n if (_this2.reject) _this2.reject(msg.data);\n break;\n\n case \"stop\":\n _this2.blob = msg.data;\n _this2.blobURL = URL.createObjectURL(msg.data);\n if (_this2.onStop) _this2.onStop();\n if (_this2.resolve) _this2.resolve(_this2.blob);\n break;\n }\n };\n });\n }\n }, {\n key: \"init\",\n value: function init() {\n return this.initAudio().then(this.initWorker.bind(this));\n }\n }, {\n key: \"startRecording\",\n value: function startRecording() {\n var _this3 = this;\n\n if (!this.stream) throw new Error(\"missing audio initialization\");\n if (!this.worker) throw new Error(\"missing worker initialization\");\n this.blob = null;\n if (this.blobURL) URL.revokeObjectURL(this.blobURL);\n this.blobURL = null;\n this.resolve = null;\n this.reject = null;\n this.worker.postMessage({\n type: \"start\",\n data: this.audioCtx.sampleRate\n });\n\n this.encNode.onaudioprocess = function (e) {\n var samples = e.inputBuffer.getChannelData(0);\n\n _this3.worker.postMessage({\n type: \"data\",\n data: samples\n });\n };\n\n this.encNode.connect(this.audioCtx.destination);\n }\n }, {\n key: \"stopRecording\",\n value: function stopRecording() {\n var _this4 = this;\n\n if (!this.stream) throw new Error(\"missing audio initialization\");\n if (!this.worker) throw new Error(\"missing worker initialization\");\n this.encNode.disconnect();\n this.encNode.onaudioprocess = null;\n this.stopTracks();\n this.worker.postMessage({\n type: \"stop\",\n data: null\n });\n return new Promise(function (resolve, reject) {\n _this4.resolve = resolve;\n _this4.reject = reject;\n });\n }\n }, {\n key: \"stopTracks\",\n value: function stopTracks() {\n // Might be missed in Safari and old FF/Chrome per MDN.\n if (this.stream.getTracks) {\n // Hide browser's recording indicator.\n this.stream.getTracks().forEach(function (track) {\n return track.stop();\n });\n }\n }\n }]);\n\n return Recorder;\n}();\n\nexports.Recorder = Recorder;\n\nvar Form =\n/*#__PURE__*/\nfunction () {\n function Form() {\n var _this5 = this;\n\n var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var resolve = arguments.length > 1 ? arguments[1] : undefined;\n var reject = arguments.length > 2 ? arguments[2] : undefined;\n\n _classCallCheck(this, Form);\n\n this.recorder = new Recorder(opts, this.onStop.bind(this));\n this.resolve = resolve;\n this.reject = reject;\n this.backdrop = null;\n this.popup = null;\n this.recordBtn = null;\n this.stopBtn = null;\n this.timer = null;\n this.audio = null;\n this.saveBtn = null;\n this.tid = 0;\n this.start = 0;\n Object.seal(this);\n this.recorder.initAudio().then(function () {\n return _this5.drawInit();\n }).then(function () {\n return _this5.recorder.initWorker();\n }).then(function () {\n return _this5.drawAll();\n }).catch(function (err) {\n return _this5.drawError(err);\n });\n }\n\n _createClass(Form, [{\n key: \"drawInit\",\n value: function drawInit() {\n var _this6 = this;\n\n if (this.backdrop) return;\n var backdrop = this.backdrop = document.createElement(\"div\");\n backdrop.className = \"vmsg-backdrop\";\n backdrop.addEventListener(\"click\", function () {\n return _this6.close(null);\n });\n var popup = this.popup = document.createElement(\"div\");\n popup.className = \"vmsg-popup\";\n popup.addEventListener(\"click\", function (e) {\n return e.stopPropagation();\n });\n var progress = document.createElement(\"div\");\n progress.className = \"vmsg-progress\";\n\n for (var i = 0; i < 3; i++) {\n var progressDot = document.createElement(\"div\");\n progressDot.className = \"vmsg-progress-dot\";\n progress.appendChild(progressDot);\n }\n\n popup.appendChild(progress);\n backdrop.appendChild(popup);\n document.body.appendChild(backdrop);\n }\n }, {\n key: \"drawTime\",\n value: function drawTime(msecs) {\n var secs = Math.round(msecs / 1000);\n this.timer.textContent = pad2(secs / 60) + \":\" + pad2(secs % 60);\n }\n }, {\n key: \"drawAll\",\n value: function drawAll() {\n var _this7 = this;\n\n this.drawInit();\n this.clearAll();\n var recordRow = document.createElement(\"div\");\n recordRow.className = \"vmsg-record-row\";\n this.popup.appendChild(recordRow);\n var recordBtn = this.recordBtn = document.createElement(\"button\");\n recordBtn.className = \"vmsg-button vmsg-record-button\";\n recordBtn.textContent = \"●\";\n recordBtn.addEventListener(\"click\", function () {\n return _this7.startRecording();\n });\n recordRow.appendChild(recordBtn);\n var stopBtn = this.stopBtn = document.createElement(\"button\");\n stopBtn.className = \"vmsg-button vmsg-stop-button\";\n stopBtn.style.display = \"none\";\n stopBtn.textContent = \"■\";\n stopBtn.addEventListener(\"click\", function () {\n return _this7.stopRecording();\n });\n recordRow.appendChild(stopBtn);\n var audio = this.audio = new Audio();\n audio.autoplay = true;\n var timer = this.timer = document.createElement(\"span\");\n timer.className = \"vmsg-timer\";\n timer.addEventListener(\"click\", function () {\n if (audio.paused) {\n if (_this7.recorder.blobURL) {\n audio.src = _this7.recorder.blobURL;\n }\n } else {\n audio.pause();\n }\n });\n this.drawTime(0);\n recordRow.appendChild(timer);\n var saveBtn = this.saveBtn = document.createElement(\"button\");\n saveBtn.className = \"vmsg-button vmsg-save-button\";\n saveBtn.textContent = \"✓\";\n saveBtn.disabled = true;\n saveBtn.addEventListener(\"click\", function () {\n return _this7.close(_this7.recorder.blob);\n });\n recordRow.appendChild(saveBtn);\n var gainWrapper = document.createElement(\"div\");\n gainWrapper.className = \"vmsg-slider-wrapper vmsg-gain-slider-wrapper\";\n var gainSlider = document.createElement(\"input\");\n gainSlider.className = \"vmsg-slider vmsg-gain-slider\";\n gainSlider.setAttribute(\"type\", \"range\");\n gainSlider.min = 0;\n gainSlider.max = 2;\n gainSlider.step = 0.2;\n gainSlider.value = 1;\n\n gainSlider.onchange = function () {\n var gain = +gainSlider.value;\n _this7.recorder.gainNode.gain.value = gain;\n };\n\n gainWrapper.appendChild(gainSlider);\n this.popup.appendChild(gainWrapper);\n var pitchWrapper = document.createElement(\"div\");\n pitchWrapper.className = \"vmsg-slider-wrapper vmsg-pitch-slider-wrapper\";\n var pitchSlider = document.createElement(\"input\");\n pitchSlider.className = \"vmsg-slider vmsg-pitch-slider\";\n pitchSlider.setAttribute(\"type\", \"range\");\n pitchSlider.min = -1;\n pitchSlider.max = 1;\n pitchSlider.step = 0.2;\n pitchSlider.value = this.recorder.pitch;\n\n pitchSlider.onchange = function () {\n var pitch = +pitchSlider.value;\n\n _this7.recorder.pitchFX.setPitchOffset(pitch);\n\n _this7.recorder.gainNode.disconnect();\n\n _this7.recorder.gainNode.connect(pitch === 0 ? _this7.recorder.encNode : _this7.recorder.pitchFX.input);\n };\n\n pitchWrapper.appendChild(pitchSlider);\n this.popup.appendChild(pitchWrapper);\n }\n }, {\n key: \"drawError\",\n value: function drawError(err) {\n console.error(err);\n this.drawInit();\n this.clearAll();\n var error = document.createElement(\"div\");\n error.className = \"vmsg-error\";\n error.textContent = err.toString();\n this.popup.appendChild(error);\n }\n }, {\n key: \"clearAll\",\n value: function clearAll() {\n if (!this.popup) return;\n this.popup.innerHTML = \"\";\n }\n }, {\n key: \"close\",\n value: function close(blob) {\n if (this.audio) this.audio.pause();\n if (this.tid) clearTimeout(this.tid);\n this.recorder.close();\n this.backdrop.remove();\n\n if (blob) {\n this.resolve(blob);\n } else {\n this.reject(new Error(\"No record made\"));\n }\n }\n }, {\n key: \"onStop\",\n value: function onStop() {\n this.recordBtn.style.display = \"\";\n this.stopBtn.style.display = \"none\";\n this.stopBtn.disabled = false;\n this.saveBtn.disabled = false;\n }\n }, {\n key: \"startRecording\",\n value: function startRecording() {\n this.audio.pause();\n this.start = Date.now();\n this.updateTime();\n this.recordBtn.style.display = \"none\";\n this.stopBtn.style.display = \"\";\n this.saveBtn.disabled = true;\n this.recorder.startRecording();\n }\n }, {\n key: \"stopRecording\",\n value: function stopRecording() {\n clearTimeout(this.tid);\n this.tid = 0;\n this.stopBtn.disabled = true;\n this.recorder.stopRecording();\n }\n }, {\n key: \"updateTime\",\n value: function updateTime() {\n var _this8 = this;\n\n // NOTE(Kagami): We can do this in `onaudioprocess` but that would\n // run too often and create unnecessary DOM updates.\n this.drawTime(Date.now() - this.start);\n this.tid = setTimeout(function () {\n return _this8.updateTime();\n }, 300);\n }\n }]);\n\n return Form;\n}();\n\nexports.Form = Form;\nvar shown = false;\n/**\n * Record a new voice message.\n *\n * @param {Object=} opts - Options\n * @param {string=} opts.wasmURL - URL of the module\n * (\"/static/js/vmsg.wasm\" by default)\n * @param {string=} opts.shimURL - URL of the WebAssembly polyfill\n * (\"/static/js/wasm-polyfill.js\" by default)\n * @param {number=} opts.pitch - Initial pitch shift ([-1, 1], 0 by default)\n * @return {Promise.} A promise that contains recorded blob when fulfilled.\n */\n\nfunction record(opts) {\n return new Promise(function (resolve, reject) {\n if (shown) throw new Error(\"Record form is already opened\");\n shown = true;\n new Form(opts, resolve, reject); // Use `.finally` once it's available in Safari and Edge.\n }).then(function (result) {\n shown = false;\n return result;\n }, function (err) {\n shown = false;\n throw err;\n });\n}\n/**\n * All available public items.\n */\n\n\nvar _default = {\n Recorder: Recorder,\n Form: Form,\n record: record\n}; // Borrowed from and slightly modified:\n// https://github.com/cwilso/Audio-Input-Effects/blob/master/js/jungle.js\n// Copyright 2012, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nexports.default = _default;\nvar delayTime = 0.100;\nvar fadeTime = 0.050;\nvar bufferTime = 0.100;\n\nfunction createFadeBuffer(context, activeTime, fadeTime) {\n var length1 = activeTime * context.sampleRate;\n var length2 = (activeTime - 2 * fadeTime) * context.sampleRate;\n var length = length1 + length2;\n var buffer = context.createBuffer(1, length, context.sampleRate);\n var p = buffer.getChannelData(0);\n var fadeLength = fadeTime * context.sampleRate;\n var fadeIndex1 = fadeLength;\n var fadeIndex2 = length1 - fadeLength; // 1st part of cycle\n\n for (var i = 0; i < length1; ++i) {\n var value;\n\n if (i < fadeIndex1) {\n value = Math.sqrt(i / fadeLength);\n } else if (i >= fadeIndex2) {\n value = Math.sqrt(1 - (i - fadeIndex2) / fadeLength);\n } else {\n value = 1;\n }\n\n p[i] = value;\n } // 2nd part\n\n\n for (var i = length1; i < length; ++i) {\n p[i] = 0;\n }\n\n return buffer;\n}\n\nfunction createDelayTimeBuffer(context, activeTime, fadeTime, shiftUp) {\n var length1 = activeTime * context.sampleRate;\n var length2 = (activeTime - 2 * fadeTime) * context.sampleRate;\n var length = length1 + length2;\n var buffer = context.createBuffer(1, length, context.sampleRate);\n var p = buffer.getChannelData(0); // 1st part of cycle\n\n for (var i = 0; i < length1; ++i) {\n if (shiftUp) // This line does shift-up transpose\n p[i] = (length1 - i) / length;else // This line does shift-down transpose\n p[i] = i / length1;\n } // 2nd part\n\n\n for (var i = length1; i < length; ++i) {\n p[i] = 0;\n }\n\n return buffer;\n}\n\nfunction Jungle(context) {\n this.context = context; // Create nodes for the input and output of this \"module\".\n\n var input = (context.createGain || context.createGainNode).call(context);\n var output = (context.createGain || context.createGainNode).call(context);\n this.input = input;\n this.output = output; // Delay modulation.\n\n var mod1 = context.createBufferSource();\n var mod2 = context.createBufferSource();\n var mod3 = context.createBufferSource();\n var mod4 = context.createBufferSource();\n this.shiftDownBuffer = createDelayTimeBuffer(context, bufferTime, fadeTime, false);\n this.shiftUpBuffer = createDelayTimeBuffer(context, bufferTime, fadeTime, true);\n mod1.buffer = this.shiftDownBuffer;\n mod2.buffer = this.shiftDownBuffer;\n mod3.buffer = this.shiftUpBuffer;\n mod4.buffer = this.shiftUpBuffer;\n mod1.loop = true;\n mod2.loop = true;\n mod3.loop = true;\n mod4.loop = true; // for switching between oct-up and oct-down\n\n var mod1Gain = (context.createGain || context.createGainNode).call(context);\n var mod2Gain = (context.createGain || context.createGainNode).call(context);\n var mod3Gain = (context.createGain || context.createGainNode).call(context);\n mod3Gain.gain.value = 0;\n var mod4Gain = (context.createGain || context.createGainNode).call(context);\n mod4Gain.gain.value = 0;\n mod1.connect(mod1Gain);\n mod2.connect(mod2Gain);\n mod3.connect(mod3Gain);\n mod4.connect(mod4Gain); // Delay amount for changing pitch.\n\n var modGain1 = (context.createGain || context.createGainNode).call(context);\n var modGain2 = (context.createGain || context.createGainNode).call(context);\n var delay1 = (context.createDelay || context.createDelayNode).call(context);\n var delay2 = (context.createDelay || context.createDelayNode).call(context);\n mod1Gain.connect(modGain1);\n mod2Gain.connect(modGain2);\n mod3Gain.connect(modGain1);\n mod4Gain.connect(modGain2);\n modGain1.connect(delay1.delayTime);\n modGain2.connect(delay2.delayTime); // Crossfading.\n\n var fade1 = context.createBufferSource();\n var fade2 = context.createBufferSource();\n var fadeBuffer = createFadeBuffer(context, bufferTime, fadeTime);\n fade1.buffer = fadeBuffer;\n fade2.buffer = fadeBuffer;\n fade1.loop = true;\n fade2.loop = true;\n var mix1 = (context.createGain || context.createGainNode).call(context);\n var mix2 = (context.createGain || context.createGainNode).call(context);\n mix1.gain.value = 0;\n mix2.gain.value = 0;\n fade1.connect(mix1.gain);\n fade2.connect(mix2.gain); // Connect processing graph.\n\n input.connect(delay1);\n input.connect(delay2);\n delay1.connect(mix1);\n delay2.connect(mix2);\n mix1.connect(output);\n mix2.connect(output); // Start\n\n var t = context.currentTime + 0.050;\n var t2 = t + bufferTime - fadeTime;\n mod1.start(t);\n mod2.start(t2);\n mod3.start(t);\n mod4.start(t2);\n fade1.start(t);\n fade2.start(t2);\n this.mod1 = mod1;\n this.mod2 = mod2;\n this.mod1Gain = mod1Gain;\n this.mod2Gain = mod2Gain;\n this.mod3Gain = mod3Gain;\n this.mod4Gain = mod4Gain;\n this.modGain1 = modGain1;\n this.modGain2 = modGain2;\n this.fade1 = fade1;\n this.fade2 = fade2;\n this.mix1 = mix1;\n this.mix2 = mix2;\n this.delay1 = delay1;\n this.delay2 = delay2;\n this.setDelay(delayTime);\n}\n\nJungle.prototype.setDelay = function (delayTime) {\n this.modGain1.gain.setTargetAtTime(0.5 * delayTime, 0, 0.010);\n this.modGain2.gain.setTargetAtTime(0.5 * delayTime, 0, 0.010);\n};\n\nJungle.prototype.setPitchOffset = function (mult) {\n if (mult > 0) {\n // pitch up\n this.mod1Gain.gain.value = 0;\n this.mod2Gain.gain.value = 0;\n this.mod3Gain.gain.value = 1;\n this.mod4Gain.gain.value = 1;\n } else {\n // pitch down\n this.mod1Gain.gain.value = 1;\n this.mod2Gain.gain.value = 1;\n this.mod3Gain.gain.value = 0;\n this.mod4Gain.gain.value = 0;\n }\n\n this.setDelay(delayTime * Math.abs(mult));\n};\n"],"sourceRoot":""}