/*
* 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.info.CompressionLevel;
import davaguine.jmac.tools.JMACException;
import java.util.Arrays;
/**
* Author: Dmitry Vaguine
* Date: 04.03.2004
* Time: 14:51:31
*/
public class PredictorDecompressNormal3930to3950 extends IPredictorDecompress {
private final static int HISTORY_ELEMENTS = 8;
private final static int WINDOW_BLOCKS = 512;
private final static int BUFFER_COUNT = 1;
private final static int M_COUNT = 8;
public PredictorDecompressNormal3930to3950(int nCompressionLevel, int nVersion) {
super(nCompressionLevel, nVersion);
m_pBuffer[0] = new int[HISTORY_ELEMENTS + WINDOW_BLOCKS];
if (nCompressionLevel == CompressionLevel.COMPRESSION_LEVEL_FAST) {
m_pNNFilter = null;
m_pNNFilter1 = null;
} else if (nCompressionLevel == CompressionLevel.COMPRESSION_LEVEL_NORMAL) {
m_pNNFilter = new NNFilter16(11, nVersion);
m_pNNFilter1 = null;
} else if (nCompressionLevel == CompressionLevel.COMPRESSION_LEVEL_HIGH) {
m_pNNFilter = new NNFilter64(11, nVersion);
m_pNNFilter1 = null;
} else if (nCompressionLevel == CompressionLevel.COMPRESSION_LEVEL_EXTRA_HIGH) {
m_pNNFilter = new NNFilter256(13, nVersion);
m_pNNFilter1 = new NNFilter32(10, nVersion);
} else {
throw new JMACException("Unknown Compression Type");
}
}
public int DecompressValue(int nInput, int notneeded) {
if (m_nCurrentIndex == WINDOW_BLOCKS) {
// copy forward and adjust pointers
System.arraycopy(m_pBuffer[0], WINDOW_BLOCKS, m_pBuffer[0], 0, HISTORY_ELEMENTS);
m_pInputBuffer_i = 0;
m_pInputBuffer_j = HISTORY_ELEMENTS;
m_nCurrentIndex = 0;
}
// stage 2: NNFilter
if (m_pNNFilter1 != null)
nInput = m_pNNFilter1.Decompress(nInput);
if (m_pNNFilter != null)
nInput = m_pNNFilter.Decompress(nInput);
// stage 1: multiple predictors (order 2 and offset 1)
int p1 = m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 1];
int p2 = m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 1] - m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 2];
int p3 = m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 2] - m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 3];
int p4 = m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 3] - m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j - 4];
m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j] = nInput + (((p1 * m_aryM[0]) + (p2 * m_aryM[1]) + (p3 * m_aryM[2]) + (p4 * m_aryM[3])) >> 9);
if (nInput > 0) {
m_aryM[0] -= ((p1 >> 30) & 2) - 1;
m_aryM[1] -= ((p2 >> 30) & 2) - 1;
m_aryM[2] -= ((p3 >> 30) & 2) - 1;
m_aryM[3] -= ((p4 >> 30) & 2) - 1;
} else if (nInput < 0) {
m_aryM[0] += ((p1 >> 30) & 2) - 1;
m_aryM[1] += ((p2 >> 30) & 2) - 1;
m_aryM[2] += ((p3 >> 30) & 2) - 1;
m_aryM[3] += ((p4 >> 30) & 2) - 1;
}
int nRetVal = m_pBuffer[m_pInputBuffer_i][m_pInputBuffer_j] + ((m_nLastValue * 31) >> 5);
m_nLastValue = nRetVal;
m_nCurrentIndex++;
m_pInputBuffer_j++;
return nRetVal;
}
public void Flush() {
if (m_pNNFilter != null) m_pNNFilter.Flush();
if (m_pNNFilter1 != null) m_pNNFilter1.Flush();
Arrays.fill(m_pBuffer[0], 0, HISTORY_ELEMENTS, 0);
Arrays.fill(m_aryM, 0);
m_aryM[0] = 360;
m_aryM[1] = 317;
m_aryM[2] = -109;
m_aryM[3] = 98;
m_pInputBuffer_i = 0;
m_pInputBuffer_j = HISTORY_ELEMENTS;
m_nLastValue = 0;
m_nCurrentIndex = 0;
}
// buffer information
protected int[][] m_pBuffer = new int[BUFFER_COUNT][];
// adaption
protected int[] m_aryM = new int[M_COUNT];
// buffer pointers
protected int m_pInputBuffer_i;
protected int m_pInputBuffer_j;
// other
protected int m_nCurrentIndex;
protected int m_nLastValue;
protected NNFilter m_pNNFilter;
protected NNFilter m_pNNFilter1;
}