aac
Version:
An AAC decoder for Aurora.js
162 lines (136 loc) • 5.23 kB
JavaScript
/*
* 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;