/* * 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.sbr2; import java.util.Arrays; import net.sourceforge.jaad.aac.AACException; import net.sourceforge.jaad.aac.syntax.BitStream; class ChannelData implements SBRConstants, HuffmanTables { //grid private boolean ampRes; private int frameClass; private int envCount, envCountPrev, noiseCount; private final int[] freqRes; private int freqResPrevious; private int pointer; private int la, laPrevious; //dtdf private final boolean[] dfEnv, dfNoise; //invf private final int[] invfMode, invfModePrevious; //envelopes private final float[][] envelopeSF; private final float[] envelopeSFPrevious; private final int[] te; //envelope time borders, p.214 private int tePrevious; //noise private final float[][] noiseFloorData; private final float[] noiseFDPrevious; //last of previous frame private final int[] tq; //noise floor time borders, p.215 //sinusoidal private boolean sinusoidalsPresent; private final boolean[] sinusoidals; private final boolean[] sIndexMappedPrevious; //chirp factors (calculated by HFGenerator) private final float[] bwArray; //values stored for assembling HFAdjustment private int noiseIndex, sineIndex; private int lTemp; private final float[][] gTmp, qTmp; ChannelData() { freqRes = new int[MAX_ENV_COUNT]; invfMode = new int[MAX_NQ]; invfModePrevious = new int[MAX_NQ]; dfEnv = new boolean[MAX_ENV_COUNT]; dfNoise = new boolean[MAX_NOISE_COUNT]; envelopeSF = new float[MAX_ENV_COUNT][MAX_BANDS]; envelopeSFPrevious = new float[MAX_BANDS]; te = new int[MAX_ENV_COUNT+1]; tePrevious = 0; noiseFloorData = new float[MAX_NOISE_COUNT][MAX_BANDS]; noiseFDPrevious = new float[MAX_BANDS]; tq = new int[MAX_NOISE_COUNT+1]; sinusoidals = new boolean[MAX_BANDS]; sIndexMappedPrevious = new boolean[MAX_BANDS]; Arrays.fill(sIndexMappedPrevious, false); bwArray = new float[MAX_CHIRP_FACTORS]; lTemp = 0; //TODO: check sizes! gTmp = new float[42][48]; qTmp = new float[42][48]; } void savePreviousData() { //lTemp for next frame lTemp = RATE*te[envCount]-TIME_SLOTS_RATE; //grid envCountPrev = envCount; freqResPrevious = freqRes[freqRes.length-1]; laPrevious = la; tePrevious = te[envCountPrev]; //invf System.arraycopy(invfMode, 0, invfModePrevious, 0, MAX_NQ); } /* ======================= decoding ======================*/ void decodeGrid(BitStream in, SBRHeader header, FrequencyTables tables) throws AACException { //read bitstream and fill envelope borders int absBordTrail = TIME_SLOTS; int relLead, relTrail; ampRes = header.getAmpRes(); switch(frameClass = in.readBits(2)) { case FIXFIX: envCount = 1<<in.readBits(2); relLead = envCount-1; if(envCount==1) ampRes = false; //check requirement (4.6.18.6.3): else if(envCount>4) throw new AACException("SBR: too many envelopes: "+envCount); Arrays.fill(freqRes, in.readBit()); te[0] = 0; te[envCount] = absBordTrail; absBordTrail = (absBordTrail+(envCount>>1))/envCount; for(int i = 0; i<relLead; i++) { te[i+1] = te[i]+absBordTrail; } break; case FIXVAR: absBordTrail += in.readBits(2); relTrail = in.readBits(2); envCount = relTrail+1; te[0] = 0; te[envCount] = absBordTrail; for(int i = 0; i<relTrail; i++) { te[envCount-1-i] = te[envCount-i]-2*in.readBits(2)-2; } pointer = in.readBits(CEIL_LOG2[envCount]); for(int i = 0; i<envCount; i++) { freqRes[envCount-1-i] = in.readBit(); } break; case VARFIX: te[0] = in.readBits(2); relLead = in.readBits(2); envCount = relLead+1; te[envCount] = absBordTrail; for(int i = 0; i<relLead; i++) { te[i+1] = te[i]+2*in.readBits(2)+2; } pointer = in.readBits(CEIL_LOG2[envCount]); for(int i = 0; i<envCount; i++) { freqRes[i] = in.readBit(); } break; default: //VARVAR te[0] = in.readBits(2); absBordTrail += in.readBits(2); relLead = in.readBits(2); relTrail = in.readBits(2); envCount = relLead+relTrail+1; if(envCount>5) throw new AACException("SBR: too many envelopes: "+envCount); te[envCount] = absBordTrail; for(int i = 0; i<relLead; i++) { te[i+1] = te[i]+2*in.readBits(2)+2; } for(int i = 0; i<relTrail; i++) { te[envCount-1-i] = te[envCount-i]-2*in.readBits(2)-2; } pointer = in.readBits(CEIL_LOG2[envCount]); for(int i = 0; i<envCount; i++) { freqRes[i] = in.readBit(); } break; } //fill noise floor time borders (4.6.18.3.3) noiseCount = (envCount>1) ? 2 : 1; tq[0] = te[0]; tq[noiseCount] = te[envCount]; if(envCount==1) tq[1] = te[1]; else { final int middleBorder; switch(frameClass) { case FIXFIX: middleBorder = envCount/2; break; case VARFIX: if(pointer==0) middleBorder = 1; else if(pointer==1) middleBorder = envCount-1; else middleBorder = pointer-1; break; default: if(pointer>1) middleBorder = envCount+1-pointer; else middleBorder = envCount-1; break; } tq[1] = te[middleBorder]; } //calculate La (table 4.157) if((frameClass==FIXVAR||frameClass==VARVAR)&&pointer>0) la = envCount+1-pointer; else if(frameClass==VARFIX&&pointer>1) la = pointer-1; else la = -1; } void decodeDTDF(BitStream in) throws AACException { for(int i = 0; i<envCount; i++) { dfEnv[i] = in.readBool(); } for(int i = 0; i<noiseCount; i++) { dfNoise[i] = in.readBool(); } } void decodeInvf(BitStream in, SBRHeader header, FrequencyTables tables) throws AACException { for(int i = 0; i<tables.getNq(); i++) { invfMode[i] = in.readBits(2); } } void decodeEnvelope(BitStream in, SBRHeader header, FrequencyTables tables, boolean secCh, boolean coupling) throws AACException { //select huffman codebooks final int[][] tHuff, fHuff; final int tLav, fLav; if(coupling&&secCh) { if(ampRes) { tHuff = T_HUFFMAN_ENV_BAL_3_0; tLav = T_HUFFMAN_ENV_BAL_3_0_LAV; fHuff = F_HUFFMAN_ENV_BAL_3_0; fLav = F_HUFFMAN_ENV_BAL_3_0_LAV; } else { tHuff = T_HUFFMAN_ENV_BAL_1_5; tLav = T_HUFFMAN_ENV_BAL_1_5_LAV; fHuff = F_HUFFMAN_ENV_BAL_1_5; fLav = F_HUFFMAN_ENV_BAL_1_5_LAV; } } else { if(ampRes) { tHuff = T_HUFFMAN_ENV_3_0; tLav = T_HUFFMAN_ENV_3_0_LAV; fHuff = F_HUFFMAN_ENV_3_0; fLav = F_HUFFMAN_ENV_3_0_LAV; } else { tHuff = T_HUFFMAN_ENV_1_5; tLav = T_HUFFMAN_ENV_1_5_LAV; fHuff = F_HUFFMAN_ENV_1_5; fLav = F_HUFFMAN_ENV_1_5_LAV; } } //read delta coded huffman data final int[] envBands = tables.getN(); final int bits = 7-((secCh&&coupling) ? 1 : 0)-(ampRes ? 1 : 0); final int delta = ((secCh&&coupling) ? 1 : 0)+1; final int odd = envBands[1]&1; int j, k, frPrev; float[] prev; for(int i = 0; i<envCount; i++) { prev = (i==0) ? envelopeSFPrevious : envelopeSF[i-1]; frPrev = (i==0) ? freqResPrevious : freqRes[i-1]; if(dfEnv[i]) { if(freqRes[i]==frPrev) { for(j = 0; j<envBands[freqRes[i]]; j++) { envelopeSF[i][j] = prev[j]+delta*(decodeHuffman(in, tHuff)-tLav); } } else if(freqRes[i]==1) { for(j = 0; j<envBands[freqRes[i]]; j++) { k = (j+odd)>>1; //fLow[k] <= fHigh[j] < fLow[k + 1] envelopeSF[i][j] = prev[k]+delta*(decodeHuffman(in, tHuff)-tLav); } } else { for(j = 0; j<envBands[freqRes[i]]; j++) { k = (j!=0) ? (2*j-odd) : 0; //fHigh[k] == fLow[j] envelopeSF[i][j] = prev[k]+delta*(decodeHuffman(in, tHuff)-tLav); } } } else { envelopeSF[i][0] = delta*in.readBits(bits); for(j = 1; j<envBands[freqRes[i]]; j++) { envelopeSF[i][j] = envelopeSF[i][j-1]+delta*(decodeHuffman(in, fHuff)-fLav); } } } //save for next frame System.arraycopy(envelopeSF[envCount-1], 0, envelopeSFPrevious, 0, MAX_BANDS); } void decodeNoise(BitStream in, SBRHeader header, FrequencyTables tables, boolean secCh, boolean coupling) throws AACException { //select huffman codebooks final int[][] tHuff, fHuff; final int tLav, fLav; if(coupling&&secCh) { tHuff = T_HUFFMAN_NOISE_BAL_3_0; tLav = T_HUFFMAN_NOISE_BAL_3_0_LAV; fHuff = F_HUFFMAN_NOISE_BAL_3_0; fLav = F_HUFFMAN_NOISE_BAL_3_0_LAV; } else { tHuff = T_HUFFMAN_NOISE_3_0; tLav = T_HUFFMAN_NOISE_3_0_LAV; fHuff = F_HUFFMAN_NOISE_3_0; fLav = F_HUFFMAN_NOISE_3_0_LAV; } //read huffman data: i=noise, j=band final int noiseBands = tables.getNq(); final int delta = ((secCh&&coupling) ? 1 : 0)+1; int j; float[] prev; for(int i = 0; i<noiseCount; i++) { if(dfNoise[i]) { prev = (i==0) ? noiseFDPrevious : noiseFloorData[i-1]; for(j = 0; j<noiseBands; j++) { noiseFloorData[i][j] = prev[j]+delta*(decodeHuffman(in, tHuff)-tLav); } } else { noiseFloorData[i][0] = delta*in.readBits(5); for(j = 1; j<noiseBands; j++) { noiseFloorData[i][j] = noiseFloorData[i][j-1]+delta*(decodeHuffman(in, fHuff)-fLav); } } } //save for next frame System.arraycopy(noiseFloorData[noiseCount-1], 0, noiseFDPrevious, 0, MAX_BANDS); } void decodeSinusoidal(BitStream in, SBRHeader header, FrequencyTables tables) throws AACException { if(sinusoidalsPresent = in.readBool()) { for(int i = 0; i<tables.getN(HIGH); i++) { sinusoidals[i] = in.readBool(); } } else Arrays.fill(sinusoidals, false); } private int decodeHuffman(BitStream in, int[][] table) throws AACException { int off = 0; int len = table[off][0]; int cw = in.readBits(len); int j; while(cw!=table[off][1]) { off++; j = table[off][0]-len; len = table[off][0]; cw <<= j; cw |= in.readBits(j); } return table[off][2]; } /* ======================= gets ======================*/ public boolean getAmpRes() { return ampRes; } public float[][] getEnvelopeScalefactors() { return envelopeSF; } //TODO:combine both public int getEnvCount() { return envCount; } public int getEnvCountPrevious() { return envCountPrev; } public int[] getTe() { return te; } public int getTePrevious() { return tePrevious; } public float[][] getNoiseFloorData() { return noiseFloorData; } public int getNoiseCount() { return noiseCount; } public int[] getTq() { return tq; } public int[] getFrequencyResolutions() { return freqRes; } int getFrameClass() { return frameClass; } public int getLa(boolean previous) { //laPrevious defined in 4.6.18.7.5 return previous ? ((laPrevious==envCountPrev) ? 0 : -1) : la; } int getPointer() { return pointer; } public boolean areSinusoidalsPresent() { return sinusoidalsPresent; } public boolean[] getSinusoidals() { return sinusoidals; } public boolean[] getSIndexMappedPrevious() { return sIndexMappedPrevious; } void setSIndexMappedPrevious(boolean[] sIndexMapped) { //used by HFAdjuster to save last sIndexMapped for next frame //fill with false, because next frame may be larger than this one Arrays.fill(sIndexMappedPrevious, false); System.arraycopy(sIndexMapped, 0, sIndexMappedPrevious, 0, sIndexMapped.length); } int[] getInvfMode(boolean previous) { return previous ? invfModePrevious : invfMode; } float[] getChirpFactors() { return bwArray; } int getNoiseIndex() { return noiseIndex; } void setNoiseIndex(int noiseIndex) { this.noiseIndex = noiseIndex; } int getSineIndex() { return sineIndex; } void setSineIndex(int sineIndex) { this.sineIndex = sineIndex; } public int getLTemp() { return lTemp; } public float[][] getGTmp() { return gTmp; } public float[][] getQTmp() { return qTmp; } /* ======================= copying ======================*/ void copyGrid(ChannelData cd) { frameClass = cd.getFrameClass(); envCount = cd.getEnvCount(); noiseCount = cd.getNoiseCount(); System.arraycopy(cd.getFrequencyResolutions(), 0, freqRes, 0, envCount); System.arraycopy(cd.getTe(), 0, te, 0, te.length); System.arraycopy(cd.getTq(), 0, tq, 0, tq.length); pointer = cd.getPointer(); } void copyInvf(ChannelData cd) { System.arraycopy(cd.getInvfMode(false), 0, invfMode, 0, MAX_NQ); } }