/* * 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.sbr; import net.sourceforge.jaad.aac.AACException; import net.sourceforge.jaad.aac.syntax.BitStream; import net.sourceforge.jaad.aac.syntax.Constants; class ChannelData implements SBRConstants, HuffmanTables { private static final int[] LOG2TABLE = {0, 0, 1, 2, 2, 3, 3, 3, 3, 4}; //read int frameClass; int pointer; private boolean addHarmonicFlag, addHarmonicFlagPrev; boolean[] addHarmonic, addHarmonicPrev; private int[] relBord, relBord0, relBord1; private int rel0, rel1; private boolean[] dfEnv; private boolean[] dfNoise; int[] invfMode, invfModePrev; //calculated boolean ampRes; int[] t_E, tEtmp, t_Q; //envelope/noise time border vectors int L_E, L_E_prev, L_Q; //length of t_E/t_Q boolean[] f; private boolean fPrev; float[][] gTempPrev; float[][] qTempPrev; int gqIndex; int[][] E; private int[] E_prev; float[][] E_orig; float[][] E_curr; int[][] Q; int[] Q_prev; float[][] Q_div, Q_div2; // private int absBordLead, absBordTrail; int prevEnvIsShort; int l_A; float[][][] Xsbr; float[] bwArray, bwArrayPrev; int indexNoisePrev, psiIsPrev; ChannelData() { addHarmonic = new boolean[64]; addHarmonicPrev = new boolean[64]; relBord = new int[9]; relBord0 = new int[9]; relBord1 = new int[9]; dfEnv = new boolean[9]; dfNoise = new boolean[3]; invfMode = new int[MAX_L_E]; invfModePrev = new int[MAX_L_E]; t_E = new int[MAX_L_E+1]; tEtmp = new int[6]; t_Q = new int[3]; f = new boolean[MAX_L_E+1]; gTempPrev = new float[5][64]; qTempPrev = new float[5][64]; E = new int[64][MAX_L_E]; E_prev = new int[64]; E_orig = new float[64][MAX_L_E]; E_curr = new float[64][MAX_L_E]; Q = new int[64][2]; Q_prev = new int[64]; Q_div = new float[64][2]; Q_div2 = new float[64][2]; bwArray = new float[64]; bwArrayPrev = new float[64]; Xsbr = new float[MAX_NTSRHFG][64][2]; gqIndex = 0; } /* ================= decoding ================= */ void decodeGrid(BitStream in) throws AACException { final int savedL_E = L_E; final int savedL_Q = L_Q; final int savedFrameClass = frameClass; int envCount = 0; int i, x, absBord0, absBord1; switch(frameClass = in.readBits(2)) { case FIXFIX: x = in.readBits(2); envCount = Math.min(1<<x, 5); final boolean b = in.readBool(); for(i = 0; i<envCount; i++) { f[i] = b; } absBordLead = 0; absBordTrail = TIME_SLOTS; //n_rel_lead = bs_num_env-1; //n_rel_trail = 0; break; case FIXVAR: absBord0 = in.readBits(2)+TIME_SLOTS; envCount = in.readBits(2)+1; for(i = 0; i<envCount-1; i++) { relBord[i] = 2*in.readBits(2)+2; } pointer = in.readBits(LOG2TABLE[envCount+1]); for(i = 0; i<envCount; i++) { f[envCount-i-1] = in.readBool(); } absBordLead = 0; absBordTrail = absBord0; //n_rel_lead = 0; //n_rel_trail = bs_num_env-1; break; case VARFIX: absBord0 = in.readBits(2); envCount = in.readBits(2)+1; for(i = 0; i<envCount-1; i++) { relBord[i] = 2*in.readBits(2)+2; } x = LOG2TABLE[envCount+1]; pointer = in.readBits(x); for(i = 0; i<envCount; i++) { f[i] = in.readBool(); } absBordLead = absBord0; absBordTrail = TIME_SLOTS; //n_rel_lead = bs_num_env-1; //n_rel_trail = 0; break; case VARVAR: absBord0 = in.readBits(2); absBord1 = in.readBits(2)+TIME_SLOTS; rel0 = in.readBits(2); rel1 = in.readBits(2); envCount = Math.min(5, rel0+rel1+1); for(i = 0; i<rel0; i++) { relBord0[i] = 2*in.readBits(2)+2; } for(i = 0; i<rel1; i++) { relBord1[i] = 2*in.readBits(2)+2; } x = LOG2TABLE[rel0+rel1+2]; pointer = in.readBits(x); for(i = 0; i<envCount; i++) { f[i] = in.readBool(); } absBordLead = absBord0; absBordTrail = absBord1; //n_rel_lead = bs_num_rel_0; //n_rel_trail = bs_num_rel_1; break; } if(frameClass==VARVAR) L_E = Math.min(envCount, 5); else L_E = Math.min(envCount, 4); if(L_E<=0) throw new AACException("L_E out of range: "+L_E); if(L_E>1) L_Q = 2; else L_Q = 1; if(!envelopeTimeBorderVector()) { Constants.LOGGER.warning("envelopeTimeBorderVector failed"); frameClass = savedFrameClass; L_E = savedL_E; L_Q = savedL_Q; } noiseFloorTimeBorderVector(); } void copyGrid(ChannelData cd) { frameClass = cd.frameClass; L_E = cd.L_E; L_Q = cd.L_Q; pointer = cd.pointer; System.arraycopy(cd.t_E, 0, t_E, 0, L_E+1); System.arraycopy(cd.f, 0, f, 0, L_E+1); System.arraycopy(cd.t_Q, 0, t_Q, 0, L_Q+1); } void decodeDTDF(BitStream in) throws AACException { int i; for(i = 0; i<L_E; i++) { dfEnv[i] = in.readBool(); } for(i = 0; i<L_Q; i++) { dfNoise[i] = in.readBool(); } } void decodeInvfMode(BitStream in, int len) throws AACException { for(int i = 0; i<len; i++) { invfMode[i] = in.readBits(2); } } void copyInvfMode(ChannelData cd, int len) { System.arraycopy(cd.invfMode, 0, invfMode, 0, len); } void decodeSinusoidalCoding(BitStream in, int len) throws AACException { if(addHarmonicFlag = in.readBool()) { for(int i = 0; i<len; i++) { addHarmonic[i] = in.readBool(); } } } /* ================= huffman ================= */ void decodeEnvelope(BitStream in, SBR sbr, int ch, boolean coupling, boolean ampRes) throws AACException { ampRes = ((L_E==1)&&(frameClass==FIXFIX)) ? false : ampRes; final int bits = 7-((coupling&&(ch==1)) ? 1 : 0)-(ampRes ? 1 : 0); int delta; int[][] huffT, huffF; if(coupling&&(ch==1)) { delta = 1; if(ampRes) { huffT = T_HUFFMAN_ENV_BAL_3_0DB; huffF = F_HUFFMAN_ENV_BAL_3_0DB; } else { huffT = T_HUFFMAN_ENV_BAL_1_5DB; huffF = F_HUFFMAN_ENV_BAL_1_5DB; } } else { delta = 0; if(ampRes) { huffT = T_HUFFMAN_ENV_3_0DB; huffF = F_HUFFMAN_ENV_3_0DB; } else { huffT = T_HUFFMAN_ENV_1_5DB; huffF = F_HUFFMAN_ENV_1_5DB; } } int j; for(int i = 0; i<L_E; i++) { if(dfEnv[i]) { for(j = 0; j<sbr.n[f[i] ? 1 : 0]; j++) { E[j][i] = decodeHuffman(in, huffT)<<delta; } } else { E[0][i] = in.readBits(bits)<<delta; for(j = 1; j<sbr.n[f[i] ? 1 : 0]; j++) { E[j][i] = decodeHuffman(in, huffF)<<delta; } } } extractEnvelopeData(sbr); } void decodeNoise(BitStream in, SBR sbr, int ch, boolean coupling) throws AACException { int delta; int[][] huffT, huffF; if(coupling&&(ch==1)) { delta = 1; huffT = T_HUFFMAN_NOISE_BAL_3_0DB; huffF = F_HUFFMAN_ENV_BAL_3_0DB; } else { delta = 0; huffT = T_HUFFMAN_NOISE_3_0DB; huffF = F_HUFFMAN_ENV_3_0DB; } final int len = sbr.N_Q; int j; for(int i = 0; i<L_Q; i++) { if(dfNoise[i]) { for(j = 0; j<len; j++) { Q[j][i] = decodeHuffman(in, huffT)<<delta; } } else { Q[0][i] = in.readBits(5)<<delta; for(j = 1; j<len; j++) { Q[j][i] = decodeHuffman(in, huffF)<<delta; } } } extractNoiseFloorData(sbr); } private int decodeHuffman(BitStream in, int[][] table) throws AACException { int index = 0; int bit; while(index>=0) { bit = in.readBit(); index = table[index][bit]; } return index+HUFFMAN_OFFSET; } /* ================== gets ================== */ public boolean hasHarmonicPrev() { return addHarmonicFlagPrev; } /* ================= computation ================= */ //constructs new time border vector private boolean envelopeTimeBorderVector() { for(int i = 0; i<6; i++) { tEtmp[i] = 0; } tEtmp[0] = RATE*absBordLead; tEtmp[L_E] = RATE*absBordTrail; int i, tmp, border; switch(frameClass) { case FIXFIX: switch(L_E) { case 4: tmp = (int) (TIME_SLOTS/4.0); tEtmp[3] = RATE*3*tmp; tEtmp[2] = RATE*2*tmp; tEtmp[1] = RATE*tmp; break; case 2: tEtmp[1] = RATE*(TIME_SLOTS/2); break; default: break; } break; case FIXVAR: if(L_E>1) { tmp = L_E; border = absBordTrail; for(i = 0; i<(L_E-1); i++) { if(border<relBord[i]) return false; border -= relBord[i]; tEtmp[--tmp] = RATE*border; } } break; case VARFIX: if(L_E>1) { tmp = 1; border = absBordLead; for(i = 0; i<(L_E-1); i++) { border += relBord[i]; if(RATE*border+T_HFADJ>TIME_SLOTS_RATE+T_HFGEN) return false; tEtmp[tmp++] = RATE*border; } } break; case VARVAR: if(rel0>0) { tmp = 1; border = absBordLead; for(i = 0; i<rel0; i++) { border += relBord0[i]; if(RATE*border+T_HFADJ>TIME_SLOTS_RATE+T_HFGEN) return false; tEtmp[tmp++] = RATE*border; } } if(rel1>0) { tmp = L_E; border = absBordTrail; for(i = 0; i<rel1; i++) { if(border<relBord1[i]) return false; border -= relBord1[i]; tEtmp[--tmp] = RATE*border; } } break; } //no error occured System.arraycopy(tEtmp, 0, t_E, 0, 6); return true; } private void noiseFloorTimeBorderVector() { t_Q[0] = t_E[0]; if(L_E==1) { t_Q[1] = t_E[1]; t_Q[2] = 0; } else { t_Q[1] = t_E[findMiddleBorder()]; t_Q[2] = t_E[L_E]; } } private int findMiddleBorder() { int r = 0; switch(frameClass) { case FIXFIX: r = L_E/2; break; case VARFIX: if(pointer==0) r = 1; else if(pointer==1) r = L_E-1; else r = pointer-1; break; case FIXVAR: case VARVAR: if(pointer>1) r = L_E+1-pointer; else r = L_E-1; break; } return r>0 ? r : 0; } private void extractEnvelopeData(SBR sbr) { int j, k; boolean g; for(int i = 0; i<L_E; i++) { if(dfEnv[i]) { g = (i==0) ? fPrev : f[i-1]; if(f[i]==g) { for(j = 0; j<sbr.n[f[i] ? 1 : 0]; j++) { E[j][i] += (i==0) ? E_prev[j] : E[j][i-1]; } } else if(g&&!f[i]) { for(j = 0; j<sbr.n[f[i] ? 1 : 0]; j++) { for(k = 0; k<sbr.N_high; k++) { if(sbr.ftRes[HI_RES][k]==sbr.ftRes[LO_RES][j]) { E[j][i] += (i==0) ? E_prev[k] : E[k][i-1]; } } } } else if(!g&&f[i]) { for(j = 0; j<sbr.n[f[i] ? 1 : 0]; j++) { for(k = 0; k<sbr.N_low; k++) { if((sbr.ftRes[LO_RES][k]<=sbr.ftRes[HI_RES][j]) &&(sbr.ftRes[HI_RES][j]<sbr.ftRes[LO_RES][k+1])) { E[j][i] += (i==0) ? E_prev[k] : E[k][i-1]; } } } } } else { for(j = 1; j<sbr.n[f[i] ? 1 : 0]; j++) { E[j][i] += E[j-1][i]; if(E[j][i]<0) E[j][i] = 0; } } } } private void extractNoiseFloorData(SBR sbr) { final int len = sbr.N_Q; int j; for(int i = 0; i<L_Q; i++) { if(dfNoise[i]) { if(i==0) { for(j = 0; j<len; j++) { Q[j][i] = Q_prev[j]+Q[j][0]; } } else { for(j = 0; j<len; j++) { Q[j][i] += Q[j][i-1]; } } } else { for(j = 1; j<len; j++) { Q[j][i] += Q[j-1][i]; } } } } /* ================= processing ================== */ void savePreviousData() { L_E_prev = L_E; fPrev = f[L_E-1]; for(int i = 0; i<MAX_M; i++) { E_prev[i] = E[i][L_E-1]; Q_prev[i] = Q[i][L_Q-1]; } System.arraycopy(addHarmonic, 0, addHarmonicPrev, 0, MAX_M); addHarmonicFlagPrev = addHarmonicFlag; prevEnvIsShort = (l_A==L_E) ? 0 : -1; } void saveMatrix() { int i, j; //copy complex values for(i = 0; i<T_HFGEN; i++) { for(j = 0; j<64; j++) { Xsbr[i][j][0] = Xsbr[i+TIME_SLOTS_RATE][j][0]; Xsbr[i][j][1] = Xsbr[i+TIME_SLOTS_RATE][j][1]; } } for(i = T_HFGEN; i<MAX_NTSRHFG; i++) { for(j = 0; j<64; j++) { Xsbr[i][j][0] = 0; Xsbr[i][j][1] = 0; } } } }