diff --git a/dist/AudioTempoChanger.js b/dist/AudioTempoChanger.js index 0141afe..59d50d7 100644 --- a/dist/AudioTempoChanger.js +++ b/dist/AudioTempoChanger.js @@ -229,7 +229,7 @@ module.exports = VH; // Clear the now-made-future tempo changes (if any) var ci = changes.length-1; - while(out_time<=changes[ci].out_time && ci>=0) { changes.pop(); ci--; } + while(ci > 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; } // Add a tempo change reflecting current state changes.push({ diff --git a/dist/AudioTempoChanger.js.map b/dist/AudioTempoChanger.js.map index f6385d7..6de48ae 100644 --- a/dist/AudioTempoChanger.js.map +++ b/dist/AudioTempoChanger.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://AudioTempoChanger/webpack/universalModuleDefinition","webpack://AudioTempoChanger/webpack/bootstrap","webpack://AudioTempoChanger/./src/vector_helper.js","webpack://AudioTempoChanger/./src/audio_tempo_changer.js","webpack://AudioTempoChanger/./src/fft.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;ACjFA;AACA;AACA;;AAEA,U;AACA,6BAA6B,8BAA8B,EAAE;AAC7D,6CAA6C,4CAA4C;AACzF;;AAEA;AACA,4CAA4C,uBAAuB;AACnE,0DAA0D,aAAa,MAAM,gCAAgC,GAAG;;AAEhH,oB;;;;;;ACdA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,mBAAO,CAAC,CAAoB;AACtC,WAAW,mBAAO,CAAC,CAAU;;AAE7B;;AAEA;AACA;AACA;;AAEA;AACA;AACA,qCAAqC;AACrC;AACA;;AAEA;AACA;AACA;;AAEA;AACA,2BAA2B;AAC3B,4BAA4B;AAC5B,oDAAoD;AACpD,6BAA6B;;AAE7B;AACA;;AAEA;AACA;AACA,yCAAyC;AACzC,qCAAqC;;AAErC;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc,aAAa;AAC3B;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,cAAc,IAAI,MAAM;AACxB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,kBAAkB,mDAAmD;;AAErE;AACA;;AAEA;AACA;;AAEA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,kBAAkB;AACrC,wBAAwB;;AAExB,eAAe,IAAI;AACnB,gBAAgB,MAAM;AACtB;;AAEA,eAAe,mBAAmB;AAClC,eAAe,oBAAoB;;AAEnC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,oDAAoD,eAAe,MAAM;;AAEzE;AACA,kB;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,eAAe,IAAI;AACnB;AACA;;AAEA,gCAAgC,qBAAqB;AACrD;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2BAA2B;AAC3B;AACA,kB;AACA;AACA;AACA,KAAK;AACL;;AAEA,kBAAkB;;;AAGlB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,eAAe,aAAa,cAAc;AAC1C;;AAEA,gCAAgC;AAChC,eAAe,cAAc;AAC7B;AACA,2EAA2E;;AAE3E;AACA;;AAEA;AACA,4CAA4C,uBAAuB,aAAa;AAChF;AACA,uCAAuC,yBAAyB,aAAa;AAC7E;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,eAAe,cAAc;;AAE7B;AACA;AACA;;AAEA;AACA;;AAEA,sCAAsC;;AAEtC;AACA,iBAAiB,UAAU;AAC3B;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,UAAU;AAC1B;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC;AAChC,oCAAoC;AACpC,KAAK,OAAO;AACZ;AACA,8BAA8B,oBAAoB,oB;AAClD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,eAAe,cAAc;AAC7B;AACA,WAAW,iBAAiB;AAC5B,yBAAyB;AACzB;;AAEA;AACA;AACA,gBAAgB;AAChB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,aAAa;AAC5B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,6BAA6B;;AAE7B;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC,QAAQ;;AAExC;AACA;AACA;AACA,eAAe,UAAU;AACzB;AACA;AACA,eAAe,qBAAqB;AACpC;AACA;;AAEA,gCAAgC,aAAa;AAC7C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,aAAa;AAC5B;AACA;AACA;;AAEA,cAAc;;AAEd;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,sB;AACA;AACA;AACA;AACA,gBAAgB,eAAe;AAC/B,iBAAiB,SAAS;AAC1B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,iBAAiB,eAAe,M;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;;AAEA;AACA,iCAAiC;;AAEjC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,iD;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,6BAA6B;AAC7B;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA,sC;AACA,UAAU;AACV;AACA;AACA,oB;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,oCAAoC;;AAEpC;AACA,uCAAuC;;AAEvC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,eAAe,eAAe;;AAE9B;AACA;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;;;;;;;;AC7eY;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,mBAAO,CAAC,CAAoB;;AAErC;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,OAAO;AACtB;AACA,cAAc,OAAO;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,mBAAmB,kBAAkB;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,OAAO;AACtB;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,cAAc;AAChC;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,mBAAmB;AAC1C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,qBAAqB;;AAErB;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uBAAuB;AACvB,6BAA6B;AAC7B,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,qB","file":"AudioTempoChanger.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"AudioTempoChanger\"] = factory();\n\telse\n\t\troot[\"AudioTempoChanger\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","\n// Define an allocator and blit function for float arrays\n// Can be used to achieve backwards compatibility down to dark ages pre IE 10 if needed\n// Also reduces code size a little with closure.\n\nvar VH = { \n\tfloat_array: function(len) { return new Float32Array(len); },\n\tblit: function(src, spos, dest, dpos, len) { dest.set(src.subarray(spos,spos+len),dpos); }\n};\n\n// Pre-IE10 versions:\n/*VH.prototype.float_array = function(len) { return new Array(len); }\nVH.prototype.blit = function(src, spos, dest, dpos, len) { for(var i=0;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k=0) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;iu&&(u=C[t]);u=1E-8*u;var J=1,ea=1;g[0]=1;for(t=2;tu&&C[t]>C[t-1]&&C[t]>=C[t+1]){var ia=t+(C[t-1]-C[t+1])/(2*(C[t-1]-2*C[t]+C[t+1]));ia-g[J-1]>G?(g[J++]=ia,ea=t):C[t]>C[ea]&&(g[J-1]=ia,ea=t)}}r=r[I]=J;t=Y[I];I=ha[I];if(0==c||0==r)for(u= 0;ub[J]&&J!=B;)++J;c=J;0.1*C[Math.round(G)]?(ea=E(d,m,G),G=2*Math.PI/k*.5*(b[c]+G)*y,ia=ea-x[c]-G,c=x[c]+da[c]+(ia-2*Math.PI*Math.round(ia/(2*Math.PI))+G)*w-ea,t[u]=ea,I[u]=c,P[u]=Math.cos(c),oa[u]=Math.sin(c)):(t[u]=E(d,m,G),I[u]=0,P[u]=1,oa[u]=0)}g[r]=2*k;c=0;w=g[c];A=g[c+1];B=P[c];b=oa[c];for(r=1;r=w&&r-w>A-r&&(++c,w=g[c],A=g[c+1],B= P[c],b=oa[c]),x=d[r]*b+m[r]*B,d[r]=d[r]*B-m[r]*b,m[r]=x}}function E(c,d,m){m=Math.floor(m);var g=1==m%2?-1:1;return Math.atan2(g*(d[m]-d[m+1]),g*(c[m]-c[m+1]))}h=h||{};var Q=h.sampleRate||44100,K=h.R||11,U=h.i||1,F=Math.pow(2,50/1200)-1,k=1<>1)+1,H=a.a(D),aa=a.a(D),V=a.a(D),R=a.a(D),ba=a.a(D),ca=a.a(D);K=(D>>1)+1;var T=[0,0],fa=[],Y=[],ha=[],O=[];for(h=0;2>h;h++)fa.push(a.a(K)), -Y.push(a.a(K)),ha.push(a.a(K)),O.push(a.a(D));var P=a.a(K),oa=a.a(K),ka=0,W=0,S=[{l:0,h:0,i:U}],pa=0,la=0,ra=1,ma=0,qa=0,M=0,N=0,ja={mapOutputToInputTime:function(c){for(var d=S.length-1;cd;d++)for(var m=0;md;d++)for(var m=0;mA&&(A=N);g=a.a(A);a.f(e,0,g,0,N);w=0;for(var I=N,B=0,b=0;;){var x=k+y-M;if(w+x>d){a.f(m,w,v,M,d-w);M+=d-w;break}else 0>=x?M-=2*y:(a.f(m,w,v,M,x),w+=x,M=k-y);ma+=2*qa;B=ma|0;ma-=B;for(b=0;bx&&(x=Math.abs(2*l.c[b]));for(b=0;bx&&(x=Math.abs(l.c[b+n+B]+l.b[b]));for(b=k-n;bx&&(x=Math.abs(2*l.b[b]));b=1/Math.floor(k/(2*n));da*x>b&&(da=b/x);for(b=0;bB&&(B=0);a.f(e,0,g,I,b-B);I+=b}a.f(e,b-B,e,0,B);N=B; diff --git a/dist/AudioTempoChanger.min.js.map b/dist/AudioTempoChanger.min.js.map index e426db9..8557363 100644 --- a/dist/AudioTempoChanger.min.js.map +++ b/dist/AudioTempoChanger.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://AudioTempoChanger/webpack/universalModuleDefinition","webpack://AudioTempoChanger/AudioTempoChanger.min.js","webpack://AudioTempoChanger/webpack/bootstrap","webpack://AudioTempoChanger/./src/vector_helper.js","webpack://AudioTempoChanger/./src/audio_tempo_changer.js","webpack://AudioTempoChanger/./src/fft.js"],"names":["window","modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","__webpack_require__.d","name","getter","o","Object","defineProperty","enumerable","get","r","__webpack_require__.r","Symbol","toStringTag","value","t","__webpack_require__.t","mode","__esModule","ns","create","key","bind","n","__webpack_require__.n","getDefault","getModuleExports","__webpack_require__.o","object","property","prototype","hasOwnProperty","p","s","VH","float_array","len","Float32Array","blit","src","spos","dest","dpos","set","subarray","FFT","AudioTempoChanger","opts","pshift_rigid","frame_ind","re","im","p_re","p_im","ratio","CUR","PREV","prev_mags","b_mags","prev_np","b_npeaks","prpeaks","b_peaks","prev_in_angs","b_in_angs","prev_peak_adeltas","b_peak_adeltas","mags","length","peaks","max","thresh","MAX_PEAK_RATIO","n_peaks","prev_pi","f_delta","MAX_PEAK_JUMP","ppos","cur_np","cur_in_angs","cur_peak_adeltas","ci","pci","interpolate_phase","pi","cpi","Math","abs","round","MATCH_MAG_THRESH","in_angle","pred","PI","windowSize","pk","ana_len","pang","delta","ang","peaks_re","cos","peaks_im","sin","cp","cnp","cre","cim","nim","ind","floor","sgn","atan2","sampleRate","wsizeLog","chosen_tempo","tempo","pow","fft","max_step_len","in_buffer","out_buffer","syn_len","win","hWS","re1","im1","re2","im2","pre2","pim2","qWS","push","in_time","out_time","changes","f_ind","prev_out_len","gain_comp","syn_drift","syn_drift_per_step","inbuffer_contains","unused_in_outbuf","obj","given_out_time","cc","discard_output_seconds","k","pop","tempo_ratio","sum","GAIN_DEAMPLIFY","lc","in_ar","in_len","mix","mult","n_len","n_ar","buf","n_steps","out_len","outp","ii","oi","left_over","res_len","n_needed","sdelta","m_re","m_im","inplace","unpack","repack","oblen","gc","ceiling","out_ar","logN","m_N","m_logN","m_invN","m_revTgt","Array","x","y","twiddleRe","twiddleIm","wIndexStep","stage","wAngleInc","obj.inplace","inverse","numFlies","span","spacing","wMulRe","wMulIm","start","iTop","iBot","wRe","wIm","flyCount","xTopRe","xTopIm","xBotRe","xBotIm","tRe","i1","revI","m_N2","obj.unpack","rre","rim","ire","iim","obj.repack","factory","define","amd","root"],"mappings":"yBASCA,aAAA;QAAA,MACD,MCAiB,SAAQ,CAACC,CAAD,CAAU,CCNnCC,UAAA,CAAAC,CAAA,EAGA,GAAAC,CAAA,CAAAD,CAAA,EACA,MAAAC,EAAA,CAAAD,CAAA,CAAAE,EAGA,KAAAC,EAAAF,CAAA,CAAAD,CAAA,CAAAG,CAAA,CACAC,EAAAJ,CADA,CAEAK,EAAA,EAFA,CAGAH,EAAA,EAHA,CAOAJ,EAAA,CAAAE,CAAA,CAAAM,KAAA,CAAAH,CAAAD,EAAA,CAAAC,CAAA,CAAAA,CAAAD,EAAA,CAAAH,CAAA,CAGAI,EAAAE,EAAA,GAGA,OAAAF,EAAAD,EApBA,CAHA,IAAAD,EAAA,EA4BAF,EAAAQ,EAAA,CAAAT,CAGAC,EAAAS,EAAA,CAAAP,CAGAF,EAAAU,EAAA,CAAAC,QAAA,CAAAR,CAAA,CAAAS,CAAA,CAAAC,CAAA,EACAb,CAAAc,EAAA,CAAAX,CAAA,CAAAS,CAAA,GACAG,MAAAC,eAAA,CAAAb,CAAA,CAAAS,CAAA,EAA0CK,WAAA,EAA1C,CAA0CC,IAAAL,CAA1C,EAFA,CAOAb,EAAAmB,EAAA,CAAAC,QAAA,CAAAjB,CAAA,EACA,oBAAAkB,OAAA,EAAAA,MAAAC,YAAA,EACAP,MAAAC,eAAA,CAAAb,CAAA,CAAAkB,MAAAC,YAAA,EAAwDC,MAAA,QAAxD,EAEAR,OAAAC,eAAA,CAAAb,CAAA,eAAiDoB,MAAA,EAAjD,EAJA,CAYAvB,EAAAwB,EAAA,CAAAC,QAAA,CAAAF,CAAA,CAAAG,CAAA,EACAA,CAAA,KAAAH,CAAA,CAAAvB,CAAA,CAAAuB,CAAA,EACA,IAAAG,CAAA,SAAAH,EACA,IAAAG,CAAA,qBAAAH,EAAA,EAAAA,CAAA,EAAAA,CAAAI,EAAA,OAAAJ,EACA;IAAAK,EAAAb,MAAAc,OAAA,MACA7B,EAAAmB,EAAA,CAAAS,CAAA,CACAb,OAAAC,eAAA,CAAAY,CAAA,YAAyCX,WAAA,EAAzC,CAAyCM,OAAzC,EACA,IAAAG,CAAA,oBAAAH,EAAA,KAAAO,KAAA,GAAAP,EAAA,CAAAvB,CAAAU,EAAA,CAAAkB,CAAA,CAAAE,CAAA,UAAAA,CAAA,EAAgH,MAAAP,EAAA,CAAAO,CAAA,CAAhH,CAAAC,KAAA,CAAqI,IAArI,CAAqID,CAArI,EACA,OAAAF,EARA,CAYA5B,EAAAgC,EAAA,CAAAC,QAAA,CAAA7B,CAAA,EACA,IAAAS,EAAAT,CAAA,EAAAA,CAAAuB,EAAA,CACAO,QAAA,GAA2B,MAAA9B,EAAA,WAA3B,CADA,CAEA+B,QAAA,GAAiC,MAAA/B,EAAjC,CACAJ,EAAAU,EAAA,CAAAG,CAAA,KAAAA,CAAA,CACA,OAAAA,EALA,CASAb,EAAAc,EAAA,CAAAsB,QAAA,CAAAC,CAAA,CAAAC,CAAA,EAAsD,MAAAvB,OAAAwB,UAAAC,eAAAjC,KAAA,CAAA8B,CAAA,CAAAC,CAAA,CAAtD,CAGAtC,EAAAyC,EAAA,GAIA,OAAAzC,EAAA,CAAAA,CAAA0C,EAAA,GDxEmC,CAAnB,CCwEhB,UAAAtC,CAAA,ECpEAA,CAAAD,EAAA,CATAwC,CACAC,UAAA,CAAAC,CAAA,EAA6B,WAAAC,YAAA,CAAAD,CAAA,CAA7B,CADAF,CAEAI,UAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAN,CAAA,EAA6CK,CAAAE,IAAA,CAAAJ,CAAAK,SAAA,CAAAJ,CAAA,CAAAA,CAAA,CAAAJ,CAAA,EAAAM,CAAA,CAA7C,CAFAR,CD6EA,EDoCO,QAAQ,CAACvC,CAAD;AAASD,CAAT,CAAkBH,CAAlB,CAAuC,CGtHtD,YASA,IAAA2C,EAAU3C,CAAA,CAAQ,CAAR,CAAV,CACAsD,EAAWtD,CAAA,CAAQ,CAAR,CAkeXI,EAAAD,EAAA,CAheAoD,QAAA,CAAAC,CAAA,EAqMAC,QAAA,GAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,MACAC,EAAAN,CAAAM,CAAA,CAAAC,GAAA,CAAAA,CAAAD,CAEAE,GAAAC,CAAA,CAAAF,CAAA,CAOA,KAVA,IAKAG,EAAAC,CAAA,CAAAJ,CAAA,CALA,CAKAK,EAAAC,EAAA,CAAAN,CAAA,CALA,CAMAO,EAAAC,CAAA,CAAAR,CAAA,CANA,CAMAS,GAAAC,EAAA,CAAAV,CAAA,CANA,CASAW,EAAAT,CAAA,CAAAH,CAAA,CATA,CAUA3D,EAAA,EAAeA,CAAf,CAAeuE,CAAAC,OAAf,CAA6BxE,CAAA,EAA7B,CAA6BuE,CAAA,CAAAvE,CAAA,EAAAsD,CAAA,CAAAtD,CAAA,EAAAsD,CAAA,CAAAtD,CAAA,EAAAuD,CAAA,CAAAvD,CAAA,EAAAuD,CAAA,CAAAvD,CAAA,CAG7ByE,GAAAP,EAAA,CAAAP,CAAA,CACAK,IAtCe,KAAf,IAAAU,EAAA,EAAe1E,EAAA,EAAaA,CAAb,CAsCfuE,CAtC4BC,OAAb,CAA2BxE,CAAA,EAA3B,CAsCfuE,CAtC0C,CAAAvE,CAAA,EAAA0E,CAAA,GAAAA,CAAA,CAsC1CH,CAtC0C,CAAAvE,CAAA,EAC1C2E,GA5JAC,IA4JAD,CAAAD,CAHA,KAKAG,EAAA,CALA,CAKAC,GAAA,CAmCAL,EAnCgC,KAChC,KAAAzE,CAAA,GAAeA,CAAf,CAkCAuE,CAlCeC,OAAf,CAA6BxE,CAAA,EAA7B,CAA6B,CAC7B,IAAA+E,EAAA/E,CAAA+E,CAAAC,CACA,IAgCAT,CAhCA,CAAAvE,CAAA,EAAA2E,CAAA,EAgCAJ,CAhCA,CAAAvE,CAAA,EAgCAuE,CAhCA,CAAAvE,CAAA,KAgCAuE,CAhCA,CAAAvE,CAAA,GAgCAuE,CAhCA,CAAAvE,CAAA,KAGA,IAAAiF,GAAAjF,CAAAiF,EA6BAV,CA7BA,CAAAvE,CAAA,GAAAiF,CA6BAV,CA7BA,CAAAvE,CAAA,GAAAiF,GAAA,CAAAA,EA6BAV,CA7BA,CAAAvE,CAAA,GAAAiF,CAAA,CAAAA,CA6BAV,CA7BA,CAAAvE,CAAA,CAAAiF,CA6BAV,CA7BA,CAAAvE,CAAA,GAAAiF,EAGAA,GAAA,CA0BAR,CA1BA,CAAAI,CAAA,IAAAE,CAAA,EA0BAN,CA1B4C,CAAAI,CAAA,GAAuB,CAAvBI,EAAuB,CAAAH,EAAA,CAAA9E,CAAnE,EA0BAuE,CAxBA,CAAAvE,CAAA,CAFA,CA0BAuE,CAxBA,CAAAO,EAAA,CAFA,GA0BAL,CAxBuC,CAAAI,CAAA,GAAyB,CAAzBI,EAAyB,CAAAH,EAAA,CAAA9E,CAFhE,CANA,CAF6B,CAkC7BkF,EAAAlB,CAAA,CAAAL,CAAA,CAAAuB,CArBAL,CAwBAM,GAAAf,CAAA,CAAAT,CAAA,CAAAyB,GAAAd,EAAA,CAAAX,CAAA,CAEA,OAAAN,CAAA,KAAA6B,CAAA,CAGA,IAAAG,CAAA;AAAA,EAAiBA,CAAjB,CAAiBH,CAAjB,CAA2BG,CAAA,EAA3B,CACAC,CACA,CADAb,CAAA,CAAAY,CAAA,CACA,CAAAlB,CAAA,CAAAkB,CAAA,EAAAhB,EAAA,CAAAgB,CAAA,EAAAE,CAAA,CAAAjC,CAAA,CAAAC,CAAA,CAAA+B,CAAA,CALA,MAiBA,IAAAD,CAAA,CADAG,CACA,CADA,CACA,CAAgBH,CAAhB,CAAgBH,CAAhB,CAA0BG,CAAA,EAA1B,CAA0B,CAI1B,IAHAC,CAGA,CAHAb,CAAA,CAAAY,CAAA,CAGA,CAAAZ,CAAA,CAAAY,CAAA,EAAApB,CAAA,CAAAuB,CAAA,GAAAA,CAAA,EAAAzB,CAAA,IAAAyB,CAEAC,GAAAD,CACA,GAAAA,CAAA,EAAAF,CAAA,CAAArB,CAAA,CAAAuB,CAAA,IAAAvB,CAAA,CAAAuB,CAAA,EAAAF,CAAA,GAAAG,CAAA,CAAAD,CAAA,GAGAE,KAAAC,IAAA,CAAA1B,CAAA,CAAAwB,CAAA,EAAAH,CAAA,EADAA,CACA,CADAN,CACA,EACAnB,CAAA,CAAA6B,IAAAE,MAAA,CAAA3B,CAAA,CAAAwB,CAAA,GADA,CA/NAI,EA+NA,CAEAtB,CAAA,CAAAmB,IAAAE,MAAA,CAAAN,CAAA,EAFA,EAKAQ,EAMoC,CANpCP,CAAA,CAAAjC,CAAA,CAAAC,CAAA,CAAA+B,CAAA,CAMoC,CA7FpCS,CA6FoC,CA7FpC,CA6FoC,CA7FpCL,IAAAM,GA6FoC,CA7FpCC,CA6FoC,CA7FpC,EA6FoC,EAJpChC,CAAAiC,CAAAT,CAAAS,CAIoC,CAJpCZ,CAIoC,EA7FpCa,CA6FoC,CA5FpC,EA4FoC,CAJpCL,EAIoC,CAJpC3B,CAAAiC,CAAAX,CAAAW,CAIoC,CA5FpCL,CA4FoC,CAFpCM,CAEoC,CALpClC,CAAA,CAAAsB,CAAA,CAKoC,CALpCpB,EAAA,CAAAoB,CAAA,CAKoC,EAlGpCa,EAkGoC,CAlGpC,CAkGoC,CAlGpCZ,IAAAM,GAkGoC,CAlGpCN,IAAAE,MAAA,CAAAU,EAAA,IAAAZ,IAAAM,GAAA,EAkGoC,CA1FpCD,CA0FoC,EAJpCrC,CAIoC,CAFpCoC,EAEoC,CADpCX,CAAA,CAAAE,CAAA,CACoC,CADpCS,EACoC,CADJV,CAAA,CAAAC,CAAA,CACI,CADJgB,CACI,CAApCE,CAAA,CAAAlB,CAAA,CAAoC,CAApCK,IAAAc,IAAA,CAAAH,CAAA,CAAoC,CAAAI,EAAA,CAAApB,CAAA,EAAAK,IAAAgB,IAAA,CAAAL,CAAA,CAXpC,GAaAlB,CAAA,CAAAE,CAAA,CACkD,CADlDE,CAAA,CAAAjC,CAAA,CAAAC,CAAA,CAAA+B,CAAA,CACkD,CAAlDF,CAAA,CAAAC,CAAA,CAAkD,CAAlD,CAAkD,CAApBkB,CAAA,CAAAlB,CAAA,CAAoB,CAApB,CAAoB,CAAAoB,EAAA,CAAApB,CAAA,GAdlD,CAV0B,CAiC1BZ,CAAA,CAAAS,CAAA,IAAAe,CAEAR,EAvEA,CAuEA,CAAAkB,GAAAlC,CAAA,CAAAgB,CAAA,CAAAmB,GAAAnC,CAAA,CAAAgB,CAAA,GACAoB,GAAAN,CAAA,CAAAd,CAAA,CAAAqB,GAAAL,EAAA,CAAAhB,CAAA,CAEA,KAAAzF,CAAA,GAAeA,CAAf,CAAesD,CAAAkB,OAAf,CAAe,CAAf,CAA6BxE,CAAA,EAA7B,CACAA,CAOgB,EAPhB2G,CAOgB,EAPhB3G,CAOgB,CAPhB2G,CAOgB,CAPhBC,CAOgB,CAPhB5G,CAOgB,GANhB,EAAAyF,CACyB,CADdkB,CACc,CADdlC,CAAA,CAAAgB,CAAA,CACc,CADGmB,CACH,CADGnC,CAAA,CAAAgB,CAAA,GACH,CAAzBoB,CAAyB;AAAzBN,CAAA,CAAAd,CAAA,CAAyB,CAAAqB,CAAA,CAAAL,EAAA,CAAAhB,CAAA,CAKT,EADhBsB,CACgB,CADhBzD,CAAA,CAAAtD,CAAA,CACgB,CADhB8G,CACgB,CADhBvD,CAAA,CAAAvD,CAAA,CACgB,CADhB6G,CACgB,CAAhBvD,CAAA,CAAAtD,CAAA,CAAgB,CAFhBsD,CAAA,CAAAtD,CAAA,CAEgB,CAFhB6G,CAEgB,CAFhBtD,CAAA,CAAAvD,CAAA,CAEgB,CAFhB8G,CAEgB,CAAAvD,CAAA,CAAAvD,CAAA,EAAA+G,CA/DhB,CAnBA,CAjDAxB,QAAA,GAAAjC,CAAA,CAAAC,CAAA,CAAAyD,CAAA,EACAhH,EAAA0F,IAAAuB,MAAA,CAAAD,CAAA,CACA,KAAAE,EAAA,GAAAlH,CAAA,OACA,OAAA0F,KAAAyB,MAAA,CAAAD,CAAA,EAAA3D,CAAA,CAAAvD,CAAA,EAAAuD,CAAA,CAAAvD,CAAA,KAAAkH,CAAA,EAAA5D,CAAA,CAAAtD,CAAA,EAAAsD,CAAA,CAAAtD,CAAA,KAHA,CA9IAmD,CAAA,CAAAA,CAAA,IACA,KAAAiE,EAAAjE,CAAAiE,aAAA,MACAC,EAAAlE,CAAAkE,IAAA,EADA,CAEAC,EAAAnE,CAAAoE,EAAAD,EAAA,CAFA,CAYAtC,EAAAU,IAAA8B,IAAA,WAAAxC,CAAA,CAZA,CAeAiB,EAAA,CAAAA,EAAAoB,CAfA,CAgBAI,EAAAxE,CAAA,CAAAoE,CAAA,CAhBA,CAoBAK,EAAA,CAAAA,EAAAL,CAAAK,CAAA,CACAA,EAAA,EAAAA,CAAA,IAGA,KAAAC,EAAArF,CAAAC,EAAA,CAAA0D,CAAA,CAAAyB,CAAA,IACAE,EAAAtF,CAAAC,EAAA,CAAA0D,CAAA,CAAAyB,CAAA,GADA,CAEAvB,EAAAuB,CAFA,CAEAG,EAAAH,CAFA,CAKAI,EAAAxF,CAAAC,EAAA,CAAA0D,CAAA,CACA,KAAAjG,CAAA,GAAcA,CAAd,CAAciG,CAAd,CAA2BjG,CAAA,EAA3B,CACA8H,CAAA,CAAA9H,CAAA,QAAA0F,IAAAc,IAAA,GAAAd,IAAAM,GAAA,CAAAhG,CAAA,CAAAiG,CAAA,EAEA,KAAA8B,GAAA9B,CAAA8B,EAAA,CAAAA,EAAA,EACAC,EAAA1F,CAAAC,EAAA,CAAAwF,CAAA,CADA,CACAE,GAAA3F,CAAAC,EAAA,CAAAwF,CAAA,CADA,CAEAG,EAAA5F,CAAAC,EAAA,CAAAwF,CAAA,CAFA,CAEAI,EAAA7F,CAAAC,EAAA,CAAAwF,CAAA,CAFA,CAGAK,GAAA9F,CAAAC,EAAA,CAAAwF,CAAA,CAHA,CAGAM,GAAA/F,CAAAC,EAAA,CAAAwF,CAAA,CAEAO,IAAAP,CAAAO,EAAA,CAAAA,EAAA,CA7CA,KA8CAtE,EAAA,KA9CA,CA8CAE,GAAA,EA9CA,CA8CAE,EAAA,EA9CA,CA8CAE,GAAA,EA9CA,CA+CAR,EAAA,EACA,KAAA9D,CAAA,GAAc,CAAd,CAAcA,CAAd,CAAkBA,CAAA,EAAlB,CACAkE,EAAAqE,KAAA,CAAAjG,CAAAC,EAAA,CAAA+F,CAAA,EAGA;AAFAlE,CAAAmE,KAAA,CAAAjG,CAAAC,EAAA,CAAA+F,CAAA,EAEA,CADAhE,EAAAiE,KAAA,CAAAjG,CAAAC,EAAA,CAAA+F,CAAA,EACA,CAAAxE,CAAAyE,KAAA,CAAAjG,CAAAC,EAAA,CAAAwF,CAAA,EApDA,KAuDAxB,EAAAjE,CAAAC,EAAA,CAAA+F,CAAA,CAvDA,CAuDA7B,GAAAnE,CAAAC,EAAA,CAAA+F,CAAA,CAvDA,CA0DAE,GAAA,CA1DA,CA0DAC,EAAA,CA1DA,CA6DAC,EAAA,EAAkBF,EAAA,CAAlB,CAAkBC,EAAA,CAAlB,CAAkBlB,EAAAD,CAAlB,EA7DA,CA+DAqB,GAAA,CA/DA,CA+DAC,GAAA,CA/DA,CA+DAC,GAAA,CA/DA,CAgEAC,GAAA,CAhEA,CAgEAC,GAAA,CAhEA,CAmEAC,EAAA,CAnEA,CAmEAC,EAAA,CAnEA,CAqEAC,GAAA,CAGA,8BAAAC,CAAA,EAEA,IADA,IAAA9D,EAAAqD,CAAAlE,OAAAa,CAAA,CACA,CAAA8D,CAAA,CAAAT,CAAA,CAAArD,CAAA,CAAAoD,EAAA,IAAApD,CAAA,EAAAA,CAAA,EACA+D,GAAAV,CAAA,CAAArD,CAAA,CACA,OAAA+D,EAAAZ,EAAA,CAAAY,CAAA7B,EAAA,EAAA4B,CAAA,CAAAC,CAAAX,EAAA,CAJA,CAHA,CAUA,eAAAY,CAAA,EACAP,EAAA,EAAmB9E,EAAA,MAGnB,SAAAhE,EAFwBgJ,CAExBhJ,CAFAiJ,CAEAjJ,CAHqC4I,EAGrC5I,CAHqC,CAGrC,CAAe,CAAf,CAAeA,CAAf,CAAmBA,CAAA,EAAnB,CACA,QAAAsJ,EAAA,EAAgBA,CAAhB,CAAgBvB,CAAhB,CAAsBuB,CAAA,EAAtB,CACAxF,CAAA,CAAA9D,CAAA,EAAAsJ,CAAA,GAEA,KAAAtJ,CAAA,GAAeA,CAAf,CAAe2H,CAAAnD,OAAf,CAAkCxE,CAAA,EAAlC,CAAkC2H,CAAA,CAAA3H,CAAA,GAClC,KAAAA,CAAA,GAAeA,CAAf,CAAe4H,CAAApD,OAAf,CAAmCxE,CAAA,EAAnC,CAAmC4H,CAAA,CAAA5H,CAAA,GAGnC,IAAAqJ,CAAA,EAGAZ,CAAA,CAAA/C,IAAAhB,IAAA,GAAA+D,CAAA,CAAAY,CAAA,CACAb,GAAA,CAAAU,EAAA,sBAAAT,CAAA,CAIA,KADApD,CACA,CADAqD,CAAAlE,OACA,CADA,CACA,CAAAiE,CAAA,EAAAC,CAAA,CAAArD,CAAA,CAAAoD,EAAA,KAAApD,CAAA,EAAoDqD,CAAAa,IAAA,EAAe,CAAAlE,CAAA,EAGnEqD,EAAAH,KAAA,EACAC,IADA,CACAC,GADA;AAEAlB,EAAAD,CAFA,EAXA,CAZA,CAVA,CA+CA,oBAAgC,MAAAA,EAAhC,CA/CA,CAgDA,kBAAAkC,CAAA,EACArD,CAAA,CAAA0B,CAAA,CAAAH,CACA,IAAA8B,CAAA,CACA3B,CADA,CACAnC,IAAAE,MAAA,CAAAO,CAAA,CAAAqD,CAAA,CADA,CAGArD,CAHA,CAGAT,IAAAE,MAAA,CAAAiC,CAAA,CAAA2B,CAAA,CAEAT,GAAA,IAAAS,CAAA,GAAA3B,CAAA,CAAA1B,CAAA,EAAAA,CAZA,KAFA,IACAxE,EAcAmG,CAdAtD,OAAA7C,CAcAkG,CAdAlG,CAAA,CADA,CACA8H,EAAA,CADA,CAEAzJ,EAAA,EAAeA,CAAf,CAAe2B,CAAf,CAAmB3B,CAAA,EAAnB,CAAmByJ,CAAA,EAanB3B,CAbmB,CAAA9H,CAAA,CAanB6H,CAbmB,CACnB,IAhGA6B,EAgGA,CAAAD,CAaAnC,EAAA,CAAAkC,CAIAG,GAAAjB,CAAA,CAAAA,CAAAlE,OAAA,GACAmF,EAAAlB,EAAA,EAAAA,CAAA,CACAkB,CAAApC,EADA,CACAiC,CADA,CAGAd,CAAAH,KAAA,EACAC,IADA,CACAC,GADA,CAEAlB,EAAAiC,CAFA,EAjBA,CAhDA,CAuEAN,GAAA,SAAkBA,GAAA,UAAA5B,CAAA,CAsOlB4B,GAAA,kBAAAU,CAAA,EAEA,IAAAC,EAAAD,CAAA,GAAApF,OAAA,CAGAsF,EAAAF,CAAA,GACA,MAAAA,CAAApF,OAAA,EACAsF,CAAA,CAAAxH,CAAAC,EAAA,CAAAqH,CAAA,GAAApF,OAAA,CAEA,KADA,IAAAuF,EAAA,CAAAA,CAAAH,CAAApF,OAAA,CACApE,EAAA,EAAgBA,CAAhB,CAAgBwJ,CAAApF,OAAhB,CAA+BpE,CAAA,EAA/B,CACA,QAAAJ,EAAA,EAAiBA,CAAjB,CAAiB6J,CAAjB,CAA0B7J,CAAA,EAA1B,CACA8J,CAAA,CAAA9J,CAAA,GAAA+J,CAAA,CAAAH,CAAA,CAAAxJ,CAAA,EAAAJ,CAAA,CALA,CASA,MAAAsH,CAAA,EAGA,KAAA2B,CAAA,CAAAD,CAAA,EACAgB,EAAAf,CAAAe,CAAAhB,CAAAgB,CAAAH,CACAI,GAAA,EACA,KAAA7J,CAAA,GAAiBA,CAAjB,CAAiBwJ,CAAApF,OAAjB,CAAgCpE,CAAA,EAAhC,CACA8J,CAIA,CAJA5H,CAAAC,EAAA,CAAAyH,CAAA,CAIA,CAHA1H,CAAAI,EAAA,CAAAkF,CAAA,GAAAsC,CAAA,GAAAjB,CAAA,CAGA;AAFA3G,CAAAI,EAAA,CAAAiF,CAAA,GAAAuC,CAAA,CAAAjB,CAAA,CAAAD,CAAA,CAEA,CADA1G,CAAAI,EAAA,CAAAkH,CAAA,CAAAxJ,CAAA,IAAA8J,CAAA,CAAAjB,CAAA,CAAAD,CAAA,CAAAa,CAAA,CACA,CAAAI,CAAA1B,KAAA,CAAA2B,CAAA,CAEAhB,GAAA,SACAW,EAAA,CAAAG,CAAoBJ,EAAA,CAAAK,CAXpB,CAeAzB,EAAA,EAAAqB,CAAA,CAAAzC,CAAiCqB,EAAA,EAAAoB,CAAA,CAAAzC,CAGjC,OAAAwC,EArBA,CA2BAO,EAAA,CAAAA,CAAAzE,IAAAuB,MAAA,CAAAvB,IAAAhB,IAAA,GADAsE,CACA,CADAa,CACA,EADA5D,CACA,CADAE,CACA,MAAAA,CAAA,EACAiE,GAAAnB,CAAAmB,CAAAvC,CAAAuC,CAAAD,CAAAC,CACA1E,IAAAuB,MAAA,CAAA6B,EAAA,CAAAC,EAAA,CAAAoB,CAAA,CAEAlB,EAAA,CAAAmB,CAAA,GAAAA,CAAA,CAAAnB,CAAA,CAGAoB,GAAA/H,CAAAC,EAAA,CAAA6H,CAAA,CAGA9H,EAAAI,EAAA,CAAAkF,CAAA,GAAAyC,CAAA,GAAApB,CAAA,CACAqB,GAAA,CAGA,KAHA,IAAAC,EAAAtB,CAAA,CAEAuB,EAAA,CAFA,CAEAC,EAAA,CACA,IAGA,IAAAC,EAAAzE,CAAAyE,CAAAvE,CAAAuE,CAAA1B,CAEA,IAAAsB,CAAA,CAAAI,CAAA,CAAAb,CAAA,EAEAvH,CAAAI,EAAA,CAAAoH,CAAA,CAAAQ,CAAA,CAAA3C,CAAA,CAAAqB,CAAA,CAAAa,CAAA,CAAAS,CAAA,CACAtB,EAAA,EAAAa,CAAA,CAAAS,CACA,MAJA,KAMA,IAAAI,CAAA,CACA1B,CADA,EACA,CADA,CACA7C,CADA,EAIA7D,CAAAI,EAAA,CAAAoH,CAAA,CAAAQ,CAAA,CAAA3C,CAAA,CAAAqB,CAAA,CAAA0B,CAAA,CAEA,CADAJ,CACA,EADAI,CACA,CAAA1B,CAAA,CAAA/C,CAAA,CAAAE,CANA,CA9IA2C,GAAA,IAAAC,EACA4B,GAAA7B,EAAA6B,CAAA,CACA7B,GAAA,EAAA6B,CAGA,KAAA3K,CAAA,GAAeA,CAAf,CAAeiG,CAAf,CAA4BjG,CAAA,EAA5B,CACAyH,CAAAmD,EAAA,CAAA5K,CAAA,CACA,CADA8H,CAAA,CAAA9H,CAAA,CACA,CADA2H,CAAA,CAAA3H,CAAA,CACA,CAAAyH,CAAAoD,EAAA,CAAA7K,CAAA,EAAA8H,CAAA,CAAA9H,CAAA,EAAA2H,CAAA,CAAAxB,CAAA,CAAAnG,CAAA,CAIAsC,EAAAI,EAAA,CAAAiF,CAAA,GAAAxB,CAAA,CACAwB,CADA,CACA,CADA,CACA1B,CADA,CACAE,CADA,CAIAsB,EAAAqD,EAAA,IACArD,EAAAsD,EAAA,CAAA/C,CAAA,CAAAC,EAAA,CAAAC,CAAA,CAAAC,CAAA,CAIA/E,EAAA,CAAAuF,EAAA,CAAAX,CAAA,CAAAC,EAAA,CAAAG,EAAA,CAAAC,EAAA,CADA,CACA,CADAR,CACA,CADA1B,CACA,CAIA/C,EAAA,CAAAuF,EAAA,GAAAT,CAAA,CAAAC,CAAA,CAAAH,CAAA,CAAAC,EAAA,CADA,CACA,EADAJ,CACA,CADA8C,CACA,EADAxE,CACA,CAGA7D,EAAAI,EAAA,CAAAwF,CAAA,GAAAE,EAAA,GAAAL,CAAA,CAA6BzF;CAAAI,EAAA,CAAAyF,CAAA,GAAAE,EAAA,GAAAN,CAAA,CAG7BN,EAAAuD,EAAA,CAAAhD,CAAA,CAAAC,EAAA,CAAAC,CAAA,CAAAC,CAAA,CACAV,EAAAqD,EAAA,IAGAG,GAAArD,CAAApD,OACAlC,EAAAI,EAAA,CAAAkF,CAAA,CAAAgB,EAAA,CACAhB,CADA,CACA,CADA,CACAqD,CADA,CACArC,EADA,CAIA,KAAA5I,CAAA,CAAAiL,CAAA,CAAArC,EAAA,CAAgC5I,CAAhC,CAAgCiL,CAAhC,CAAwCjL,CAAA,EAAxC,CAAwC4H,CAAA,CAAA5H,CAAA,GAIxC0E,GAAA,MAAAwG,GAAArC,EACA,KAAA7I,CAAA,GAAeA,CAAf,CAAe6H,CAAf,CAAyB7H,CAAA,EAAzB,CACA0F,IAAAC,IAAA,GAAA8B,CAAAmD,EAAA,CAAA5K,CAAA,GAAA0E,CAAA,GACAA,CADA,CACAgB,IAAAC,IAAA,GAAA8B,CAAAmD,EAAA,CAAA5K,CAAA,EADA,CAEA,KAAAA,CAAA,GAAeA,CAAf,CAAeiG,CAAf,CAAe4B,CAAf,CAAoC7H,CAAA,EAApC,CACA0F,IAAAC,IAAA,CAAA8B,CAAAmD,EAAA,CAAA5K,CAAA,CAAA6H,CAAA,CAAA8C,CAAA,EAAAlD,CAAAoD,EAAA,CAAA7K,CAAA,GAAA0E,CAAA,GACAA,CADA,CACAgB,IAAAC,IAAA,CAAA8B,CAAAmD,EAAA,CAAA5K,CAAA,CAAA6H,CAAA,CAAA8C,CAAA,EAAAlD,CAAAoD,EAAA,CAAA7K,CAAA,EADA,CAGA,KAAAA,CAAA,CAAAiG,CAAA,CAAA4B,CAAA,CAAgC7H,CAAhC,CAAgCiG,CAAhC,CAA6CjG,CAAA,EAA7C,CACA0F,IAAAC,IAAA,GAAA8B,CAAAoD,EAAA,CAAA7K,CAAA,GAAA0E,CAAA,GACAA,CADA,CACAgB,IAAAC,IAAA,GAAA8B,CAAAoD,EAAA,CAAA7K,CAAA,EADA,CAIAmL,GAAA,CAAAA,CAAAzF,IAAAuB,MAAA,CAAAhB,CAAA,IAAA4B,CAAA,EACAqD,GAAA,CAAAxG,CAAA,CAAAyG,CAAA,GAEAD,EAFA,CAEAC,CAFA,CAEAzG,CAFA,CAMA,KAAA1E,CAAA,GAAeA,CAAf,CAAeiG,CAAf,CAA4BjG,CAAA,EAA5B,CACA4H,CAAA,CAAA5H,CAAA,CACA,EADAkL,EACA,CADAzD,CAAAmD,EAAA,CAAA5K,CAAA,CACA,CAAA4H,CAAA,CAAA5H,CAAA,CAAA6H,CAAA,CAAA8C,CAAA,GAAAO,EAAA,CAAAzD,CAAAoD,EAAA,CAAA7K,CAAA,CAGA2I,GAAA,GAEA,GAFcC,EAEd,CAFc,CAEd,CAFcf,CAEd,CAFc8C,CAyFdnC,GAAA,IAAArC,CAAA,CAAAiB,CAAoCqB,EAAA,EAAAgC,CAAA,CAAArD,CAGpCoD,EAAA,CAAAD,CAAA,CAAAE,CAAA,CAAAL,CAAuC,GAAAI,CAAA,GAAAA,CAAA,GAGvClI,EAAAI,EAAA,CAAAkF,CAAA,GAAAyC,CAAA,CAAAE,CAAA,CAAAE,CAAA,CAAAD,CAAA,CAEAD,EAAA,EAAAE,CAlCA,CAsCAnI,CAAAI,EAAA,CAAAkF,CAAA,CAAA6C,CAAA,CAAAD,CAAA,CAAA5C,CAAA,GAAA4C,CAAA,CACAvB,EAAA,CAAAuB,CAKAY;CAAAA,CAAA,EACA,KAAAhL,CAAA,GAAeA,CAAf,CAAewJ,CAAApF,OAAf,CAA8BpE,CAAA,EAA9B,CAA8BgL,CAAA7C,KAAA,CAAA8B,CAAA,CAE9B,OAAAe,EAvGA,CA0GA,OAAAlC,GA5dA,CAZA,IHsHsD,CCpCtD,CE2ZC,SAAAnJ,CAAA,CAAAD,CAAA,CAAAH,CAAA,ECneD,IAAA2C,EAAS3C,CAAA,CAAQ,CAAR,CAoKTI,EAAAD,EAAA,CAlKAmD,QAAA,CAAAoI,CAAA,EAeA,IAZA,IAAAC,EAAA,CAAAA,EAAAD,CAAA,CAGAnC,EAAA,CACAqC,EAAAF,CADA,CACAC,GADA,CAEAE,EAAA,CAAAA,CAAAF,CAFA,CAGAV,EAAAtI,CAAAC,EAAA,CAAA+I,CAAA,CAHA,CAIAT,EAAAvI,CAAAC,EAAA,CAAA+I,CAAA,CAJA,CAKAG,EAAAC,KAAA,CAAAJ,CAAA,CALA,CAHA,CAYAhC,EAAA,EAAeA,CAAf,CAAegC,CAAf,CAAsBhC,CAAA,EAAtB,CAAsB,CAEtB,IAFsB,IACtBqC,EAAArC,CADsB,CACtBsC,EAAA,CADsB,CAEtB5L,EAAA,EAAcA,CAAd,CAAcqL,CAAd,CAAqBrL,CAAA,EAArB,CACA4L,CAEA,GAFA,CAEA,CADAA,CACA,EADAD,CACA,CADA,CACA,CAAAA,CAAA,IAEAzC,EAAAuC,EAAA,CAAAnC,CAAA,EAAAsC,CAPsB,CAgBtB1C,CAAA2C,EAAA,CAAAvJ,CAAAC,EAAA,CAAA2G,CAAAqC,EAAA,CACArC,EAAA4C,EAAA,CAAAxJ,CAAAC,EAAA,CAAA2G,CAAAqC,EAAA,CAEAQ,GAAA,CACA,KAAAC,CAAA,GAAmBA,CAAnB,CAAmB9C,CAAAqC,EAAnB,CAAqCS,CAAA,EAArC,CACAC,CAGA,CAHA,CAGA,CAHAF,CAGA,CAHArG,IAAAM,GAGA,CAHAkD,CAAAsC,EAGA,CAFAtC,CAAA2C,EAAA,CAAAG,CAAA,CAEA,CAFAtG,IAAAc,IAAA,CAAAyF,CAAA,CAEA,CADA/C,CAAA4C,EAAA,CAAAE,CAAA,CACA,CADAtG,IAAAgB,IAAA,CAAAuF,CAAA,CACA,CAAAF,CAAA,IAIA7C,EAAA4B,EAAA,CAAAoB,QAAA,CAAAC,CAAA,MAEAvB,EAAA1B,CAAA0B,EAFA,CAEAC,EAAA3B,CAAA2B,EAFA,CAGAS,EAAApC,CAAAoC,EAHA,CAGAC,EAAArC,CAAAqC,EAHA,CAKAa,EAAAd,CAAAc,EAAA,CALA,CAMAC,EAAAf,CAAAe,EAAA,CANA,CAOAC,EAAAhB,CAEA,IAAAa,CAAA,CAEA,IADA,IAAAX,EAAA,CAAAA,CAAAF,CAAA,CACAtL,EAAA,EAAeA,CAAf,CAAesL,CAAf,CAAsBtL,CAAA,EAAtB,CACA4K,CAAA,CAAA5K,CAAA,CACA,EADAwL,CACA,CAAAX,CAAA,CAAA7K,CAAA,GAAAwL,CAKA,KAAAQ,CAAA,GAAkBA,CAAlB,CAAkBT,CAAlB,CAAgCS,CAAA,EAAhC,CAAgC,CAChCO,EAAArD,CAAA2C,EAAA,CAAAG,CAAA,CACA,KAAAQ,GAAAtD,CAAA4C,EAAA,CAAAE,CAAA,CACAG,EAAA,GAAAK,EAAA;AAAA,GAGA,KADA,IAAAC,EAAA,CACA,CAAAA,CAAA,CAAAnB,CAAA,GAKA,IALA,IACAoB,EAAAD,CADA,CACAE,GAAAF,CAAAE,CAAAN,CADA,CAEAO,GAAA,CAFA,CAEAC,EAAA,CAFA,CAKAC,GAAA,EAAuBA,EAAvB,CAAuBV,CAAvB,CAA0CU,EAAA,EAA1C,CAA0C,CAE1C,IAAAC,EAAAnC,CAAA,CAAA8B,CAAA,EACAM,GAAAnC,CAAA,CAAA6B,CAAA,CADA,CAEAO,EAAArC,CAAA,CAAA+B,EAAA,CAFA,CAGAO,EAAArC,CAAA,CAAA8B,EAAA,CAGA/B,EAAA,CAAA8B,CAAA,EAAAK,CAAA,CAAAE,CACApC,EAAA,CAAA6B,CAAA,EAAAM,EAAA,CAAAE,CAIAD,EAAA,CAAAF,CAAA,CAAAE,CACAC,EAAA,CAAAF,EAAA,CAAAE,CAEAtC,EAAA,CAAA+B,EAAA,EAAAM,CAAA,CAAAL,EAAA,CAAAM,CAAA,CAAAL,CACAhC,EAAA,CAAA8B,EAAA,EAAAM,CAAA,CAAAJ,CAAA,CAAAK,CAAA,CAAAN,EAGAF,EAAA,EACAC,GAAA,EAKAQ,GAAAP,EACAA,GAAA,CAAAA,EAAA,CAAAL,CAAA,CAAAM,CAAA,CAAAL,EACAK,EAAA,CAAAM,CAAA,CAAAX,EAAA,CAAAK,CAAA,CAAAN,CA5B0C,CA8B1CE,CAAA,EAAAH,CAnCA,CAqCAF,CAAA,IACAC,EAAA,IACAC,EAAA,IA7CgC,CAgDhCb,EAAAvC,CAAAuC,EACA,KAAA2B,CAAA,GAAeA,CAAf,CAAe9B,CAAf,CAAuB8B,CAAA,EAAvB,CACA3B,CAAA,CAAA2B,CAAA,EAAAA,CAAA,GAKAC,CAMA,CANA5B,CAAA,CAAA2B,CAAA,CAMA,CALAlD,CAKA,CALAU,CAAA,CAAAyC,CAAA,CAKA,CAJAzC,CAAA,CAAAyC,CAAA,CAIA,CAJAzC,CAAA,CAAAwC,CAAA,CAIA,CAHAxC,CAAA,CAAAwC,CAAA,CAGA,CAHAlD,CAGA,CAFAA,CAEA,CAFAW,CAAA,CAAAwC,CAAA,CAEA,CADAxC,CAAA,CAAAwC,CAAA,CACA,CADAxC,CAAA,CAAAuC,CAAA,CACA,CAAAvC,CAAA,CAAAuC,CAAA,EAAAlD,CAXA,CApEA,CAmFA,KAAAoD,EAAAhC,CAAAgC,EAAA,CAKApE,EAAA6B,EAAA,CAAAwC,QAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,EACAH,CAAA,IAAAtE,CAAA0B,EAAA,GAAuB8C,EAAA,IAAAxE,CAAA2B,EAAA,GACvB4C,EAAA,IAAAE,CAAA,KACAH,EAAA,CAAAF,CAAA,EAAApE,CAAA0B,EAAA,CAAA0C,CAAA,CACAI,EAAA,CAAAJ,CAAA,EAAApE,CAAA2B,EAAA,CAAAyC,CAAA,CACAG,EAAA,CAAAH,CAAA,EAAAK,CAAA,CAAAL,CAAA,GACA,SAAAtN,EAAA,EAAgBA,CAAhB,CAAgBsN,CAAhB,CAAuBtN,CAAA,EAAvB,CACAwN,CAAA,CAAAxN,CAAA,CAGA,EAHAkJ,CAAA0B,EAAA,CAAA5K,CAAA,CAGA,CAHAkJ,CAAA0B,EAAA,CAAAU,CAAA,CAAAtL,CAAA,CAGA,EAHA,CAGA,CAFAyN,CAAA,CAAAzN,CAAA,CAEA,EAFAkJ,CAAA2B,EAAA,CAAA7K,CAAA,CAEA,CAFAkJ,CAAA2B,EAAA,CAAAS,CAAA,CAAAtL,CAAA,CAEA,EAFA,CAEA,CADA0N,CAAA,CAAA1N,CAAA,CACA,EADAkJ,CAAA2B,EAAA,CAAA7K,CAAA,CACA,CADAkJ,CAAA2B,EAAA,CAAAS,CAAA;AAAAtL,CAAA,CACA,EADA,CACA,CAAA2N,CAAA,CAAA3N,CAAA,IAAAkJ,CAAA0B,EAAA,CAAA5K,CAAA,EAAAkJ,CAAA0B,EAAA,CAAAU,CAAA,CAAAtL,CAAA,IAVA,CAiBAkJ,EAAA8B,EAAA,CAAA4C,QAAA,CAAAJ,CAAA,CAAAC,CAAA,CAAAC,CAAA,CAAAC,CAAA,EACAzE,CAAA0B,EAAA,IAAA4C,CAAA,GAAuBtE,EAAA2B,EAAA,IAAA6C,CAAA,GACvBxE,EAAA0B,EAAA,CAAA0C,CAAA,EAAAE,CAAA,CAAAF,CAAA,CAA6BpE,EAAA2B,EAAA,CAAAyC,CAAA,EAAAI,CAAA,CAAAJ,CAAA,CAC7B,SAAAtN,EAAA,EAAgBA,CAAhB,CAAgBsN,CAAhB,CAAuBtN,CAAA,EAAvB,CACAkJ,CAAA0B,EAAA,CAAA5K,CAAA,CAGA,CAHAwN,CAAA,CAAAxN,CAAA,CAGA,CAHA2N,CAAA,CAAA3N,CAAA,CAGA,CAFAkJ,CAAA2B,EAAA,CAAA7K,CAAA,CAEA,CAFAyN,CAAA,CAAAzN,CAAA,CAEA,CAFA0N,CAAA,CAAA1N,CAAA,CAEA,CADAkJ,CAAA0B,EAAA,CAAAU,CAAA,CAAAtL,CAAA,CACA,CADAwN,CAAA,CAAAxN,CAAA,CACA,CADA2N,CAAA,CAAA3N,CAAA,CACA,CAAAkJ,CAAA2B,EAAA,CAAAS,CAAA,CAAAtL,CAAA,GAAAyN,CAAA,CAAAzN,CAAA,EAAA0N,CAAA,CAAA1N,CAAA,CAPA,CAWA,OAAAkJ,EA/JA,CDieC,CF3ZD,CDxEgB,CDDf,CARD,iBAAApJ,QAAA,mBAAAC,OAAA,CACAA,MAAAD,EADA,CACA+N,EAAA,EADA,CAEA,mBAAAC,OAAA,EAAAA,MAAAC,EAAA,CACAD,MAAA,IAAAD,EAAA,CADA,CAEA,iBAAA/N,QAAA,CACAA,OAAA,kBADA,CACA+N,EAAA,EADA,CAGAG,EAAA,kBAHA,CAGAH,EAAA","file":"AudioTempoChanger.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"AudioTempoChanger\"] = factory();\n\telse\n\t\troot[\"AudioTempoChanger\"] = factory();\n})(window, function() {\nreturn ","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"AudioTempoChanger\"] = factory();\n\telse\n\t\troot[\"AudioTempoChanger\"] = factory();\n})(window, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\n\n// Define an allocator and blit function for float arrays\n// Can be used to achieve backwards compatibility down to dark ages pre IE 10 if needed\n// Also reduces code size a little with closure.\n\nvar VH = { \n\tfloat_array: function(len) { return new Float32Array(len); },\n\tblit: function(src, spos, dest, dpos, len) { dest.set(src.subarray(spos,spos+len),dpos); }\n};\n\n// Pre-IE10 versions:\n/*VH.prototype.float_array = function(len) { return new Array(len); }\nVH.prototype.blit = function(src, spos, dest, dpos, len) { for(var i=0;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k=0) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k=0) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i=0) { changes.pop(); ci--; } + while(ci > 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; } // Add a tempo change reflecting current state changes.push({ diff --git a/dist/test.js.map b/dist/test.js.map index 081d8bb..ae45462 100644 --- a/dist/test.js.map +++ b/dist/test.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://test/webpack/bootstrap","webpack://test/./src/vector_helper.js","webpack://test/./src/test.js","webpack://test/./src/audio_tempo_changer.js","webpack://test/./src/fft.js"],"names":[],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;ACjFA;AACA;AACA;;AAEA,U;AACA,6BAA6B,8BAA8B,EAAE;AAC7D,6CAA6C,4CAA4C;AACzF;;AAEA;AACA,4CAA4C,uBAAuB;AACnE,0DAA0D,aAAa,MAAM,gCAAgC,GAAG;;AAEhH,oB;;;;;;;ACda;;AAEb;AACA;AACA;AACA;AACA;;AAEA,yBAAyB,mBAAO,CAAC,CAA0B;AAC3D,UAAU,mBAAO,CAAC,CAAoB;;AAEtC;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,6BAA6B;AAC7B;;AAEA,6BAA6B;;AAE7B;;AAEA,6BAA6B;;AAE7B,qBAAqB;AACrB,sBAAsB;AACtB,sBAAsB;AACtB,6BAA6B;AAC7B,oDAAoD;AACpD,yCAAyC;AACzC,uBAAuB;;AAEvB,6BAA6B;;AAE7B;AACA;AACA,aAAa,aAAa;AAC1B;;AAEA;AACA;;;AAGA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,IAAI;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,IAAI;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,iCAAiC,0EAA0E;AAC3G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,oCAAoC,oBAAoB,G;AACxD;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,E;;;;;;ACpJb;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,mBAAO,CAAC,CAAoB;AACtC,WAAW,mBAAO,CAAC,CAAU;;AAE7B;;AAEA;AACA;AACA;;AAEA;AACA;AACA,qCAAqC;AACrC;AACA;;AAEA;AACA;AACA;;AAEA;AACA,2BAA2B;AAC3B,4BAA4B;AAC5B,oDAAoD;AACpD,6BAA6B;;AAE7B;AACA;;AAEA;AACA;AACA,yCAAyC;AACzC,qCAAqC;;AAErC;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc,aAAa;AAC3B;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,cAAc,IAAI,MAAM;AACxB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,kBAAkB,mDAAmD;;AAErE;AACA;;AAEA;AACA;;AAEA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,kBAAkB;AACrC,wBAAwB;;AAExB,eAAe,IAAI;AACnB,gBAAgB,MAAM;AACtB;;AAEA,eAAe,mBAAmB;AAClC,eAAe,oBAAoB;;AAEnC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,oDAAoD,eAAe,MAAM;;AAEzE;AACA,kB;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,eAAe,IAAI;AACnB;AACA;;AAEA,gCAAgC,qBAAqB;AACrD;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2BAA2B;AAC3B;AACA,kB;AACA;AACA;AACA,KAAK;AACL;;AAEA,kBAAkB;;;AAGlB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,eAAe,aAAa,cAAc;AAC1C;;AAEA,gCAAgC;AAChC,eAAe,cAAc;AAC7B;AACA,2EAA2E;;AAE3E;AACA;;AAEA;AACA,4CAA4C,uBAAuB,aAAa;AAChF;AACA,uCAAuC,yBAAyB,aAAa;AAC7E;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,eAAe,cAAc;;AAE7B;AACA;AACA;;AAEA;AACA;;AAEA,sCAAsC;;AAEtC;AACA,iBAAiB,UAAU;AAC3B;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,UAAU;AAC1B;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC;AAChC,oCAAoC;AACpC,KAAK,OAAO;AACZ;AACA,8BAA8B,oBAAoB,oB;AAClD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,eAAe,cAAc;AAC7B;AACA,WAAW,iBAAiB;AAC5B,yBAAyB;AACzB;;AAEA;AACA;AACA,gBAAgB;AAChB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,aAAa;AAC5B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,6BAA6B;;AAE7B;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC,QAAQ;;AAExC;AACA;AACA;AACA,eAAe,UAAU;AACzB;AACA;AACA,eAAe,qBAAqB;AACpC;AACA;;AAEA,gCAAgC,aAAa;AAC7C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,aAAa;AAC5B;AACA;AACA;;AAEA,cAAc;;AAEd;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,sB;AACA;AACA;AACA;AACA,gBAAgB,eAAe;AAC/B,iBAAiB,SAAS;AAC1B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,iBAAiB,eAAe,M;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;;AAEA;AACA,iCAAiC;;AAEjC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,iD;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,6BAA6B;AAC7B;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA,sC;AACA,UAAU;AACV;AACA;AACA,oB;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,oCAAoC;;AAEpC;AACA,uCAAuC;;AAEvC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,eAAe,eAAe;;AAE9B;AACA;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;;;;;;;;AC7eY;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,mBAAO,CAAC,CAAoB;;AAErC;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,OAAO;AACtB;AACA,cAAc,OAAO;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,mBAAmB,kBAAkB;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,OAAO;AACtB;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,cAAc;AAChC;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,mBAAmB;AAC1C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,qBAAqB;;AAErB;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uBAAuB;AACvB,6BAA6B;AAC7B,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,qB","file":"test.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","\n// Define an allocator and blit function for float arrays\n// Can be used to achieve backwards compatibility down to dark ages pre IE 10 if needed\n// Also reduces code size a little with closure.\n\nvar VH = { \n\tfloat_array: function(len) { return new Float32Array(len); },\n\tblit: function(src, spos, dest, dpos, len) { dest.set(src.subarray(spos,spos+len),dpos); }\n};\n\n// Pre-IE10 versions:\n/*VH.prototype.float_array = function(len) { return new Array(len); }\nVH.prototype.blit = function(src, spos, dest, dpos, len) { for(var i=0;i nsamples-read_ind) N = Math.max(0,nsamples-read_ind);\n\t\tvar vec = VH.float_array(N);\n\t\tfor(var i=0;i nsamples-read_ind) N = Math.max(0,nsamples-read_ind);\n\t\tvar vec = VH.float_array(N);\n\t\tfor(var i=0;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k=0) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i nsamples-read_ind) N = Math.max(0,nsamples-read_ind);\n\t\tvar vec = VH.float_array(N);\n\t\tfor(var i=0;i nsamples-read_ind) N = Math.max(0,nsamples-read_ind);\n\t\tvar vec = VH.float_array(N);\n\t\tfor(var i=0;i> 1) + 1;\n\t\tvar re1 = VH.float_array(hWS), im1 = VH.float_array(hWS);\n\t\tvar re2 = VH.float_array(hWS), im2 = VH.float_array(hWS);\n\t\tvar pre2 = VH.float_array(hWS), pim2 = VH.float_array(hWS);\n\n\t\tvar qWS = (hWS >> 1) + 1;\n\t\tvar b_npeaks = [0,0], b_peaks = [], b_in_angs = [], b_peak_adeltas = [];\n\t\tvar b_mags = [];\n\t\tfor(var i=0;i<2;i++) { // Double buffering\n\t\t\tb_peaks.push(VH.float_array(qWS));\n\t\t\tb_in_angs.push(VH.float_array(qWS));\n\t\t\tb_peak_adeltas.push(VH.float_array(qWS));\n\t\t\tb_mags.push(VH.float_array(hWS));\n\t\t}\n\t\t\n\t\tvar peaks_re = VH.float_array(qWS), peaks_im = VH.float_array(qWS);\n\n\t\t// Keep track of time (in samples) in both input and output streams\n\t\tvar in_time = 0.0, out_time = 0.0;\n\n\t\t// Track the changes for mapOutputToInputTime\n\t\tvar changes = [{ in_time: 0.0, out_time: 0.0, tempo: chosen_tempo }];\n\n\t\tvar f_ind = 0, prev_out_len = 0, gain_comp = 1.0;\n\t\tvar syn_drift = 0.0, syn_drift_per_step = 0.0;\n\n\t\t// Two variables used for \"process\"\n\t\tvar inbuffer_contains = 0, unused_in_outbuf = 0;\n\n\t\tvar obj = { };\n\n\t\t// Should map time in output to time in input\n\t\tobj['mapOutputToInputTime'] = function(given_out_time) {\n\t\t\tvar ci = changes.length-1;\n\t\t\twhile(given_out_time0) ci--;\n\t\t\tvar cc = changes[ci];\n\t\t\treturn cc.in_time + cc.tempo*(given_out_time-cc.out_time);\n\t\t};\n\n\t\tobj['flush'] = function(discard_output_seconds) {\n\t\t\tsyn_drift = 0.0; b_npeaks = [0,0]; prev_out_len = 0;\n\t\t\tunused_in_outbuf = 0; inbuffer_contains = 0;\n\n\t\t\tfor(var i=0;i<2;i++)\n\t\t\t\tfor(var k=0;k 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; }\n\n\t\t\t\t// Add a tempo change reflecting current state\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: chosen_tempo\n\t\t\t\t})\n\t\t\t}\n\t\t};\n\n\t\t// Small utility function to calculate gain compensation\n\t\tvar compute_gain_comp = function(win,syn_len) {\n\t\t\tvar n = win.length / syn_len | 0, sum = 0.0;\n\t\t\tfor(var i=0;i= 1.0) {\n\t\t\t\tsyn_len = Math.round(ana_len / tempo_ratio);\n\t\t\t} else {\n\t\t\t\tana_len = Math.round(syn_len * tempo_ratio);\n\t\t\t}\n\t\t\tsyn_drift_per_step = (1.0 / tempo_ratio - 1.0 * syn_len / ana_len) * ana_len;\n\t\t\tgain_comp = compute_gain_comp(win,syn_len);\n\t\t\tchosen_tempo = tempo_ratio;\n\t\t\t//console.log(\"TEMPO CHANGE\",tempo_ratio,\"LENS\",ana_len,syn_len,\"GAIN\",gain_comp);\n\n\t\t\t// Handle book-keeping for time map\n\t\t\tvar lc = changes[changes.length-1];\n\t\t\tif (lc.out_time == out_time) // no samples since last change\n\t\t\t\tlc.tempo = tempo_ratio; // Just replace last change event\n\t\t\telse //add new entry\n\t\t\t\tchanges.push({ \n\t\t\t\t\tin_time: in_time, out_time: out_time,\n\t\t\t\t\ttempo: tempo_ratio\n\t\t\t\t})\n\t\t};\n\n\t\tobj['flush'](0); obj['setTempo'](chosen_tempo);\n\n\n\t\t/**************************\n\t\t* Small utility functions\n\t\t**************************/\n\t\t\n\t\t// Estimate the phase at (fractional) fft bin ind\n\t\tvar interpolate_phase = function(re,im,ind) {\n\t\t\tvar i = Math.floor(ind);\n\t\t\tvar sgn = i % 2 == 1 ? -1.0 : 1.0;\n\t\t\treturn Math.atan2(sgn * (im[i] - im[i + 1]),sgn * (re[i] - re[i + 1]));\n\t\t};\n\n\t\t// Get ang between -PI and PI\n\t\tvar unwrap = function(ang) {\n\t\t\treturn ang - 2 * Math.PI * Math.round(ang / (2 * Math.PI) );\n\t\t};\n\n\t\t// Try to estimate the phase change if window lengths differ by ratio\n\t\tvar estimate_phase_change = function(ang,k,pang,pk,ratio) {\n\t\t\tvar pred = 2 * Math.PI / windowSize * 0.5 * (pk + k) * ana_len;\n\t\t\tvar ywang = unwrap(ang - pang - pred);\n\n\t\t\treturn (ywang + pred) * ratio;\n\t\t};\n\n\t\t/**************************\n\t\t* Find peaks of spectrum\n\t\t**************************/\n\n\t\tvar find_rpeaks = function(mags,res) {\n\n\t\t\tvar max = 0; for(var i=0;imax) max=mags[i];\n\t\t\tvar thresh = MAX_PEAK_RATIO * max;\n\n\t\t\tvar n_peaks = 1, prev_pi = 1; res[0] = 1.0;\n\t\t\tfor(var i=2;ithresh && mags[i] > mags[i - 1] && mags[i] >= mags[i + 1]) { // Is local peak\n\n\t\t\t\t\t// Use quadratic interpolation to fine-tune the peak location\n\t\t\t\t\tvar ppos = i + (mags[i - 1] - mags[i + 1]) / (2 * (mags[i - 1] - 2 * mags[i] + mags[i + 1]));\n\n\t\t\t\t\t// If far enough from previous peak, add to list\n\t\t\t\t\tif(ppos - res[n_peaks - 1] > f_delta) { res[n_peaks++] = ppos; prev_pi = i; }\n\t\t\t\t\t// Else, if not far enough, but higher than previous, just replace prev \n\t\t\t\t\telse if(mags[i] > mags[prev_pi]) { res[n_peaks - 1] = ppos;\tprev_pi = i; }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn n_peaks;\n\t\t};\n\n\t\t/**************************\n\t\t* Rigid phase shift\n\t\t**************************/\n\n\t\tvar pshift_rigid = function(frame_ind,re,im,p_re,p_im,ratio) {\n\t\t\tvar CUR = frame_ind % 2, PREV = 1 - CUR;\n\n\t\t\tvar prev_mags = b_mags[PREV];\n\n\t\t\tvar prev_np = b_npeaks[PREV], prpeaks = b_peaks[PREV];\n\t\t\tvar prev_in_angs = b_in_angs[PREV], prev_peak_adeltas = b_peak_adeltas[PREV];\n\n\t\t\t// Calc new mags\n\t\t\tvar mags = b_mags[CUR];\n\t\t\tfor(var i=1;i prpeaks[pi] && pi != prev_np) ++pi;\n\n\t\t\t\tvar cpi = pi;\n\t\t\t\tif(pi > 0 && pci - prpeaks[pi - 1] < prpeaks[pi] - pci) cpi = pi - 1;\n\n\t\t\t\tvar peak_delta = pci * MAX_PEAK_JUMP;\n\t\t\t\tif(Math.abs(prpeaks[cpi] - pci) < peak_delta && \n\t\t\t\t\tprev_mags[Math.round(prpeaks[cpi])] > \n\t\t\t\t\t\tMATCH_MAG_THRESH * mags[Math.round(pci)]) {\n\n\t\t\t\t\t// Found a matching peak in previous frame, so predict based on the diff\n\t\t\t\t\tvar in_angle = interpolate_phase(re,im,pci);\n\t\t\t\t\tvar out_angle = prev_in_angs[cpi] + prev_peak_adeltas[cpi] +\n\t\t\t\t\t\t\testimate_phase_change(in_angle,pci,prev_in_angs[cpi],prpeaks[cpi],ratio);\n\n\t\t\t\t\tvar delta = out_angle - in_angle;\n\t\t\t\t\tcur_in_angs[ci] = in_angle; cur_peak_adeltas[ci] = delta;\n\t\t\t\t\tpeaks_re[ci] = Math.cos(delta);\tpeaks_im[ci] = Math.sin(delta);\n\t\t\t\t} else { // Not matched - use the same phase as input\n\t\t\t\t\tcur_in_angs[ci] = interpolate_phase(re,im,pci);\n\t\t\t\t\tcur_peak_adeltas[ci] = 0; peaks_re[ci] = 1.0;\tpeaks_im[ci] = 0.0;\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t /********************************************************\n\t\t * Adjust phase of all bins based on closest peak\n\t\t *********************************************************/\n\n\t\t // Add a \"dummy\" peak at the end of array\n\t\t\tpeaks[cur_np] = 2 * windowSize;\n\t\t\t\n\t\t\tvar cpi = 0, cp = peaks[cpi], cnp = peaks[cpi + 1];\n\t\t\tvar cre = peaks_re[cpi], cim = peaks_im[cpi];\n\n\t\t\tfor(var i=1;i= cp && i - cp > cnp - i) {\n\t\t\t\t\t++cpi; cp = peaks[cpi];\tcnp = peaks[cpi + 1];\n\t\t\t\t\tcre = peaks_re[cpi]; cim = peaks_im[cpi];\n\t\t\t\t}\n\n\t\t\t\tvar nre = re[i] * cre - im[i] * cim;\n\t\t\t\tvar nim = re[i] * cim + im[i] * cre;\n\t\t\t\tre[i] = nre; im[i] = nim;\n\t\t\t}\n\t\t}\n\n\t\t/***********************************\n\t\t* Perform two syn/ana steps \n\t\t*\t(using the two-for-one fft trick)\n\t \t* Takes windowSize + ana_len samples from in_buffer\n\t \t* and shifts in_buffer back by 2*ana_len\n\t \t* Outputs samples to out_buffer\n\t\t***********************************/\n\n\t\tvar two_steps = function() {\n\n\t\t\t// To better match the given ratio,\n\t \t// occasionally tweak syn_len by 1 or 2\n\t\t\tsyn_drift += 2 * syn_drift_per_step;\n\t\t\tvar sdelta = syn_drift | 0;\n\t\t\tsyn_drift -= sdelta;\n\t\t\t\n\t\t\t// Pack two steps into fft object\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_re[i]);\n\t\t\tfor(var i=0;i max)\n\t\t\t\t\tmax = Math.abs(fft.m_re[i + syn_len + sdelta] + fft.m_im[i]);\n\n\t\t\tfor(var i=windowSize-syn_len;i max)\n\t\t\t\t\tmax = Math.abs(2 * fft.m_im[i]);\n\n\t\t\t// Find allowed ceiling of a two-step sum and lower gain if needed\n\t\t\tvar ceiling = 1.0 / Math.floor(1.0 * windowSize / (2 * syn_len));\n\t\t\tif(gc * max > ceiling) {\n\t\t\t\t//console.log(\"Gain overflow, lowering volume: \",ceiling / max,gc,max);\n\t\t\t\tgc = ceiling / max;\n\t\t\t}\n\n\t\t\t// Write results to out_buffer\n\t\t\tfor(var i=0;i1) {\n\t\t\t\tmix = VH.float_array(in_ar[0].length);\n\t\t\t\tvar mult = 1.0/in_ar.length;\n\t\t\t\tfor(var c=0;c0) {\n\t\t\t\t\tvar n_len = unused_in_outbuf + inbuffer_contains + in_len;\n\t\t\t\t\tvar n_ar = [];\n\t\t\t\t\tfor(var c=0;cout_len) out_len = unused_in_outbuf;\n\n\t\t\t// Allocate output\n\t\t\tvar outp = VH.float_array(out_len);\n\n\t\t\t// Copy previously unused but ready values to output\n\t\t\tVH.blit(out_buffer,0,outp,0,unused_in_outbuf); \n\t\t\tvar ii = 0, oi = unused_in_outbuf;\n\t\t\t\n\t\t\tvar left_over = 0, res_len = 0;\n\t\t\twhile(true) {\n\n\t\t\t\t// Calculate how many new samples we need to call two_steps\n\t\t\t\tvar n_needed = windowSize + ana_len - inbuffer_contains;\n\t\t\t\t\n\t\t\t\tif (ii+n_needed>in_len) { // Not enough samples for next step\n\t\t\t\t\t// Copy whats left to inbuffer and break out of the loop\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,in_len-ii);\n\t\t\t\t\tinbuffer_contains += in_len-ii; ii = in_len;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (n_needed <= 0) // Already enough - can happen if tempo changed\n\t\t\t\t\tinbuffer_contains -= 2 * ana_len; \n\t\t\t\telse { // Main case - we have enough\n\t\t\t\t\t// Copy over this many samples from input\n\t\t\t\t\tVH.blit(mix,ii,in_buffer,inbuffer_contains,n_needed);\n\t\t\t\t\tii += n_needed;\t\t\t\t\t\n\t\t\t\t\tinbuffer_contains = windowSize - ana_len;\n\t\t\t\t}\n\n\t\t\t\t// Invariant: left_over should be 0 here as it should break!\n\n\t\t\t\t// Run the vocoder\n\t\t\t\tres_len = two_steps();\n\n\t\t\t\t// Move time pointers\n\t\t\t\tin_time += 2*ana_len/sampleRate; out_time += res_len/sampleRate;\n\n\t\t\t\t// Calculate how many samples are left over (usually 0)\n\t\t\t\tleft_over = oi + res_len - out_len; if(left_over < 0) left_over = 0;\n\n\t\t\t\t// Copy fully ready samples out\n\t\t VH.blit(out_buffer,0,outp,oi,res_len-left_over);\n\n\t\t\t\toi += res_len;\n\t\t\t}\n\n\t\t\t// Copy left over samples to the beginning of out_buffer\n \t\t\tVH.blit(out_buffer,res_len-left_over,out_buffer,0,left_over);\n \t\t\tunused_in_outbuf = left_over;\n\n \t\t\t//////////////////////// DONE\n\n\t\t\t// Clone the result to match the number of input channels\n\t\t\tvar out_ar = [];\n\t\t\tfor(var c=0;c>= 1;\n\t\t}\n\t\tobj.m_revTgt[k] = y;\n\t}\n\n // Compute a multiplier factor for the \"twiddle factors\".\n // The twiddle factors are complex unit vectors spaced at\n // regular angular intervals. The angle by which the twiddle\n // factor advances depends on the FFT stage. In many FFT\n // implementations the twiddle factors are cached.\n\n\tobj.twiddleRe = VH.float_array(obj.m_logN);\n\tobj.twiddleIm = VH.float_array(obj.m_logN);\n\n\tvar wIndexStep = 1;\n\tfor(var stage = 0; stage> 1;\n\t\tvar span = m_N >> 1;\n\t\tvar spacing = m_N;\n\n\t\tif(inverse) {\n\t\t\tvar m_invN = 1.0/m_N;\n\t\t\tfor(var i=0; i>= 1;\n\t\t\tspan >>= 1;\n\t\t\tspacing >>= 1;\n\t\t}\n\n\t\tvar revI, buf, m_revTgt = obj.m_revTgt;\n\t\tfor(var i1=0; i1 i1) {\n // Bit-Reversal is an involution i.e.\n // x.revTgt.revTgt==x\n // So switching values around\n // restores the original order\n\t\t\t\trevI = m_revTgt[i1];\n\t\t\t\tbuf = m_re[revI];\n\t\t\t\tm_re[revI] = m_re[i1];\n\t\t\t\tm_re[i1] = buf;\n\t\t\t\tbuf = m_im[revI];\n\t\t\t\tm_im[revI] = m_im[i1];\n\t\t\t\tm_im[i1] = buf;\n\t\t\t}\n\t}\n\n\tvar m_N2 = m_N >> 1; // m_N/2 needed in un/repack below\n\n\t// Two-for-one trick for real-valued FFT:\n\t// Put one series in re, other in im, run \"inplace\",\n\t// then call this \"unpack\" function\n\tobj.unpack = function(rre,rim,ire,iim) {\n\t\trre[0] = obj.m_re[0]; ire[0] = obj.m_im[0];\n\t\trim[0] = iim[0] = 0;\n\t\trre[m_N2] = obj.m_re[m_N2];\n\t\tire[m_N2] = obj.m_im[m_N2];\n\t\trim[m_N2] = iim[m_N2] = 0;\n\t\tfor(var i = 1;i=0) { changes.pop(); ci--; } + while(ci > 0 && out_time <= changes[ci].out_time) { changes.pop(); ci--; } // Add a tempo change reflecting current state changes.push({