/*
* 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.encoder;
import davaguine.jmac.info.SpecialFrame;
import davaguine.jmac.info.WaveFormat;
import davaguine.jmac.prediction.IPredictorCompress;
import davaguine.jmac.prediction.PredictorCompressNormal;
import davaguine.jmac.tools.*;
import java.io.IOException;
/**
* Author: Dmitry Vaguine
* Date: 08.05.2004
* Time: 11:18:47
*/
public class APECompressCore {
public APECompressCore(File pIO, WaveFormat pwfeInput, int nMaxFrameBlocks, int nCompressionLevel) {
m_spBitArray = new BitArray(pIO);
m_spDataX = new int[nMaxFrameBlocks];
m_spDataY = new int[nMaxFrameBlocks];
m_spPrepare = new Prepare();
m_spPredictorX = new PredictorCompressNormal(nCompressionLevel);
m_spPredictorY = new PredictorCompressNormal(nCompressionLevel);
m_wfeInput = pwfeInput;
m_nPeakLevel.value = 0;
}
private IntegerPointer m_nSpecialCodes = new IntegerPointer();
public void EncodeFrame(ByteArrayReader pInputData, int nInputBytes) throws IOException {
// variables
int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
m_nSpecialCodes.value = 0;
// always start a new frame on a byte boundary
m_spBitArray.AdvanceToByteBoundary();
// do the preparation stage
Prepare(pInputData, nInputBytes, m_nSpecialCodes);
m_spPredictorX.Flush();
m_spPredictorY.Flush();
m_spBitArray.FlushState(m_BitArrayStateX);
m_spBitArray.FlushState(m_BitArrayStateY);
m_spBitArray.FlushBitArray();
if (m_wfeInput.nChannels == 2) {
boolean bEncodeX = true;
boolean bEncodeY = true;
if ((m_nSpecialCodes.value & SpecialFrame.SPECIAL_FRAME_LEFT_SILENCE) > 0 &&
(m_nSpecialCodes.value & SpecialFrame.SPECIAL_FRAME_RIGHT_SILENCE) > 0) {
bEncodeX = false;
bEncodeY = false;
}
if ((m_nSpecialCodes.value & SpecialFrame.SPECIAL_FRAME_PSEUDO_STEREO) > 0) {
bEncodeY = false;
}
if (bEncodeX && bEncodeY) {
int nLastX = 0;
for (int z = 0; z < nInputBlocks; z++) {
m_spBitArray.EncodeValue(m_spPredictorY.CompressValue(m_spDataY[z], nLastX), m_BitArrayStateY);
m_spBitArray.EncodeValue(m_spPredictorX.CompressValue(m_spDataX[z], m_spDataY[z]), m_BitArrayStateX);
nLastX = m_spDataX[z];
}
} else if (bEncodeX) {
for (int z = 0; z < nInputBlocks; z++) {
m_spBitArray.EncodeValue(m_spPredictorX.CompressValue(m_spDataX[z]), m_BitArrayStateX);
}
} else if (bEncodeY) {
for (int z = 0; z < nInputBlocks; z++) {
m_spBitArray.EncodeValue(m_spPredictorY.CompressValue(m_spDataY[z]), m_BitArrayStateY);
}
}
} else if (m_wfeInput.nChannels == 1) {
if ((m_nSpecialCodes.value & SpecialFrame.SPECIAL_FRAME_MONO_SILENCE) <= 0) {
for (int z = 0; z < nInputBlocks; z++) {
m_spBitArray.EncodeValue(m_spPredictorX.CompressValue(m_spDataX[z]), m_BitArrayStateX);
}
}
}
m_spBitArray.Finalize();
}
public BitArray GetBitArray() {
return m_spBitArray;
}
public int GetPeakLevel() {
return m_nPeakLevel.value;
}
private BitArray m_spBitArray;
private IPredictorCompress m_spPredictorX;
private IPredictorCompress m_spPredictorY;
private BitArrayState m_BitArrayStateX = new BitArrayState();
private BitArrayState m_BitArrayStateY = new BitArrayState();
private int[] m_spDataX;
private int[] m_spDataY;
private Prepare m_spPrepare;
private WaveFormat m_wfeInput;
private IntegerPointer m_nPeakLevel = new IntegerPointer();
private Crc32 crc = new Crc32();
private void Prepare(ByteArrayReader pInputData, int nInputBytes, IntegerPointer pSpecialCodes) throws IOException {
// variable declares
pSpecialCodes.value = 0;
// do the preparation
m_spPrepare.prepare(pInputData, nInputBytes, m_wfeInput, m_spDataX, m_spDataY,
crc, pSpecialCodes, m_nPeakLevel);
// store the CRC
m_spBitArray.EncodeUnsignedLong(crc.getCrc());
// store any special codes
if (pSpecialCodes.value != 0)
m_spBitArray.EncodeUnsignedLong(pSpecialCodes.value);
}
}