/* * 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.tools; import net.sourceforge.jaad.aac.AACException; import net.sourceforge.jaad.aac.SampleFrequency; import net.sourceforge.jaad.aac.syntax.BitStream; import net.sourceforge.jaad.aac.syntax.Constants; import net.sourceforge.jaad.aac.syntax.ICSInfo; import net.sourceforge.jaad.aac.syntax.ICStream; import java.util.logging.Level; /** * Intra-channel prediction used in profile Main * @author in-somnia */ public class ICPrediction { private static final float SF_SCALE = 1.0f/-1024.0f; private static final float INV_SF_SCALE = 1.0f/SF_SCALE; private static final int MAX_PREDICTORS = 672; private static final float A = 0.953125f; //61.0 / 64 private static final float ALPHA = 0.90625f; //29.0 / 32 private boolean predictorReset; private int predictorResetGroup; private boolean[] predictionUsed; private PredictorState[] states; private static final class PredictorState { float cor0 = 0.0f; float cor1 = 0.0f; float var0 = 0.0f; float var1 = 0.0f; float r0 = 1.0f; float r1 = 1.0f; } public ICPrediction() { states = new PredictorState[MAX_PREDICTORS]; resetAllPredictors(); } public void decode(BitStream in, int maxSFB, SampleFrequency sf) throws AACException { final int predictorCount = sf.getPredictorCount(); if(predictorReset = in.readBool()) predictorResetGroup = in.readBits(5); final int maxPredSFB = sf.getMaximalPredictionSFB(); final int length = Math.min(maxSFB, maxPredSFB); predictionUsed = new boolean[length]; for(int sfb = 0; sfb<length; sfb++) { predictionUsed[sfb] = in.readBool(); } Constants.LOGGER.log(Level.WARNING, "ICPrediction: maxSFB={0}, maxPredSFB={1}", new int[]{maxSFB, maxPredSFB}); /*//if maxSFB<maxPredSFB set remaining to false for(int sfb = length; sfb<maxPredSFB; sfb++) { predictionUsed[sfb] = false; }*/ } public void setPredictionUnused(int sfb) { predictionUsed[sfb] = false; } public void process(ICStream ics, float[] data, SampleFrequency sf) { final ICSInfo info = ics.getInfo(); if(info.isEightShortFrame()) resetAllPredictors(); else { final int len = Math.min(sf.getMaximalPredictionSFB(), info.getMaxSFB()); final int[] swbOffsets = info.getSWBOffsets(); int k; for(int sfb = 0; sfb<len; sfb++) { for(k = swbOffsets[sfb]; k<swbOffsets[sfb+1]; k++) { predict(data, k, predictionUsed[sfb]); } } if(predictorReset) resetPredictorGroup(predictorResetGroup); } } private void resetPredictState(int index) { if(states[index]==null) states[index] = new PredictorState(); states[index].r0 = 0; states[index].r1 = 0; states[index].cor0 = 0; states[index].cor1 = 0; states[index].var0 = 0x3F80; states[index].var1 = 0x3F80; } private void resetAllPredictors() { int i; for(i = 0; i<states.length; i++) { resetPredictState(i); } } private void resetPredictorGroup(int group) { int i; for(i = group-1; i<states.length; i += 30) { resetPredictState(i); } } private void predict(float[] data, int off, boolean output) { if(states[off]==null) states[off] = new PredictorState(); final PredictorState state = states[off]; final float r0 = state.r0, r1 = state.r1; final float cor0 = state.cor0, cor1 = state.cor1; final float var0 = state.var0, var1 = state.var1; final float k1 = var0>1 ? cor0*even(A/var0) : 0; final float k2 = var1>1 ? cor1*even(A/var1) : 0; final float pv = round(k1*r0+k2*r1); if(output) data[off] += pv*SF_SCALE; final float e0 = (data[off]*INV_SF_SCALE); final float e1 = e0-k1*r0; state.cor1 = trunc(ALPHA*cor1+r1*e1); state.var1 = trunc(ALPHA*var1+0.5f*(r1*r1+e1*e1)); state.cor0 = trunc(ALPHA*cor0+r0*e0); state.var0 = trunc(ALPHA*var0+0.5f*(r0*r0+e0*e0)); state.r1 = trunc(A*(r0-k1*e0)); state.r0 = trunc(A*e0); } private float round(float pf) { return Float.intBitsToFloat((Float.floatToIntBits(pf)+0x00008000)&0xFFFF0000); } private float even(float pf) { int i = Float.floatToIntBits(pf); i = (i+0x00007FFF+(i&0x00010000>>16))&0xFFFF0000; return Float.intBitsToFloat(i); } private float trunc(float pf) { return Float.intBitsToFloat(Float.floatToIntBits(pf)&0xFFFF0000); } }