/* * 21.04.2004 Original verion. davagin@udm.ru. *----------------------------------------------------------------------- * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------- */ package davaguine.jmac.prediction; import davaguine.jmac.tools.JMACException; import davaguine.jmac.tools.RollBufferShort; import java.util.Arrays; /** * Author: Dmitry Vaguine * Date: 04.03.2004 * Time: 14:51:31 */ public abstract class NNFilter { public final static int NN_WINDOW_ELEMENTS = 512; public NNFilter(int nOrder, int nShift, int nVersion) { if ((nOrder <= 0) || ((nOrder % 16) != 0)) throw new JMACException("Wrong Order"); m_nOrder = nOrder; m_nShift = nShift; m_nVersion = nVersion; m_rbInput.Create(512 /* NN_WINDOW_ELEMENTS */, nOrder); m_rbDeltaM.Create(512 /*NN_WINDOW_ELEMENTS */, nOrder); m_paryM = new short[nOrder]; } public int Compress(int nInput) { RollBufferShort input = m_rbInput; RollBufferShort delta = m_rbDeltaM; int order = m_nOrder; int shift = m_nShift; short[] pary = m_paryM; short[] inputData = input.m_pData; int inputIndex = input.index; short[] deltaData = delta.m_pData; int deltaIndex = delta.index; // convert the input to a short and store it inputData[inputIndex] = (short) ((nInput >= Short.MIN_VALUE && nInput <= Short.MAX_VALUE) ? nInput : (nInput >> 31) ^ 0x7FFF); // figure a dot product int nDotProduct = CalculateDotProductNoMMX(inputData, inputIndex - order, pary, 0); // calculate the output int nOutput = nInput - ((nDotProduct + (1 << (m_nShift - 1))) >> m_nShift); // adapt AdaptNoMMX(pary, 0, deltaData, deltaIndex - order, nOutput); int nTempABS = Math.abs(nInput); if (nTempABS > (m_nRunningAverage * 3)) deltaData[deltaIndex] = (short) (((nInput >> 25) & 64) - 32); else if (nTempABS > (m_nRunningAverage * 4) / 3) deltaData[deltaIndex] = (short) (((nInput >> 26) & 32) - 16); else if (nTempABS > 0) deltaData[deltaIndex] = (short) (((nInput >> 27) & 16) - 8); else deltaData[deltaIndex] = (short) 0; m_nRunningAverage += (nTempABS - m_nRunningAverage) / 16; deltaData[deltaIndex - 1] >>= 1; deltaData[deltaIndex - 2] >>= 1; deltaData[deltaIndex - 8] >>= 1; // increment and roll if necessary // input.IncrementSafe(); if ((++input.index) == orderPlusWindow) { System.arraycopy(inputData, input.index - order, inputData, 0, order); input.index = order; } // delta.IncrementSafe(); if ((++delta.index) == orderPlusWindow) { System.arraycopy(deltaData, delta.index - order, deltaData, 0, order); delta.index = order; } return nOutput; } public int Decompress(int nInput) { // figure a dot product RollBufferShort input = m_rbInput; RollBufferShort delta = m_rbDeltaM; int order = m_nOrder; int shift = m_nShift; short[] pary = m_paryM; short[] inputData = input.m_pData; int inputIndex = input.index; short[] deltaData = delta.m_pData; int deltaIndex = delta.index; int nDotProduct = CalculateDotProductNoMMX(inputData, inputIndex - order, pary, 0); // adapt AdaptNoMMX(pary, 0, deltaData, deltaIndex - order, nInput); // store the output value int nOutput = nInput + ((nDotProduct + (1 << (shift - 1))) >> shift); // update the input buffer inputData[inputIndex] = (short) ((nOutput >= Short.MIN_VALUE && nOutput <= Short.MAX_VALUE) ? nOutput : (nOutput >> 31) ^ 0x7FFF); if (m_nVersion >= 3980) { int nTempABS = Math.abs(nOutput); if (nTempABS > (m_nRunningAverage * 3)) deltaData[deltaIndex] = (short) (((nOutput >> 25) & 64) - 32); else if (nTempABS > (m_nRunningAverage * 4) / 3) deltaData[deltaIndex] = (short) (((nOutput >> 26) & 32) - 16); else if (nTempABS > 0) deltaData[deltaIndex] = (short) (((nOutput >> 27) & 16) - 8); else deltaData[deltaIndex] = 0; m_nRunningAverage += (nTempABS - m_nRunningAverage) / 16; deltaData[deltaIndex - 1] >>= 1; deltaData[deltaIndex - 2] >>= 1; deltaData[deltaIndex - 8] >>= 1; } else { deltaData[deltaIndex] = (short) ((nOutput == 0) ? 0 : ((nOutput >> 28) & 8) - 4); deltaData[deltaIndex - 4] >>= 1; deltaData[deltaIndex - 8] >>= 1; } // increment and roll if necessary // input.IncrementSafe(); if ((++input.index) == orderPlusWindow) { System.arraycopy(inputData, input.index - order, inputData, 0, order); input.index = order; } // delta.IncrementSafe(); if ((++delta.index) == orderPlusWindow) { System.arraycopy(deltaData, delta.index - order, deltaData, 0, order); delta.index = order; } return nOutput; } public void Flush() { Arrays.fill(m_paryM, (short) 0); m_rbInput.Flush(); m_rbDeltaM.Flush(); m_nRunningAverage = 0; } protected int m_nOrder; protected int m_nShift; protected int m_nVersion; protected int orderPlusWindow; private int m_nRunningAverage; private RollBufferShort m_rbInput = new RollBufferShort(); private RollBufferShort m_rbDeltaM = new RollBufferShort(); private short[] m_paryM; protected abstract int CalculateDotProductNoMMX(short[] pA, int indexA, short[] pB, int indexB); protected abstract void AdaptNoMMX(short[] pM, int indexM, short[] pAdapt, int indexA, int nDirection); }