diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 10bb5ec..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "commonjs": true, - "es6": true - }, - "extends": "eslint:recommended", - "rules": { - "indent": [ - "error", - 2 - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ] - } -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..9ba60e6 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "root": true, + "env": { "browser": true, "es2020": true }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "ignorePatterns": ["dist", ".eslintrc.js", ".prettierrc.js"], + "parser": "@typescript-eslint/parser", + "rules": { + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], + "quotes": ["error", "single"], + "semi": ["error", "always"], + "no-var": ["off"] + }, + "ignorePatterns": ["**/node_modules/", ".eslintrc.json", "/dist/*"], + "settings": { + "react": { + "version": "detect" + } + } +} diff --git a/.gitignore b/.gitignore index 1235c12..4e2bf24 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ npm-debug.log *.log *.pdf *.gz +*.lock +.DS_Store +package-lock.json +*.lock diff --git a/bench/index.js b/bench/index.js index a329021..fedff3a 100644 --- a/bench/index.js +++ b/bench/index.js @@ -1,19 +1,20 @@ -'use strict'; +import FFT from '../dist/fft.js'; +import jensnockert from 'fft'; +import dspjs from 'dsp.js'; +import drom from 'fourier'; +import fourierTransform from 'fourier-transform'; +import benchmark from 'benchmark'; -const FFT = require('../'); const external = { - jensnockert: require('fft'), - dspjs: require('dsp.js'), - drom: require('fourier'), - fourierTransform: require('fourier-transform') + jensnockert, + dspjs, + drom, + fourierTransform, }; -const benchmark = require('benchmark'); function regexFilter(value) { - if (value !== undefined && value.length !== 0) - return new RegExp(value, 'ig'); - else - return /./g; + if (value !== undefined && value.length !== 0) return new RegExp(value, 'ig'); + else return /./g; } /*eslint-disable no-undef */ @@ -22,16 +23,14 @@ const filter1 = regexFilter(process.argv[3]); /*eslint-enable no-undef */ function addFiltered(suite, name, body) { - if (name.match(filter1) === null) - return; + if (name.match(filter1) === null) return; suite.add(name, body); } function createInput(size) { const res = new Array(size); - for (let i = 0; i < res.length; i++) - res[i] = Math.random() * 2 - 1; + for (let i = 0; i < res.length; i++) res[i] = Math.random() * 2 - 1; return res; } @@ -49,10 +48,9 @@ function addSelf(suite, size) { const f = new FFT(size); const input = createInput(f.size); const data = f.toComplexArray(input); - const out = f.createComplexArray(); addFiltered(suite, 'fft.js', () => { - f.transform(out, data); + f.transform(data); }); } @@ -84,7 +82,7 @@ function addDrom(suite, size) { const stdlib = { Math: Math, Float32Array: Float32Array, - Float64Array: Float64Array + Float64Array: Float64Array, }; const f = new external.drom.custom[`fft_f64_${size}_asm`](stdlib, null, heap); @@ -110,10 +108,9 @@ function addRealSelf(suite, size) { const f = new FFT(size); const input = createInput(f.size); const data = f.toComplexArray(input); - const out = f.createComplexArray(); addFiltered(suite, 'fft.js', () => { - f.realTransform(out, data); + f.realTransform(data); }); } @@ -147,18 +144,19 @@ const benchmarks = [ { title: 'realTransform size=2048', suite: realTransform(2048) }, { title: 'realTransform size=4096', suite: realTransform(4096) }, { title: 'realTransform size=8192', suite: realTransform(8192) }, - { title: 'realTransform size=16384', suite: realTransform(16384) } + { title: 'realTransform size=16384', suite: realTransform(16384) }, ]; /* eslint-disable no-console */ benchmarks.forEach((bench) => { - if (bench.title.match(filter0) === null) - return; + if (bench.title.match(filter0) === null) return; console.log('===== %s =====', bench.title); - bench.suite.on('cycle', (event) => { - console.log(' '+ String(event.target)); - }).on('complete', function() { - console.log(' Fastest is ' + this.filter('fastest').map('name')); - }); + bench.suite + .on('cycle', (event) => { + console.log(' ' + String(event.target)); + }) + .on('complete', function () { + console.log(' Fastest is ' + this.filter('fastest').map('name')); + }); bench.suite.run(); }); diff --git a/bench/package.json b/bench/package.json index 1b4835c..2b10f62 100644 --- a/bench/package.json +++ b/bench/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "private": true, "description": "Benchmarks for fft.js", + "type": "module", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/dist/fft.d.ts b/dist/fft.d.ts new file mode 100644 index 0000000..cc18eec --- /dev/null +++ b/dist/fft.d.ts @@ -0,0 +1,13 @@ +export default class FFT { + #private; + size: number; + table: number[]; + constructor(size: number); + fromComplexArray(complex: number[]): number[]; + createComplexArray(): number[]; + toComplexArray(input: number[]): number[]; + completeSpectrum(spectrum: number[]): number[]; + transform(data: number[]): number[]; + realTransform(data: number[]): number[]; + inverseTransform(data: number[]): number[]; +} diff --git a/dist/fft.js b/dist/fft.js index 7faa3fe..cebbbfd 100644 --- a/dist/fft.js +++ b/dist/fft.js @@ -1 +1,425 @@ -var FFTJS=function(t){function r(e){if(i[e])return i[e].exports;var o=i[e]={i:e,l:!1,exports:{}};return t[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var i={};return r.m=t,r.c=i,r.i=function(t){return t},r.d=function(t,i,e){r.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:e})},r.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(i,"a",i),i},r.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},r.p="",r(r.s=0)}([function(t,r,i){"use strict";function e(t){if(this.size=0|t,this.size<=1||0!=(this.size&this.size-1))throw new Error("FFT size must be a power of two and bigger than 1");this._csize=t<<1;for(var r=new Array(2*this.size),i=0;in;n<<=1)o++;this._width=o%2==0?o-1:o,this._bitrev=new Array(1<>>a&3)<>>1),e=0;e>>1]=t[e];return i},e.prototype.createComplexArray=function(){for(var t=new Array(this._csize),r=0;r>>1],i[e+1]=0;return i},e.prototype.completeSpectrum=function(t){for(var r=this._csize,i=r>>>1,e=2;e>=2;n>=2;n>>=2){s=e/n<<1;var l=s>>>2;for(t=0;t>>1,n>>>1)}else for(t=0,r=0;t>>1,n>>>1)}var u=this._inv?-1:1,_=this.table;for(n>>=2;n>=2;n>>=2){s=e/n<<1;var l=s>>>1,p=l>>>1,v=p>>>1;for(t=0;t t; t <<= 1) + power++; + // 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 `power` to give len=4 + __classPrivateFieldSet(this, _FFT_width, power % 2 === 0 ? power - 1 : power, "f"); + // Pre-compute bit-reversal patterns + __classPrivateFieldSet(this, _FFT_bitrev, new Array(1 << __classPrivateFieldGet(this, _FFT_width, "f")), "f"); + for (var j = 0; j < __classPrivateFieldGet(this, _FFT_bitrev, "f").length; j++) { + __classPrivateFieldGet(this, _FFT_bitrev, "f")[j] = 0; + for (var shift = 0; shift < __classPrivateFieldGet(this, _FFT_width, "f"); shift += 2) { + var revShift = __classPrivateFieldGet(this, _FFT_width, "f") - shift - 2; + __classPrivateFieldGet(this, _FFT_bitrev, "f")[j] |= ((j >>> shift) & 3) << revShift; + } + } + __classPrivateFieldSet(this, _FFT_out, [], "f"); + __classPrivateFieldSet(this, _FFT_data, [], "f"); + __classPrivateFieldSet(this, _FFT_inv, 0, "f"); + } + fromComplexArray(complex) { + var res = new Array(complex.length >>> 1); + for (var i = 0; i < complex.length; i += 2) + res[i >>> 1] = complex[i]; + return res; + } + createComplexArray() { + const res = new Array(__classPrivateFieldGet(this, _FFT_csize, "f")); + for (var i = 0; i < res.length; i++) + res[i] = 0; + return res; + } + toComplexArray(input) { + var res = this.createComplexArray(); + for (var i = 0; i < res.length; i += 2) { + res[i] = input[i >>> 1]; + res[i + 1] = 0; + } + return res; + } + completeSpectrum(spectrum) { + var size = __classPrivateFieldGet(this, _FFT_csize, "f"); + var half = size >>> 1; + for (var i = 2; i < half; i += 2) { + spectrum[size - i] = spectrum[i]; + spectrum[size - i + 1] = -spectrum[i + 1]; + } + return spectrum; + } + transform(data) { + const out = []; + __classPrivateFieldSet(this, _FFT_out, out, "f"); + __classPrivateFieldSet(this, _FFT_data, data, "f"); + __classPrivateFieldSet(this, _FFT_inv, 0, "f"); + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_transform4).call(this); + __classPrivateFieldSet(this, _FFT_out, [], "f"); + __classPrivateFieldSet(this, _FFT_data, [], "f"); + return out; + } + realTransform(data) { + const out = []; + __classPrivateFieldSet(this, _FFT_out, out, "f"); + __classPrivateFieldSet(this, _FFT_data, data, "f"); + __classPrivateFieldSet(this, _FFT_inv, 0, "f"); + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_realTransform4).call(this); + __classPrivateFieldSet(this, _FFT_out, [], "f"); + __classPrivateFieldSet(this, _FFT_data, [], "f"); + return out; + } + inverseTransform(data) { + const out = []; + __classPrivateFieldSet(this, _FFT_out, out, "f"); + __classPrivateFieldSet(this, _FFT_data, data, "f"); + __classPrivateFieldSet(this, _FFT_inv, 1, "f"); + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_transform4).call(this); + for (var i = 0; i < out.length; i++) + out[i] /= this.size; + __classPrivateFieldSet(this, _FFT_out, [], "f"); + __classPrivateFieldSet(this, _FFT_data, [], "f"); + return out; + } +} +_FFT_csize = new WeakMap(), _FFT_width = new WeakMap(), _FFT_bitrev = new WeakMap(), _FFT_out = new WeakMap(), _FFT_data = new WeakMap(), _FFT_inv = new WeakMap(), _FFT_instances = new WeakSet(), _FFT_transform4 = function _FFT_transform4() { + var out = __classPrivateFieldGet(this, _FFT_out, "f"); + var size = __classPrivateFieldGet(this, _FFT_csize, "f"); + // Initial step (permute and transform) + var width = __classPrivateFieldGet(this, _FFT_width, "f"); + var step = 1 << width; + var len = (size / step) << 1; + var outOff; + var t; + var bitrev = __classPrivateFieldGet(this, _FFT_bitrev, "f"); + if (len === 4) { + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_singleTransform2).call(this, outOff, off, step); + } + } + else { + // len === 8 + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_singleTransform4).call(this, outOff, off, step); + } + } + // Loop through steps in decreasing order + var inv = __classPrivateFieldGet(this, _FFT_inv, "f") ? -1 : 1; + var table = this.table; + for (step >>= 2; step >= 2; step >>= 2) { + len = (size / step) << 1; + var quarterLen = len >>> 2; + // Loop through offsets in the data + for (outOff = 0; outOff < size; outOff += len) { + // Full case + var limit = outOff + quarterLen; + for (var i = outOff, k = 0; i < limit; i += 2, k += step) { + const A = i; + const B = A + quarterLen; + const C = B + quarterLen; + const D = C + quarterLen; + // Original values + const Ar = out[A]; + const Ai = out[A + 1]; + const Br = out[B]; + const Bi = out[B + 1]; + const Cr = out[C]; + const Ci = out[C + 1]; + const Dr = out[D]; + const Di = out[D + 1]; + // Middle values + const MAr = Ar; + const MAi = Ai; + const tableBr = table[k]; + const tableBi = inv * table[k + 1]; + const MBr = Br * tableBr - Bi * tableBi; + const MBi = Br * tableBi + Bi * tableBr; + const tableCr = table[2 * k]; + const tableCi = inv * table[2 * k + 1]; + const MCr = Cr * tableCr - Ci * tableCi; + const MCi = Cr * tableCi + Ci * tableCr; + const tableDr = table[3 * k]; + const tableDi = inv * table[3 * k + 1]; + const MDr = Dr * tableDr - Di * tableDi; + const MDi = Dr * tableDi + Di * tableDr; + // Pre-Final values + const T0r = MAr + MCr; + const T0i = MAi + MCi; + const T1r = MAr - MCr; + const T1i = MAi - MCi; + const T2r = MBr + MDr; + const T2i = MBi + MDi; + const T3r = inv * (MBr - MDr); + const T3i = inv * (MBi - MDi); + // Final values + const FAr = T0r + T2r; + const FAi = T0i + T2i; + const FCr = T0r - T2r; + const FCi = T0i - T2i; + const FBr = T1r + T3i; + const FBi = T1i - T3r; + const FDr = T1r - T3i; + const FDi = T1i + T3r; + out[A] = FAr; + out[A + 1] = FAi; + out[B] = FBr; + out[B + 1] = FBi; + out[C] = FCr; + out[C + 1] = FCi; + out[D] = FDr; + out[D + 1] = FDi; + } + } + } +}, _FFT_singleTransform2 = function _FFT_singleTransform2(outOff, off, step) { + const out = __classPrivateFieldGet(this, _FFT_out, "f"); + const data = __classPrivateFieldGet(this, _FFT_data, "f"); + const evenR = data[off]; + const evenI = data[off + 1]; + const oddR = data[off + step]; + const oddI = data[off + step + 1]; + const leftR = evenR + oddR; + const leftI = evenI + oddI; + const rightR = evenR - oddR; + const rightI = evenI - oddI; + out[outOff] = leftR; + out[outOff + 1] = leftI; + out[outOff + 2] = rightR; + out[outOff + 3] = rightI; +}, _FFT_singleTransform4 = function _FFT_singleTransform4(outOff, off, step) { + const out = __classPrivateFieldGet(this, _FFT_out, "f"); + const data = __classPrivateFieldGet(this, _FFT_data, "f"); + const inv = __classPrivateFieldGet(this, _FFT_inv, "f") ? -1 : 1; + const step2 = step * 2; + const step3 = step * 3; + // Original values + const Ar = data[off]; + const Ai = data[off + 1]; + const Br = data[off + step]; + const Bi = data[off + step + 1]; + const Cr = data[off + step2]; + const Ci = data[off + step2 + 1]; + const Dr = data[off + step3]; + const Di = data[off + step3 + 1]; + // Pre-Final values + const T0r = Ar + Cr; + const T0i = Ai + Ci; + const T1r = Ar - Cr; + const T1i = Ai - Ci; + const T2r = Br + Dr; + const T2i = Bi + Di; + const T3r = inv * (Br - Dr); + const T3i = inv * (Bi - Di); + // Final values + const FAr = T0r + T2r; + const FAi = T0i + T2i; + const FBr = T1r + T3i; + const FBi = T1i - T3r; + const FCr = T0r - T2r; + const FCi = T0i - T2i; + const FDr = T1r - T3i; + const FDi = T1i + T3r; + out[outOff] = FAr; + out[outOff + 1] = FAi; + out[outOff + 2] = FBr; + out[outOff + 3] = FBi; + out[outOff + 4] = FCr; + out[outOff + 5] = FCi; + out[outOff + 6] = FDr; + out[outOff + 7] = FDi; +}, _FFT_realTransform4 = function _FFT_realTransform4() { + var out = __classPrivateFieldGet(this, _FFT_out, "f"); + var size = __classPrivateFieldGet(this, _FFT_csize, "f"); + // Initial step (permute and transform) + var width = __classPrivateFieldGet(this, _FFT_width, "f"); + var step = 1 << width; + var len = (size / step) << 1; + var outOff; + var t; + var bitrev = __classPrivateFieldGet(this, _FFT_bitrev, "f"); + if (len === 4) { + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_singleRealTransform2).call(this, outOff, off >>> 1, step >>> 1); + } + } + else { + // len === 8 + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + __classPrivateFieldGet(this, _FFT_instances, "m", _FFT_singleRealTransform4).call(this, outOff, off >>> 1, step >>> 1); + } + } + // Loop through steps in decreasing order + var inv = __classPrivateFieldGet(this, _FFT_inv, "f") ? -1 : 1; + var table = this.table; + for (step >>= 2; step >= 2; step >>= 2) { + len = (size / step) << 1; + var halfLen = len >>> 1; + var quarterLen = halfLen >>> 1; + var hquarterLen = quarterLen >>> 1; + // Loop through offsets in the data + for (outOff = 0; outOff < size; outOff += len) { + for (var i = 0, k = 0; i <= hquarterLen; i += 2, k += step) { + var A = outOff + i; + var B = A + quarterLen; + var C = B + quarterLen; + var D = C + quarterLen; + // Original values + var Ar = out[A]; + var Ai = out[A + 1]; + var Br = out[B]; + var Bi = out[B + 1]; + var Cr = out[C]; + var Ci = out[C + 1]; + var Dr = out[D]; + var Di = out[D + 1]; + // Middle values + var MAr = Ar; + var MAi = Ai; + var tableBr = table[k]; + var tableBi = inv * table[k + 1]; + var MBr = Br * tableBr - Bi * tableBi; + var MBi = Br * tableBi + Bi * tableBr; + var tableCr = table[2 * k]; + var tableCi = inv * table[2 * k + 1]; + var MCr = Cr * tableCr - Ci * tableCi; + var MCi = Cr * tableCi + Ci * tableCr; + var tableDr = table[3 * k]; + var tableDi = inv * table[3 * k + 1]; + var MDr = Dr * tableDr - Di * tableDi; + var MDi = Dr * tableDi + Di * tableDr; + // Pre-Final values + var T0r = MAr + MCr; + var T0i = MAi + MCi; + var T1r = MAr - MCr; + var T1i = MAi - MCi; + var T2r = MBr + MDr; + var T2i = MBi + MDi; + var T3r = inv * (MBr - MDr); + var T3i = inv * (MBi - MDi); + // Final values + var FAr = T0r + T2r; + var FAi = T0i + T2i; + var FBr = T1r + T3i; + var FBi = T1i - T3r; + out[A] = FAr; + out[A + 1] = FAi; + out[B] = FBr; + out[B + 1] = FBi; + // Output final middle point + if (i === 0) { + var FCr = T0r - T2r; + var FCi = T0i - T2i; + out[C] = FCr; + out[C + 1] = FCi; + continue; + } + // Do not overwrite ourselves + if (i === hquarterLen) + continue; + // In the flipped case: + // MAi = -MAi + // MBr=-MBi, MBi=-MBr + // MCr=-MCr + // MDr=MDi, MDi=MDr + var ST0r = T1r; + var ST0i = -T1i; + var ST1r = T0r; + var ST1i = -T0i; + var ST2r = -inv * T3i; + var ST2i = -inv * T3r; + var ST3r = -inv * T2i; + var ST3i = -inv * T2r; + var SFAr = ST0r + ST2r; + var SFAi = ST0i + ST2i; + var SFBr = ST1r + ST3i; + var SFBi = ST1i - ST3r; + var SA = outOff + quarterLen - i; + var SB = outOff + halfLen - i; + out[SA] = SFAr; + out[SA + 1] = SFAi; + out[SB] = SFBr; + out[SB + 1] = SFBi; + } + } + } +}, _FFT_singleRealTransform2 = function _FFT_singleRealTransform2(outOff, off, step) { + const out = __classPrivateFieldGet(this, _FFT_out, "f"); + const data = __classPrivateFieldGet(this, _FFT_data, "f"); + const evenR = data[off]; + const oddR = data[off + step]; + const leftR = evenR + oddR; + const rightR = evenR - oddR; + out[outOff] = leftR; + out[outOff + 1] = 0; + out[outOff + 2] = rightR; + out[outOff + 3] = 0; +}, _FFT_singleRealTransform4 = function _FFT_singleRealTransform4(outOff, off, step) { + const out = __classPrivateFieldGet(this, _FFT_out, "f"); + const data = __classPrivateFieldGet(this, _FFT_data, "f"); + const inv = __classPrivateFieldGet(this, _FFT_inv, "f") ? -1 : 1; + const step2 = step * 2; + const step3 = step * 3; + // Original values + const Ar = data[off]; + const Br = data[off + step]; + const Cr = data[off + step2]; + const Dr = data[off + step3]; + // Pre-Final values + const T0r = Ar + Cr; + const T1r = Ar - Cr; + const T2r = Br + Dr; + const T3r = inv * (Br - Dr); + // Final values + const FAr = T0r + T2r; + const FBr = T1r; + const FBi = -T3r; + const FCr = T0r - T2r; + const FDr = T1r; + const FDi = T3r; + out[outOff] = FAr; + out[outOff + 1] = 0; + out[outOff + 2] = FBr; + out[outOff + 3] = FBi; + out[outOff + 4] = FCr; + out[outOff + 5] = 0; + out[outOff + 6] = FDr; + out[outOff + 7] = FDi; +}; +export default FFT; +//# sourceMappingURL=fft.js.map \ No newline at end of file diff --git a/dist/fft.js.map b/dist/fft.js.map new file mode 100644 index 0000000..fba69e1 --- /dev/null +++ b/dist/fft.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fft.js","sourceRoot":"","sources":["../lib/fft.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/fft.d.ts b/lib/fft.d.ts deleted file mode 100644 index 8134edb..0000000 --- a/lib/fft.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export = FFT; - -declare class FFT { - constructor(size: number); - size: number; - table: number[]; - fromComplexArray(complex: number[], storage?: number[]): number[]; - createComplexArray(): number[]; - toComplexArray(input: number[], storage?: number[]): number[]; - completeSpectrum(spectrum: number[]): void; - transform(out: number[], data: number[]): void; - realTransform(out: number[], data: number[]): void; - inverseTransform(out: number[], data: number[]): void; -} diff --git a/lib/fft.js b/lib/fft.js deleted file mode 100644 index c13b408..0000000 --- a/lib/fft.js +++ /dev/null @@ -1,507 +0,0 @@ -'use strict'; - -function FFT(size) { - this.size = size | 0; - if (this.size <= 1 || (this.size & (this.size - 1)) !== 0) - throw new Error('FFT size must be a power of two and bigger than 1'); - - this._csize = size << 1; - - // NOTE: Use of `var` is intentional for old V8 versions - var table = new Array(this.size * 2); - for (var i = 0; i < table.length; i += 2) { - const angle = Math.PI * i / this.size; - table[i] = Math.cos(angle); - table[i + 1] = -Math.sin(angle); - } - this.table = table; - - // Find size's power of two - var power = 0; - for (var t = 1; this.size > t; t <<= 1) - power++; - - // 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 `power` to give len=4 - this._width = power % 2 === 0 ? power - 1 : power; - - // Pre-compute bit-reversal patterns - this._bitrev = new Array(1 << this._width); - for (var j = 0; j < this._bitrev.length; j++) { - this._bitrev[j] = 0; - for (var shift = 0; shift < this._width; shift += 2) { - var revShift = this._width - shift - 2; - this._bitrev[j] |= ((j >>> shift) & 3) << revShift; - } - } - - this._out = null; - this._data = null; - this._inv = 0; -} -module.exports = FFT; - -FFT.prototype.fromComplexArray = function fromComplexArray(complex, storage) { - var res = storage || new Array(complex.length >>> 1); - for (var i = 0; i < complex.length; i += 2) - res[i >>> 1] = complex[i]; - return res; -}; - -FFT.prototype.createComplexArray = function createComplexArray() { - const res = new Array(this._csize); - for (var i = 0; i < res.length; i++) - res[i] = 0; - return res; -}; - -FFT.prototype.toComplexArray = function toComplexArray(input, storage) { - var res = storage || this.createComplexArray(); - for (var i = 0; i < res.length; i += 2) { - res[i] = input[i >>> 1]; - res[i + 1] = 0; - } - return res; -}; - -FFT.prototype.completeSpectrum = function completeSpectrum(spectrum) { - var size = this._csize; - var half = size >>> 1; - for (var i = 2; i < half; i += 2) { - spectrum[size - i] = spectrum[i]; - spectrum[size - i + 1] = -spectrum[i + 1]; - } -}; - -FFT.prototype.transform = function transform(out, data) { - if (out === data) - throw new Error('Input and output buffers must be different'); - - this._out = out; - this._data = data; - this._inv = 0; - this._transform4(); - this._out = null; - this._data = null; -}; - -FFT.prototype.realTransform = function realTransform(out, data) { - if (out === data) - throw new Error('Input and output buffers must be different'); - - this._out = out; - this._data = data; - this._inv = 0; - this._realTransform4(); - this._out = null; - this._data = null; -}; - -FFT.prototype.inverseTransform = function inverseTransform(out, data) { - if (out === data) - throw new Error('Input and output buffers must be different'); - - this._out = out; - this._data = data; - this._inv = 1; - this._transform4(); - for (var i = 0; i < out.length; i++) - out[i] /= this.size; - this._out = null; - this._data = null; -}; - -// radix-4 implementation -// -// NOTE: Uses of `var` are intentional for older V8 version that do not -// support both `let compound assignments` and `const phi` -FFT.prototype._transform4 = function _transform4() { - var out = this._out; - var size = this._csize; - - // Initial step (permute and transform) - var width = this._width; - var step = 1 << width; - var len = (size / step) << 1; - - var outOff; - var t; - var bitrev = this._bitrev; - if (len === 4) { - for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { - const off = bitrev[t]; - this._singleTransform2(outOff, off, step); - } - } else { - // len === 8 - for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { - const off = bitrev[t]; - this._singleTransform4(outOff, off, step); - } - } - - // Loop through steps in decreasing order - var inv = this._inv ? -1 : 1; - var table = this.table; - for (step >>= 2; step >= 2; step >>= 2) { - len = (size / step) << 1; - var quarterLen = len >>> 2; - - // Loop through offsets in the data - for (outOff = 0; outOff < size; outOff += len) { - // Full case - var limit = outOff + quarterLen; - for (var i = outOff, k = 0; i < limit; i += 2, k += step) { - const A = i; - const B = A + quarterLen; - const C = B + quarterLen; - const D = C + quarterLen; - - // Original values - const Ar = out[A]; - const Ai = out[A + 1]; - const Br = out[B]; - const Bi = out[B + 1]; - const Cr = out[C]; - const Ci = out[C + 1]; - const Dr = out[D]; - const Di = out[D + 1]; - - // Middle values - const MAr = Ar; - const MAi = Ai; - - const tableBr = table[k]; - const tableBi = inv * table[k + 1]; - const MBr = Br * tableBr - Bi * tableBi; - const MBi = Br * tableBi + Bi * tableBr; - - const tableCr = table[2 * k]; - const tableCi = inv * table[2 * k + 1]; - const MCr = Cr * tableCr - Ci * tableCi; - const MCi = Cr * tableCi + Ci * tableCr; - - const tableDr = table[3 * k]; - const tableDi = inv * table[3 * k + 1]; - const MDr = Dr * tableDr - Di * tableDi; - const MDi = Dr * tableDi + Di * tableDr; - - // Pre-Final values - const T0r = MAr + MCr; - const T0i = MAi + MCi; - const T1r = MAr - MCr; - const T1i = MAi - MCi; - const T2r = MBr + MDr; - const T2i = MBi + MDi; - const T3r = inv * (MBr - MDr); - const T3i = inv * (MBi - MDi); - - // Final values - const FAr = T0r + T2r; - const FAi = T0i + T2i; - - const FCr = T0r - T2r; - const FCi = T0i - T2i; - - const FBr = T1r + T3i; - const FBi = T1i - T3r; - - const FDr = T1r - T3i; - const FDi = T1i + T3r; - - out[A] = FAr; - out[A + 1] = FAi; - out[B] = FBr; - out[B + 1] = FBi; - out[C] = FCr; - out[C + 1] = FCi; - out[D] = FDr; - out[D + 1] = FDi; - } - } - } -}; - -// radix-2 implementation -// -// NOTE: Only called for len=4 -FFT.prototype._singleTransform2 = function _singleTransform2(outOff, off, - step) { - const out = this._out; - const data = this._data; - - const evenR = data[off]; - const evenI = data[off + 1]; - const oddR = data[off + step]; - const oddI = data[off + step + 1]; - - const leftR = evenR + oddR; - const leftI = evenI + oddI; - const rightR = evenR - oddR; - const rightI = evenI - oddI; - - out[outOff] = leftR; - out[outOff + 1] = leftI; - out[outOff + 2] = rightR; - out[outOff + 3] = rightI; -}; - -// radix-4 -// -// NOTE: Only called for len=8 -FFT.prototype._singleTransform4 = function _singleTransform4(outOff, off, - step) { - const out = this._out; - const data = this._data; - const inv = this._inv ? -1 : 1; - const step2 = step * 2; - const step3 = step * 3; - - // Original values - const Ar = data[off]; - const Ai = data[off + 1]; - const Br = data[off + step]; - const Bi = data[off + step + 1]; - const Cr = data[off + step2]; - const Ci = data[off + step2 + 1]; - const Dr = data[off + step3]; - const Di = data[off + step3 + 1]; - - // Pre-Final values - const T0r = Ar + Cr; - const T0i = Ai + Ci; - const T1r = Ar - Cr; - const T1i = Ai - Ci; - const T2r = Br + Dr; - const T2i = Bi + Di; - const T3r = inv * (Br - Dr); - const T3i = inv * (Bi - Di); - - // Final values - const FAr = T0r + T2r; - const FAi = T0i + T2i; - - const FBr = T1r + T3i; - const FBi = T1i - T3r; - - const FCr = T0r - T2r; - const FCi = T0i - T2i; - - const FDr = T1r - T3i; - const FDi = T1i + T3r; - - out[outOff] = FAr; - out[outOff + 1] = FAi; - out[outOff + 2] = FBr; - out[outOff + 3] = FBi; - out[outOff + 4] = FCr; - out[outOff + 5] = FCi; - out[outOff + 6] = FDr; - out[outOff + 7] = FDi; -}; - -// Real input radix-4 implementation -FFT.prototype._realTransform4 = function _realTransform4() { - var out = this._out; - var size = this._csize; - - // Initial step (permute and transform) - var width = this._width; - var step = 1 << width; - var len = (size / step) << 1; - - var outOff; - var t; - var bitrev = this._bitrev; - if (len === 4) { - for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { - const off = bitrev[t]; - this._singleRealTransform2(outOff, off >>> 1, step >>> 1); - } - } else { - // len === 8 - for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { - const off = bitrev[t]; - this._singleRealTransform4(outOff, off >>> 1, step >>> 1); - } - } - - // Loop through steps in decreasing order - var inv = this._inv ? -1 : 1; - var table = this.table; - for (step >>= 2; step >= 2; step >>= 2) { - len = (size / step) << 1; - var halfLen = len >>> 1; - var quarterLen = halfLen >>> 1; - var hquarterLen = quarterLen >>> 1; - - // Loop through offsets in the data - for (outOff = 0; outOff < size; outOff += len) { - for (var i = 0, k = 0; i <= hquarterLen; i += 2, k += step) { - var A = outOff + i; - var B = A + quarterLen; - var C = B + quarterLen; - var D = C + quarterLen; - - // Original values - var Ar = out[A]; - var Ai = out[A + 1]; - var Br = out[B]; - var Bi = out[B + 1]; - var Cr = out[C]; - var Ci = out[C + 1]; - var Dr = out[D]; - var Di = out[D + 1]; - - // Middle values - var MAr = Ar; - var MAi = Ai; - - var tableBr = table[k]; - var tableBi = inv * table[k + 1]; - var MBr = Br * tableBr - Bi * tableBi; - var MBi = Br * tableBi + Bi * tableBr; - - var tableCr = table[2 * k]; - var tableCi = inv * table[2 * k + 1]; - var MCr = Cr * tableCr - Ci * tableCi; - var MCi = Cr * tableCi + Ci * tableCr; - - var tableDr = table[3 * k]; - var tableDi = inv * table[3 * k + 1]; - var MDr = Dr * tableDr - Di * tableDi; - var MDi = Dr * tableDi + Di * tableDr; - - // Pre-Final values - var T0r = MAr + MCr; - var T0i = MAi + MCi; - var T1r = MAr - MCr; - var T1i = MAi - MCi; - var T2r = MBr + MDr; - var T2i = MBi + MDi; - var T3r = inv * (MBr - MDr); - var T3i = inv * (MBi - MDi); - - // Final values - var FAr = T0r + T2r; - var FAi = T0i + T2i; - - var FBr = T1r + T3i; - var FBi = T1i - T3r; - - out[A] = FAr; - out[A + 1] = FAi; - out[B] = FBr; - out[B + 1] = FBi; - - // Output final middle point - if (i === 0) { - var FCr = T0r - T2r; - var FCi = T0i - T2i; - out[C] = FCr; - out[C + 1] = FCi; - continue; - } - - // Do not overwrite ourselves - if (i === hquarterLen) - continue; - - // In the flipped case: - // MAi = -MAi - // MBr=-MBi, MBi=-MBr - // MCr=-MCr - // MDr=MDi, MDi=MDr - var ST0r = T1r; - var ST0i = -T1i; - var ST1r = T0r; - var ST1i = -T0i; - var ST2r = -inv * T3i; - var ST2i = -inv * T3r; - var ST3r = -inv * T2i; - var ST3i = -inv * T2r; - - var SFAr = ST0r + ST2r; - var SFAi = ST0i + ST2i; - - var SFBr = ST1r + ST3i; - var SFBi = ST1i - ST3r; - - var SA = outOff + quarterLen - i; - var SB = outOff + halfLen - i; - - out[SA] = SFAr; - out[SA + 1] = SFAi; - out[SB] = SFBr; - out[SB + 1] = SFBi; - } - } - } -}; - -// radix-2 implementation -// -// NOTE: Only called for len=4 -FFT.prototype._singleRealTransform2 = function _singleRealTransform2(outOff, - off, - step) { - const out = this._out; - const data = this._data; - - const evenR = data[off]; - const oddR = data[off + step]; - - const leftR = evenR + oddR; - const rightR = evenR - oddR; - - out[outOff] = leftR; - out[outOff + 1] = 0; - out[outOff + 2] = rightR; - out[outOff + 3] = 0; -}; - -// radix-4 -// -// NOTE: Only called for len=8 -FFT.prototype._singleRealTransform4 = function _singleRealTransform4(outOff, - off, - step) { - const out = this._out; - const data = this._data; - const inv = this._inv ? -1 : 1; - const step2 = step * 2; - const step3 = step * 3; - - // Original values - const Ar = data[off]; - const Br = data[off + step]; - const Cr = data[off + step2]; - const Dr = data[off + step3]; - - // Pre-Final values - const T0r = Ar + Cr; - const T1r = Ar - Cr; - const T2r = Br + Dr; - const T3r = inv * (Br - Dr); - - // Final values - const FAr = T0r + T2r; - - const FBr = T1r; - const FBi = -T3r; - - const FCr = T0r - T2r; - - const FDr = T1r; - const FDi = T3r; - - out[outOff] = FAr; - out[outOff + 1] = 0; - out[outOff + 2] = FBr; - out[outOff + 3] = FBi; - out[outOff + 4] = FCr; - out[outOff + 5] = 0; - out[outOff + 6] = FDr; - out[outOff + 7] = FDi; -}; diff --git a/lib/fft.ts b/lib/fft.ts new file mode 100644 index 0000000..a952133 --- /dev/null +++ b/lib/fft.ts @@ -0,0 +1,506 @@ +export default class FFT { + size: number; + table: number[]; + #csize: number; + #width: number; + #bitrev: number[]; + #out: number[]; + #data: number[]; + #inv: number; + + constructor(size: number) { + this.size = size | 0; + if (this.size <= 1 || (this.size & (this.size - 1)) !== 0) throw new Error('FFT size must be a power of two and bigger than 1'); + + this.#csize = size << 1; + + // NOTE: Use of `var` is intentional for old V8 versions + var table = new Array(this.size * 2); + for (var i = 0; i < table.length; i += 2) { + const angle = (Math.PI * i) / this.size; + table[i] = Math.cos(angle); + table[i + 1] = -Math.sin(angle); + } + this.table = table; + + // Find size's power of two + var power = 0; + for (var t = 1; this.size > t; t <<= 1) power++; + + // 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 `power` to give len=4 + this.#width = power % 2 === 0 ? power - 1 : power; + + // Pre-compute bit-reversal patterns + this.#bitrev = new Array(1 << this.#width); + for (var j = 0; j < this.#bitrev.length; j++) { + this.#bitrev[j] = 0; + for (var shift = 0; shift < this.#width; shift += 2) { + var revShift = this.#width - shift - 2; + this.#bitrev[j] |= ((j >>> shift) & 3) << revShift; + } + } + + this.#out = []; + this.#data = []; + this.#inv = 0; + } + + fromComplexArray(complex: number[]) { + var res: number[] = new Array(complex.length >>> 1); + for (var i = 0; i < complex.length; i += 2) res[i >>> 1] = complex[i]; + return res; + } + + createComplexArray() { + const res: number[] = new Array(this.#csize); + for (var i = 0; i < res.length; i++) res[i] = 0; + return res; + } + + toComplexArray(input: number[]) { + var res: number[] = this.createComplexArray(); + for (var i = 0; i < res.length; i += 2) { + res[i] = input[i >>> 1]; + res[i + 1] = 0; + } + return res; + } + + completeSpectrum(spectrum: number[]) { + var size = this.#csize; + var half = size >>> 1; + for (var i = 2; i < half; i += 2) { + spectrum[size - i] = spectrum[i]; + spectrum[size - i + 1] = -spectrum[i + 1]; + } + return spectrum; + } + + transform(data: number[]) { + const out: number[] = []; + + this.#out = out; + this.#data = data; + this.#inv = 0; + this.#transform4(); + this.#out = []; + this.#data = []; + + return out; + } + + realTransform(data: number[]) { + const out: number[] = []; + this.#out = out; + this.#data = data; + this.#inv = 0; + this.#realTransform4(); + this.#out = []; + this.#data = []; + + return out; + } + + inverseTransform(data: number[]) { + const out: number[] = []; + + this.#out = out; + this.#data = data; + this.#inv = 1; + this.#transform4(); + for (var i = 0; i < out.length; i++) out[i] /= this.size; + this.#out = []; + this.#data = []; + + return out; + } + + // radix-4 implementation + // + // NOTE: Uses of `var` are intentional for older V8 version that do not + // support both `let compound assignments` and `const phi` + #transform4() { + var out = this.#out; + var size = this.#csize; + + // Initial step (permute and transform) + var width = this.#width; + var step = 1 << width; + var len = (size / step) << 1; + + var outOff; + var t; + var bitrev = this.#bitrev; + if (len === 4) { + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + this.#singleTransform2(outOff, off, step); + } + } else { + // len === 8 + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + this.#singleTransform4(outOff, off, step); + } + } + + // Loop through steps in decreasing order + var inv = this.#inv ? -1 : 1; + var table = this.table; + for (step >>= 2; step >= 2; step >>= 2) { + len = (size / step) << 1; + var quarterLen = len >>> 2; + + // Loop through offsets in the data + for (outOff = 0; outOff < size; outOff += len) { + // Full case + var limit = outOff + quarterLen; + for (var i = outOff, k = 0; i < limit; i += 2, k += step) { + const A = i; + const B = A + quarterLen; + const C = B + quarterLen; + const D = C + quarterLen; + + // Original values + const Ar = out[A]; + const Ai = out[A + 1]; + const Br = out[B]; + const Bi = out[B + 1]; + const Cr = out[C]; + const Ci = out[C + 1]; + const Dr = out[D]; + const Di = out[D + 1]; + + // Middle values + const MAr = Ar; + const MAi = Ai; + + const tableBr = table[k]; + const tableBi = inv * table[k + 1]; + const MBr = Br * tableBr - Bi * tableBi; + const MBi = Br * tableBi + Bi * tableBr; + + const tableCr = table[2 * k]; + const tableCi = inv * table[2 * k + 1]; + const MCr = Cr * tableCr - Ci * tableCi; + const MCi = Cr * tableCi + Ci * tableCr; + + const tableDr = table[3 * k]; + const tableDi = inv * table[3 * k + 1]; + const MDr = Dr * tableDr - Di * tableDi; + const MDi = Dr * tableDi + Di * tableDr; + + // Pre-Final values + const T0r = MAr + MCr; + const T0i = MAi + MCi; + const T1r = MAr - MCr; + const T1i = MAi - MCi; + const T2r = MBr + MDr; + const T2i = MBi + MDi; + const T3r = inv * (MBr - MDr); + const T3i = inv * (MBi - MDi); + + // Final values + const FAr = T0r + T2r; + const FAi = T0i + T2i; + + const FCr = T0r - T2r; + const FCi = T0i - T2i; + + const FBr = T1r + T3i; + const FBi = T1i - T3r; + + const FDr = T1r - T3i; + const FDi = T1i + T3r; + + out[A] = FAr; + out[A + 1] = FAi; + out[B] = FBr; + out[B + 1] = FBi; + out[C] = FCr; + out[C + 1] = FCi; + out[D] = FDr; + out[D + 1] = FDi; + } + } + } + } + + // radix-2 implementation + // + // NOTE: Only called for len=4 + #singleTransform2(outOff: number, off: number, step: number) { + const out = this.#out; + const data = this.#data; + + const evenR = data[off]; + const evenI = data[off + 1]; + const oddR = data[off + step]; + const oddI = data[off + step + 1]; + + const leftR = evenR + oddR; + const leftI = evenI + oddI; + const rightR = evenR - oddR; + const rightI = evenI - oddI; + + out[outOff] = leftR; + out[outOff + 1] = leftI; + out[outOff + 2] = rightR; + out[outOff + 3] = rightI; + } + + // radix-4 + // + // NOTE: Only called for len=8 + #singleTransform4(outOff: number, off: number, step: number) { + const out = this.#out; + const data = this.#data; + const inv = this.#inv ? -1 : 1; + const step2 = step * 2; + const step3 = step * 3; + + // Original values + const Ar = data[off]; + const Ai = data[off + 1]; + const Br = data[off + step]; + const Bi = data[off + step + 1]; + const Cr = data[off + step2]; + const Ci = data[off + step2 + 1]; + const Dr = data[off + step3]; + const Di = data[off + step3 + 1]; + + // Pre-Final values + const T0r = Ar + Cr; + const T0i = Ai + Ci; + const T1r = Ar - Cr; + const T1i = Ai - Ci; + const T2r = Br + Dr; + const T2i = Bi + Di; + const T3r = inv * (Br - Dr); + const T3i = inv * (Bi - Di); + + // Final values + const FAr = T0r + T2r; + const FAi = T0i + T2i; + + const FBr = T1r + T3i; + const FBi = T1i - T3r; + + const FCr = T0r - T2r; + const FCi = T0i - T2i; + + const FDr = T1r - T3i; + const FDi = T1i + T3r; + + out[outOff] = FAr; + out[outOff + 1] = FAi; + out[outOff + 2] = FBr; + out[outOff + 3] = FBi; + out[outOff + 4] = FCr; + out[outOff + 5] = FCi; + out[outOff + 6] = FDr; + out[outOff + 7] = FDi; + } + + // Real input radix-4 implementation + #realTransform4() { + var out = this.#out; + var size = this.#csize; + + // Initial step (permute and transform) + var width = this.#width; + var step = 1 << width; + var len = (size / step) << 1; + + var outOff; + var t; + var bitrev = this.#bitrev; + if (len === 4) { + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + this.#singleRealTransform2(outOff, off >>> 1, step >>> 1); + } + } else { + // len === 8 + for (outOff = 0, t = 0; outOff < size; outOff += len, t++) { + const off = bitrev[t]; + this.#singleRealTransform4(outOff, off >>> 1, step >>> 1); + } + } + + // Loop through steps in decreasing order + var inv = this.#inv ? -1 : 1; + var table = this.table; + for (step >>= 2; step >= 2; step >>= 2) { + len = (size / step) << 1; + var halfLen = len >>> 1; + var quarterLen = halfLen >>> 1; + var hquarterLen = quarterLen >>> 1; + + // Loop through offsets in the data + for (outOff = 0; outOff < size; outOff += len) { + for (var i = 0, k = 0; i <= hquarterLen; i += 2, k += step) { + var A = outOff + i; + var B = A + quarterLen; + var C = B + quarterLen; + var D = C + quarterLen; + + // Original values + var Ar = out[A]; + var Ai = out[A + 1]; + var Br = out[B]; + var Bi = out[B + 1]; + var Cr = out[C]; + var Ci = out[C + 1]; + var Dr = out[D]; + var Di = out[D + 1]; + + // Middle values + var MAr = Ar; + var MAi = Ai; + + var tableBr = table[k]; + var tableBi = inv * table[k + 1]; + var MBr = Br * tableBr - Bi * tableBi; + var MBi = Br * tableBi + Bi * tableBr; + + var tableCr = table[2 * k]; + var tableCi = inv * table[2 * k + 1]; + var MCr = Cr * tableCr - Ci * tableCi; + var MCi = Cr * tableCi + Ci * tableCr; + + var tableDr = table[3 * k]; + var tableDi = inv * table[3 * k + 1]; + var MDr = Dr * tableDr - Di * tableDi; + var MDi = Dr * tableDi + Di * tableDr; + + // Pre-Final values + var T0r = MAr + MCr; + var T0i = MAi + MCi; + var T1r = MAr - MCr; + var T1i = MAi - MCi; + var T2r = MBr + MDr; + var T2i = MBi + MDi; + var T3r = inv * (MBr - MDr); + var T3i = inv * (MBi - MDi); + + // Final values + var FAr = T0r + T2r; + var FAi = T0i + T2i; + + var FBr = T1r + T3i; + var FBi = T1i - T3r; + + out[A] = FAr; + out[A + 1] = FAi; + out[B] = FBr; + out[B + 1] = FBi; + + // Output final middle point + if (i === 0) { + var FCr = T0r - T2r; + var FCi = T0i - T2i; + out[C] = FCr; + out[C + 1] = FCi; + continue; + } + + // Do not overwrite ourselves + if (i === hquarterLen) continue; + + // In the flipped case: + // MAi = -MAi + // MBr=-MBi, MBi=-MBr + // MCr=-MCr + // MDr=MDi, MDi=MDr + var ST0r = T1r; + var ST0i = -T1i; + var ST1r = T0r; + var ST1i = -T0i; + var ST2r = -inv * T3i; + var ST2i = -inv * T3r; + var ST3r = -inv * T2i; + var ST3i = -inv * T2r; + + var SFAr = ST0r + ST2r; + var SFAi = ST0i + ST2i; + + var SFBr = ST1r + ST3i; + var SFBi = ST1i - ST3r; + + var SA = outOff + quarterLen - i; + var SB = outOff + halfLen - i; + + out[SA] = SFAr; + out[SA + 1] = SFAi; + out[SB] = SFBr; + out[SB + 1] = SFBi; + } + } + } + } + + // radix-2 implementation + // + // NOTE: Only called for len=4 + #singleRealTransform2(outOff: number, off: number, step: number) { + const out = this.#out; + const data = this.#data; + + const evenR = data[off]; + const oddR = data[off + step]; + + const leftR = evenR + oddR; + const rightR = evenR - oddR; + + out[outOff] = leftR; + out[outOff + 1] = 0; + out[outOff + 2] = rightR; + out[outOff + 3] = 0; + } + + // radix-4 + // + // NOTE: Only called for len=8 + #singleRealTransform4(outOff: number, off: number, step: number) { + const out = this.#out; + const data = this.#data; + const inv = this.#inv ? -1 : 1; + const step2 = step * 2; + const step3 = step * 3; + + // Original values + const Ar = data[off]; + const Br = data[off + step]; + const Cr = data[off + step2]; + const Dr = data[off + step3]; + + // Pre-Final values + const T0r = Ar + Cr; + const T1r = Ar - Cr; + const T2r = Br + Dr; + const T3r = inv * (Br - Dr); + + // Final values + const FAr = T0r + T2r; + + const FBr = T1r; + const FBi = -T3r; + + const FCr = T0r - T2r; + + const FDr = T1r; + const FDi = T3r; + + out[outOff] = FAr; + out[outOff + 1] = 0; + out[outOff + 2] = FBr; + out[outOff + 3] = FBi; + out[outOff + 4] = FCr; + out[outOff + 5] = 0; + out[outOff + 6] = FDr; + out[outOff + 7] = FDi; + } +} diff --git a/package.json b/package.json index 4e2e89e..dcf9ca2 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,15 @@ "name": "fft.js", "version": "4.0.4", "description": "Insanely Fast Fourier Transform (radix-4)", - "main": "lib/fft.js", - "types": "lib/fft.d.ts", + "type": "module", + "main": "dist/fft.js", + "module": "dist/fft.js", + "types": "dist/fft.d.ts", "scripts": { - "format": "eslint --fix lib/*.js test/*.js bench/index.js", - "lint": "eslint lib/*.js test/*.js bench/index.js", + "format": "eslint --fix lib/*.ts test/*.js bench/index.js", + "lint": "eslint lib/*.ts test/*.js bench/index.js", "bench": "cd bench && npm install && node .", - "types": "npx typescript lib/fft.js --declaration --allowJs --emitDeclarationOnly --outDir lib\n", - "build": "webpack --progress --colors -p --output-library FFTJS", + "build": "tsc -b", "test": "mocha --reporter=spec test/*-test.js && npm run lint", "version": "npm run build && git add dist/" }, @@ -28,13 +29,17 @@ }, "homepage": "https://github.com/indutny/fft.js#readme", "devDependencies": { - "babel-core": "^6.23.1", - "babel-loader": "^6.4.0", - "babel-preset-es2015": "^6.22.0", - "babel-preset-react": "^6.23.0", - "eslint": "^3.17.0", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", + "benchmark": "^2.1.4", + "dsp.js": "^1.0.1", + "eslint": "^8.57.0", + "eslint-plugin-prettier": "^5.2.1", "fft": "^0.2.1", - "mocha": "^8.2.1", - "webpack": "^2.2.1" + "fourier": "^0.3.0", + "fourier-transform": "^1.1.2", + "mocha": "^11.0.1", + "prettier": "^3.4.2", + "typescript": "^5.7.2" } } diff --git a/test/.eslintrc.js b/test/.eslintrc.js deleted file mode 100644 index 2cfeb09..0000000 --- a/test/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - "env": { - "mocha": true, - "commonjs": true, - "es6": true - }, - "extends": "eslint:recommended", - "rules": { - "indent": [ - "error", - 2 - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ] - } -}; diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 0000000..1dbab91 --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "env": { + "mocha": true, + "commonjs": true, + "es6": true + }, + "extends": "eslint:recommended", + "rules": { + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], + "quotes": ["error", "single"], + "semi": ["error", "always"] + } +} diff --git a/test/fft-test.js b/test/fft-test.js index 5b0c9f6..646cc7f 100644 --- a/test/fft-test.js +++ b/test/fft-test.js @@ -1,16 +1,13 @@ -'use strict'; - -const assert = require('assert'); -const external = require('fft'); -const FFT = require('../'); +import assert from 'assert'; +import external from 'fft'; +import FFT from '../dist/fft.js'; function fixRoundEqual(actual, expected) { function fixRound(r) { return Math.round(r * 1000) / 1000; } - assert.strictEqual(actual.map(fixRound).join(':'), - expected.map(fixRound).join(':')); + assert.strictEqual(actual.map(fixRound).join(':'), expected.map(fixRound).join(':')); } describe('FFT.js', () => { @@ -56,93 +53,75 @@ describe('FFT.js', () => { it('should convert to complex array', () => { const f = new FFT(4); - assert.deepEqual(f.toComplexArray([ 1, 2, 3, 4 ]), - [ 1, 0, 2, 0, 3, 0, 4, 0 ]); + assert.deepEqual(f.toComplexArray([1, 2, 3, 4]), [1, 0, 2, 0, 3, 0, 4, 0]); }); it('should convert from complex array', () => { const f = new FFT(4); - assert.deepEqual(f.fromComplexArray(f.toComplexArray([ 1, 2, 3, 4 ])), - [ 1, 2, 3, 4 ]); - }); - - it('should throw on invalid transform inputs', () => { - const f = new FFT(8); - const output = f.createComplexArray(); - - assert.throws(() => { - f.transform(output, output); - }, /must be different/); + assert.deepEqual(f.fromComplexArray(f.toComplexArray([1, 2, 3, 4])), [1, 2, 3, 4]); }); it('should transform trivial radix-2 case', () => { const f = new FFT(2); - const out = f.createComplexArray(); - let data = f.toComplexArray([ 0.5, -0.5 ]); - f.transform(out, data); - assert.deepEqual(out, [ 0, 0, 1, 0 ]); + let data = f.toComplexArray([0.5, -0.5]); + let out = f.transform(data); + assert.deepEqual(out, [0, 0, 1, 0]); - data = f.toComplexArray([ 0.5, 0.5 ]); - f.transform(out, data); - assert.deepEqual(out, [ 1, 0, 0, 0 ]); + data = f.toComplexArray([0.5, 0.5]); + out = f.transform(data); + assert.deepEqual(out, [1, 0, 0, 0]); // Linear combination - data = f.toComplexArray([ 1, 0 ]); - f.transform(out, data); - assert.deepEqual(out, [ 1, 0, 1, 0 ]); + data = f.toComplexArray([1, 0]); + out = f.transform(data); + assert.deepEqual(out, [1, 0, 1, 0]); }); it('should transform trivial case', () => { const f = new FFT(4); - const out = f.createComplexArray(); - let data = f.toComplexArray([ 1, 0.707106, 0, -0.707106 ]); - f.transform(out, data); - fixRoundEqual(out, [ 1, 0, 1, -1.414, 1, 0, 1, 1.414 ]); + let data = f.toComplexArray([1, 0.707106, 0, -0.707106]); + let out = f.transform(data); + fixRoundEqual(out, [1, 0, 1, -1.414, 1, 0, 1, 1.414]); - data = f.toComplexArray([ 1, 0, -1, 0 ]); - f.transform(out, data); - assert.deepEqual(out, [ 0, 0, 2, 0, 0, 0, 2, 0 ]); + data = f.toComplexArray([1, 0, -1, 0]); + out = f.transform(data); + assert.deepEqual(out, [0, 0, 2, 0, 0, 0, 2, 0]); }); it('should inverse-transform', () => { const f = new FFT(4); - const out = f.createComplexArray(); - const data = f.toComplexArray([ 1, 0.707106, 0, -0.707106 ]); - f.transform(out, data); - fixRoundEqual(out, [ 1, 0, 1, -1.414, 1, 0, 1, 1.414 ]); - f.inverseTransform(data, out); - assert.deepEqual(f.fromComplexArray(data), [ 1, 0.707106, 0, -0.707106 ]); + const data = f.toComplexArray([1, 0.707106, 0, -0.707106]); + let out = f.transform(data); + fixRoundEqual(out, [1, 0, 1, -1.414, 1, 0, 1, 1.414]); + out = f.inverseTransform(data); + assert.deepEqual(f.fromComplexArray(data), [1, 0.707106, 0, -0.707106]); }); it('should transform big recursive case', () => { const input = []; - for (let i = 0; i < 256; i++) - input.push(i); + for (let i = 0; i < 256; i++) input.push(i); const f = new FFT(input.length); - const out = f.createComplexArray(); let data = f.toComplexArray(input); - f.transform(out, data); - f.inverseTransform(data, out); + let out = f.transform(data); + data = f.inverseTransform(out); fixRoundEqual(f.fromComplexArray(data), input); }); it('should transform big recursive radix-2 case', () => { const input = []; - for (let i = 0; i < 128; i++) - input.push(i); + for (let i = 0; i < 128; i++) input.push(i); const f = new FFT(input.length); - const out = f.createComplexArray(); let data = f.toComplexArray(input); - f.transform(out, data); - f.inverseTransform(data, out); + const out = f.transform(data); + data = f.inverseTransform(out); fixRoundEqual(f.fromComplexArray(data), input); }); @@ -151,15 +130,13 @@ describe('FFT.js', () => { const ex = new external.complex(size, false); const input = new Float64Array(size * 2); - for (let i = 0; i < input.length; i += 2) - input[i] = generator(i >>> 1); + for (let i = 0; i < input.length; i += 2) input[i] = generator(i >>> 1); const expected = new Float64Array(size * 2); ex.simple(expected, input, 'complex'); const self = new FFT(size); - const out = self.createComplexArray(); - self.transform(out, input); + const out = self.transform(input); fixRoundEqual(out, expected); }); } @@ -174,13 +151,10 @@ describe('FFT.js', () => { input[i] = generator(i >>> 1); realInput[i >>> 1] = input[i]; } - const expected = complex.createComplexArray(); - - complex.transform(expected, input, 'complex'); + const expected = complex.transform(input, 'complex'); const self = new FFT(size); - const out = self.createComplexArray(); - self.realTransform(out, realInput); + const out = self.realTransform(realInput); self.completeSpectrum(out); fixRoundEqual(out, expected); }); @@ -201,8 +175,7 @@ describe('FFT.js', () => { ex.simple(expected, input, 'complex'); const self = new FFT(size); - const out = self.createComplexArray(); - self.realTransform(out, realInput); + const out = self.realTransform(realInput); self.completeSpectrum(out); fixRoundEqual(out, expected); }); @@ -221,7 +194,7 @@ describe('FFT.js', () => { return (Math.random() - 0.5) * 2; } - const sizes = [ 2, 4, 8, 16, 512, 1024, 2048, 4096 ]; + const sizes = [2, 4, 8, 16, 512, 1024, 2048, 4096]; sizes.forEach((size) => { describe(`size=${size}`, () => { function every(generator) { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..621a5e9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "tsBuildInfoFile": "node_modules/.tmp/tsconfig.tsbuildinfo", + + /* Modules */ + "module": "ESNext", + + /* Emit */ + "declaration": true, + "sourceMap": true, + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + + /* Type Checking */ + "strict": true, + "skipLibCheck": true + }, + "include": ["lib"] +} diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 9d88b80..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const path = require('path'); - -const DIST = path.join(__dirname, 'dist'); -const LIB = path.join(__dirname, 'lib'); - -const loaders = [ - { - test: /\.js$/, - loader: 'babel-loader', - query: { - presets: [ 'es2015', 'react' ] - } - } -]; - -module.exports = [{ - target: 'web', - entry: path.join(LIB, 'fft.js'), - output: { - path: DIST, - filename: 'fft.js' - }, - module: { - loaders: loaders - } -}];