flocking
Version:
Creative audio synthesis for the Web
1,551 lines (1,326 loc) • 265 kB
JavaScript
/*! Flocking 3.0.1, Copyright 2022 Colin Clark | flockingjs.org */
// -*- mode: javascript; tab-width: 2; indent-tabs-mode: nil; -*-
//------------------------------------------------------------------------------
// Web Array Math API - JavaScript polyfill
//
// Copyright(c) 2013 Marcus Geelnard
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the
// use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not claim
// that you wrote the original software. If you use this software in a
// product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//------------------------------------------------------------------------------
"use strict";
//------------------------------------------------------------------------------
// interface ArrayMath
//------------------------------------------------------------------------------
(function () {
var context = typeof (window) !== "undefined" ? window :
typeof (self) !== "undefined" ? self :
typeof module !== "undefined" && module.exports ? module.exports :
global;
if (context.ArrayMath) return;
var ArrayMath = {};
ArrayMath.add = function (dst, x, y) {
var k;
if (x instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = x[k] + y[k];
else
for (k = Math.min(dst.length, y.length) - 1; k >= 0; --k)
dst[k] = x + y[k];
};
ArrayMath.sub = function (dst, x, y) {
var k;
if (x instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = x[k] - y[k];
else
for (k = Math.min(dst.length, y.length) - 1; k >= 0; --k)
dst[k] = x - y[k];
};
ArrayMath.mul = function (dst, x, y) {
var k;
if (x instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = x[k] * y[k];
else
for (k = Math.min(dst.length, y.length) - 1; k >= 0; --k)
dst[k] = x * y[k];
};
ArrayMath.mulCplx = function (dstReal, dstImag, xReal, xImag, yReal, yImag) {
var k, xr, xi, yr, yi;
if (xReal instanceof Float32Array)
for (k = Math.min(dstReal.length, dstImag.length, xReal.length, xImag.length, yReal.length, yImag.length) - 1; k >= 0; --k) {
xr = xReal[k], xi = xImag[k], yr = yReal[k], yi = yImag[k];
dstReal[k] = xr * yr - xi * yi;
dstImag[k] = xr * yi + xi * yr;
}
else
for (k = Math.min(dstReal.length, dstImag.length, yReal.length, yImag.length) - 1; k >= 0; --k) {
yr = yReal[k], yi = yImag[k];
dstReal[k] = xReal * yr - xImag * yi;
dstImag[k] = xReal * yi + xImag * yr;
}
};
ArrayMath.div = function (dst, x, y) {
var k;
if (x instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = x[k] / y[k];
else
for (k = Math.min(dst.length, y.length) - 1; k >= 0; --k)
dst[k] = x / y[k];
};
ArrayMath.divCplx = function (dstReal, dstImag, xReal, xImag, yReal, yImag) {
var k, xr, xi, yr, yi, denom;
if (xReal instanceof Float32Array)
for (k = Math.min(dstReal.length, dstImag.length, xReal.length, xImag.length, yReal.length, yImag.length) - 1; k >= 0; --k) {
xr = xReal[k], xi = xImag[k], yr = yReal[k], yi = yImag[k];
denom = 1 / (yr * yr + yi * yi);
dstReal[k] = (xr * yr + xi * yi) * denom;
dstImag[k] = (xi * yr - xr * yi) * denom;
}
else {
for (k = Math.min(dstReal.length, dstImag.length, yReal.length, yImag.length) - 1; k >= 0; --k) {
yr = yReal[k], yi = yImag[k];
denom = 1 / (yr * yr + yi * yi);
dstReal[k] = (xReal * yr + xImag * yi) * denom;
dstImag[k] = (xImag * yr - xReal * yi) * denom;
}
}
};
ArrayMath.madd = function (dst, x, y, z) {
var k;
if (x instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length, z.length) - 1; k >= 0; --k)
dst[k] = x[k] * y[k] + z[k];
else
for (k = Math.min(dst.length, y.length, z.length) - 1; k >= 0; --k)
dst[k] = x * y[k] + z[k];
};
ArrayMath.abs = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.abs(x[k]);
};
ArrayMath.absCplx = function (dst, real, imag) {
for (var k = Math.min(dst.length, real.length, imag.length) - 1; k >= 0; --k)
dst[k] = Math.sqrt(real[k] * real[k] + imag[k] * imag[k]);
};
ArrayMath.acos = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.acos(x[k]);
};
ArrayMath.asin = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.asin(x[k]);
};
ArrayMath.atan = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.atan(x[k]);
};
ArrayMath.atan2 = function (dst, y, x) {
for (var k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = Math.atan2(y[k], x[k]);
};
ArrayMath.ceil = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.ceil(x[k]);
};
ArrayMath.cos = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.cos(x[k]);
};
ArrayMath.exp = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.exp(x[k]);
};
ArrayMath.floor = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.floor(x[k]);
};
ArrayMath.log = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.log(x[k]);
};
ArrayMath.max = function (x) {
var ret = -Infinity;
for (var k = x.length - 1; k >= 0; --k) {
var val = x[k];
if (val > ret)
ret = val;
}
return ret;
};
ArrayMath.min = function (x) {
var ret = Infinity;
for (var k = x.length - 1; k >= 0; --k) {
var val = x[k];
if (val < ret)
ret = val;
}
return ret;
};
ArrayMath.pow = function (dst, x, y) {
var k;
if (y instanceof Float32Array)
for (k = Math.min(dst.length, x.length, y.length) - 1; k >= 0; --k)
dst[k] = Math.pow(x[k], y[k]);
else {
for (k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.pow(x[k], y);
}
};
ArrayMath.random = function (dst, low, high) {
if (!low)
low = 0;
if (isNaN(parseFloat(high)))
high = 1;
var scale = high - low;
for (var k = dst.length - 1; k >= 0; --k)
dst[k] = Math.random() * scale + low;
};
ArrayMath.round = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.round(x[k]);
};
ArrayMath.sin = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.sin(x[k]);
};
ArrayMath.sqrt = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.sqrt(x[k]);
};
ArrayMath.tan = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = Math.tan(x[k]);
};
ArrayMath.clamp = function (dst, x, xMin, xMax) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k) {
var val = x[k];
dst[k] = val < xMin ? xMin : val > xMax ? xMax : val;
}
};
ArrayMath.fract = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k) {
var val = x[k];
dst[k] = val - Math.floor(val);
}
};
ArrayMath.fill = function (dst, value) {
for (var k = dst.length - 1; k >= 0; --k) {
dst[k] = value;
}
};
ArrayMath.ramp = function (dst, first, last) {
var maxIdx = dst.length - 1;
if (maxIdx >= 0)
dst[0] = first;
if (maxIdx > 0) {
var step = (last - first) / maxIdx;
for (var k = 1; k <= maxIdx; ++k)
dst[k] = first + step * k;
}
};
ArrayMath.sign = function (dst, x) {
for (var k = Math.min(dst.length, x.length) - 1; k >= 0; --k)
dst[k] = x[k] < 0 ? -1 : 1;
};
ArrayMath.sum = function (x) {
// TODO(m): We should use pairwise summation or similar here.
var ret = 0;
for (var k = x.length - 1; k >= 0; --k)
ret += x[k];
return ret;
};
ArrayMath.sampleLinear = function (dst, x, t) {
var xLen = x.length, maxIdx = xLen - 1;
for (var k = Math.min(dst.length, t.length) - 1; k >= 0; --k) {
var t2 = t[k];
t2 = t2 < 0 ? 0 : t2 > maxIdx ? maxIdx : t2;
var idx = Math.floor(t2);
var w = t2 - idx;
var p1 = x[idx];
var p2 = x[idx < maxIdx ? idx + 1 : maxIdx];
dst[k] = p1 + w * (p2 - p1);
}
};
ArrayMath.sampleLinearRepeat = function (dst, x, t) {
var xLen = x.length, maxIdx = xLen - 1;
for (var k = Math.min(dst.length, t.length) - 1; k >= 0; --k) {
var t2 = t[k];
t2 = t2 - Math.floor(t2/xLen) * xLen;
var idx = Math.floor(t2);
var w = t2 - idx;
var p1 = x[idx];
var p2 = x[idx < maxIdx ? idx + 1 : 0];
dst[k] = p1 + w * (p2 - p1);
}
};
ArrayMath.sampleCubic = function (dst, x, t) {
var xLen = x.length, maxIdx = xLen - 1;
for (var k = Math.min(dst.length, t.length) - 1; k >= 0; --k) {
var t2 = t[k];
t2 = t2 < 0 ? 0 : t2 > maxIdx ? maxIdx : t2;
var idx = Math.floor(t2);
var w = t2 - idx;
var w2 = w * w;
var w3 = w2 * w;
var h2 = -2*w3 + 3*w2;
var h1 = 1 - h2;
var h4 = w3 - w2;
var h3 = h4 - w2 + w;
var p1 = x[idx > 0 ? idx - 1 : 0];
var p2 = x[idx];
var p3 = x[idx < maxIdx ? idx + 1 : maxIdx];
var p4 = x[idx < maxIdx - 1 ? idx + 2 : maxIdx];
dst[k] = h1 * p2 + h2 * p3 + 0.5 * (h3 * (p3 - p1) + h4 * (p4 - p2));
}
};
ArrayMath.sampleCubicRepeat = function (dst, x, t) {
var xLen = x.length, maxIdx = xLen - 1;
for (var k = Math.min(dst.length, t.length) - 1; k >= 0; --k) {
var t2 = t[k];
t2 = t2 - Math.floor(t2/xLen) * xLen;
var idx = Math.floor(t2);
var w = t2 - idx;
var w2 = w * w;
var w3 = w2 * w;
var h2 = -2*w3 + 3*w2;
var h1 = 1 - h2;
var h4 = w3 - w2;
var h3 = h4 - w2 + w;
var p1 = x[idx > 0 ? idx - 1 : maxIdx];
var p2 = x[idx];
var p3 = x[idx < maxIdx ? idx + 1 : 0];
var p4 = x[idx < maxIdx - 1 ? idx + 2 : (idx + 2 - Math.floor((idx + 2)/xLen) * xLen)];
dst[k] = h1 * p2 + h2 * p3 + 0.5 * (h3 * (p3 - p1) + h4 * (p4 - p2));
}
};
ArrayMath.pack = function (dst, offset, stride, src1, src2, src3, src4) {
var dstCount = Math.floor(Math.max(0, (dst.length - offset)) / stride);
var count = Math.min(dstCount, src1.length);
if (src2) {
var count = Math.min(count, src2.length);
if (src3) {
var count = Math.min(count, src3.length);
if (src4) {
var count = Math.min(count, src4.length);
for (var k = 0; k < count; ++k) {
dst[offset] = src1[k];
dst[offset + 1] = src2[k];
dst[offset + 2] = src3[k];
dst[offset + 3] = src4[k];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst[offset] = src1[k];
dst[offset + 1] = src2[k];
dst[offset + 2] = src3[k];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst[offset] = src1[k];
dst[offset + 1] = src2[k];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst[offset] = src1[k];
offset += stride;
}
};
ArrayMath.unpack = function (src, offset, stride, dst1, dst2, dst3, dst4) {
var srcCount = Math.floor(Math.max(0, (src.length - offset)) / stride);
var count = Math.min(srcCount, dst1.length);
if (dst2) {
var count = Math.min(count, dst2.length);
if (dst3) {
var count = Math.min(count, dst3.length);
if (dst4) {
var count = Math.min(count, dst4.length);
for (var k = 0; k < count; ++k) {
dst1[k] = src[offset];
dst2[k] = src[offset + 1];
dst3[k] = src[offset + 2];
dst4[k] = src[offset + 3];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst1[k] = src[offset];
dst2[k] = src[offset + 1];
dst3[k] = src[offset + 2];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst1[k] = src[offset];
dst2[k] = src[offset + 1];
offset += stride;
}
}
else
for (var k = 0; k < count; ++k) {
dst1[k] = src[offset];
offset += stride;
}
};
context.ArrayMath = ArrayMath;
})();
//------------------------------------------------------------------------------
// interface Filter
//------------------------------------------------------------------------------
(function () {
var context = typeof (window) !== "undefined" ? window :
typeof (self) !== "undefined" ? self :
typeof module !== "undefined" && module.exports ? module.exports :
global;
if (context.Filter) return;
var Filter = function (bSize, aSize) {
if (isNaN(parseFloat(bSize)) || !isFinite(bSize))
bSize = 1;
if (!aSize)
aSize = 0;
this._b = new Float32Array(bSize);
this._b[0] = 1;
this._a = new Float32Array(aSize);
this._bHist = new Float32Array(bSize);
this._aHist = new Float32Array(aSize);
};
Filter.prototype.filter = function (dst, x) {
// Put commonly accessed objects and properties in local variables
var a = this._a, aLen = a.length,
b = this._b, bLen = b.length,
aHist = this._aHist, bHist = this._bHist,
xLen = x.length, dstLen = dst.length;
// Perform run-in part using the history (slow)
var bHistRunIn = bLen - 1;
var aHistRunIn = aLen;
var k;
for (k = 0; (bHistRunIn || aHistRunIn) && k < xLen; ++k) {
var m, noHistLen;
// FIR part
noHistLen = bLen - bHistRunIn;
bHistRunIn && bHistRunIn--;
var res = b[0] * x[k];
for (m = 1; m < noHistLen; ++m)
res += b[m] * x[k - m];
for (; m < bLen; ++m)
res += b[m] * bHist[m - noHistLen];
// Recursive part
noHistLen = aLen - aHistRunIn;
aHistRunIn && aHistRunIn--;
for (m = 0; m < noHistLen; ++m)
res -= a[m] * dst[k - 1 - m];
for (; m < aLen; ++m)
res -= a[m] * aHist[m - noHistLen];
dst[k] = res;
}
// Perform history-free part (fast)
if (bLen == 3 && aLen == 2) {
// Optimized special case: biquad filter
var b0 = b[0], b1 = b[1], b2 = b[2], a1 = a[0], a2 = a[1];
var x0 = x[k-1], x1 = x[k-2], x2;
var y0 = dst[k-1], y1 = dst[k-2], y2;
for (; k < xLen; ++k) {
x2 = x1;
x1 = x0;
x0 = x[k];
y2 = y1;
y1 = y0;
y0 = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
dst[k] = y0;
}
}
else {
// Generic case
for (; k < xLen; ++k) {
var m;
// FIR part
var res = b[0] * x[k];
for (m = 1; m < bLen; ++m)
res += b[m] * x[k - m];
// Recursive part
for (m = 0; m < aLen; ++m)
res -= a[m] * dst[k - 1 - m];
dst[k] = res;
}
}
// Update history state
var histCopy = Math.min(bLen - 1, xLen);
for (k = bLen - 2; k >= histCopy; --k)
bHist[k] = bHist[k - histCopy];
for (k = 0; k < histCopy; ++k)
bHist[k] = x[xLen - 1 - k];
histCopy = Math.min(aLen, dstLen);
for (k = aLen - 1; k >= histCopy; --k)
aHist[k] = aHist[k - histCopy];
for (k = 0; k < histCopy; ++k)
aHist[k] = dst[xLen - 1 - k];
};
Filter.prototype.clearHistory = function () {
for (var k = this._bHist.length - 1; k >= 0; --k)
this._bHist[k] = 0;
for (var k = this._aHist.length - 1; k >= 0; --k)
this._aHist[k] = 0;
};
Filter.prototype.setB = function (values) {
var len = Math.min(this._b.length, values.length);
for (var k = 0; k < len; ++k)
this._b[k] = values[k];
};
Filter.prototype.setA = function (values) {
var len = Math.min(this._a.length, values.length);
for (var k = 0; k < len; ++k)
this._a[k] = values[k];
};
context.Filter = Filter;
})();
//------------------------------------------------------------------------------
// interface FFT
//
// NOTE: This is essentially a hand-translation of the C language Kiss FFT
// library, copyright by Mark Borgerding, relicensed with permission from the
// author.
//
// The algorithm implements mixed radix FFT and supports transforms of any size
// (not just powers of 2). For optimal performance, use sizes that can be
// factorized into factors 2, 3, 4 and 5.
//------------------------------------------------------------------------------
(function () {
var context = typeof (window) !== "undefined" ? window :
typeof (self) !== "undefined" ? self :
typeof module !== "undefined" && module.exports ? module.exports :
global;
if (context.FFT) return;
var butterfly2 = function (outRe, outIm, outIdx, stride, twRe, twIm, m) {
var scratch0Re, scratch0Im,
out0Re, out0Im, out1Re, out1Im,
tRe, tIm;
var tw1 = 0,
idx0 = outIdx,
idx1 = outIdx + m;
var scale = 0.7071067811865475; // sqrt(1/2)
var idx0End = idx0 + m;
while (idx0 < idx0End) {
// out0 = out[idx0] / sqrt(2)
out0Re = outRe[idx0] * scale;
out0Im = outIm[idx0] * scale;
// out1 = out[idx1] / sqrt(2)
out1Re = outRe[idx1] * scale;
out1Im = outIm[idx1] * scale;
// scratch0 = out1 * tw[tw1]
tRe = twRe[tw1]; tIm = twIm[tw1];
scratch0Re = out1Re * tRe - out1Im * tIm;
scratch0Im = out1Re * tIm + out1Im * tRe;
// out[idx1] = out0 - scratch0
outRe[idx1] = out0Re - scratch0Re;
outIm[idx1] = out0Im - scratch0Im;
// out[idx0] = out0 + scratch0
outRe[idx0] = out0Re + scratch0Re;
outIm[idx0] = out0Im + scratch0Im;
tw1 += stride;
++idx0; ++idx1;
}
};
var butterfly3 = function (outRe, outIm, outIdx, stride, twRe, twIm, m) {
var scratch0Re, scratch0Im, scratch1Re, scratch1Im,
scratch2Re, scratch2Im, scratch3Re, scratch3Im,
out0Re, out0Im, out1Re, out1Im, out2Re, out2Im,
tRe, tIm;
var tw1 = 0,
tw2 = 0,
stride2 = 2 * stride,
idx0 = outIdx,
idx1 = outIdx + m,
idx2 = outIdx + 2 * m;
var epi3Im = twIm[stride*m];
var scale = 0.5773502691896258; // sqrt(1/3)
var idx0End = idx0 + m;
while (idx0 < idx0End) {
// out0 = out[idx0] / sqrt(3)
out0Re = outRe[idx0] * scale;
out0Im = outIm[idx0] * scale;
// out1 = out[idx1] / sqrt(3)
out1Re = outRe[idx1] * scale;
out1Im = outIm[idx1] * scale;
// out2 = out[idx2] / sqrt(3)
out2Re = outRe[idx2] * scale;
out2Im = outIm[idx2] * scale;
// scratch1 = out1 * tw[tw1]
tRe = twRe[tw1]; tIm = twIm[tw1];
scratch1Re = out1Re * tRe - out1Im * tIm;
scratch1Im = out1Re * tIm + out1Im * tRe;
// scratch2 = out2 * tw[tw2]
tRe = twRe[tw2]; tIm = twIm[tw2];
scratch2Re = out2Re * tRe - out2Im * tIm;
scratch2Im = out2Re * tIm + out2Im * tRe;
// scratch3 = scratch1 + scratch2
scratch3Re = scratch1Re + scratch2Re;
scratch3Im = scratch1Im + scratch2Im;
// scratch0 = scratch1 - scratch2
scratch0Re = scratch1Re - scratch2Re;
scratch0Im = scratch1Im - scratch2Im;
// out1 = out0 - scratch3 / 2
out1Re = out0Re - scratch3Re * 0.5;
out1Im = out0Im - scratch3Im * 0.5;
// scratch0 *= epi3.i
scratch0Re *= epi3Im;
scratch0Im *= epi3Im;
// out[idx0] = out0 + scratch3
outRe[idx0] = out0Re + scratch3Re;
outIm[idx0] = out0Im + scratch3Im;
outRe[idx2] = out1Re + scratch0Im;
outIm[idx2] = out1Im - scratch0Re;
outRe[idx1] = out1Re - scratch0Im;
outIm[idx1] = out1Im + scratch0Re;
tw1 += stride; tw2 += stride2;
++idx0; ++idx1; ++idx2;
}
};
var butterfly4 = function (outRe, outIm, outIdx, stride, twRe, twIm, m, inverse) {
var scratch0Re, scratch0Im, scratch1Re, scratch1Im, scratch2Re, scratch2Im,
scratch3Re, scratch3Im, scratch4Re, scratch4Im, scratch5Re, scratch5Im,
out0Re, out0Im, out1Re, out1Im, out2Re, out2Im, out3Re, out3Im,
tRe, tIm;
var tw1 = 0,
tw2 = 0,
tw3 = 0,
stride2 = 2 * stride,
stride3 = 3 * stride,
idx0 = outIdx,
idx1 = outIdx + m,
idx2 = outIdx + 2 * m,
idx3 = outIdx + 3 * m;
var scale = 0.5; // sqrt(1/4)
var idx0End = idx0 + m;
while (idx0 < idx0End) {
// out0 = out[idx0] / sqrt(4)
out0Re = outRe[idx0] * scale;
out0Im = outIm[idx0] * scale;
// out1 = out[idx1] / sqrt(4)
out1Re = outRe[idx1] * scale;
out1Im = outIm[idx1] * scale;
// out2 = out[idx2] / sqrt(4)
out2Re = outRe[idx2] * scale;
out2Im = outIm[idx2] * scale;
// out3 = out[idx3] / sqrt(4)
out3Re = outRe[idx3] * scale;
out3Im = outIm[idx3] * scale;
// scratch0 = out1 * tw[tw1]
tRe = twRe[tw1]; tIm = twIm[tw1];
scratch0Re = out1Re * tRe - out1Im * tIm;
scratch0Im = out1Re * tIm + out1Im * tRe;
// scratch1 = out2 * tw[tw2]
tRe = twRe[tw2]; tIm = twIm[tw2];
scratch1Re = out2Re * tRe - out2Im * tIm;
scratch1Im = out2Re * tIm + out2Im * tRe;
// scratch2 = out3 * tw[tw3]
tRe = twRe[tw3]; tIm = twIm[tw3];
scratch2Re = out3Re * tRe - out3Im * tIm;
scratch2Im = out3Re * tIm + out3Im * tRe;
// scratch5 = out0 - scratch1
scratch5Re = out0Re - scratch1Re;
scratch5Im = out0Im - scratch1Im;
// out0 += scratch1
out0Re += scratch1Re;
out0Im += scratch1Im;
// scratch3 = scratch0 + scratch2
scratch3Re = scratch0Re + scratch2Re;
scratch3Im = scratch0Im + scratch2Im;
// scratch4 = scratch0 - scratch2
scratch4Re = scratch0Re - scratch2Re;
scratch4Im = scratch0Im - scratch2Im;
// out[idx2] = out0 - scratch3
outRe[idx2] = out0Re - scratch3Re;
outIm[idx2] = out0Im - scratch3Im;
// out[idx0] = out0 + scratch3
outRe[idx0] = out0Re + scratch3Re;
outIm[idx0] = out0Im + scratch3Im;
if (inverse) {
outRe[idx1] = scratch5Re - scratch4Im;
outIm[idx1] = scratch5Im + scratch4Re;
outRe[idx3] = scratch5Re + scratch4Im;
outIm[idx3] = scratch5Im - scratch4Re;
}
else {
outRe[idx1] = scratch5Re + scratch4Im;
outIm[idx1] = scratch5Im - scratch4Re;
outRe[idx3] = scratch5Re - scratch4Im;
outIm[idx3] = scratch5Im + scratch4Re;
}
tw1 += stride; tw2 += stride2; tw3 += stride3;
++idx0; ++idx1; ++idx2; ++idx3;
}
};
var butterfly5 = function (outRe, outIm, outIdx, stride, twRe, twIm, m) {
var scratch0Re, scratch0Im, scratch1Re, scratch1Im, scratch2Re, scratch2Im,
scratch3Re, scratch3Im, scratch4Re, scratch4Im, scratch5Re, scratch5Im,
scratch6Re, scratch6Im, scratch7Re, scratch7Im, scratch8Re, scratch8Im,
scratch9Re, scratch9Im, scratch10Re, scratch10Im, scratch11Re, scratch11Im,
scratch12Re, scratch12Im,
out0Re, out0Im, out1Re, out1Im, out2Re, out2Im, out3Re, out3Im, out4Re, out4Im,
tRe, tIm;
var tw1 = 0,
tw2 = 0,
tw3 = 0,
tw4 = 0,
stride2 = 2 * stride,
stride3 = 3 * stride,
stride4 = 4 * stride;
var idx0 = outIdx,
idx1 = outIdx + m,
idx2 = outIdx + 2 * m,
idx3 = outIdx + 3 * m,
idx4 = outIdx + 4 * m;
// ya = tw[stride*m];
var yaRe = twRe[stride * m],
yaIm = twIm[stride * m];
// yb = tw[stride*2*m];
var ybRe = twRe[stride * 2 * m],
ybIm = twIm[stride * 2 * m];
var scale = 0.4472135954999579; // sqrt(1/5)
var idx0End = idx0 + m;
while (idx0 < idx0End) {
// out0 = out[idx0] / sqrt(5)
out0Re = outRe[idx0] * scale;
out0Im = outIm[idx0] * scale;
// out1 = out[idx1] / sqrt(5)
out1Re = outRe[idx1] * scale;
out1Im = outIm[idx1] * scale;
// out2 = out[idx2] / sqrt(5)
out2Re = outRe[idx2] * scale;
out2Im = outIm[idx2] * scale;
// out3 = out[idx3] / sqrt(5)
out3Re = outRe[idx3] * scale;
out3Im = outIm[idx3] * scale;
// out4 = out[idx4] / sqrt(5)
out4Re = outRe[idx4] * scale;
out4Im = outIm[idx4] * scale;
// scratch0 = out0;
scratch0Re = out0Re;
scratch0Im = out0Im;
// scratch1 = out1 * tw[tw1]
tRe = twRe[tw1]; tIm = twIm[tw1];
scratch1Re = out1Re * tRe - out1Im * tIm;
scratch1Im = out1Re * tIm + out1Im * tRe;
// scratch2 = out2 * tw[tw2]
tRe = twRe[tw2]; tIm = twIm[tw2];
scratch2Re = out2Re * tRe - out2Im * tIm;
scratch2Im = out2Re * tIm + out2Im * tRe;
// scratch3 = out3 * tw[tw3]
tRe = twRe[tw3]; tIm = twIm[tw3];
scratch3Re = out3Re * tRe - out3Im * tIm;
scratch3Im = out3Re * tIm + out3Im * tRe;
// scratch4 = out4 * tw[tw4]
tRe = twRe[tw4]; tIm = twIm[tw4];
scratch4Re = out4Re * tRe - out4Im * tIm;
scratch4Im = out4Re * tIm + out4Im * tRe;
// scratch7 = scratch1 + scratch4
scratch7Re = scratch1Re + scratch4Re;
scratch7Im = scratch1Im + scratch4Im;
// scratch10 = scratch1 - scratch4
scratch10Re = scratch1Re - scratch4Re;
scratch10Im = scratch1Im - scratch4Im;
// scratch8 = scratch2 + scratch2
scratch8Re = scratch2Re + scratch3Re;
scratch8Im = scratch2Im + scratch3Im;
// scratch9 = scratch2 - scratch3
scratch9Re = scratch2Re - scratch3Re;
scratch9Im = scratch2Im - scratch3Im;
// out[idx0] = out0 + scratch7 + scratch8
outRe[idx0] = out0Re + scratch7Re + scratch8Re;
outIm[idx0] = out0Im + scratch7Im + scratch8Im;
scratch5Re = scratch0Re + scratch7Re * yaRe + scratch8Re * ybRe;
scratch5Im = scratch0Im + scratch7Im * yaRe + scratch8Im * ybRe;
scratch6Re = scratch10Im * yaIm + scratch9Im * ybIm;
scratch6Im = -scratch10Re * yaIm - scratch9Re * ybIm;
// out[idx1] = scratch5 - scratch6
outRe[idx1] = scratch5Re - scratch6Re;
outIm[idx1] = scratch5Im - scratch6Im;
// out[idx4] = scratch5 + scratch6
outRe[idx4] = scratch5Re + scratch6Re;
outIm[idx4] = scratch5Im + scratch6Im;
scratch11Re = scratch0Re + scratch7Re * ybRe + scratch8Re * yaRe;
scratch11Im = scratch0Im + scratch7Im * ybRe + scratch8Im * yaRe;
scratch12Re = -scratch10Im * ybIm + scratch9Im * yaIm;
scratch12Im = scratch10Re * ybIm - scratch9Re * yaIm;
// out[idx2] = scratch11 + scratch12
outRe[idx2] = scratch11Re + scratch12Re;
outIm[idx2] = scratch11Im + scratch12Im;
// out[idx3] = scratch11 - scratch12
outRe[idx3] = scratch11Re - scratch12Re;
outIm[idx3] = scratch11Im - scratch12Im;
tw1 += stride; tw2 += stride2; tw3 += stride3; tw4 += stride4;
++idx0; ++idx1; ++idx2; ++idx3; ++idx4;
}
};
var butterflyN = function (outRe, outIm, outIdx, stride, twRe, twIm, m, p, size) {
var u, q1, q, idx0;
var out0Re, out0Im, aRe, aIm, tRe, tIm;
// FIXME: Allocate statically
var scratchRe = new Float32Array(p);
var scratchIm = new Float32Array(p);
var scale = Math.sqrt(1 / p);
for (u = 0; u < m; ++u) {
idx0 = outIdx + u;
for (q1 = 0; q1 < p; ++q1) {
// scratch[q1] = out[idx0] / sqrt(p)
scratchRe[q1] = outRe[idx0] * scale;
scratchIm[q1] = outIm[idx0] * scale;
idx0 += m;
}
idx0 = outIdx + u;
var tw1Incr = stride * u;
for (q1 = 0; q1 < p; ++q1) {
// out0 = scratch[0]
out0Re = scratchRe[0];
out0Im = scratchIm[0];
var tw1 = 0;
for (q = 1; q < p; ++q) {
tw1 += tw1Incr;
if (tw1 >= size)
tw1 -= size;
// out0 += scratch[q] * tw[tw1]
aRe = scratchRe[q], aIm = scratchIm[q];
tRe = twRe[tw1], tIm = twIm[tw1];
out0Re += aRe * tRe - aIm * tIm;
out0Im += aRe * tIm + aIm * tRe;
}
// out[idx0] = out0
outRe[idx0] = out0Re;
outIm[idx0] = out0Im;
idx0 += m;
tw1Incr += stride;
}
}
};
var work = function (outRe, outIm, outIdx, fRe, fIm, fIdx, stride, inStride, factors, factorsIdx, twRe, twIm, size, inverse) {
var p = factors[factorsIdx++]; // Radix
var m = factors[factorsIdx++]; // Stage's FFT length / p
var outIdxBeg = outIdx;
var outIdxEnd = outIdx + p * m;
var fIdxIncr = stride * inStride;
if (m == 1) {
do {
outRe[outIdx] = fRe[fIdx];
outIm[outIdx] = fIm[fIdx];
fIdx += fIdxIncr;
++outIdx;
}
while (outIdx != outIdxEnd);
}
else {
do {
// DFT of size m*p performed by doing p instances of smaller DFTs of
// size m, each one takes a decimated version of the input.
work(outRe, outIm, outIdx, fRe, fIm, fIdx, stride * p, inStride, factors, factorsIdx, twRe, twIm, size, inverse);
fIdx += fIdxIncr;
outIdx += m;
}
while (outIdx != outIdxEnd);
}
outIdx = outIdxBeg;
// Recombine the p smaller DFTs
switch (p) {
case 2: butterfly2(outRe, outIm, outIdx, stride, twRe, twIm, m); break;
case 3: butterfly3(outRe, outIm, outIdx, stride, twRe, twIm, m); break;
case 4: butterfly4(outRe, outIm, outIdx, stride, twRe, twIm, m, inverse); break;
case 5: butterfly5(outRe, outIm, outIdx, stride, twRe, twIm, m); break;
default: butterflyN(outRe, outIm, outIdx, stride, twRe, twIm, m, p, size); break;
}
};
/* facBuf is populated by p1,m1,p2,m2, ...
where
p[i] * m[i] = m[i-1]
m0 = n */
var factor = function (n, facBuf) {
// Factor out powers of 4, powers of 2, then any remaining primes
var p = 4;
var floorSqrt = Math.floor(Math.sqrt(n));
var idx = 0;
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p > floorSqrt)
p = n;
}
n = Math.floor(n / p);
facBuf[idx++] = p;
facBuf[idx++] = n;
}
while (n > 1);
};
var FFT = function (size) {
if (!size)
size = 256;
Object.defineProperty(this, "size", {
configurable: false,
writable: false,
value: size
});
// Allocate arrays for twiddle factors
this._twiddlesFwdRe = new Float32Array(size);
this._twiddlesFwdIm = new Float32Array(size);
this._twiddlesInvRe = this._twiddlesFwdRe;
this._twiddlesInvIm = new Float32Array(size);
// Init twiddle factors (both forward & reverse)
for (var i = 0; i < size; ++i) {
var phase = -2 * Math.PI * i / size;
var cosPhase = Math.cos(phase), sinPhase = Math.sin(phase);
this._twiddlesFwdRe[i] = cosPhase;
this._twiddlesFwdIm[i] = sinPhase;
this._twiddlesInvIm[i] = -sinPhase;
}
// Allocate arrays for radix plan
this._factors = new Int32Array(2 * 32); // MAXFACTORS = 32
// Init radix factors (mixed radix breakdown)
// FIXME: Something seems to go wrong when using an FFT size that can be
// factorized into more than one butterflyN (e.g. try an FFT size of 11*13).
factor(size, this._factors);
};
FFT.prototype.forwardCplx = function (dstReal, dstImag, xReal, xImag) {
var twRe = this._twiddlesFwdRe;
var twIm = this._twiddlesFwdIm;
work(dstReal, dstImag, 0, xReal, xImag, 0, 1, 1, this._factors, 0, twRe, twIm, this.size, false);
};
FFT.prototype.forward = function (dstReal, dstImag, x) {
// FIXME: Optimize this case (real input signal)
this.forwardCplx(dstReal, dstImag, x, new Float32Array(this.size));
};
FFT.prototype.inverseCplx = function (dstReal, dstImag, xReal, xImag) {
var twRe = this._twiddlesInvRe;
var twIm = this._twiddlesInvIm;
work(dstReal, dstImag, 0, xReal, xImag, 0, 1, 1, this._factors, 0, twRe, twIm, this.size, true);
};
FFT.prototype.inverse = function (dst, xReal, xImag) {
// FIXME: Optimize this case (real output signal)
this.inverseCplx(dst, new Float32Array(this.size), xReal, xImag);
};
context.FFT = FFT;
})();
;
/** Random.js library.
*
* The code is licensed as LGPL.
*/
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
var Random = function(seed) {
seed = (seed === undefined) ? (new Date()).getTime() : seed;
if (typeof(seed) !== 'number' // ARG_CHECK
|| Math.ceil(seed) != Math.floor(seed)) { // ARG_CHECK
throw new TypeError("seed value must be an integer"); // ARG_CHECK
} // ARG_CHECK
/* Period parameters */
this.N = 624;
this.M = 397;
this.MATRIX_A = 0x9908b0df; /* constant vector a */
this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
this.mt = new Array(this.N); /* the array for the state vector */
this.mti=this.N+1; /* mti==N+1 means mt[N] is not initialized */
//this.init_genrand(seed);
this.init_by_array([seed], 1);
};
/* initializes mt[N] with a seed */
Random.prototype.init_genrand = function(s) {
this.mt[0] = s >>> 0;
for (this.mti=1; this.mti<this.N; this.mti++) {
var s = this.mt[this.mti-1] ^ (this.mt[this.mti-1] >>> 30);
this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)
+ this.mti;
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
this.mt[this.mti] >>>= 0;
/* for >32 bit machines */
}
};
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
Random.prototype.init_by_array = function(init_key, key_length) {
var i, j, k;
this.init_genrand(19650218);
i=1; j=0;
k = (this.N>key_length ? this.N : key_length);
for (; k; k--) {
var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30);
this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525)))
+ init_key[j] + j; /* non linear */
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=this.N-1; k; k--) {
var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30);
this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941))
- i; /* non linear */
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
i++;
if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
}
this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
};
/* generates a random number on [0,0xffffffff]-interval */
Random.prototype.genrand_int32 = function() {
var y;
var mag01 = new Array(0x0, this.MATRIX_A);
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (this.mti >= this.N) { /* generate N words at one time */
var kk;
if (this.mti == this.N+1) /* if init_genrand() has not been called, */
this.init_genrand(5489); /* a default initial seed is used */
for (kk=0;kk<this.N-this.M;kk++) {
y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
this.mt[kk] = this.mt[kk+this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
}
for (;kk<this.N-1;kk++) {
y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
this.mt[kk] = this.mt[kk+(this.M-this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
}
y = (this.mt[this.N-1]&this.UPPER_MASK)|(this.mt[0]&this.LOWER_MASK);
this.mt[this.N-1] = this.mt[this.M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
this.mti = 0;
}
y = this.mt[this.mti++];
/* Tempering */
y ^= (y >>> 11);
y ^= (y << 7) & 0x9d2c5680;
y ^= (y << 15) & 0xefc60000;
y ^= (y >>> 18);
return y >>> 0;
};
/* generates a random number on [0,0x7fffffff]-interval */
Random.prototype.genrand_int31 = function() {
return (this.genrand_int32()>>>1);
};
/* generates a random number on [0,1]-real-interval */
Random.prototype.genrand_real1 = function() {
return this.genrand_int32()*(1.0/4294967295.0);
/* divided by 2^32-1 */
};
/* generates a random number on [0,1)-real-interval */
Random.prototype.random = function() {
if (this.pythonCompatibility) {
if (this.skip) {
this.genrand_int32();
}
this.skip = true;
}
return this.genrand_int32()*(1.0/4294967296.0);
/* divided by 2^32 */
};
/* generates a random number on (0,1)-real-interval */
Random.prototype.genrand_real3 = function() {
return (this.genrand_int32() + 0.5)*(1.0/4294967296.0);
/* divided by 2^32 */
};
/* generates a random number on [0,1) with 53-bit resolution*/
Random.prototype.genrand_res53 = function() {
var a=this.genrand_int32()>>>5, b=this.genrand_int32()>>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
};
/* These real versions are due to Isaku Wada, 2002/01/09 added */
/**************************************************************************/
Random.prototype.LOG4 = Math.log(4.0);
Random.prototype.SG_MAGICCONST = 1.0 + Math.log(4.5);
Random.prototype.exponential = function (lambda) {
if (arguments.length != 1) { // ARG_CHECK
throw new SyntaxError("exponential() must " // ARG_CHECK
+ " be called with 'lambda' parameter"); // ARG_CHECK
} // ARG_CHECK
var r = this.random();
return -Math.log(r) / lambda;
};
Random.prototype.gamma = function (alpha, beta) {
if (arguments.length != 2) { // ARG_CHECK
throw new SyntaxError("gamma() must be called" // ARG_CHECK
+ " with alpha and beta parameters"); // ARG_CHECK
} // ARG_CHECK
/* Based on Python 2.6 source code of random.py.
*/
if (alpha > 1.0) {
var ainv = Math.sqrt(2.0 * alpha - 1.0);
var bbb = alpha - this.LOG4;
var ccc = alpha + ainv;
while (true) {
var u1 = this.random();
if ((u1 < 1e-7) || (u > 0.9999999)) {
continue;
}
var u2 = 1.0 - this.random();
var v = Math.log(u1 / (1.0 - u1)) / ainv;
var x = alpha * Math.exp(v);
var z = u1 * u1 * u2;
var r = bbb + ccc * v - x;
if ((r + this.SG_MAGICCONST - 4.5 * z >= 0.0) || (r >= Math.log(z))) {
return x * beta;
}
}
} else if (alpha == 1.0) {
var u = this.random();
while (u <= 1e-7) {
u = this.random();
}
return - Math.log(u) * beta;
} else {
while (true) {
var u = this.random();
var b = (Math.E + alpha) / Math.E;
var p = b * u;
if (p <= 1.0) {
var x = Math.pow(p, 1.0 / alpha);
} else {
var x = - Math.log((b - p) / alpha);
}
var u1 = this.random();
if (p > 1.0) {
if (u1 <= Math.pow(x, (alpha - 1.0))) {
break;
}
} else if (u1 <= Math.exp(-x)) {
break;
}
}
return x * beta;
}
};
Random.prototype.normal = function (mu, sigma) {
if (arguments.length != 2) { // ARG_CHECK
throw new SyntaxError("normal() must be called" // ARG_CHECK
+ " with mu and sigma parameters"); // ARG_CHECK
} // ARG_CHECK
var z = this.lastNormal;
this.lastNormal = NaN;
if (!z) {
var a = this.random() * 2 * Math.PI;
var b = Math.sqrt(-2.0 * Math.log(1.0 - this.random()));
z = Math.cos(a) * b;
this.lastNormal = Math.sin(a) * b;
}
return mu + z * sigma;
};
Random.prototype.pareto = function (alpha) {
if (arguments.length != 1) { // ARG_CHECK
throw new SyntaxError("pareto() must be called" // ARG_CHECK
+ " with alpha parameter"); // ARG_CHECK
} // ARG_CHECK
var u = this.random();
return 1.0 / Math.pow((1 - u), 1.0 / alpha);
};
Random.prototype.triangular = function (lower, upper, mode) {
// http://en.wikipedia.org/wiki/Triangular_distribution
if (arguments.length != 3) { // ARG_CHECK
throw new SyntaxError("triangular() must be called" // ARG_CHECK
+ " with lower, upper and mode parameters"); // ARG_CHECK
} // ARG_CHECK
var c = (mode - lower) / (upper - lower);
var u = this.random();
if (u <= c) {
return lower + Math.sqrt(u * (upper - lower) * (mode - lower));
} else {
return upper - Math.sqrt((1 - u) * (upper - lower) * (upper - mode));
}
};
Random.prototype.uniform = function (lower, upper) {
if (arguments.length != 2) { // ARG_CHECK
throw new SyntaxError("uniform() must be called" // ARG_CHECK
+ " with lower and upper parameters"); // ARG_CHECK
} // ARG_CHECK
return lower + this.random() * (upper - lower);
};
Random.prototype.weibull = function (alpha, beta) {
if (arguments.length != 2) { // ARG_CHECK
throw new SyntaxError("weibull() must be called" // ARG_CHECK
+ " with alpha and beta parameters"); // ARG_CHECK
} // ARG_CHECK
var u = 1.0 - this.random();
return alpha * Math.pow(-Math.log(u), 1.0 / beta);
};
if (typeof window === "undefined" && typeof module !== "undefined" && module.exports) {
module.exports = Random;
}
;/*
* Flocking - Creative audio synthesis for the Web!
* https://github.com/continuing-creativity/flocking
*
* Copyright 2011-2018, Colin Clark
* Dual licensed under the MIT and GPL Version 2 licenses.
*/
/*global require, Float32Array, window, AudioContext, webkitAudioContext*/
/*jshint white: false, newcap: true, regexp: true, browser: true,
forin: false, nomen: true, bitwise: false, maxerr: 100,
indent: 4, plusplus: false, curly: true, eqeqeq: true,
freeze: true, latedef: true, noarg: true, nonew: true, quotmark: double, undef: true,
unused: true, strict: true, asi: false, boss: false, evil: false, expr: false,
funcscope: false*/
var fluid = fluid || require("infusion"),
flock = fluid.registerNamespace("flock");
(function () {
"use strict";
var $ = fluid.registerNamespace("jQuery");
flock.fluid = fluid;
flock.init = function (options) {
// TODO: Distribute these from top level on the environment to the audioSystem
// so that users can more easily specify them in their environment's defaults.
var enviroOpts = !options ? undefined : {
components: {
audioSystem: {
options: {
model: options
}
}
}
};
var enviro = flock.enviro(enviroOpts);
return enviro;
};
flock.ALL_CHANNELS = 32; // TODO: This should go.
flock.OUT_UGEN_ID = "flocking-out";
flock.PI = Math.PI;
flock.TWOPI = 2.0 * Math.PI;
flock.HALFPI = Math.PI / 2.0;
flock.LOG01 = Math.log(0.1);
flock.LOG001 = Math.log(0.001);
flock.ROOT2 = Math.sqrt(2);
flock.rates = {
AUDIO: "audio",
CONTROL: "control",
SCHEDULED: "scheduled",
DEMAND: "demand",
CONSTANT: "constant"
};
fluid.registerNamespace("flock.debug");
flock.debug.failHard = true;
flock.browser = function () {
if (typeof navigator === "undefined") {
return {};
}
// This is a modified version of jQuery's browser detection code,
// which they removed from jQuery 2.0.
// Some of us still have to live in the messy reality of the web.
var ua = navigator.userAgent.toLowerCase(),
browser = {},
match,
matched;
match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
matched = {
browser: match[1] || "",
version: match[2] || "0"
};
if (matched.browser) {
browser[matched.browser] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if (browser.chrome) {
browser.webkit = true;
} else if (browser.webkit) {
browser.safari = true;
}
return browser;
};
// TODO: Move to components in the static environment and into the appropriate platform files.
fluid.registerNamespace("flock.platform");
flock.platform.isBrowser = typeof window !== "undefined";
flock.platform.hasRequire = typeof require !== "undefined";
flock.platform.os = flock.platform.isBrowser ? window.navigator.platform : require("os").platform();
flock.platform.isLinux = flock.platform.os.indexOf("Linux") > -1;
flock.platform.isAndroid = flock.platform.isLinux && flock.platform.os.indexOf("arm") > -1;
flock.platform.isIOS = flock.platform.os === "iPhone" || flock.platform.os === "iPad" || flock.platform.os === "iPod";
flock.platform.isMobile = flock.platform.isAndroid || flock.platform.isIOS;
flock.platform.browser = flock.browser();
flock.platform.isWebAudio = typeof AudioContext !== "undefined" || typeof webkitAudioContext !== "undefined";
flock.platform.audioEngine = flock.platform.isBrowser ? "webAudio" : "unknown";
if (flock.platform.browser && flock.platform.browser.version !== undefined) {
var dotIdx = flock.platform.browser.version.indexOf(".");
flock.platform.browser.majorVersionNumber = Number(dotIdx < 0 ?
flock.platform.browser.version :
flock.platform.browser.version.substring(0, dotIdx));
}
flock.shim = {
URL: flock.platform.isBrowser ? (window.URL || window.webkitURL || window.msURL) : undefined
};
flock.requireModule = function (moduleName, globalName) {
if (flock.platform.isBrowser) {
return window[globalName || moduleName];
}
if (!flock.platform.hasRequire) {
return undefined;
}
var resolvedName = flock.requireModule.paths[moduleName] || moduleName;
var togo = require(resolvedName);
return globalName ? togo[globalName] : togo;
};
flock.requireModule.paths = {
webarraymath: "../third-party/webarraymath/js/webarraymath.js",
Random: "../third-party/simjs/js/random-0.26.js"
};
/*************
* Utilities *