UNPKG

flocking

Version:

Creative audio synthesis for the Web

1,551 lines (1,326 loc) 265 kB
/*! 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 *