UNPKG

aac

Version:
162 lines (136 loc) 5.23 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/>. */ var ICStream = require('./ics'); var Huffman = require('./huffman'); // Channel Coupling Element function CCEElement(config) { this.ics = new ICStream(config); this.channelPair = new Array(8); this.idSelect = new Int32Array(8); this.chSelect = new Int32Array(8); this.gain = new Array(16); } CCEElement.BEFORE_TNS = 0; CCEElement.AFTER_TNS = 1; CCEElement.AFTER_IMDCT = 2; const CCE_SCALE = new Float32Array([ 1.09050773266525765921, 1.18920711500272106672, 1.4142135623730950488016887, 2.0 ]); CCEElement.prototype = { decode: function(stream, config) { var channelPair = this.channelPair, idSelect = this.idSelect, chSelect = this.chSelect; this.couplingPoint = 2 * stream.read(1); this.coupledCount = stream.read(3); var gainCount = 0; for (var i = 0; i <= this.coupledCount; i++) { gainCount++; channelPair[i] = stream.read(1); idSelect[i] = stream.read(4); if (channelPair[i]) { chSelect[i] = stream.read(2); if (chSelect[i] === 3) gainCount++; } else { chSelect[i] = 2; } } this.couplingPoint += stream.read(1); this.couplingPoint |= (this.couplingPoint >>> 1); var sign = stream.read(1), scale = CCE_SCALE[stream.read(2)]; this.ics.decode(stream, config, false); var groupCount = this.ics.info.groupCount, maxSFB = this.ics.info.maxSFB, bandTypes = this.ics.bandTypes; for (var i = 0; i < gainCount; i++) { var idx = 0, cge = 1, gain = 0, gainCache = 1; if (i > 0) { cge = this.couplingPoint === CCEElement.AFTER_IMDCT ? 1 : stream.read(1); gain = cge ? Huffman.decodeScaleFactor(stream) - 60 : 0; gainCache = Math.pow(scale, -gain); } var gain_i = this.gain[i] = new Float32Array(120); if (this.couplingPoint === CCEElement.AFTER_IMDCT) { gain_i[0] = gainCache; } else { for (var g = 0; g < groupCount; g++) { for (var sfb = 0; sfb < maxSFB; sfb++) { if (bandTypes[idx] !== ICStream.ZERO_BT) { if (cge === 0) { var t = Huffman.decodeScaleFactor(stream) - 60; if (t !== 0) { var s = 1; t = gain += t; if (!sign) { s -= 2 * (t & 0x1); t >>>= 1; } gainCache = Math.pow(scale, -t) * s; } } gain_i[idx++] = gainCache; } } } } } }, applyIndependentCoupling: function(index, data) { var gain = this.gain[index][0], iqData = this.ics.data; for (var i = 0; i < data.length; i++) { data[i] += gain * iqData[i]; } }, applyDependentCoupling: function(index, data) { var info = this.ics.info, swbOffsets = info.swbOffsets, groupCount = info.groupCount, maxSFB = info.maxSFB, bandTypes = this.ics.bandTypes, iqData = this.ics.data; var idx = 0, offset = 0, gains = this.gain[index]; for (var g = 0; g < groupCount; g++) { var len = info.groupLength[g]; for (var sfb = 0; sfb < maxSFB; sfb++, idx++) { if (bandTypes[idx] !== ICStream.ZERO_BT) { var gain = gains[idx]; for (var group = 0; group < len; group++) { for (var k = swbOffsets[sfb]; k < swbOffsets[swb + 1]; k++) { data[offset + group * 128 + k] += gain * iqData[offset + group * 128 + k]; } } } } offset += len * 128; } } }; module.exports = CCEElement;