1'use strict';
sourced from https://github.com/indutny/fft.js/ LICENSE This software is licensed under the MIT License. Copyright Fedor Indutny, 2017. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOTE: Use of var is intentional for old V8 versions
Calculate initial step's width:
- If we are full radix-4 - it is 2x smaller to give inital len=8
- Otherwise it is the same as
powerto give len=4
34 this._width = power % 2 === 0 ? power - 1 : power;
Pre-compute bit-reversal patterns
46 this._out = null; 47 this._data = null; 48 this._inv = 0; 49 } 50 fromComplexArray(complex, storage) { 51 var res = storage || new Array(complex.length >>> 1); 52 for (var i = 0; i < complex.length; i += 2) res[i >>> 1] = complex[i]; 53 return res; 54 } 55 createComplexArray() { 56 const res = new Array(this._csize); 57 for (var i = 0; i < res.length; i++) res[i] = 0; 58 return res; 59 } 60 toComplexArray(input, storage) { 61 var res = storage || this.createComplexArray(); 62 for (var i = 0; i < res.length; i += 2) { 63 res[i] = input[i >>> 1]; 64 res[i + 1] = 0; 65 } 66 return res; 67 } 68 completeSpectrum(spectrum) { 69 var size = this._csize; 70 var half = size >>> 1; 71 for (var i = 2; i < half; i += 2) { 72 spectrum[size - i] = spectrum[i]; 73 spectrum[size - i + 1] = -spectrum[i + 1]; 74 } 75 } 76 transform(out, data) { 77 if (out === data) throw new Error('Input and output buffers must be different'); 78 79 this._out = out; 80 this._data = data; 81 this._inv = 0; 82 this._transform4(); 83 this._out = null; 84 this._data = null; 85 } 86 realTransform(out, data) { 87 if (out === data) throw new Error('Input and output buffers must be different'); 88 89 this._out = out; 90 this._data = data; 91 this._inv = 0; 92 this._realTransform4(); 93 this._out = null; 94 this._data = null; 95 } 96 inverseTransform(out, data) { 97 if (out === data) throw new Error('Input and output buffers must be different'); 98 99 this._out = out; 100 this._data = data; 101 this._inv = 1; 102 this._transform4(); 103 for (var i = 0; i < out.length; i++) out[i] /= this.size; 104 this._out = null; 105 this._data = null; 106 } 107 // radix-4 implementation 108 // 109 // NOTE: Uses of `var` are intentional for older V8 version that do not 110 // support both `let compound assignments` and `const phi` 111 _transform4() { 112 var out = this._out; 113 var size = this._csize;
Initial step (permute and transform)
120 var outOff; 121 var t; 122 var bitrev = this._bitrev; 123 if (len === 4) { 124 for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { 125 const off = bitrev[t]; 126 this._singleTransform2(outOff, off, step); 127 } 128 } else { 129 // len === 8 130 for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { 131 const off = bitrev[t]; 132 this._singleTransform4(outOff, off, step); 133 } 134 }
Loop through steps in decreasing order
Loop through offsets in the data
Original values
167 const tableBr = table[k]; 168 const tableBi = inv * table[k + 1]; 169 const MBr = Br * tableBr - Bi * tableBi; 170 const MBi = Br * tableBi + Bi * tableBr; 171 172 const tableCr = table[2 * k]; 173 const tableCi = inv * table[2 * k + 1]; 174 const MCr = Cr * tableCr - Ci * tableCi; 175 const MCi = Cr * tableCi + Ci * tableCr; 176 177 const tableDr = table[3 * k]; 178 const tableDi = inv * table[3 * k + 1]; 179 const MDr = Dr * tableDr - Di * tableDi; 180 const MDi = Dr * tableDi + Di * tableDr;
Pre-Final values
196 const FCr = T0r - T2r; 197 const FCi = T0i - T2i; 198 199 const FBr = T1r + T3i; 200 const FBi = T1i - T3r; 201 202 const FDr = T1r - T3i; 203 const FDi = T1i + T3r; 204 205 out[A] = FAr; 206 out[A + 1] = FAi; 207 out[B] = FBr; 208 out[B + 1] = FBi; 209 out[C] = FCr; 210 out[C + 1] = FCi; 211 out[D] = FDr; 212 out[D + 1] = FDi; 213 } 214 } 215 } 216 } 217 // radix-2 implementation 218 // 219 // NOTE: Only called for len=4 220 _singleTransform2(outOff, off, step) { 221 const out = this._out; 222 const data = this._data; 223 224 const evenR = data[off]; 225 const evenI = data[off + 1]; 226 const oddR = data[off + step]; 227 const oddI = data[off + step + 1]; 228 229 const leftR = evenR + oddR; 230 const leftI = evenI + oddI; 231 const rightR = evenR - oddR; 232 const rightI = evenI - oddI; 233 234 out[outOff] = leftR; 235 out[outOff + 1] = leftI; 236 out[outOff + 2] = rightR; 237 out[outOff + 3] = rightI; 238 } 239 // radix-4 240 // 241 // NOTE: Only called for len=8 242 _singleTransform4(outOff, off, step) { 243 const out = this._out; 244 const data = this._data; 245 const inv = this._inv ? -1 : 1; 246 const step2 = step * 2; 247 const step3 = step * 3;
Original values
Pre-Final values
273 const FBr = T1r + T3i; 274 const FBi = T1i - T3r; 275 276 const FCr = T0r - T2r; 277 const FCi = T0i - T2i; 278 279 const FDr = T1r - T3i; 280 const FDi = T1i + T3r; 281 282 out[outOff] = FAr; 283 out[outOff + 1] = FAi; 284 out[outOff + 2] = FBr; 285 out[outOff + 3] = FBi; 286 out[outOff + 4] = FCr; 287 out[outOff + 5] = FCi; 288 out[outOff + 6] = FDr; 289 out[outOff + 7] = FDi; 290 } 291 // Real input radix-4 implementation 292 _realTransform4() { 293 var out = this._out; 294 var size = this._csize;
Initial step (permute and transform)
301 var outOff; 302 var t; 303 var bitrev = this._bitrev; 304 if (len === 4) { 305 for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { 306 const off = bitrev[t]; 307 this._singleRealTransform2(outOff, off >>> 1, step >>> 1); 308 } 309 } else { 310 // len === 8 311 for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { 312 const off = bitrev[t]; 313 this._singleRealTransform4(outOff, off >>> 1, step >>> 1); 314 } 315 }
Loop through steps in decreasing order
Loop through offsets in the data
Original values
348 var tableBr = table[k]; 349 var tableBi = inv * table[k + 1]; 350 var MBr = Br * tableBr - Bi * tableBi; 351 var MBi = Br * tableBi + Bi * tableBr; 352 353 var tableCr = table[2 * k]; 354 var tableCi = inv * table[2 * k + 1]; 355 var MCr = Cr * tableCr - Ci * tableCi; 356 var MCi = Cr * tableCi + Ci * tableCr; 357 358 var tableDr = table[3 * k]; 359 var tableDi = inv * table[3 * k + 1]; 360 var MDr = Dr * tableDr - Di * tableDi; 361 var MDi = Dr * tableDi + Di * tableDr;
Pre-Final values
Output final middle point
Do not overwrite ourselves
395 if (i === hquarterLen) continue;
In the flipped case: MAi = -MAi MBr=-MBi, MBi=-MBr MCr=-MCr MDr=MDi, MDi=MDr
411 var SFAr = ST0r + ST2r; 412 var SFAi = ST0i + ST2i; 413 414 var SFBr = ST1r + ST3i; 415 var SFBi = ST1i - ST3r; 416 417 var SA = outOff + quarterLen - i; 418 var SB = outOff + halfLen - i; 419 420 out[SA] = SFAr; 421 out[SA + 1] = SFAi; 422 out[SB] = SFBr; 423 out[SB + 1] = SFBi; 424 } 425 } 426 } 427 } 428 // radix-2 implementation 429 // 430 // NOTE: Only called for len=4 431 _singleRealTransform2(outOff, off, step) { 432 const out = this._out; 433 const data = this._data; 434 435 const evenR = data[off]; 436 const oddR = data[off + step]; 437 438 const leftR = evenR + oddR; 439 const rightR = evenR - oddR; 440 441 out[outOff] = leftR; 442 out[outOff + 1] = 0; 443 out[outOff + 2] = rightR; 444 out[outOff + 3] = 0; 445 } 446 // radix-4 447 // 448 // NOTE: Only called for len=8 449 _singleRealTransform4(outOff, off, step) { 450 const out = this._out; 451 const data = this._data; 452 const inv = this._inv ? -1 : 1; 453 const step2 = step * 2; 454 const step3 = step * 3;
Original values
Pre-Final values
Final values
469 const FAr = T0r + T2r;
471 const FBr = T1r; 472 const FBi = -T3r; 473 474 const FCr = T0r - T2r; 475 476 const FDr = T1r; 477 const FDi = T3r; 478 479 out[outOff] = FAr; 480 out[outOff + 1] = 0; 481 out[outOff + 2] = FBr; 482 out[outOff + 3] = FBi; 483 out[outOff + 4] = FCr; 484 out[outOff + 5] = 0; 485 out[outOff + 6] = FDr; 486 out[outOff + 7] = FDi; 487 } 488}