mirror of
https://github.com/Tonejs/Tone.js
synced 2025-01-10 10:58:52 +00:00
540 lines
16 KiB
JavaScript
540 lines
16 KiB
JavaScript
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.FFT = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||
|
/*===========================================================================*\
|
||
|
* Fast Fourier Transform (Cooley-Tukey Method)
|
||
|
*
|
||
|
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
|
||
|
*
|
||
|
* This code is not designed to be highly optimized but as an educational
|
||
|
* tool to understand the Fast Fourier Transform.
|
||
|
\*===========================================================================*/
|
||
|
module.exports = {
|
||
|
fft: require('./src/fft').fft,
|
||
|
ifft: require('./src/ifft').ifft,
|
||
|
fftInPlace: require('./src/fft').fftInPlace,
|
||
|
util: require('./src/fftutil'),
|
||
|
dft: require('./src/dft')
|
||
|
};
|
||
|
|
||
|
},{"./src/dft":4,"./src/fft":5,"./src/fftutil":6,"./src/ifft":7}],2:[function(require,module,exports){
|
||
|
/**
|
||
|
* Bit twiddling hacks for JavaScript.
|
||
|
*
|
||
|
* Author: Mikola Lysenko
|
||
|
*
|
||
|
* Ported from Stanford bit twiddling hack library:
|
||
|
* http://graphics.stanford.edu/~seander/bithacks.html
|
||
|
*/
|
||
|
|
||
|
"use strict"; "use restrict";
|
||
|
|
||
|
//Number of bits in an integer
|
||
|
var INT_BITS = 32;
|
||
|
|
||
|
//Constants
|
||
|
exports.INT_BITS = INT_BITS;
|
||
|
exports.INT_MAX = 0x7fffffff;
|
||
|
exports.INT_MIN = -1<<(INT_BITS-1);
|
||
|
|
||
|
//Returns -1, 0, +1 depending on sign of x
|
||
|
exports.sign = function(v) {
|
||
|
return (v > 0) - (v < 0);
|
||
|
}
|
||
|
|
||
|
//Computes absolute value of integer
|
||
|
exports.abs = function(v) {
|
||
|
var mask = v >> (INT_BITS-1);
|
||
|
return (v ^ mask) - mask;
|
||
|
}
|
||
|
|
||
|
//Computes minimum of integers x and y
|
||
|
exports.min = function(x, y) {
|
||
|
return y ^ ((x ^ y) & -(x < y));
|
||
|
}
|
||
|
|
||
|
//Computes maximum of integers x and y
|
||
|
exports.max = function(x, y) {
|
||
|
return x ^ ((x ^ y) & -(x < y));
|
||
|
}
|
||
|
|
||
|
//Checks if a number is a power of two
|
||
|
exports.isPow2 = function(v) {
|
||
|
return !(v & (v-1)) && (!!v);
|
||
|
}
|
||
|
|
||
|
//Computes log base 2 of v
|
||
|
exports.log2 = function(v) {
|
||
|
var r, shift;
|
||
|
r = (v > 0xFFFF) << 4; v >>>= r;
|
||
|
shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
|
||
|
shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
|
||
|
shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
|
||
|
return r | (v >> 1);
|
||
|
}
|
||
|
|
||
|
//Computes log base 10 of v
|
||
|
exports.log10 = function(v) {
|
||
|
return (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :
|
||
|
(v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :
|
||
|
(v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
//Counts number of bits
|
||
|
exports.popCount = function(v) {
|
||
|
v = v - ((v >>> 1) & 0x55555555);
|
||
|
v = (v & 0x33333333) + ((v >>> 2) & 0x33333333);
|
||
|
return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
|
||
|
}
|
||
|
|
||
|
//Counts number of trailing zeros
|
||
|
function countTrailingZeros(v) {
|
||
|
var c = 32;
|
||
|
v &= -v;
|
||
|
if (v) c--;
|
||
|
if (v & 0x0000FFFF) c -= 16;
|
||
|
if (v & 0x00FF00FF) c -= 8;
|
||
|
if (v & 0x0F0F0F0F) c -= 4;
|
||
|
if (v & 0x33333333) c -= 2;
|
||
|
if (v & 0x55555555) c -= 1;
|
||
|
return c;
|
||
|
}
|
||
|
exports.countTrailingZeros = countTrailingZeros;
|
||
|
|
||
|
//Rounds to next power of 2
|
||
|
exports.nextPow2 = function(v) {
|
||
|
v += v === 0;
|
||
|
--v;
|
||
|
v |= v >>> 1;
|
||
|
v |= v >>> 2;
|
||
|
v |= v >>> 4;
|
||
|
v |= v >>> 8;
|
||
|
v |= v >>> 16;
|
||
|
return v + 1;
|
||
|
}
|
||
|
|
||
|
//Rounds down to previous power of 2
|
||
|
exports.prevPow2 = function(v) {
|
||
|
v |= v >>> 1;
|
||
|
v |= v >>> 2;
|
||
|
v |= v >>> 4;
|
||
|
v |= v >>> 8;
|
||
|
v |= v >>> 16;
|
||
|
return v - (v>>>1);
|
||
|
}
|
||
|
|
||
|
//Computes parity of word
|
||
|
exports.parity = function(v) {
|
||
|
v ^= v >>> 16;
|
||
|
v ^= v >>> 8;
|
||
|
v ^= v >>> 4;
|
||
|
v &= 0xf;
|
||
|
return (0x6996 >>> v) & 1;
|
||
|
}
|
||
|
|
||
|
var REVERSE_TABLE = new Array(256);
|
||
|
|
||
|
(function(tab) {
|
||
|
for(var i=0; i<256; ++i) {
|
||
|
var v = i, r = i, s = 7;
|
||
|
for (v >>>= 1; v; v >>>= 1) {
|
||
|
r <<= 1;
|
||
|
r |= v & 1;
|
||
|
--s;
|
||
|
}
|
||
|
tab[i] = (r << s) & 0xff;
|
||
|
}
|
||
|
})(REVERSE_TABLE);
|
||
|
|
||
|
//Reverse bits in a 32 bit word
|
||
|
exports.reverse = function(v) {
|
||
|
return (REVERSE_TABLE[ v & 0xff] << 24) |
|
||
|
(REVERSE_TABLE[(v >>> 8) & 0xff] << 16) |
|
||
|
(REVERSE_TABLE[(v >>> 16) & 0xff] << 8) |
|
||
|
REVERSE_TABLE[(v >>> 24) & 0xff];
|
||
|
}
|
||
|
|
||
|
//Interleave bits of 2 coordinates with 16 bits. Useful for fast quadtree codes
|
||
|
exports.interleave2 = function(x, y) {
|
||
|
x &= 0xFFFF;
|
||
|
x = (x | (x << 8)) & 0x00FF00FF;
|
||
|
x = (x | (x << 4)) & 0x0F0F0F0F;
|
||
|
x = (x | (x << 2)) & 0x33333333;
|
||
|
x = (x | (x << 1)) & 0x55555555;
|
||
|
|
||
|
y &= 0xFFFF;
|
||
|
y = (y | (y << 8)) & 0x00FF00FF;
|
||
|
y = (y | (y << 4)) & 0x0F0F0F0F;
|
||
|
y = (y | (y << 2)) & 0x33333333;
|
||
|
y = (y | (y << 1)) & 0x55555555;
|
||
|
|
||
|
return x | (y << 1);
|
||
|
}
|
||
|
|
||
|
//Extracts the nth interleaved component
|
||
|
exports.deinterleave2 = function(v, n) {
|
||
|
v = (v >>> n) & 0x55555555;
|
||
|
v = (v | (v >>> 1)) & 0x33333333;
|
||
|
v = (v | (v >>> 2)) & 0x0F0F0F0F;
|
||
|
v = (v | (v >>> 4)) & 0x00FF00FF;
|
||
|
v = (v | (v >>> 16)) & 0x000FFFF;
|
||
|
return (v << 16) >> 16;
|
||
|
}
|
||
|
|
||
|
|
||
|
//Interleave bits of 3 coordinates, each with 10 bits. Useful for fast octree codes
|
||
|
exports.interleave3 = function(x, y, z) {
|
||
|
x &= 0x3FF;
|
||
|
x = (x | (x<<16)) & 4278190335;
|
||
|
x = (x | (x<<8)) & 251719695;
|
||
|
x = (x | (x<<4)) & 3272356035;
|
||
|
x = (x | (x<<2)) & 1227133513;
|
||
|
|
||
|
y &= 0x3FF;
|
||
|
y = (y | (y<<16)) & 4278190335;
|
||
|
y = (y | (y<<8)) & 251719695;
|
||
|
y = (y | (y<<4)) & 3272356035;
|
||
|
y = (y | (y<<2)) & 1227133513;
|
||
|
x |= (y << 1);
|
||
|
|
||
|
z &= 0x3FF;
|
||
|
z = (z | (z<<16)) & 4278190335;
|
||
|
z = (z | (z<<8)) & 251719695;
|
||
|
z = (z | (z<<4)) & 3272356035;
|
||
|
z = (z | (z<<2)) & 1227133513;
|
||
|
|
||
|
return x | (z << 2);
|
||
|
}
|
||
|
|
||
|
//Extracts nth interleaved component of a 3-tuple
|
||
|
exports.deinterleave3 = function(v, n) {
|
||
|
v = (v >>> n) & 1227133513;
|
||
|
v = (v | (v>>>2)) & 3272356035;
|
||
|
v = (v | (v>>>4)) & 251719695;
|
||
|
v = (v | (v>>>8)) & 4278190335;
|
||
|
v = (v | (v>>>16)) & 0x3FF;
|
||
|
return (v<<22)>>22;
|
||
|
}
|
||
|
|
||
|
//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
|
||
|
exports.nextCombination = function(v) {
|
||
|
var t = v | (v - 1);
|
||
|
return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
|
||
|
}
|
||
|
|
||
|
|
||
|
},{}],3:[function(require,module,exports){
|
||
|
//-------------------------------------------------
|
||
|
// Add two complex numbers
|
||
|
//-------------------------------------------------
|
||
|
var complexAdd = function (a, b)
|
||
|
{
|
||
|
return [a[0] + b[0], a[1] + b[1]];
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Subtract two complex numbers
|
||
|
//-------------------------------------------------
|
||
|
var complexSubtract = function (a, b)
|
||
|
{
|
||
|
return [a[0] - b[0], a[1] - b[1]];
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Multiply two complex numbers
|
||
|
//
|
||
|
// (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
||
|
//-------------------------------------------------
|
||
|
var complexMultiply = function (a, b)
|
||
|
{
|
||
|
return [(a[0] * b[0] - a[1] * b[1]),
|
||
|
(a[0] * b[1] + a[1] * b[0])];
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Calculate |a + bi|
|
||
|
//
|
||
|
// sqrt(a*a + b*b)
|
||
|
//-------------------------------------------------
|
||
|
var complexMagnitude = function (c)
|
||
|
{
|
||
|
return Math.sqrt(c[0]*c[0] + c[1]*c[1]);
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Exports
|
||
|
//-------------------------------------------------
|
||
|
module.exports = {
|
||
|
add: complexAdd,
|
||
|
subtract: complexSubtract,
|
||
|
multiply: complexMultiply,
|
||
|
magnitude: complexMagnitude
|
||
|
};
|
||
|
|
||
|
},{}],4:[function(require,module,exports){
|
||
|
/*===========================================================================*\
|
||
|
* Discrete Fourier Transform (O(n^2) brute-force method)
|
||
|
*
|
||
|
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
|
||
|
*
|
||
|
* This code is not designed to be highly optimized but as an educational
|
||
|
* tool to understand the Fast Fourier Transform.
|
||
|
\*===========================================================================*/
|
||
|
|
||
|
//------------------------------------------------
|
||
|
// Note: this code is not optimized and is
|
||
|
// primarily designed as an educational and testing
|
||
|
// tool.
|
||
|
//------------------------------------------------
|
||
|
var complex = require('./complex');
|
||
|
var fftUtil = require('./fftutil');
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Calculate brute-force O(n^2) DFT for vector.
|
||
|
//-------------------------------------------------
|
||
|
var dft = function(vector) {
|
||
|
var X = [],
|
||
|
N = vector.length;
|
||
|
|
||
|
for (var k = 0; k < N; k++) {
|
||
|
X[k] = [0, 0]; //Initialize to a 0-valued complex number.
|
||
|
|
||
|
for (var i = 0; i < N; i++) {
|
||
|
var exp = fftUtil.exponent(k * i, N);
|
||
|
var term = complex.multiply([vector[i], 0], exp); //Complex mult of the signal with the exponential term.
|
||
|
X[k] = complex.add(X[k], term); //Complex summation of X[k] and exponential
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return X;
|
||
|
};
|
||
|
|
||
|
module.exports = dft;
|
||
|
},{"./complex":3,"./fftutil":6}],5:[function(require,module,exports){
|
||
|
/*===========================================================================*\
|
||
|
* Fast Fourier Transform (Cooley-Tukey Method)
|
||
|
*
|
||
|
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
|
||
|
*
|
||
|
* This code is not designed to be highly optimized but as an educational
|
||
|
* tool to understand the Fast Fourier Transform.
|
||
|
\*===========================================================================*/
|
||
|
|
||
|
//------------------------------------------------
|
||
|
// Note: Some of this code is not optimized and is
|
||
|
// primarily designed as an educational and testing
|
||
|
// tool.
|
||
|
// To get high performace would require transforming
|
||
|
// the recursive calls into a loop and then loop
|
||
|
// unrolling. All of this is best accomplished
|
||
|
// in C or assembly.
|
||
|
//-------------------------------------------------
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// The following code assumes a complex number is
|
||
|
// an array: [real, imaginary]
|
||
|
//-------------------------------------------------
|
||
|
var complex = require('./complex'),
|
||
|
fftUtil = require('./fftutil'),
|
||
|
twiddle = require('bit-twiddle');
|
||
|
|
||
|
module.exports = {
|
||
|
//-------------------------------------------------
|
||
|
// Calculate FFT for vector where vector.length
|
||
|
// is assumed to be a power of 2.
|
||
|
//-------------------------------------------------
|
||
|
fft: function fft(vector) {
|
||
|
var X = [],
|
||
|
N = vector.length;
|
||
|
|
||
|
// Base case is X = x + 0i since our input is assumed to be real only.
|
||
|
if (N == 1) {
|
||
|
if (Array.isArray(vector[0])) //If input vector contains complex numbers
|
||
|
return [[vector[0][0], vector[0][1]]];
|
||
|
else
|
||
|
return [[vector[0], 0]];
|
||
|
}
|
||
|
|
||
|
// Recurse: all even samples
|
||
|
var X_evens = fft(vector.filter(even)),
|
||
|
|
||
|
// Recurse: all odd samples
|
||
|
X_odds = fft(vector.filter(odd));
|
||
|
|
||
|
// Now, perform N/2 operations!
|
||
|
for (var k = 0; k < N / 2; k++) {
|
||
|
// t is a complex number!
|
||
|
var t = X_evens[k],
|
||
|
e = complex.multiply(fftUtil.exponent(k, N), X_odds[k]);
|
||
|
|
||
|
X[k] = complex.add(t, e);
|
||
|
X[k + (N / 2)] = complex.subtract(t, e);
|
||
|
}
|
||
|
|
||
|
function even(__, ix) {
|
||
|
return ix % 2 == 0;
|
||
|
}
|
||
|
|
||
|
function odd(__, ix) {
|
||
|
return ix % 2 == 1;
|
||
|
}
|
||
|
|
||
|
return X;
|
||
|
},
|
||
|
//-------------------------------------------------
|
||
|
// Calculate FFT for vector where vector.length
|
||
|
// is assumed to be a power of 2. This is the in-
|
||
|
// place implementation, to avoid the memory
|
||
|
// footprint used by recursion.
|
||
|
//-------------------------------------------------
|
||
|
fftInPlace: function(vector) {
|
||
|
var N = vector.length;
|
||
|
|
||
|
var trailingZeros = twiddle.countTrailingZeros(N); //Once reversed, this will be leading zeros
|
||
|
|
||
|
// Reverse bits
|
||
|
for (var k = 0; k < N; k++) {
|
||
|
var p = twiddle.reverse(k) >>> (twiddle.INT_BITS - trailingZeros);
|
||
|
if (p > k) {
|
||
|
var complexTemp = [vector[k], 0];
|
||
|
vector[k] = vector[p];
|
||
|
vector[p] = complexTemp;
|
||
|
} else {
|
||
|
vector[p] = [vector[p], 0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Do the DIT now in-place
|
||
|
for (var len = 2; len <= N; len += len) {
|
||
|
for (var i = 0; i < len / 2; i++) {
|
||
|
var w = fftUtil.exponent(i, len);
|
||
|
for (var j = 0; j < N / len; j++) {
|
||
|
var t = complex.multiply(w, vector[j * len + i + len / 2]);
|
||
|
vector[j * len + i + len / 2] = complex.subtract(vector[j * len + i], t);
|
||
|
vector[j * len + i] = complex.add(vector[j * len + i], t);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
},{"./complex":3,"./fftutil":6,"bit-twiddle":2}],6:[function(require,module,exports){
|
||
|
/*===========================================================================*\
|
||
|
* Fast Fourier Transform Frequency/Magnitude passes
|
||
|
*
|
||
|
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
|
||
|
*
|
||
|
* This code is not designed to be highly optimized but as an educational
|
||
|
* tool to understand the Fast Fourier Transform.
|
||
|
\*===========================================================================*/
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// The following code assumes a complex number is
|
||
|
// an array: [real, imaginary]
|
||
|
//-------------------------------------------------
|
||
|
var complex = require('./complex');
|
||
|
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// By Eulers Formula:
|
||
|
//
|
||
|
// e^(i*x) = cos(x) + i*sin(x)
|
||
|
//
|
||
|
// and in DFT:
|
||
|
//
|
||
|
// x = -2*PI*(k/N)
|
||
|
//-------------------------------------------------
|
||
|
var mapExponent = {},
|
||
|
exponent = function (k, N) {
|
||
|
var x = -2 * Math.PI * (k / N);
|
||
|
|
||
|
mapExponent[N] = mapExponent[N] || {};
|
||
|
mapExponent[N][k] = mapExponent[N][k] || [Math.cos(x), Math.sin(x)];// [Real, Imaginary]
|
||
|
|
||
|
return mapExponent[N][k];
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Calculate FFT Magnitude for complex numbers.
|
||
|
//-------------------------------------------------
|
||
|
var fftMag = function (fftBins) {
|
||
|
var ret = fftBins.map(complex.magnitude);
|
||
|
return ret.slice(0, ret.length / 2);
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Calculate Frequency Bins
|
||
|
//
|
||
|
// Returns an array of the frequencies (in hertz) of
|
||
|
// each FFT bin provided, assuming the sampleRate is
|
||
|
// samples taken per second.
|
||
|
//-------------------------------------------------
|
||
|
var fftFreq = function (fftBins, sampleRate) {
|
||
|
var stepFreq = sampleRate / (fftBins.length);
|
||
|
var ret = fftBins.slice(0, fftBins.length / 2);
|
||
|
|
||
|
return ret.map(function (__, ix) {
|
||
|
return ix * stepFreq;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// Exports
|
||
|
//-------------------------------------------------
|
||
|
module.exports = {
|
||
|
fftMag: fftMag,
|
||
|
fftFreq: fftFreq,
|
||
|
exponent: exponent
|
||
|
};
|
||
|
|
||
|
},{"./complex":3}],7:[function(require,module,exports){
|
||
|
/*===========================================================================*\
|
||
|
* Inverse Fast Fourier Transform (Cooley-Tukey Method)
|
||
|
*
|
||
|
* (c) Maximilian Bügler. 2016
|
||
|
*
|
||
|
* Based on and using the code by
|
||
|
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
|
||
|
*
|
||
|
* This code is not designed to be highly optimized but as an educational
|
||
|
* tool to understand the Fast Fourier Transform.
|
||
|
\*===========================================================================*/
|
||
|
|
||
|
//------------------------------------------------
|
||
|
// Note: Some of this code is not optimized and is
|
||
|
// primarily designed as an educational and testing
|
||
|
// tool.
|
||
|
// To get high performace would require transforming
|
||
|
// the recursive calls into a loop and then loop
|
||
|
// unrolling. All of this is best accomplished
|
||
|
// in C or assembly.
|
||
|
//-------------------------------------------------
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
// The following code assumes a complex number is
|
||
|
// an array: [real, imaginary]
|
||
|
//-------------------------------------------------
|
||
|
|
||
|
var fft = require('./fft').fft;
|
||
|
|
||
|
|
||
|
module.exports = {
|
||
|
ifft: function ifft(signal){
|
||
|
//Interchange real and imaginary parts
|
||
|
var csignal=[];
|
||
|
for(var i=0; i<signal.length; i++){
|
||
|
csignal[i]=[signal[i][1], signal[i][0]];
|
||
|
}
|
||
|
|
||
|
//Apply fft
|
||
|
var ps=fft(csignal);
|
||
|
|
||
|
//Interchange real and imaginary parts and normalize
|
||
|
var res=[];
|
||
|
for(var j=0; j<ps.length; j++){
|
||
|
res[j]=[ps[j][1]/ps.length, ps[j][0]/ps.length];
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
},{"./fft":5}]},{},[1])(1)
|
||
|
});
|