/*
* Copyright (C) 2011 in-somnia
*
* This file is part of JAAD.
*
* JAAD 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.
*
* JAAD 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/>.
*/
package net.sourceforge.jaad.aac.syntax;
import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.DecoderConfig;
import net.sourceforge.jaad.aac.huffman.HCB;
import net.sourceforge.jaad.aac.huffman.Huffman;
class CCE extends Element implements Constants {
public static final int BEFORE_TNS = 0;
public static final int AFTER_TNS = 1;
public static final int AFTER_IMDCT = 2;
private static final float[] CCE_SCALE = {
1.09050773266525765921f,
1.18920711500272106672f,
1.4142135623730950488016887f,
2f};
private final ICStream ics;
private float[] iqData;
private int couplingPoint;
private int coupledCount;
private final boolean[] channelPair;
private final int[] idSelect;
private final int[] chSelect;
/*[0] shared list of gains; [1] list of gains for right channel;
*[2] list of gains for left channel; [3] lists of gains for both channels
*/
private final float[][] gain;
CCE(int frameLength) {
super();
ics = new ICStream(frameLength);
channelPair = new boolean[8];
idSelect = new int[8];
chSelect = new int[8];
gain = new float[16][120];
}
int getCouplingPoint() {
return couplingPoint;
}
int getCoupledCount() {
return coupledCount;
}
boolean isChannelPair(int index) {
return channelPair[index];
}
int getIDSelect(int index) {
return idSelect[index];
}
int getCHSelect(int index) {
return chSelect[index];
}
void decode(BitStream in, DecoderConfig conf) throws AACException {
couplingPoint = 2*in.readBit();
coupledCount = in.readBits(3);
int gainCount = 0;
int i;
for(i = 0; i<=coupledCount; i++) {
gainCount++;
channelPair[i] = in.readBool();
idSelect[i] = in.readBits(4);
if(channelPair[i]) {
chSelect[i] = in.readBits(2);
if(chSelect[i]==3) gainCount++;
}
else chSelect[i] = 2;
}
couplingPoint += in.readBit();
couplingPoint |= (couplingPoint>>1);
final boolean sign = in.readBool();
final double scale = CCE_SCALE[in.readBits(2)];
ics.decode(in, false, conf);
final ICSInfo info = ics.getInfo();
final int windowGroupCount = info.getWindowGroupCount();
final int maxSFB = info.getMaxSFB();
//TODO:
final int[][] sfbCB = null;//ics.getSectionData().getSfbCB();
for(i = 0; i<gainCount; i++) {
int idx = 0;
int cge = 1;
int xg = 0;
float gainCache = 1.0f;
if(i>0) {
cge = couplingPoint==2 ? 1 : in.readBit();
xg = cge==0 ? 0 : Huffman.decodeScaleFactor(in)-60;
gainCache = (float) Math.pow(scale, -xg);
}
if(couplingPoint==2) gain[i][0] = gainCache;
else {
int sfb;
for(int g = 0; g<windowGroupCount; g++) {
for(sfb = 0; sfb<maxSFB; sfb++, idx++) {
if(sfbCB[g][sfb]!=HCB.ZERO_HCB) {
if(cge==0) {
int t = Huffman.decodeScaleFactor(in)-60;
if(t!=0) {
int s = 1;
t = xg += t;
if(!sign) {
s -= 2*(t&0x1);
t >>= 1;
}
gainCache = (float) (Math.pow(scale, -t)*s);
}
}
gain[i][idx] = gainCache;
}
}
}
}
}
}
void process() throws AACException {
iqData = ics.getInvQuantData();
}
void applyIndependentCoupling(int index, float[] data) {
final double g = gain[index][0];
for(int i = 0; i<data.length; i++) {
data[i] += g*iqData[i];
}
}
void applyDependentCoupling(int index, float[] data) {
final ICSInfo info = ics.getInfo();
final int[] swbOffsets = info.getSWBOffsets();
final int windowGroupCount = info.getWindowGroupCount();
final int maxSFB = info.getMaxSFB();
//TODO:
final int[][] sfbCB = null; //ics.getSectionData().getSfbCB();
int srcOff = 0;
int dstOff = 0;
int len, sfb, group, k, idx = 0;
float x;
for(int g = 0; g<windowGroupCount; g++) {
len = info.getWindowGroupLength(g);
for(sfb = 0; sfb<maxSFB; sfb++, idx++) {
if(sfbCB[g][sfb]!=HCB.ZERO_HCB) {
x = gain[index][idx];
for(group = 0; group<len; group++) {
for(k = swbOffsets[sfb]; k<swbOffsets[sfb+1]; k++) {
data[dstOff+group*128+k] += x*iqData[srcOff+group*128+k];
}
}
}
}
dstOff += len*128;
srcOff += len*128;
}
}
}