/* * 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.Profile; import net.sourceforge.jaad.aac.SampleFrequency; import net.sourceforge.jaad.aac.tools.ICPrediction; import net.sourceforge.jaad.aac.tools.LTPrediction; import java.util.Arrays; public class ICSInfo implements Constants, ScaleFactorBands { public static final int WINDOW_SHAPE_SINE = 0; public static final int WINDOW_SHAPE_KAISER = 1; public static final int PREVIOUS = 0; public static final int CURRENT = 1; public static enum WindowSequence { ONLY_LONG_SEQUENCE, LONG_START_SEQUENCE, EIGHT_SHORT_SEQUENCE, LONG_STOP_SEQUENCE; public static WindowSequence forInt(int i) throws AACException { WindowSequence w; switch(i) { case 0: w = ONLY_LONG_SEQUENCE; break; case 1: w = LONG_START_SEQUENCE; break; case 2: w = EIGHT_SHORT_SEQUENCE; break; case 3: w = LONG_STOP_SEQUENCE; break; default: throw new AACException("unknown window sequence type"); } return w; } } private final int frameLength; private WindowSequence windowSequence; private int[] windowShape; private int maxSFB; //prediction private boolean predictionDataPresent; private ICPrediction icPredict; boolean ltpData1Present, ltpData2Present; private LTPrediction ltPredict1, ltPredict2; //windows/sfbs private int windowCount; private int windowGroupCount; private int[] windowGroupLength; private int swbCount; private int[] swbOffsets; public ICSInfo(int frameLength) { this.frameLength = frameLength; windowShape = new int[2]; windowSequence = WindowSequence.ONLY_LONG_SEQUENCE; windowGroupLength = new int[MAX_WINDOW_GROUP_COUNT]; ltpData1Present = false; ltpData2Present = false; } /* ========== decoding ========== */ public void decode(BitStream in, DecoderConfig conf, boolean commonWindow) throws AACException { final SampleFrequency sf = conf.getSampleFrequency(); if(sf.equals(SampleFrequency.SAMPLE_FREQUENCY_NONE)) throw new AACException("invalid sample frequency"); in.skipBit(); //reserved windowSequence = WindowSequence.forInt(in.readBits(2)); windowShape[PREVIOUS] = windowShape[CURRENT]; windowShape[CURRENT] = in.readBit(); windowGroupCount = 1; windowGroupLength[0] = 1; if(windowSequence.equals(WindowSequence.EIGHT_SHORT_SEQUENCE)) { maxSFB = in.readBits(4); int i; for(i = 0; i<7; i++) { if(in.readBool()) windowGroupLength[windowGroupCount-1]++; else { windowGroupCount++; windowGroupLength[windowGroupCount-1] = 1; } } windowCount = 8; swbOffsets = SWB_OFFSET_SHORT_WINDOW[sf.getIndex()]; swbCount = SWB_SHORT_WINDOW_COUNT[sf.getIndex()]; predictionDataPresent = false; } else { maxSFB = in.readBits(6); windowCount = 1; swbOffsets = SWB_OFFSET_LONG_WINDOW[sf.getIndex()]; swbCount = SWB_LONG_WINDOW_COUNT[sf.getIndex()]; predictionDataPresent = in.readBool(); if(predictionDataPresent) readPredictionData(in, conf.getProfile(), sf, commonWindow); } } private void readPredictionData(BitStream in, Profile profile, SampleFrequency sf, boolean commonWindow) throws AACException { switch(profile) { case AAC_MAIN: if(icPredict==null) icPredict = new ICPrediction(); icPredict.decode(in, maxSFB, sf); break; case AAC_LTP: if(ltpData1Present = in.readBool()) { if(ltPredict1==null) ltPredict1 = new LTPrediction(frameLength); ltPredict1.decode(in, this, profile); } if(commonWindow) { if(ltpData2Present = in.readBool()) { if(ltPredict2==null) ltPredict2 = new LTPrediction(frameLength); ltPredict2.decode(in, this, profile); } } break; case ER_AAC_LTP: if(!commonWindow) { if(ltpData1Present = in.readBool()) { if(ltPredict1==null) ltPredict1 = new LTPrediction(frameLength); ltPredict1.decode(in, this, profile); } } break; default: throw new AACException("unexpected profile for LTP: "+profile); } } /* =========== gets ============ */ public int getMaxSFB() { return maxSFB; } public int getSWBCount() { return swbCount; } public int[] getSWBOffsets() { return swbOffsets; } public int getSWBOffsetMax() { return swbOffsets[swbCount]; } public int getWindowCount() { return windowCount; } public int getWindowGroupCount() { return windowGroupCount; } public int getWindowGroupLength(int g) { return windowGroupLength[g]; } public WindowSequence getWindowSequence() { return windowSequence; } public boolean isEightShortFrame() { return windowSequence.equals(WindowSequence.EIGHT_SHORT_SEQUENCE); } public int getWindowShape(int index) { return windowShape[index]; } public boolean isICPredictionPresent() { return predictionDataPresent; } public ICPrediction getICPrediction() { return icPredict; } public boolean isLTPrediction1Present() { return ltpData1Present; } public LTPrediction getLTPrediction1() { return ltPredict1; } public boolean isLTPrediction2Present() { return ltpData2Present; } public LTPrediction getLTPrediction2() { return ltPredict2; } public void unsetPredictionSFB(int sfb) { if(predictionDataPresent) icPredict.setPredictionUnused(sfb); if(ltpData1Present) ltPredict1.setPredictionUnused(sfb); if(ltpData2Present) ltPredict2.setPredictionUnused(sfb); } public void setData(ICSInfo info) { windowSequence = WindowSequence.valueOf(info.windowSequence.name()); windowShape[PREVIOUS] = windowShape[CURRENT]; windowShape[CURRENT] = info.windowShape[CURRENT]; maxSFB = info.maxSFB; predictionDataPresent = info.predictionDataPresent; if(predictionDataPresent) icPredict = info.icPredict; ltpData1Present = info.ltpData1Present; if(ltpData1Present) { ltPredict1.copy(info.ltPredict1); ltPredict2.copy(info.ltPredict2); } windowCount = info.windowCount; windowGroupCount = info.windowGroupCount; windowGroupLength = Arrays.copyOf(info.windowGroupLength, info.windowGroupLength.length); swbCount = info.swbCount; swbOffsets = Arrays.copyOf(info.swbOffsets, info.swbOffsets.length); } }