UNPKG

aac

Version:
195 lines (163 loc) 5.33 kB
/* * AAC.js - Advanced Audio Coding decoder in JavaScript * Created by Devon Govett * Copyright (c) 2012, Official.fm Labs * * AAC.js is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * AAC.js is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see <http://www.gnu.org/licenses/>. */ function FFT(length) { this.length = length; switch (length) { case 64: this.roots = generateFFTTableShort(64); break; case 512: this.roots = generateFFTTableLong(512); break; case 60: this.roots = generateFFTTableShort(60); break; case 480: this.roots = generateFFTTableLong(480); break; default: throw new Error("unexpected FFT length: " + length); } // processing buffers this.rev = new Array(length); for (var i = 0; i < length; i++) { this.rev[i] = new Float32Array(2); } this.a = new Float32Array(2); this.b = new Float32Array(2); this.c = new Float32Array(2); this.d = new Float32Array(2); this.e1 = new Float32Array(2); this.e2 = new Float32Array(2); } function generateFFTTableShort(len) { var t = 2 * Math.PI / len, cosT = Math.cos(t), sinT = Math.sin(t), f = new Array(len); for (var i = 0; i < len; i++) { f[i] = new Float32Array(2); } f[0][0] = 1; f[0][1] = 0; var lastImag = 0; for (var i = 1; i < len; i++) { f[i][0] = f[i - 1][0] * cosT + lastImag * sinT; lastImag = lastImag * cosT - f[i - 1][0] * sinT; f[i][1] = -lastImag; } return f; } function generateFFTTableLong(len) { var t = 2 * Math.PI / len, cosT = Math.cos(t), sinT = Math.sin(t), f = new Array(len); for (var i = 0; i < len; i++) { f[i] = new Float32Array(3); } f[0][0] = 1; f[0][1] = 0; f[0][2] = 0; for (var i = 1; i < len; i++) { f[i][0] = f[i - 1][0] * cosT + f[i - 1][2] * sinT; f[i][2] = f[i - 1][2] * cosT - f[i - 1][0] * sinT; f[i][1] = -f[i][2]; } return f; } FFT.prototype.process = function(input, forward) { var length = this.length, imOffset = (forward ? 2 : 1), scale = (forward ? length : 1), rev = this.rev, roots = this.roots; // bit-reversal var ii = 0; for (var i = 0; i < length; i++) { rev[i][0] = input[ii][0]; rev[i][1] = input[ii][1]; var k = length >>> 1; while (ii >= k && k > 0) { ii -= k; k >>= 1; } ii += k; } var a = this.a, b = this.b, c = this.c, d = this.d, e1 = this.e1, e2 = this.e2; for (var i = 0; i < length; i++) { input[i][0] = rev[i][0]; input[i][1] = rev[i][1]; } // bottom base-4 round for (var i = 0; i < length; i += 4) { a[0] = input[i][0] + input[i + 1][0]; a[1] = input[i][1] + input[i + 1][1]; b[0] = input[i + 2][0] + input[i + 3][0]; b[1] = input[i + 2][1] + input[i + 3][1]; c[0] = input[i][0] - input[i + 1][0]; c[1] = input[i][1] - input[i + 1][1]; d[0] = input[i + 2][0] - input[i + 3][0]; d[1] = input[i + 2][1] - input[i + 3][1]; input[i][0] = a[0] + b[0]; input[i][1] = a[1] + b[1]; input[i + 2][0] = a[0] - b[0]; input[i + 2][1] = a[1] - b[1]; e1[0] = c[0] - d[1]; e1[1] = c[1] + d[0]; e2[0] = c[0] + d[1]; e2[1] = c[1] - d[0]; if (forward) { input[i + 1][0] = e2[0]; input[i + 1][1] = e2[1]; input[i + 3][0] = e1[0]; input[i + 3][1] = e1[1]; } else { input[i + 1][0] = e1[0]; input[i + 1][1] = e1[1]; input[i + 3][0] = e2[0]; input[i + 3][1] = e2[1]; } } // iterations from bottom to top for (var i = 4; i < length; i <<= 1) { var shift = i << 1, m = length / shift; for(var j = 0; j < length; j += shift) { for(var k = 0; k < i; k++) { var km = k * m, rootRe = roots[km][0], rootIm = roots[km][imOffset], zRe = input[i + j + k][0] * rootRe - input[i + j + k][1] * rootIm, zIm = input[i + j + k][0] * rootIm + input[i + j + k][1] * rootRe; input[i + j + k][0] = (input[j + k][0] - zRe) * scale; input[i + j + k][1] = (input[j + k][1] - zIm) * scale; input[j + k][0] = (input[j + k][0] + zRe) * scale; input[j + k][1] = (input[j + k][1] + zIm) * scale; } } } }; module.exports = FFT;