From db0902751afe27b89fe9636252a27ed8307c0b0e Mon Sep 17 00:00:00 2001 From: morkt Date: Tue, 4 Aug 2015 22:26:00 +0400 Subject: [PATCH] Entis code moved to separate source files. --- ArcFormats/AudioMIO.cs | 1298 ---------------------------------- ArcFormats/EriReader.cs | 1375 ++++++++++++++++++++++++++++++++++++ ArcFormats/ImageERI.cs | 1366 ----------------------------------- ArcFormats/MioDecoder.cs | 1307 ++++++++++++++++++++++++++++++++++ Properties/AssemblyInfo.cs | 4 +- 5 files changed, 2684 insertions(+), 2666 deletions(-) create mode 100644 ArcFormats/EriReader.cs create mode 100644 ArcFormats/MioDecoder.cs diff --git a/ArcFormats/AudioMIO.cs b/ArcFormats/AudioMIO.cs index 0701f6db..4db8329a 100644 --- a/ArcFormats/AudioMIO.cs +++ b/ArcFormats/AudioMIO.cs @@ -384,1302 +384,4 @@ namespace GameRes.Formats.Entis } #endregion } - -/***************************************************************************** - E R I S A - L i b r a r y - ----------------------------------------------------------------------------- - Copyright (C) 2002-2007 Leshade Entis, Entis-soft. All rights reserved. - *****************************************************************************/ - - internal class MioInfoHeader - { - public int Version; - public CvType Transformation; - public EriCode Architecture; - public int ChannelCount; - public uint SamplesPerSec; - public uint BlocksetCount; - public int SubbandDegree; - public uint AllSampleCount; - public uint LappedDegree; - public uint BitsPerSample; - } - - internal class MioDataHeader - { - public byte Version; - public byte Flags; - public uint SampleCount; - } - - internal struct EriSinCos - { - public float rSin; - public float rCos; - } - - internal class MioDecoder - { - MioInfoHeader m_mioih; - - uint m_nBufLength = 0; - int[] m_ptrBuffer1; - int[] m_ptrBuffer2; - sbyte[] m_ptrBuffer3; - byte[] m_ptrBuffer4; - byte[] m_ptrDivisionTable; - byte[] m_ptrRevolveCode; - int[] m_ptrWeightCode; - int[] m_ptrCoefficient; - - float[] m_ptrMatrixBuf; - float[] m_ptrInternalBuf; - float[] m_ptrWorkBuf; - float[] m_ptrWeightTable; - float[] m_ptrLastDCT; - - int m_ptrNextDivision; - int m_ptrNextRevCode; - int m_ptrNextWeight; - int m_ptrNextCoefficient; - int m_ptrNextSource; - int m_ptrLastDCTBuf; - int m_nSubbandDegree; - int m_nDegreeNum; - EriSinCos[] m_pRevolveParam; - readonly int[] m_nFrequencyPoint = new int[7]; - - const int MIN_DCT_DEGREE = 2; - const int MAX_DCT_DEGREE = 12; - - static MioDecoder () - { - eriInitializeMatrix(); - } - - public MioDecoder (MioInfoHeader info) - { - m_nBufLength = 0; - m_mioih = info; - - if (!Initialize()) - throw new InvalidFormatException(); - } - - bool Initialize () - { - if ((m_mioih.ChannelCount != 1) && (m_mioih.ChannelCount != 2)) - { - return false; - } - - if (m_mioih.Transformation == CvType.Lossless_ERI) - { - if (m_mioih.Architecture != EriCode.RunlengthHuffman) - { - return false; - } - if ((m_mioih.BitsPerSample != 8) && (m_mioih.BitsPerSample != 16)) - { - return false; - } - } - else if ((m_mioih.Transformation == CvType.LOT_ERI) - || (m_mioih.Transformation == CvType.LOT_ERI_MSS)) - { - if ((m_mioih.Architecture != EriCode.RunlengthGamma) - && (m_mioih.Architecture != EriCode.RunlengthHuffman) - && (m_mioih.Architecture != EriCode.Nemesis)) - { - return false; - } - if (m_mioih.BitsPerSample != 16) - { - return false; - } - if ((m_mioih.SubbandDegree < 8) || (m_mioih.SubbandDegree > MAX_DCT_DEGREE)) - { - return false; - } - if (m_mioih.LappedDegree != 1) - { - return false; - } - int subband = (sizeof(float) << m_mioih.SubbandDegree) / sizeof(float); - int block_size = m_mioih.ChannelCount * subband; - m_ptrBuffer1 = new int[block_size]; - m_ptrMatrixBuf = new float[block_size]; - m_ptrInternalBuf = new float[block_size]; - m_ptrWorkBuf = new float[subband]; - - m_ptrWeightTable = new float[subband]; - - uint nBlocksetSamples = (uint)(m_mioih.ChannelCount << m_mioih.SubbandDegree); - uint nLappedSamples = nBlocksetSamples * m_mioih.LappedDegree; - if (nLappedSamples > 0) - { - m_ptrLastDCT = new float[nLappedSamples]; - } - InitializeWithDegree (m_mioih.SubbandDegree); - } - else - { - return false; - } - return true; - } - - public bool DecodeSound (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) - { - context.FlushBuffer(); - - if (m_mioih.Transformation == CvType.Lossless_ERI) - { - if (m_mioih.BitsPerSample == 8) - { - return DecodeSoundPCM8 (context, datahdr, ptrWaveBuf, wave_pos); - } - else if (m_mioih.BitsPerSample == 16) - { - return DecodeSoundPCM16 (context, datahdr, ptrWaveBuf, wave_pos); - } - } - else if ((m_mioih.Transformation == CvType.LOT_ERI) - || (m_mioih.Transformation == CvType.LOT_ERI_MSS)) - { - if ((m_mioih.ChannelCount != 2) || (m_mioih.Transformation == CvType.LOT_ERI)) - { - return DecodeSoundDCT (context, datahdr, ptrWaveBuf, wave_pos); - } - else - { - return DecodeSoundDCT_MSS (context, datahdr, ptrWaveBuf, wave_pos); - } - } - return false; - } - - bool DecodeSoundPCM8 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) - { - uint nSampleCount = datahdr.SampleCount; - if (nSampleCount > m_nBufLength) - { - m_ptrBuffer3 = new sbyte [nSampleCount * m_mioih.ChannelCount]; - m_nBufLength = nSampleCount; - } - if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) - { - (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); - } - uint nBytes = nSampleCount * (uint)m_mioih.ChannelCount; - if (context.DecodeBytes (m_ptrBuffer3, nBytes) < nBytes) - { - return false; - } - int ptrSrcBuf = 0; // (PBYTE) m_ptrBuffer3; - int nStep = m_mioih.ChannelCount; - for (int i = 0; i < m_mioih.ChannelCount; i ++ ) - { - int ptrDstBuf = wave_pos + i; - sbyte bytValue = 0; - for (uint j = 0; j < nSampleCount; j++) - { - bytValue += m_ptrBuffer3[ptrSrcBuf++]; - ptrWaveBuf[ptrDstBuf] = (byte)bytValue; - ptrDstBuf += nStep; - } - } - return true; - } - - bool DecodeSoundPCM16 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) - { - uint nSampleCount = datahdr.SampleCount; - uint nChannelCount = (uint)m_mioih.ChannelCount; - uint nAllSampleCount = nSampleCount * nChannelCount; - - if (nSampleCount > m_nBufLength) - { - m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; - m_ptrBuffer4 = new byte[nAllSampleCount * sizeof(short)]; - m_nBufLength = nSampleCount; - } - if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) - { - (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); - } - uint nBytes = nAllSampleCount * sizeof(short); - if (context.DecodeBytes (m_ptrBuffer3, nBytes) < nBytes) - { - return false; - } - int pbytSrcBuf1, pbytSrcBuf2, pbytDstBuf; - for (int i = 0; i < m_mioih.ChannelCount; i++) - { - int nOffset = i * (int)nSampleCount * sizeof(short); - pbytSrcBuf1 = nOffset; // ((PBYTE) m_ptrBuffer3) + nOffset; - pbytSrcBuf2 = pbytSrcBuf1 + (int)nSampleCount; // pbytSrcBuf1 + nSampleCount; - pbytDstBuf = nOffset; // ((PBYTE) m_ptrBuffer4) + nOffset; - - for (uint j = 0; j < nSampleCount; j ++) - { - sbyte bytLow = m_ptrBuffer3[pbytSrcBuf2 + j]; - sbyte bytHigh = m_ptrBuffer3[pbytSrcBuf1 + j]; - m_ptrBuffer4[pbytDstBuf + j * sizeof(short) + 0] = (byte)bytLow; - m_ptrBuffer4[pbytDstBuf + j * sizeof(short) + 1] = (byte)(bytHigh ^ (bytLow >> 7)); - } - } - int ptrSrcBuf = 0; // (SWORD*) m_ptrBuffer4; - int nStep = m_mioih.ChannelCount; - for (int i = 0; i < m_mioih.ChannelCount; i++) - { - int ptrDstBuf = wave_pos + i*sizeof(short); // (SWORD*) ptrWaveBuf; - short wValue = 0; - short wDelta = 0; - for (uint j = 0; j < nSampleCount; j++) - { - wDelta += LittleEndian.ToInt16 (m_ptrBuffer4, ptrSrcBuf); - wValue += wDelta; - LittleEndian.Pack (wValue, ptrWaveBuf, ptrDstBuf); // *ptrDstBuf = wValue; - ptrSrcBuf += sizeof(short); - ptrDstBuf += nStep; - } - } - return true; - } - - static readonly int[] FreqWidth = new int[7] { -6, -6, -5, -4, -3, -2, -1 }; - - void InitializeWithDegree (int nSubbandDegree) - { - m_pRevolveParam = eriCreateRevolveParameter (nSubbandDegree); - for (int i = 0, j = 0; i < 7; i ++) - { - int nFrequencyWidth = 1 << (nSubbandDegree + FreqWidth[i]); - m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2); - j += nFrequencyWidth; - } - m_nSubbandDegree = nSubbandDegree; - m_nDegreeNum = 1 << nSubbandDegree; - } - - const uint MIO_LEAD_BLOCK = 0x01; - - bool DecodeSoundDCT (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) - { - uint i, j, k; - uint nDegreeWidth = 1u << m_mioih.SubbandDegree; - uint nSampleCount = (datahdr.SampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); - uint nSubbandCount = (nSampleCount >> m_mioih.SubbandDegree); - uint nChannelCount = (uint)m_mioih.ChannelCount; - uint nAllSampleCount = nSampleCount * nChannelCount; - uint nAllSubbandCount = nSubbandCount * nChannelCount; - - if (nSampleCount > m_nBufLength) - { - m_ptrBuffer2 = new int[nAllSampleCount]; - m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; - m_ptrDivisionTable = new byte[nAllSubbandCount]; - m_ptrWeightCode = new int[nAllSubbandCount * 5]; - m_ptrCoefficient = new int[nAllSubbandCount * 5]; - m_nBufLength = nSampleCount; - } - if (context.GetABit() != 0) - { - return false; - } - int[] pLastDivision = new int [nChannelCount]; - m_ptrNextDivision = 0; // within m_ptrDivisionTable; - m_ptrNextWeight = 0; // within m_ptrWeightCode; - m_ptrNextCoefficient = 0; // within m_ptrCoefficient; - - for (i = 0; i < nChannelCount; i++) - { - pLastDivision[i] = -1; - } - for (i = 0; i < nSubbandCount; i++) - { - for (j = 0; j < nChannelCount; j++) - { - int nDivisionCode = (int)context.GetNBits(2); - m_ptrDivisionTable[m_ptrNextDivision++] = (byte)nDivisionCode; - - if (nDivisionCode != pLastDivision[j]) - { - if (i != 0) - { - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - pLastDivision[j] = nDivisionCode; - } - - uint nDivisionCount = 1u << nDivisionCode; - for (k = 0; k < nDivisionCount; k ++) - { - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - } - } - if (nSubbandCount > 0) - { - for (i = 0; i < nChannelCount; i++) - { - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - } - - if (context.GetABit() != 0) - { - return false; - } - if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) - { - if (m_mioih.Architecture != EriCode.Nemesis) - { - (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); - } - else - { - throw new NotImplementedException ("Nemesis encoding not implemented"); -// context.PrepareToDecodeERISACode(); - } - } - else if (m_mioih.Architecture == EriCode.Nemesis) - { - throw new NotImplementedException ("Nemesis encoding not implemented"); -// context.InitializeERISACode(); - } - if (m_mioih.Architecture != EriCode.Nemesis) - { - if (context.DecodeBytes (m_ptrBuffer3, nAllSampleCount * 2 ) < nAllSampleCount * 2) - { - return false; - } - int ptrHBuf = 0; // within m_ptrBuffer3; - int ptrLBuf = (int)nAllSampleCount; // within m_ptrBuffer3 - - for (i = 0; i < nDegreeWidth; i++) - { - int ptrQuantumized = (int)i; // within (PINT) m_ptrBuffer2 - for (j = 0; j < nAllSubbandCount; j++) - { - int nLow = m_ptrBuffer3[ptrLBuf++]; - int nHigh = m_ptrBuffer3[ptrHBuf++] ^ (nLow >> 8); - m_ptrBuffer2[ptrQuantumized] = (nLow & 0xFF) | (nHigh << 8); - ptrQuantumized += (int)nDegreeWidth; - } - } - } - else - { - throw new NotImplementedException ("Nemesis encoding not implemented"); - /* - if (context.DecodeERISACodeWords (m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) - { - return false; - } - for (i = 0; i < nAllSampleCount; i++) - { - ((PINT)m_ptrBuffer2)[i] = ((SWORD*)m_ptrBuffer3)[i]; - } - */ - } - uint nSamples; - uint[] pRestSamples = new uint [nChannelCount]; - int[] ptrDstBuf = new int [nChannelCount]; // indices within ptrWaveBuf - - m_ptrNextDivision = 0; // within m_ptrDivisionTable; - m_ptrNextWeight = 0; // within m_ptrWeightCode; - m_ptrNextCoefficient = 0; // within m_ptrCoefficient; - m_ptrNextSource = 0; // within (PINT) m_ptrBuffer2; - - for (i = 0; i < nChannelCount; i++) - { - pLastDivision[i] = -1; - pRestSamples[i] = datahdr.SampleCount; - ptrDstBuf[i] = wave_pos + (int)i*sizeof(short); - } - int nCurrentDivision = -1; - - for (i = 0; i < nSubbandCount; i++) - { - for (j = 0; j < nChannelCount; j++) - { - int nDivisionCode = m_ptrDivisionTable[m_ptrNextDivision++]; - int nDivisionCount = 1 << nDivisionCode; - int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * j); - m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT - - bool fLeadBlock = false; - if (pLastDivision[j] != nDivisionCode) - { - if (i != 0) - { - if (nCurrentDivision != pLastDivision[j]) - { - InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[j]); - nCurrentDivision = pLastDivision[j]; - } - nSamples = pRestSamples[j]; - if (nSamples > m_nDegreeNum) - { - nSamples = (uint)m_nDegreeNum; - } - DecodePostBlock (ptrWaveBuf, ptrDstBuf[j], nSamples); - pRestSamples[j] -= nSamples; - ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short)); - } - pLastDivision[j] = (int)nDivisionCode; - fLeadBlock = true; - } - if (nCurrentDivision != nDivisionCode) - { - InitializeWithDegree (m_mioih.SubbandDegree - nDivisionCode); - nCurrentDivision = nDivisionCode; - } - for (k = 0; k < nDivisionCount; k++) - { - if (fLeadBlock) - { - DecodeLeadBlock(); - fLeadBlock = false; - } - else - { - nSamples = pRestSamples[j]; - if (nSamples > m_nDegreeNum) - { - nSamples = (uint)m_nDegreeNum; - } - DecodeInternalBlock (ptrWaveBuf, ptrDstBuf[j], nSamples); - pRestSamples[j] -= nSamples; - ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short)); - } - } - } - } - if (nSubbandCount > 0) - { - for (i = 0; i < nChannelCount; i ++) - { - int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * i); - m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT - - if (nCurrentDivision != pLastDivision[i]) - { - InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[i]); - nCurrentDivision = pLastDivision[i]; - } - nSamples = pRestSamples[i]; - if (nSamples > m_nDegreeNum) - { - nSamples = (uint)m_nDegreeNum; - } - DecodePostBlock (ptrWaveBuf, ptrDstBuf[i], nSamples); - pRestSamples[i] -= nSamples; - ptrDstBuf[i] += (int)(nSamples * nChannelCount * sizeof(short)); - } - } - return true; - } - - void DecodeInternalBlock (byte[] ptrDst, int iDst, uint nSamples) - { - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer2, m_ptrNextSource, m_nDegreeNum, nWeightCode, nCoefficient); - m_ptrNextSource += (int)m_nDegreeNum; - - eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree); - eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree); - eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, 0, m_nSubbandDegree); - - Array.Copy (m_ptrMatrixBuf, 0, m_ptrLastDCT, m_ptrLastDCTBuf, m_nDegreeNum); - Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, 0, m_nDegreeNum); - - eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 0, 1, m_ptrWorkBuf, m_nSubbandDegree); - if (nSamples != 0) - { - eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples); - } - } - - void DecodeLeadBlock () - { - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - uint i; - uint nHalfDegree = (uint)m_nDegreeNum / 2; - for (i = 0; i < nHalfDegree; i++) - { - m_ptrBuffer1[i * 2] = 0; - m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; - } - IQuantumize (m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); - eriOddGivensInverseMatrix (m_ptrLastDCT, m_ptrLastDCTBuf, m_pRevolveParam, m_nSubbandDegree); - for (i = 0; i < m_nDegreeNum; i += 2) - { - m_ptrLastDCT[m_ptrLastDCTBuf + i] = m_ptrLastDCT[m_ptrLastDCTBuf + i + 1]; - } - eriFastIPLOT (m_ptrLastDCT, m_ptrLastDCTBuf, m_nSubbandDegree); - } - - void DecodePostBlock (byte[] ptrDst, int iDst, uint nSamples) - { - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - uint i; - uint nHalfDegree = (uint)m_nDegreeNum / 2; - for (i = 0; i < nHalfDegree; i++) - { - m_ptrBuffer1[i * 2] = 0; - m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; - } - IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); - eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree); - - for (i = 0; i < m_nDegreeNum; i += 2) - { - m_ptrMatrixBuf[i] = - m_ptrMatrixBuf[i + 1]; - } - - eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree); - eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, 0, m_nSubbandDegree); - - Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, 0, m_nDegreeNum); - - eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 0, 1, m_ptrWorkBuf, m_nSubbandDegree); - if (nSamples != 0) - { - eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples); - } - } - - bool DecodeSoundDCT_MSS (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) - { - uint nDegreeWidth = 1u << m_mioih.SubbandDegree; - uint nSampleCount = (datahdr.SampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); - uint nSubbandCount = (nSampleCount >> m_mioih.SubbandDegree); - uint nChannelCount = (uint)m_mioih.ChannelCount; - uint nAllSampleCount = nSampleCount * nChannelCount; - uint nAllSubbandCount = nSubbandCount; - - if (nSampleCount > m_nBufLength) - { - m_ptrBuffer2 = new int[nAllSampleCount]; - m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; - m_ptrDivisionTable = new byte[nAllSubbandCount]; - m_ptrRevolveCode = new byte[nAllSubbandCount * 10]; - m_ptrWeightCode = new int[nAllSubbandCount * 10]; - m_ptrCoefficient = new int[nAllSubbandCount * 10]; - m_nBufLength = nSampleCount; - } - if (context.GetABit() != 0) - { - return false; - } - - int nLastDivision = -1; - m_ptrNextDivision = 0; // within m_ptrDivisionTable; - m_ptrNextRevCode = 0; // within m_ptrRevolveCode; - m_ptrNextWeight = 0; // within m_ptrWeightCode; - m_ptrNextCoefficient = 0; // within m_ptrCoefficient; - - uint i, j, k; - for (i = 0; i < nSubbandCount; i ++) - { - int nDivisionCode = (int)context.GetNBits (2); - m_ptrDivisionTable[m_ptrNextDivision++] = (byte)nDivisionCode; - - bool fLeadBlock = false; - if (nDivisionCode != nLastDivision) - { - if (i != 0) - { - m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - fLeadBlock = true; - nLastDivision = nDivisionCode; - } - uint nDivisionCount = 1u << nDivisionCode; - for (k = 0; k < nDivisionCount; k++) - { - if (fLeadBlock) - { - m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); - fLeadBlock = false; - } - else - { - m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (4); - } - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - } - if (nSubbandCount > 0) - { - m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); - m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); - m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); - } - if (context.GetABit() != 0) - { - return false; - } - if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) - { - if (m_mioih.Architecture != EriCode.Nemesis) - { - (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); - } - else - { - throw new NotImplementedException ("Nemesis encoding not implemented"); -// context.PrepareToDecodeERISACode( ); - } - } - else if (m_mioih.Architecture == EriCode.Nemesis) - { - throw new NotImplementedException ("Nemesis encoding not implemented"); -// context.InitializeERISACode( ); - } - if (m_mioih.Architecture != EriCode.Nemesis) - { - if (context.DecodeBytes (m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) - { - return false; - } - int ptrHBuf = 0; // within m_ptrBuffer3; - int ptrLBuf = (int)nAllSampleCount; // within m_ptrBuffer3 - - for (i = 0; i < nDegreeWidth * 2; i++) - { - int ptrQuantumized = (int)i; // within (PINT) m_ptrBuffer2 - for (j = 0; j < nAllSubbandCount; j++) - { - int nLow = m_ptrBuffer3[ptrLBuf++]; - int nHigh = m_ptrBuffer3[ptrHBuf++] ^ (nLow >> 8); - m_ptrBuffer2[ptrQuantumized] = (nLow & 0xFF) | (nHigh << 8); - ptrQuantumized += (int)nDegreeWidth * 2; - } - } - } - else - { - throw new NotImplementedException ("Nemesis encoding not implemented"); - /* - if ( context.DecodeERISACodeWords - ( (SWORD*) m_ptrBuffer3, nAllSampleCount ) < nAllSampleCount ) - { - return false; - } - for ( i = 0; i < nAllSampleCount; i ++ ) - { - ((PINT)m_ptrBuffer2)[i] = ((SWORD*)m_ptrBuffer3)[i]; - } - */ - } - uint nSamples; - uint nRestSamples = datahdr.SampleCount; -// int ptrDstBuf = wave_pos; // within (SWORD*) ptrWaveBuf; - - nLastDivision = -1; - m_ptrNextDivision = 0; // m_ptrDivisionTable; - m_ptrNextRevCode = 0; // m_ptrRevolveCode; - m_ptrNextWeight = 0; // m_ptrWeightCode; - m_ptrNextCoefficient = 0; // m_ptrCoefficient; - m_ptrNextSource = 0; // (PINT) m_ptrBuffer2; - - for (i = 0; i < nSubbandCount; i++) - { - int nDivisionCode = m_ptrDivisionTable[m_ptrNextDivision++]; - uint nDivisionCount = 1u << nDivisionCode; - - bool fLeadBlock = false; - if (nLastDivision != nDivisionCode) - { - if (i != 0) - { - nSamples = Math.Min (nRestSamples, (uint)m_nDegreeNum); - DecodePostBlock_MSS (ptrWaveBuf, wave_pos, nSamples); - nRestSamples -= nSamples; - wave_pos += (int)(nSamples * nChannelCount * sizeof(short)); - } - InitializeWithDegree (m_mioih.SubbandDegree - nDivisionCode); - nLastDivision = nDivisionCode; - fLeadBlock = true; - } - for (k = 0; k < nDivisionCount; k++) - { - if (fLeadBlock) - { - DecodeLeadBlock_MSS(); - fLeadBlock = false; - } - else - { - nSamples = nRestSamples; - if (nSamples > m_nDegreeNum) - { - nSamples = (uint)m_nDegreeNum; - } - DecodeInternalBlock_MSS (ptrWaveBuf, wave_pos, nSamples); - nRestSamples -= nSamples; - wave_pos += (int)(nSamples * nChannelCount * sizeof(short)); - } - } - } - if (nSubbandCount > 0) - { - nSamples = nRestSamples; - if (nSamples > m_nDegreeNum) - { - nSamples = (uint)m_nDegreeNum; - } - DecodePostBlock_MSS (ptrWaveBuf, wave_pos, nSamples); - nRestSamples -= nSamples; - wave_pos += (int)(nSamples * nChannelCount) * sizeof(short); - } - return true; - } - - void DecodeLeadBlock_MSS () - { - uint i, j; - uint nHalfDegree = (uint)m_nDegreeNum / 2; - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - int ptrLapBuf = 0; // within m_ptrLastDCT; - - for (i = 0; i < 2; i++) - { - int ptrSrcBuf = 0; // within (PINT) m_ptrBuffer1; - for (j = 0; j < nHalfDegree; j++) - { - m_ptrBuffer1[ptrSrcBuf + j * 2] = 0; - m_ptrBuffer1[ptrSrcBuf + j * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; - } - IQuantumize (m_ptrLastDCT, ptrLapBuf, m_ptrBuffer1, ptrSrcBuf, m_nDegreeNum, nWeightCode, nCoefficient); - ptrLapBuf += (int)m_nDegreeNum; - } - int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; - - int ptrLapBuf1 = 0; // m_ptrLastDCT; - int ptrLapBuf2 = (int)m_nDegreeNum; // m_ptrLastDCT - - float rSin = (float)Math.Sin (nRevCode * Math.PI / 8); - float rCos = (float)Math.Cos (nRevCode * Math.PI / 8); - eriRevolve2x2 (m_ptrLastDCT, ptrLapBuf1, m_ptrLastDCT, ptrLapBuf2, rSin, rCos, 1, m_nDegreeNum); - - ptrLapBuf = 0; //m_ptrLastDCT; - for (i = 0; i < 2; i++) - { - eriOddGivensInverseMatrix (m_ptrLastDCT, ptrLapBuf, m_pRevolveParam, m_nSubbandDegree); - - for (j = 0; j < m_nDegreeNum; j += 2) - { - m_ptrLastDCT[ptrLapBuf + j] = m_ptrLastDCT[ptrLapBuf + j + 1]; - } - eriFastIPLOT (m_ptrLastDCT, ptrLapBuf, m_nSubbandDegree); - ptrLapBuf += (int)m_nDegreeNum; - } - } - - void DecodeInternalBlock_MSS (byte[] ptrDst, int iDst, uint nSamples) - { - int ptrSrcBuf = 0; // m_ptrMatrixBuf; - int ptrLapBuf = 0; // m_ptrLastDCT; - - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - - for (int i = 0; i < 2; i++) - { - IQuantumize (m_ptrMatrixBuf, ptrSrcBuf, m_ptrBuffer2, m_ptrNextSource, m_nDegreeNum, nWeightCode, nCoefficient); - m_ptrNextSource += m_nDegreeNum; - ptrSrcBuf += m_nDegreeNum; - } - int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; - int nRevCode1 = (nRevCode >> 2) & 0x03; - int nRevCode2 = (nRevCode & 0x03); - - int ptrSrcBuf1 = 0; // m_ptrMatrixBuf; - int ptrSrcBuf2 = m_nDegreeNum; // m_ptrMatrixBuf + m_nDegreeNum; - - float rSin = (float) Math.Sin (nRevCode1 * Math.PI / 8); - float rCos = (float) Math.Cos (nRevCode1 * Math.PI / 8); - eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1, m_ptrMatrixBuf, ptrSrcBuf2, rSin, rCos, 2, m_nDegreeNum / 2); - - rSin = (float) Math.Sin (nRevCode2 * Math.PI / 8); - rCos = (float) Math.Cos (nRevCode2 * Math.PI / 8); - eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1 + 1, m_ptrMatrixBuf, ptrSrcBuf2 + 1, rSin, rCos, 2, m_nDegreeNum / 2); - - ptrSrcBuf = 0; // m_ptrMatrixBuf; - - for (int i = 0; i < 2; i++) - { - eriOddGivensInverseMatrix (m_ptrMatrixBuf, ptrSrcBuf, m_pRevolveParam, m_nSubbandDegree); - eriFastIPLOT (m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); - eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, ptrLapBuf, m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); - - Array.Copy (m_ptrMatrixBuf, ptrSrcBuf, m_ptrLastDCT, ptrLapBuf, m_nDegreeNum); - Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, ptrSrcBuf, m_nDegreeNum); - - eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, ptrSrcBuf, 1, m_ptrWorkBuf, m_nSubbandDegree); - if (nSamples != 0) - { - eriRoundR32ToWordArray (ptrDst, iDst + (int)i*2, 2, m_ptrInternalBuf, (int)nSamples); - } - ptrSrcBuf += m_nDegreeNum; - ptrLapBuf += m_nDegreeNum; - } - } - - void DecodePostBlock_MSS (byte[] ptrDst, int iDst, uint nSamples) - { - int ptrLapBuf = 0; // m_ptrLastDCT; - int ptrSrcBuf = 0; // m_ptrMatrixBuf; - - int i, j; - uint nHalfDegree = (uint)m_nDegreeNum / 2u; - int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; - int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; - - for (i = 0; i < 2; i++) - { - for (j = 0; j < nHalfDegree; j++) - { - m_ptrBuffer1[j * 2] = 0; - m_ptrBuffer1[j * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; - } - IQuantumize (m_ptrMatrixBuf, ptrSrcBuf, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); - ptrSrcBuf += m_nDegreeNum; - } - float rSin, rCos; - int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; - - int ptrSrcBuf1 = 0; // m_ptrMatrixBuf; - int ptrSrcBuf2 = m_nDegreeNum; // m_ptrMatrixBuf + m_nDegreeNum; - - rSin = (float) Math.Sin (nRevCode * Math.PI / 8); - rCos = (float) Math.Cos (nRevCode * Math.PI / 8); - eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1, m_ptrMatrixBuf, ptrSrcBuf2, rSin, rCos, 1, m_nDegreeNum); - - ptrSrcBuf = 0; // m_ptrMatrixBuf; - - for (i = 0; i < 2; i ++) - { - eriOddGivensInverseMatrix (m_ptrMatrixBuf, ptrSrcBuf, m_pRevolveParam, m_nSubbandDegree); - - for (j = 0; j < m_nDegreeNum; j += 2) - { - m_ptrMatrixBuf[ptrSrcBuf + j] = -m_ptrMatrixBuf[ptrSrcBuf + j + 1]; - } - eriFastIPLOT (m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); - eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, ptrLapBuf, m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); - - Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, ptrSrcBuf, m_nDegreeNum); - - eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, ptrSrcBuf, 1, m_ptrWorkBuf, m_nSubbandDegree); - if (nSamples != 0) - { - eriRoundR32ToWordArray (ptrDst, iDst + (int)i*2, 2, m_ptrInternalBuf, (int)nSamples); - } - ptrLapBuf += m_nDegreeNum; - ptrSrcBuf += m_nDegreeNum; - } - } - - void IQuantumize (float[] ptrDestination, int dst, int[] ptrQuantumized, int qsrc, int nDegreeNum, int nWeightCode, int nCoefficient) - { - int i, j; - double rMatrixScale = Math.Sqrt (2.0 / nDegreeNum); - double rCoefficient = rMatrixScale * nCoefficient; - double[] rAvgRatio = new double[7]; - for (i = 0; i < 6; i++) - { - rAvgRatio[i] = 1.0 / Math.Pow (2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5); - } - rAvgRatio[6] = 1.0; - for (i = 0; i < m_nFrequencyPoint[0]; i++) - { - m_ptrWeightTable[i] = (float) rAvgRatio[0]; - } - for (j = 1; j < 7; j++) - { - double a = rAvgRatio[j - 1]; - double k = (rAvgRatio[j] - a) / (m_nFrequencyPoint[j] - m_nFrequencyPoint[j - 1]); - while (i < m_nFrequencyPoint[j]) - { - m_ptrWeightTable[i] = (float)(k * (i - m_nFrequencyPoint[j - 1]) + a); - i++; - } - } - while (i < nDegreeNum) - { - m_ptrWeightTable[i++] = (float)rAvgRatio[6]; - } - float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0); - for (i = 15; i < nDegreeNum; i += 16) - { - m_ptrWeightTable[i] *= rOddWeight; - } - m_ptrWeightTable[nDegreeNum-1] = (float) nCoefficient; - for (i = 0; i < nDegreeNum; i++) - { - m_ptrWeightTable[i] = 1.0F / m_ptrWeightTable[i]; - } - for (i = 0; i < nDegreeNum; i ++) - { - ptrDestination[dst + i] = (float) (rCoefficient * m_ptrWeightTable[i] * ptrQuantumized[qsrc+i]); - } - } - - static readonly float ERI_rCosPI4 = (float)Math.Cos (Math.PI / 4); - static readonly float ERI_r2CosPI4 = 2 * ERI_rCosPI4; - static readonly float[] ERI_DCTofK2 = new float[2]; // = cos( (2*i+1) / 8 ) - static readonly float[] ERI_DCTofK4 = new float[4]; // = cos( (2*i+1) / 16 ) - static readonly float[] ERI_DCTofK8 = new float[8]; // = cos( (2*i+1) / 32 ) - static readonly float[] ERI_DCTofK16 = new float[16]; // = cos( (2*i+1) / 64 ) - static readonly float[] ERI_DCTofK32 = new float[32]; // = cos( (2*i+1) / 128 ) - static readonly float[] ERI_DCTofK64 = new float[64]; // = cos( (2*i+1) / 256 ) - static readonly float[] ERI_DCTofK128 = new float[128]; // = cos( (2*i+1) / 512 ) - static readonly float[] ERI_DCTofK256 = new float[256]; // = cos( (2*i+1) / 1024 ) - static readonly float[] ERI_DCTofK512 = new float[512]; // = cos( (2*i+1) / 2048 ) - static readonly float[] ERI_DCTofK1024 = new float[1024]; // = cos( (2*i+1) / 4096 ) - static readonly float[] ERI_DCTofK2048 = new float[2048]; // = cos( (2*i+1) / 8192 ) - - static readonly float[][] ERI_pMatrixDCTofK = new float[MAX_DCT_DEGREE][] - { - null, - ERI_DCTofK2, - ERI_DCTofK4, - ERI_DCTofK8, - ERI_DCTofK16, - ERI_DCTofK32, - ERI_DCTofK64, - ERI_DCTofK128, - ERI_DCTofK256, - ERI_DCTofK512, - ERI_DCTofK1024, - ERI_DCTofK2048 - }; - - static void eriInitializeMatrix () - { - for (int i = 1; i < MAX_DCT_DEGREE; i++) - { - int n = (1 << i); - float[] pDCTofK = ERI_pMatrixDCTofK[i]; - double nr = Math.PI / (4.0 * n); - double dr = nr + nr; - double ir = nr; - for (int j = 0; j < n; j++) - { - pDCTofK[j] = (float)Math.Cos (ir); - ir += dr; - } - } - } - - static void eriRoundR32ToWordArray (byte[] ptrDst, int dst, int nStep, float[] ptrSrc, int nCount) - { - nStep *= 2; - for (int i = 0; i < nCount; i++) - { - int nValue = eriRoundR32ToInt (ptrSrc[i]); - if (nValue <= -0x8000) - { - LittleEndian.Pack ((short)-0x8000, ptrDst, dst); - } - else if (nValue >= 0x7FFF) - { - LittleEndian.Pack ((short)0x7FFF, ptrDst, dst); - } - else - { - LittleEndian.Pack ((short)nValue, ptrDst, dst); - } - dst += nStep; - } - } - - static int eriRoundR32ToInt (float r) - { - if (r >= 0.0) - return (int)Math.Floor (r + 0.5); - else - return (int)Math.Ceiling (r - 0.5); - } - - static EriSinCos[] eriCreateRevolveParameter (int nDegreeDCT) - { - int nDegreeNum = 1 << nDegreeDCT; - int lc = 1; - for (int n = nDegreeNum / 2; n >= 8; n /= 8) - { - ++lc; - } - EriSinCos[] ptrRevolve = new EriSinCos[lc*8]; - - double k = Math.PI / (nDegreeNum * 2); - int ptrNextRev = 0; - int nStep = 2; - do - { - for (int i = 0; i < 7; i++) - { - double ws = 1.0; - double a = 0.0; - for (int j = 0; j < i; j++) - { - a += nStep; - ws = ws * ptrRevolve[ptrNextRev+j].rSin + ptrRevolve[ptrNextRev+j].rCos * Math.Cos (a * k); - } - double r = Math.Atan2 (ws, Math.Cos ((a + nStep) * k)); - ptrRevolve[ptrNextRev+i].rSin = (float)Math.Sin (r); - ptrRevolve[ptrNextRev+i].rCos = (float)Math.Cos (r); - } - ptrNextRev += 7; - nStep *= 8; - } - while (nStep < nDegreeNum); - return ptrRevolve; - } - - static void eriOddGivensInverseMatrix (float[] ptrSrc, int src, EriSinCos[] ptrRevolve, int nDegreeDCT) - { - int nDegreeNum = 1 << nDegreeDCT; - int index = 1; - int nStep = 2; - int lc = (nDegreeNum / 2) / 8; - int resolve_idx = 0; - for (;;) - { - resolve_idx += 7; - index += nStep * 7; - nStep *= 8; - if (lc <= 8) - break; - lc /= 8; - } - int k = index + nStep * (lc - 2); - int j; - float r1, r2; - for (j = lc - 2; j >= 0; j--) - { - r1 = ptrSrc[src + k]; - r2 = ptrSrc[src + k + nStep]; - ptrSrc[src + k] = r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin; - ptrSrc[src + k + nStep] = r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin; - k -= nStep; - } - for (; lc <= (nDegreeNum / 2) / 8; lc *= 8) - { - resolve_idx -= 7; - nStep /= 8; - index -= nStep * 7; - for (int i = 0; i < lc; i++) - { - k = i * (nStep * 8) + index + nStep * 6; - for ( j = 6; j >= 0; j -- ) - { - r1 = ptrSrc[src + k]; - r2 = ptrSrc[src + k + nStep]; - ptrSrc[src + k] = - r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin; - ptrSrc[src + k + nStep] = - r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin; - k -= nStep; - } - } - } - } - - static void eriFastIPLOT (float[] ptrSrc, int src, int nDegreeDCT) - { - int nDegreeNum = 1 << nDegreeDCT; - for (int i = 0; i < nDegreeNum; i += 2) - { - float r1 = ptrSrc[src + i]; - float r2 = ptrSrc[src + i + 1]; - ptrSrc[src + i] = 0.5f * (r1 + r2); - ptrSrc[src + i + 1] = 0.5f * (r1 - r2); - } - } - - static void eriFastILOT (float[] ptrDst, float[] ptrSrc1, int src1, float[] ptrSrc2, int src2, int nDegreeDCT) - { - int nDegreeNum = 1 << nDegreeDCT; - for (int i = 0; i < nDegreeNum; i += 2) - { - float r1 = ptrSrc1[src1 + i]; - float r2 = ptrSrc2[src2 + i + 1]; - ptrDst[i] = r1 + r2; - ptrDst[i + 1] = r1 - r2; - } - } - - static void eriFastDCT (float[] ptrDst, int dst, int nDstInterval, float[] ptrSrc, int src, float[] ptrWorkBuf, int work, int nDegreeDCT) - { - Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE)); - - if (nDegreeDCT == MIN_DCT_DEGREE) - { - float[] r32Buf = new float[4]; - r32Buf[0] = ptrSrc[src] + ptrSrc[src+3]; - r32Buf[2] = ptrSrc[src] - ptrSrc[src+3]; - r32Buf[1] = ptrSrc[src+1] + ptrSrc[src+2]; - r32Buf[3] = ptrSrc[src+1] - ptrSrc[src+2]; - - ptrDst[dst] = 0.5f * (r32Buf[0] + r32Buf[1]); - ptrDst[dst+nDstInterval * 2] = ERI_rCosPI4 * (r32Buf[0] - r32Buf[1]); - - r32Buf[2] = ERI_DCTofK2[0] * r32Buf[2]; - r32Buf[3] = ERI_DCTofK2[1] * r32Buf[3]; - - r32Buf[0] = r32Buf[2] + r32Buf[3]; - r32Buf[1] = ERI_r2CosPI4 * (r32Buf[2] - r32Buf[3]); - - r32Buf[1] -= r32Buf[0]; - - ptrDst[dst+nDstInterval] = r32Buf[0]; - ptrDst[dst+nDstInterval * 3] = r32Buf[1]; - } - else - { - uint i; - uint nDegreeNum = 1u << nDegreeDCT; - uint nHalfDegree = nDegreeNum >> 1; - for (i = 0; i < nHalfDegree; i++) - { - ptrWorkBuf[work+i] = ptrSrc[src+i] + ptrSrc[src + nDegreeNum - i - 1]; - ptrWorkBuf[work+i + nHalfDegree] = ptrSrc[src+i] - ptrSrc[src + nDegreeNum - i - 1]; - } - int nDstStep = nDstInterval << 1; - eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, work, ptrSrc, src, nDegreeDCT - 1); - - float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1]; - src = (int)(work+nHalfDegree); // ptrSrc = ptrWorkBuf + nHalfDegree; - dst += nDstInterval; // ptrDst += nDstInterval; - - for (i = 0; i < nHalfDegree; i++) - { - ptrWorkBuf[src + i] *= pDCTofK[i]; - } - - eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, src, ptrWorkBuf, work, nDegreeDCT - 1); - // eriFastDCT (ptrDst, nDstStep, ptrSrc, ptrWorkBuf, nDegreeDCT - 1); - - int ptrNext = dst; // within ptrDst; - for (i = 0; i < nHalfDegree; i++) - { - ptrDst[ptrNext] += ptrDst[ptrNext]; // *ptrNext += *ptrNext; - ptrNext += nDstStep; - } - ptrNext = dst; - for (i = 1; i < nHalfDegree; i ++) - { - ptrDst[ptrNext + nDstStep] -= ptrDst[ptrNext]; - ptrNext += nDstStep; - } - } - } - - static void eriFastIDCT (float[] ptrDst, float[] srcBuf, int ptrSrc, int nSrcInterval, float[] ptrWorkBuf, int nDegreeDCT) - { - Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE)); - - if (nDegreeDCT == MIN_DCT_DEGREE) - { - float[] r32Buf1 = new float[2]; - float[] r32Buf2 = new float[4]; - - r32Buf1[0] = srcBuf[ptrSrc]; - r32Buf1[1] = ERI_rCosPI4 * srcBuf[ptrSrc + nSrcInterval * 2]; - - r32Buf2[0] = r32Buf1[0] + r32Buf1[1]; - r32Buf2[1] = r32Buf1[0] - r32Buf1[1]; - - r32Buf1[0] = ERI_DCTofK2[0] * srcBuf[ptrSrc + nSrcInterval]; - r32Buf1[1] = ERI_DCTofK2[1] * srcBuf[ptrSrc + nSrcInterval * 3]; - - r32Buf2[2] = r32Buf1[0] + r32Buf1[1]; - r32Buf2[3] = ERI_r2CosPI4 * (r32Buf1[0] - r32Buf1[1]); - - r32Buf2[3] -= r32Buf2[2]; - - ptrDst[0] = r32Buf2[0] + r32Buf2[2]; - ptrDst[3] = r32Buf2[0] - r32Buf2[2]; - ptrDst[1] = r32Buf2[1] + r32Buf2[3]; - ptrDst[2] = r32Buf2[1] - r32Buf2[3]; - } - else - { - uint nDegreeNum = 1u << nDegreeDCT; - uint nHalfDegree = nDegreeNum >> 1; - int nSrcStep = nSrcInterval << 1; - eriFastIDCT (ptrDst, srcBuf, ptrSrc, nSrcStep, ptrWorkBuf, nDegreeDCT - 1); - - float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1]; - int pOddDst = (int)nHalfDegree; // within ptrDst - int ptrNext = ptrSrc + nSrcInterval; // within srcBuf - - uint i; - for (i = 0; i < nHalfDegree; i++) - { - ptrWorkBuf[i] = srcBuf[ptrNext] * pDCTofK[i]; - ptrNext += nSrcStep; - } - - eriFastDCT (ptrDst, pOddDst, 1, ptrWorkBuf, 0, ptrWorkBuf, (int)nHalfDegree, nDegreeDCT - 1); - // eriFastDCT(pOddDst, 1, ptrWorkBuf, (ptrWorkBuf + nHalfDegree), nDegreeDCT - 1); - - for (i = 0; i < nHalfDegree; i ++) - { - ptrDst[pOddDst + i] += ptrDst[pOddDst + i]; - } - - for (i = 1; i < nHalfDegree; i++) - { - ptrDst[pOddDst + i] -= ptrDst[pOddDst + i - 1]; - } - float[] r32Buf = new float[4]; - uint nQuadDegree = nHalfDegree >> 1; - for (i = 0; i < nQuadDegree; i++) - { - r32Buf[0] = ptrDst[i] + ptrDst[nHalfDegree + i]; - r32Buf[3] = ptrDst[i] - ptrDst[nHalfDegree + i]; - r32Buf[1] = ptrDst[nHalfDegree - 1 - i] + ptrDst[nDegreeNum - 1 - i]; - r32Buf[2] = ptrDst[nHalfDegree - 1 - i] - ptrDst[nDegreeNum - 1 - i]; - - ptrDst[i] = r32Buf[0]; - ptrDst[nHalfDegree - 1 - i] = r32Buf[1]; - ptrDst[nHalfDegree + i] = r32Buf[2]; - ptrDst[nDegreeNum - 1 - i] = r32Buf[3]; - } - } - } - - void eriRevolve2x2 (float[] buf1, int ptrBuf1, float[] buf2, int ptrBuf2, float rSin, float rCos, int nStep, int nCount) - { - for (int i = 0; i < nCount; i++) - { - float r1 = buf1[ptrBuf1]; - float r2 = buf2[ptrBuf2]; - - buf1[ptrBuf1] = r1 * rCos - r2 * rSin; - buf2[ptrBuf2] = r1 * rSin + r2 * rCos; - - ptrBuf1 += nStep; - ptrBuf2 += nStep; - } - } - } } diff --git a/ArcFormats/EriReader.cs b/ArcFormats/EriReader.cs new file mode 100644 index 00000000..8d7f99e0 --- /dev/null +++ b/ArcFormats/EriReader.cs @@ -0,0 +1,1375 @@ +// ***************************************************************************** +// E R I S A - L i b r a r y +// ----------------------------------------------------------------------------- +// Copyright (C) 2002-2004 Leshade Entis, Entis-soft. All rights reserved. +// ***************************************************************************** +// +// C# port by morkt +// + +using System; +using System.Diagnostics; +using System.IO; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace GameRes.Formats.Entis +{ + internal class EriReader + { + EriMetaData m_info; + byte[] m_output; + ERISADecodeContext m_context; + int m_dst; + + uint m_nBlockSize; + uint m_nBlockArea; + uint m_nBlockSamples; + uint m_nChannelCount; + uint m_nWidthBlocks; + uint m_nHeightBlocks; + + int m_dwBytesPerLine; + uint m_dwClippedPixel; + + int m_ptrDstBlock; + int m_nDstLineBytes; + int m_nDstPixelBytes; + uint m_nDstWidth; + uint m_nDstHeight; + uint m_fdwDecFlags; + + // buffers for lossless encoding + byte[] m_ptrOperations; + sbyte[] m_ptrColumnBuf; + sbyte[] m_ptrLineBuf; + sbyte[] m_ptrDecodeBuf; + sbyte[] m_ptrArrangeBuf; + int[] m_pArrangeTable = new int[4]; + + HuffmanTree m_pHuffmanTree; + + PtrProcedure[] m_pfnColorOperation; + + public byte[] Data { get { return m_output; } } + public PixelFormat Format { get; private set; } + public int Stride { get { return Math.Abs (m_dwBytesPerLine); } } + public BitmapPalette Palette { get; private set; } + + public EriReader (Stream stream, EriMetaData info, Color[] palette) + { + m_info = info; + if (CvType.Lossless_ERI == m_info.Transformation) + InitializeLossless(); + else if (CvType.LOT_ERI == m_info.Transformation + || CvType.DCT_ERI == m_info.Transformation) + InitializeLossy(); + else + throw new NotSupportedException ("Not supported ERI compression"); + if (null != palette) + Palette = new BitmapPalette (palette); + CreateImageBuffer(); + m_context.AttachInputFile (stream); + + m_pfnColorOperation = new PtrProcedure[0x10] + { + ColorOperation0000, + ColorOperation0000, + ColorOperation0000, + ColorOperation0000, + ColorOperation0000, + ColorOperation0101, + ColorOperation0110, + ColorOperation0111, + ColorOperation0000, + ColorOperation1001, + ColorOperation1010, + ColorOperation1011, + ColorOperation0000, + ColorOperation1101, + ColorOperation1110, + ColorOperation1111 + }; + } + + private void InitializeLossless () + { + switch (m_info.Architecture) + { + case EriCode.Nemesis: + throw new NotSupportedException ("Not supported ERI compression"); + case EriCode.RunlengthHuffman: + case EriCode.RunlengthGamma: + break; + default: + throw new InvalidFormatException(); + } + if (0 == m_info.BlockingDegree) + throw new InvalidFormatException(); + + switch (m_info.FormatType & (int)EriImage.TypeMask) + { + case (int)EriImage.RGB: + if (m_info.BPP <= 8) + m_nChannelCount = 1; + else if (0 == (m_info.FormatType & (int)EriImage.WithAlpha)) + m_nChannelCount = 3; + else + m_nChannelCount = 4; + break; + + case (int)EriImage.Gray: + m_nChannelCount = 1; + break; + + default: + throw new InvalidFormatException(); + } + + m_nBlockSize = (uint) (1 << m_info.BlockingDegree); + m_nBlockArea = (uint) (1 << (m_info.BlockingDegree * 2)); + m_nBlockSamples = m_nBlockArea * m_nChannelCount; + m_nWidthBlocks = (uint)((m_info.Width + m_nBlockSize - 1) >> m_info.BlockingDegree); + m_nHeightBlocks = (uint)((m_info.Height + m_nBlockSize - 1) >> m_info.BlockingDegree); + + m_ptrOperations = new byte[m_nWidthBlocks * m_nHeightBlocks]; + m_ptrColumnBuf = new sbyte[m_nBlockSize * m_nChannelCount]; + m_ptrLineBuf = new sbyte[m_nChannelCount * (m_nWidthBlocks << m_info.BlockingDegree)]; + m_ptrDecodeBuf = new sbyte[m_nBlockSamples]; + m_ptrArrangeBuf = new sbyte[m_nBlockSamples]; + + InitializeArrangeTable(); + if (0x00020200 == m_info.Version) + { + if (EriCode.RunlengthHuffman == m_info.Architecture) + { + m_pHuffmanTree = new HuffmanTree(); + } + /* + else if (EriCode.Nemesis == m_info.Architecture) + { + m_pProbERISA = new ERISA_PROB_MODEL ; + } + */ + } + if (EriCode.RunlengthHuffman == m_info.Architecture) + m_context = new HuffmanDecodeContext (0x10000); + else + m_context = new RLEDecodeContext (0x10000); + } + + private void InitializeLossy () + { + throw new NotImplementedException ("Lossy ERI compression not implemented"); + } + + int[] m_ptrTable; + + void InitializeArrangeTable () + { + uint i, j, k, l, m; + + m_ptrTable = new int[m_nBlockSamples * 4]; + m_pArrangeTable[0] = 0; + m_pArrangeTable[1] = (int)m_nBlockSamples; + m_pArrangeTable[2] = (int)m_nBlockSamples * 2; + m_pArrangeTable[3] = (int)m_nBlockSamples * 3; + + int ptrNext = m_pArrangeTable[0]; + for (i = 0; i < m_nBlockSamples; ++i) + { + m_ptrTable[ptrNext+i] = (int)i; + } + + ptrNext = m_pArrangeTable[1]; + l = 0; + for (i = 0; i < m_nChannelCount; i++) + { + for (j = 0; j < m_nBlockSize; j++) + { + m = l + j; + for (k = 0; k < m_nBlockSize; k++) + { + m_ptrTable[ptrNext++] = (int)m; + m += m_nBlockSize; + } + } + l += m_nBlockArea; + } + ptrNext = m_pArrangeTable[2]; + for (i = 0; i < m_nBlockArea; i++) + { + k = i; + for (j = 0; j < m_nChannelCount; j++) + { + m_ptrTable[ptrNext++] = (int)k; + k += m_nBlockArea; + } + } + ptrNext = m_pArrangeTable[3]; + for (i = 0; i < m_nBlockSize; i++) + { + l = i; + for (j = 0; j < m_nBlockSize; j++) + { + m = l; + l += m_nBlockSize; + for (k = 0; k < m_nChannelCount; k++) + { + m_ptrTable[ptrNext++] = (int)m; + m += m_nBlockArea; + } + } + } + } + + private void CreateImageBuffer () + { + uint stride = ((m_info.Width * (uint)m_info.BPP / 8u) + 0x03u) & ~0x03u; + uint image_bytes = stride * m_info.Height; + m_output = new byte[image_bytes]; + m_dwBytesPerLine = (int)stride; + m_dwClippedPixel = 0; + if (!m_info.VerticalFlip) + { + m_dst = ((int)m_info.Height - 1) * m_dwBytesPerLine; + m_dwBytesPerLine = -m_dwBytesPerLine; + } + else + { + m_dst = 0; + } + } + + public void DecodeImage () + { + if (CvType.Lossless_ERI == m_info.Transformation) + DecodeLosslessImage (m_context as RLEDecodeContext); + else + DecodeLossyImage (m_context as HuffmanDecodeContext); + } + + private delegate void PtrProcedure (); + + private void DecodeLosslessImage (RLEDecodeContext context) + { + context.FlushBuffer(); + + uint nERIVersion = context.GetNBits (8); + uint fOpTable = context.GetNBits (8); + uint fEncodeType = context.GetNBits (8); + uint nBitCount = context.GetNBits (8); + + if (0 != fOpTable || 0 != (fEncodeType & 0xFE)) + { + throw new InvalidFormatException(); + } + switch (nERIVersion) + { + case 1: + if (nBitCount != 0) + throw new InvalidFormatException(); + break; + case 8: + if (nBitCount != 8) + throw new InvalidFormatException(); + break; + case 16: + if ((nBitCount != 8) || (fEncodeType != 0)) + throw new InvalidFormatException(); + break; + default: + throw new InvalidFormatException(); + } + m_nDstPixelBytes = m_info.BPP >> 3; + m_nDstLineBytes = m_dwBytesPerLine; + var pfnRestoreFunc = GetLLRestoreFunc (m_info.FormatType, m_info.BPP); + if (null == pfnRestoreFunc) + throw new InvalidFormatException(); + /* + if (EriCode.Nemesis == m_info.Architecture) + { + Debug.Assert (m_pProbERISA != null); + m_pProbERISA.Initialize(); + } + */ + int i; + int ptrNextOperation = 0; // index within m_ptrOperations + if ((0 != (fEncodeType & 0x01)) && (m_nChannelCount >= 3)) + { + Debug.Assert (m_info.Architecture != EriCode.Nemesis); + int nAllBlockCount = (int)(m_nWidthBlocks * m_nHeightBlocks); + for (i = 0; i < nAllBlockCount; i++) + { + if (EriCode.RunlengthGamma == m_info.Architecture) + { + m_ptrOperations[i] = (byte)(context.GetNBits(4) | 0xC0); + } + else + { + Debug.Assert (EriCode.RunlengthHuffman == m_info.Architecture); + m_ptrOperations[i] = (byte)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree); + } + } + } + if (context.GetABit() != 0) + throw new InvalidFormatException(); + + if (EriCode.RunlengthGamma == m_info.Architecture) + { + if (0 != (fEncodeType & 0x01)) + { + context.InitGammaContext(); + } + } + else if (EriCode.RunlengthHuffman == m_info.Architecture) + { + (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); + } + /* + else + { + Debug.Assert (EriCode.Nemesis == m_info.Architecture); + context.PrepareToDecodeERISACode(); + } + */ + int nWidthSamples = (int)(m_nChannelCount * m_nWidthBlocks * m_nBlockSize); + for (i = 0; i < nWidthSamples; ++i) + m_ptrLineBuf[i] = 0; + + int nAllBlockLines = (int)(m_nBlockSize * m_nChannelCount); + int nLeftHeight = (int)m_info.Height; + + for (int nPosY = 0; nPosY < (int) m_nHeightBlocks; ++nPosY) + { + int nColumnBufSamples = (int)(m_nBlockSize * m_nChannelCount); + for (i = 0; i < nColumnBufSamples; ++i) + m_ptrColumnBuf[i] = 0; + + m_ptrDstBlock = m_dst + nPosY * m_dwBytesPerLine * (int)m_nBlockSize; + m_nDstHeight = m_nBlockSize; + if ((int)m_nDstHeight > nLeftHeight) + { + m_nDstHeight = (uint)nLeftHeight; + } + int nLeftWidth = (int)m_info.Width; + int ptrNextLineBuf = 0; // m_ptrLineBuf; + + for (int nPosX = 0; nPosX < (int)m_nWidthBlocks; ++nPosX) + { + m_nDstWidth = Math.Min (m_nBlockSize, (uint)nLeftWidth); + + uint dwOperationCode; + if (m_nChannelCount >= 3) + { + if (0 != (fEncodeType & 1)) + { + dwOperationCode = m_ptrOperations[ptrNextOperation++]; + } + else if (m_info.Architecture == EriCode.RunlengthHuffman) + { + dwOperationCode = (uint)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree); + } + /* + else if (m_info.Architecture == EriCode.Nemesis) + { + dwOperationCode = context.DecodeERISACode (m_pProbERISA); + } + */ + else + { + Debug.Assert (EriCode.RunlengthGamma == m_info.Architecture); + dwOperationCode = context.GetNBits (4) | 0xC0; + context.InitGammaContext(); + } + } + else + { + if ((int)EriImage.Gray == m_info.FormatType) + { + dwOperationCode = 0xC0; + } + else + { + dwOperationCode = 0x00; + } + if (0 == (fEncodeType & 0x01) && m_info.Architecture == EriCode.RunlengthGamma) + { + context.InitGammaContext(); + } + } + if (context.DecodeBytes (m_ptrArrangeBuf, m_nBlockSamples) < m_nBlockSamples) + { + throw new InvalidFormatException(); + } + PerformOperation (dwOperationCode, nAllBlockLines, m_ptrLineBuf, ptrNextLineBuf); + ptrNextLineBuf += nColumnBufSamples; + + pfnRestoreFunc(); + + m_ptrDstBlock += (int)(m_nDstPixelBytes * m_nBlockSize); + nLeftWidth -= (int) m_nBlockSize; + } + nLeftHeight -= (int)m_nBlockSize; + } + } + + private void DecodeLossyImage (HuffmanDecodeContext context) + { + throw new NotImplementedException ("Lossy ERI compression not implemented"); + } + + void PerformOperation (uint dwOpCode, int nAllBlockLines, sbyte[] pNextLineBuf, int iNextLineIdx ) + { + int i, j, k; + uint nArrangeCode, nColorOperation, nDiffOperation; + nColorOperation = dwOpCode & 0x0F; + nArrangeCode = (dwOpCode >> 4) & 0x03; + nDiffOperation = (dwOpCode >> 6) & 0x03; + + if (0 == nArrangeCode) + { + Buffer.BlockCopy (m_ptrArrangeBuf, 0, m_ptrDecodeBuf, 0, (int)m_nBlockSamples); + if (0 == dwOpCode) + { + return; + } + } + else + { + int pArrange = m_pArrangeTable[nArrangeCode]; + for (i = 0; i < (int)m_nBlockSamples; i++) + { + m_ptrDecodeBuf[m_ptrTable[pArrange + i]] = m_ptrArrangeBuf[i]; + } + } + m_pfnColorOperation[nColorOperation](); + + int ptrNextBuf = 0; // m_ptrDecodeBuf + int ptrNextColBuf = 0; // m_ptrColumnBuf + if (0 != (nDiffOperation & 0x01)) + { + for (i = 0; i < nAllBlockLines; i++) + { + sbyte nLastVal = m_ptrColumnBuf[ptrNextColBuf]; + for (j = 0; j < (int)m_nBlockSize; j++) + { + nLastVal += m_ptrDecodeBuf[ptrNextBuf]; + m_ptrDecodeBuf[ptrNextBuf++] = nLastVal; + } + m_ptrColumnBuf[ptrNextColBuf++] = nLastVal; + } + } + else + { + for (i = 0; i < nAllBlockLines; i ++) + { + m_ptrColumnBuf[ptrNextColBuf++] = m_ptrDecodeBuf[ptrNextBuf + m_nBlockSize - 1]; + ptrNextBuf += (int)m_nBlockSize; + } + } + int iNextDst = 0; + for (k = 0; k < (int)m_nChannelCount; k++) + { + sbyte[] ptrLastLine = pNextLineBuf; + int idxLastLine = iNextLineIdx; + for (i = 0; i < (int)m_nBlockSize; i++) + { + for (j = 0; j < (int)m_nBlockSize; j++) + { + m_ptrDecodeBuf[iNextDst+j] += ptrLastLine[idxLastLine+j]; + } + ptrLastLine = m_ptrDecodeBuf; + idxLastLine = iNextDst; + iNextDst += (int)m_nBlockSize; + } + Buffer.BlockCopy (ptrLastLine, idxLastLine, pNextLineBuf, iNextLineIdx, (int)m_nBlockSize); + iNextLineIdx += (int)m_nBlockSize; + } + } + + PtrProcedure GetLLRestoreFunc (int fdwFormatType, int dwBitsPerPixel) + { + switch (dwBitsPerPixel) + { + case 32: + if ((int)EriImage.RGBA == fdwFormatType) + { + Format = PixelFormats.Bgra32; + return RestoreRGBA32; + } + Format = PixelFormats.Bgr32; + return RestoreRGB24; + case 24: + Format = PixelFormats.Bgr24; + return RestoreRGB24; + case 16: + Format = PixelFormats.Bgr555; + return RestoreRGB16; + case 8: + if (null == Palette) + Format = PixelFormats.Gray8; + else + Format = PixelFormats.Indexed8; + return RestoreGray8; + } + return null; + } + + void RestoreRGBA32 () + { + int ptrDstLine = m_ptrDstBlock; + int ptrSrcLine = 0; //m_ptrDecodeBuf; + int nBlockSamples = (int)m_nBlockArea; + int nBlockSamplesX3 = nBlockSamples * 3; + + for (uint y = 0; y < m_nDstHeight; y++) + { + int ptrDstNext = ptrDstLine; + int ptrSrcNext = ptrSrcLine; + + for (uint x = 0; x < m_nDstWidth; x++) + { + m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext]; + m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples]; + m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2]; + m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamplesX3]; + ptrSrcNext ++; + } + ptrSrcLine += (int)m_nBlockSize; + ptrDstLine += m_nDstLineBytes; + } + } + + void RestoreRGB24() + { + int ptrDstLine = m_ptrDstBlock; + int ptrSrcLine = 0; //m_ptrDecodeBuf; + int nBytesPerPixel = m_nDstPixelBytes; + int nBlockSamples = (int)m_nBlockArea; + + for (uint y = 0; y < m_nDstHeight; y++) + { + int ptrDstNext = ptrDstLine; + int ptrSrcNext = ptrSrcLine; + + for (uint x = 0; x < m_nDstWidth; x++) + { + m_output[ptrDstNext] = (byte)m_ptrDecodeBuf[ptrSrcNext]; + m_output[ptrDstNext+1] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples]; + m_output[ptrDstNext+2] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2]; + ptrSrcNext ++; + ptrDstNext += nBytesPerPixel; + } + ptrSrcLine += (int)m_nBlockSize; + ptrDstLine += m_nDstLineBytes; + } + } + + void RestoreRGB16() + { + int ptrDstLine = m_ptrDstBlock; + int ptrSrcLine = 0; //m_ptrDecodeBuf; + int nBlockSamples = (int)m_nBlockArea; + + for (uint y = 0; y < m_nDstHeight; y++) + { + int ptrDstNext = ptrDstLine; + int ptrSrcNext = ptrSrcLine; + + for (uint x = 0; x < m_nDstWidth; x++) + { + int word = (m_ptrDecodeBuf[ptrSrcNext] & 0x1F) | + ((m_ptrDecodeBuf[ptrSrcNext + nBlockSamples] & 0x1F) << 5) | + ((m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2] & 0x1F) << 10); + m_output[ptrDstNext++] = (byte)word; + m_output[ptrDstNext++] = (byte)(word >> 8); + ptrSrcNext ++; + } + ptrSrcLine += (int)m_nBlockSize; + ptrDstLine += m_nDstLineBytes; + } + } + + void RestoreGray8() + { + int ptrDstLine = m_ptrDstBlock; + int ptrSrcLine = 0; //m_ptrDecodeBuf; + + for (uint y = 0; y < m_nDstHeight; y++) + { + Buffer.BlockCopy (m_ptrDecodeBuf, ptrSrcLine, m_output, ptrDstLine, (int)m_nDstWidth); + ptrSrcLine += (int)m_nBlockSize; + ptrDstLine += m_nDstLineBytes; + } + } + + void ColorOperation0000 () + { + } + + void ColorOperation0101 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext]; + m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation0110 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea * 2; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext]; + m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation0111 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext]; + m_ptrDecodeBuf[ptrNext + nChSamples] += nBase; + m_ptrDecodeBuf[ptrNext + nChSamples * 2] += nBase; + ptrNext ++; + } + while (0 != --nRepCount); + } + + void ColorOperation1001 () + { + int ptrNext = 0; //m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; + m_ptrDecodeBuf[ptrNext++] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation1010 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; + m_ptrDecodeBuf[ptrNext++ + nChSamples * 2] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation1011 () + { + int ptrNext = 0; //m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; + m_ptrDecodeBuf[ptrNext] += nBase; + m_ptrDecodeBuf[ptrNext + nChSamples * 2] += nBase; + ptrNext ++; + } + while (0 != --nRepCount); + } + + void ColorOperation1101 () + { + int ptrNext = 0; //m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea * 2; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; + m_ptrDecodeBuf[ptrNext++] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation1110 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples * 2]; + m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; + } + while (0 != --nRepCount); + } + + void ColorOperation1111 () + { + int ptrNext = 0; // m_ptrDecodeBuf; + uint nChSamples = m_nBlockArea; + uint nRepCount = m_nBlockArea; + do + { + sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples * 2]; + m_ptrDecodeBuf[ptrNext] += nBase; + m_ptrDecodeBuf[ptrNext + nChSamples] += nBase; + ptrNext ++; + } + while (0 != --nRepCount); + } + } + + internal static class Erina + { + public const int CodeFlag = int.MinValue; + public const int HuffmanEscape = 0x7FFFFFFF; + public const int HuffmanNull = 0x8000; + public const int HuffmanMax = 0x4000; + public const int HuffmanRoot = 0x200; + }; + + internal class HuffmanNode + { + public ushort Weight; + public ushort Parent; + public int ChildCode; + + public void CopyFrom (HuffmanNode other) + { + this.Weight = other.Weight; + this.Parent = other.Parent; + this.ChildCode = other.ChildCode; + } + } + + internal class HuffmanTree + { + public HuffmanNode[] m_hnTree = new HuffmanNode[0x201]; + public int[] m_iSymLookup = new int[0x100]; + public int m_iEscape; + public int m_iTreePointer; + + public HuffmanTree () + { + Initialize(); + } + + public void Initialize () + { + for (int i = 0; i < 0x201; i++) + { + m_hnTree[i] = new HuffmanNode(); + } + for (int i = 0; i < 0x100; i++) + { + m_iSymLookup[i] = (int)Erina.HuffmanNull; + } + m_iEscape = (int)Erina.HuffmanNull; + m_iTreePointer = (int)Erina.HuffmanRoot; + m_hnTree[Erina.HuffmanRoot].Weight = 0; + m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull; + m_hnTree[Erina.HuffmanRoot].ChildCode = Erina.HuffmanNull; + } + + public void IncreaseOccuredCount (int iEntry) + { + m_hnTree[iEntry].Weight++; + Normalize (iEntry); + if (m_hnTree[Erina.HuffmanRoot].Weight >= Erina.HuffmanMax) + { + HalfAndRebuild(); + } + } + + private void RecountOccuredCount (int iParent) + { + int iChild = m_hnTree[iParent].ChildCode; + m_hnTree[iParent].Weight = (ushort)(m_hnTree[iChild].Weight + m_hnTree[iChild + 1].Weight); + } + + private void Normalize (int iEntry) + { + while (iEntry < Erina.HuffmanRoot) + { + int iSwap = iEntry + 1; + ushort weight = m_hnTree[iEntry].Weight; + while (iSwap < Erina.HuffmanRoot) + { + if (m_hnTree[iSwap].Weight >= weight) + break; + ++iSwap; + } + if (iEntry == --iSwap) + { + iEntry = m_hnTree[iEntry].Parent; + RecountOccuredCount (iEntry); + continue; + } + int iChild, nCode; + if (0 == (m_hnTree[iEntry].ChildCode & Erina.CodeFlag)) + { + iChild = m_hnTree[iEntry].ChildCode; + m_hnTree[iChild].Parent = (ushort)iSwap; + m_hnTree[iChild + 1].Parent = (ushort)iSwap; + } + else + { + nCode = m_hnTree[iEntry].ChildCode & ~Erina.CodeFlag; + if (nCode != Erina.HuffmanEscape) + m_iSymLookup[nCode & 0xFF] = iSwap; + else + m_iEscape = iSwap; + } + if (0 == (m_hnTree[iSwap].ChildCode & Erina.CodeFlag)) + { + iChild = m_hnTree[iSwap].ChildCode; + m_hnTree[iChild].Parent = (ushort)iEntry; + m_hnTree[iChild+1].Parent = (ushort)iEntry; + } + else + { + nCode = m_hnTree[iSwap].ChildCode & ~Erina.CodeFlag; + if (nCode != Erina.HuffmanEscape) + m_iSymLookup[nCode & 0xFF] = iEntry; + else + m_iEscape = iEntry; + } + var node = m_hnTree[iSwap]; // XXX + ushort iEntryParent = m_hnTree[iEntry].Parent; + ushort iSwapParent = m_hnTree[iSwap].Parent; + + m_hnTree[iSwap] = m_hnTree[iEntry]; + m_hnTree[iEntry] = node; + m_hnTree[iSwap].Parent = iSwapParent; + m_hnTree[iEntry].Parent = iEntryParent; + + RecountOccuredCount (iSwapParent); + iEntry = iSwapParent; + } + } + + public void AddNewEntry (int nNewCode) + { + if (m_iTreePointer > 0) + { + m_iTreePointer -= 2; + int i = m_iTreePointer; + var phnNew = m_hnTree[i]; + phnNew.Weight = 1; + phnNew.ChildCode = Erina.CodeFlag | nNewCode; + m_iSymLookup[nNewCode & 0xFF] = i ; + + var phnRoot = m_hnTree[Erina.HuffmanRoot]; + if (phnRoot.ChildCode != Erina.HuffmanNull) + { + var phnParent = m_hnTree[i + 2]; + var phnChild = m_hnTree[i + 1]; + phnChild.CopyFrom (phnParent); // m_hnTree[i + 1] = m_hnTree[i + 2]; + + if (0 != (phnChild.ChildCode & Erina.CodeFlag)) + { + int nCode = phnChild.ChildCode & ~Erina.CodeFlag; + if (nCode != Erina.HuffmanEscape) + m_iSymLookup[nCode & 0xFF] = i + 1; + else + m_iEscape = i + 1; + } + phnParent.Weight = (ushort)(phnNew.Weight + phnChild.Weight); + phnParent.Parent = phnChild.Parent; + phnParent.ChildCode = i; + + phnNew.Parent = phnChild.Parent = (ushort)(i + 2); + Normalize (i + 2); + } + else + { + phnNew.Parent = Erina.HuffmanRoot; + m_iEscape = i + 1; + var phnEscape = m_hnTree[m_iEscape]; + phnEscape.Weight = 1; + phnEscape.Parent = Erina.HuffmanRoot; + phnEscape.ChildCode = Erina.CodeFlag | Erina.HuffmanEscape; + + phnRoot.Weight = 2; + phnRoot.ChildCode = i; + } + } + else + { + int i = m_iTreePointer; + var phnEntry = m_hnTree[i]; + if (phnEntry.ChildCode == (Erina.CodeFlag | Erina.HuffmanEscape)) + { + phnEntry = m_hnTree[i + 1]; + } + phnEntry.ChildCode = Erina.CodeFlag | nNewCode; + } + } + + private void HalfAndRebuild () + { + int i; + int iNextEntry = Erina.HuffmanRoot; + for (i = Erina.HuffmanRoot - 1; i >= m_iTreePointer; i--) + { + if (0 != (m_hnTree[i].ChildCode & Erina.CodeFlag)) + { + m_hnTree[i].Weight = (ushort)((m_hnTree[i].Weight + 1) >> 1); + m_hnTree[iNextEntry--].CopyFrom (m_hnTree[i]); + } + } + ++iNextEntry; + + int iChild, nCode; + i = m_iTreePointer; + for (;;) + { + m_hnTree[i].CopyFrom (m_hnTree[iNextEntry]); + m_hnTree[i + 1].CopyFrom (m_hnTree[iNextEntry + 1]); + iNextEntry += 2; + var phnChild1 = m_hnTree[i]; + var phnChild2 = m_hnTree[i + 1]; + + if (0 == (phnChild1.ChildCode & Erina.CodeFlag)) + { + iChild = phnChild1.ChildCode; + m_hnTree[iChild].Parent = (ushort)i; + m_hnTree[iChild + 1].Parent = (ushort)i; + } + else + { + nCode = phnChild1.ChildCode & ~Erina.CodeFlag; + if (Erina.HuffmanEscape == nCode) + m_iEscape = i; + else + m_iSymLookup[nCode & 0xFF] = i; + } + if (0 == (phnChild2.ChildCode & Erina.CodeFlag)) + { + iChild = phnChild2.ChildCode; + m_hnTree[iChild].Parent = (ushort)(i + 1); + m_hnTree[iChild + 1].Parent = (ushort)(i + 1); + } + else + { + nCode = phnChild2.ChildCode & ~Erina.CodeFlag; + if (Erina.HuffmanEscape == nCode) + m_iEscape = i + 1; + else + m_iSymLookup[nCode & 0xFF] = i + 1; + } + ushort weight = (ushort)(phnChild1.Weight + phnChild2.Weight); + + if (iNextEntry <= Erina.HuffmanRoot) + { + int j = iNextEntry; + for (;;) + { + if (weight <= m_hnTree[j].Weight) + { + m_hnTree[j - 1].Weight = weight; + m_hnTree[j - 1].ChildCode = i; + break; + } + m_hnTree[j - 1].CopyFrom (m_hnTree[j]); + if (++j > Erina.HuffmanRoot) + { + m_hnTree[Erina.HuffmanRoot].Weight = weight; + m_hnTree[Erina.HuffmanRoot].ChildCode = i; + break; + } + } + --iNextEntry; + } + else + { + m_hnTree[Erina.HuffmanRoot].Weight = weight; + m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull; + m_hnTree[Erina.HuffmanRoot].ChildCode = i; + phnChild1.Parent = Erina.HuffmanRoot; + phnChild2.Parent = Erina.HuffmanRoot; + break; + } + i += 2; + } + } + } + + internal class RLEDecodeContext : ERISADecodeContext + { + protected int m_flgZero; + protected uint m_nLength; + + public RLEDecodeContext (uint nBufferingSize) : base (nBufferingSize) + { + } + + public void InitGammaContext () + { + m_flgZero = GetABit(); + m_nLength = 0; + } + + public override uint DecodeBytes (Array ptrDst, uint nCount) + { + return DecodeGammaCodeBytes (ptrDst as sbyte[], nCount); + } + + public uint DecodeGammaCodeBytes (sbyte[] ptrDst, uint nCount) + { + int dst = 0; + uint nDecoded = 0; + + if (m_nLength == 0) + { + m_nLength = (uint)GetGammaCode(); + if (0 == m_nLength) + { + return nDecoded; + } + } + for (;;) + { + uint nRepeat = Math.Min (m_nLength, nCount); + Debug.Assert (nRepeat > 0); + m_nLength -= nRepeat; + nCount -= nRepeat; + + if (0 == m_flgZero) + { + nDecoded += nRepeat; + do + { + ptrDst[dst++] = 0; + } + while (0 != --nRepeat); + } + else + { + do + { + sbyte nSign = (sbyte)GetABit(); + sbyte nCode = (sbyte)GetGammaCode(); + if (0 == nCode) + { + return nDecoded; + } + nDecoded ++; + ptrDst[dst++] = (sbyte)((nCode ^ nSign) - nSign); + } + while (0 != --nRepeat); + } + if (0 == nCount) + { + if (0 == m_nLength) + { + m_flgZero = ~m_flgZero; + } + return nDecoded; + } + m_flgZero = ~m_flgZero; + m_nLength = (uint) GetGammaCode(); + if (0 == m_nLength) + { + return nDecoded; + } + } + } + + protected int GetGammaCode() + { + if (!PrefetchBuffer()) + { + return 0; + } + m_nIntBufCount--; + uint dwIntBuf = m_dwIntBuffer; + m_dwIntBuffer <<= 1; + if (0 == (dwIntBuf & 0x80000000)) + { + return 1; + } + if (!PrefetchBuffer()) + { + return 0; + } + int nCode = 0; + if ((0 != (~m_dwIntBuffer & 0x55000000)) && (m_nIntBufCount >= 8)) + { + uint i = (m_dwIntBuffer >> 24) << 1; + nCode = nGammaCodeLookup[i]; + int nBitCount = nGammaCodeLookup[i + 1]; + Debug.Assert (nBitCount <= m_nIntBufCount); + Debug.Assert (nCode > 0); + m_nIntBufCount -= nBitCount; + m_dwIntBuffer <<= nBitCount; + return nCode; + } + int nBase = 2; + for (;;) + { + if (m_nIntBufCount >= 2) + { + dwIntBuf = m_dwIntBuffer; + m_dwIntBuffer <<= 2; + nCode = (int)(((uint)nCode << 1) | (dwIntBuf >> 31)); + m_nIntBufCount -= 2; + if (0 == (dwIntBuf & 0x40000000)) + { + return nCode + nBase; + } + nBase <<= 1; + } + else + { + if (!PrefetchBuffer()) + { + return 0; + } + nCode = (int)(((uint)nCode << 1) | (m_dwIntBuffer >> 31)); + m_nIntBufCount --; + m_dwIntBuffer <<= 1; + + if (!PrefetchBuffer()) + { + return 0; + } + dwIntBuf = m_dwIntBuffer; + m_nIntBufCount --; + m_dwIntBuffer <<= 1; + if (0 == (dwIntBuf & 0x80000000)) + { + return nCode + nBase; + } + nBase <<= 1; + } + } + } + + static readonly byte[] nGammaCodeLookup = new byte[0x200] + { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 8, 6, 8, 6, 8, 6, 8, 6, 16, 8, 0xff, 0xff, 17, 8, 0xff, 0xff, + 9, 6, 9, 6, 9, 6, 9, 6, 18, 8, 0xff, 0xff, 19, 8, 0xff, 0xff, + 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, + 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, + 10, 6, 10, 6, 10, 6, 10, 6, 20, 8, 0xff, 0xff, 21, 8, 0xff, 0xff, + 11, 6, 11, 6, 11, 6, 11, 6, 22, 8, 0xff, 0xff, 23, 8, 0xff, 0xff, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, + 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, + 12, 6, 12, 6, 12, 6, 12, 6, 24, 8, 0xff, 0xff, 25, 8, 0xff, 0xff, + 13, 6, 13, 6, 13, 6, 13, 6, 26, 8, 0xff, 0xff, 27, 8, 0xff, 0xff, + 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, + 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, + 14, 6, 14, 6, 14, 6, 14, 6, 28, 8, 0xff, 0xff, 29, 8, 0xff, 0xff, + 15, 6, 15, 6, 15, 6, 15, 6, 30, 8, 0xff, 0xff, 31, 8, 0xff, 0xff + }; + } + + internal class HuffmanDecodeContext : RLEDecodeContext + { + int m_dwERINAFlags; + HuffmanTree m_pLastHuffmanTree; + HuffmanTree[] m_ppHuffmanTree; + + // ERINAEncodingFlag + public const int efERINAOrder0 = 0x0000; + public const int efERINAOrder1 = 0x0001; + + public HuffmanDecodeContext (uint nBufferingSize) : base (nBufferingSize) + { + } + + public void PrepareToDecodeERINACode (int flags = efERINAOrder1) + { + int i; + if (null == m_ppHuffmanTree) + { + m_ppHuffmanTree = new HuffmanTree[0x101]; + } + m_dwERINAFlags = flags; + m_nLength = 0; + if (efERINAOrder0 == flags) + { + m_ppHuffmanTree[0] = new HuffmanTree(); + m_ppHuffmanTree[0x100] = new HuffmanTree(); + for (i = 1; i < 0x100; i++) + { + m_ppHuffmanTree[i] = m_ppHuffmanTree[0]; + } + } + else + { + for (i = 0; i < 0x101; i++) + { + m_ppHuffmanTree[i] = new HuffmanTree(); + } + } + m_pLastHuffmanTree = m_ppHuffmanTree[0]; + } + + public override uint DecodeBytes (Array ptrDst, uint nCount) + { + return DecodeErinaCodeBytes (ptrDst as sbyte[], nCount); + } + + public uint DecodeErinaCodeBytes (sbyte[] ptrDst, uint nCount) + { + var tree = m_pLastHuffmanTree; + int symbol, length; + uint i = 0; + if (m_nLength > 0) + { + length = (int)Math.Min (m_nLength, nCount); + m_nLength -= (uint)length; + do + { + ptrDst[i++] = 0; + } + while (0 != --length); + } + while (i < nCount) + { + symbol = GetHuffmanCode (tree); + if (Erina.HuffmanEscape == symbol) + { + break; + } + ptrDst[i++] = (sbyte)symbol; + + if (0 == symbol) + { + length = GetLengthHuffman (m_ppHuffmanTree[0x100]); + if (Erina.HuffmanEscape == length) + { + break; + } + if (0 != --length) + { + m_nLength = (uint)length; + if (i + length > nCount) + { + length = (int)(nCount - i); + } + m_nLength -= (uint)length; + while (length > 0) + { + ptrDst[i++] = 0; + --length; + } + } + } + tree = m_ppHuffmanTree[symbol & 0xFF]; + } + m_pLastHuffmanTree = tree; + return i; + } + + private int GetLengthHuffman (HuffmanTree tree) + { + int nCode; + if (tree.m_iEscape != Erina.HuffmanNull) + { + int iEntry = Erina.HuffmanRoot; + int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode; + do + { + if (!PrefetchBuffer()) + { + return Erina.HuffmanEscape; + } + iEntry = iChild + (int)(m_dwIntBuffer >> 31); + iChild = tree.m_hnTree[iEntry].ChildCode; + m_dwIntBuffer <<= 1; + --m_nIntBufCount; + } + while (0 == (iChild & Erina.CodeFlag)); + + if ((m_dwERINAFlags != efERINAOrder0) || + (tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1)) + { + tree.IncreaseOccuredCount (iEntry); + } + nCode = iChild & ~Erina.CodeFlag; + if (nCode != Erina.HuffmanEscape) + { + return nCode ; + } + } + nCode = GetGammaCode(); + if (-1 == nCode) + { + return Erina.HuffmanEscape; + } + tree.AddNewEntry (nCode); + return nCode; + } + + public int GetHuffmanCode (HuffmanTree tree) + { + int nCode; + if (tree.m_iEscape != Erina.HuffmanNull) + { + int iEntry = Erina.HuffmanRoot; + int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode; + do + { + if (!PrefetchBuffer()) + { + return Erina.HuffmanEscape; + } + iEntry = iChild + (int)(m_dwIntBuffer >> 31); + iChild = tree.m_hnTree[iEntry].ChildCode; + m_dwIntBuffer <<= 1; + --m_nIntBufCount; + } + while (0 == (iChild & Erina.CodeFlag)); + + if ((m_dwERINAFlags != efERINAOrder0) || + (tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1)) + { + tree.IncreaseOccuredCount (iEntry); + } + nCode = iChild & ~Erina.CodeFlag; + if (nCode != Erina.HuffmanEscape) + { + return nCode; + } + } + nCode = (int)GetNBits (8); + tree.AddNewEntry (nCode); + + return nCode; + } + } +} diff --git a/ArcFormats/ImageERI.cs b/ArcFormats/ImageERI.cs index 98461f0a..68d3949a 100644 --- a/ArcFormats/ImageERI.cs +++ b/ArcFormats/ImageERI.cs @@ -25,10 +25,8 @@ using System; using System.ComponentModel.Composition; -using System.Diagnostics; using System.IO; using System.Windows.Media; -using System.Windows.Media.Imaging; using GameRes.Utility; namespace GameRes.Formats.Entis @@ -228,1368 +226,4 @@ namespace GameRes.Formats.Entis throw new NotImplementedException ("EriFormat.Write not implemented"); } } - -/***************************************************************************** - E R I S A - L i b r a r y - ----------------------------------------------------------------------------- - Copyright (C) 2002-2004 Leshade Entis, Entis-soft. All rights reserved. - *****************************************************************************/ - - internal class EriReader - { - EriMetaData m_info; - byte[] m_output; - ERISADecodeContext m_context; - int m_dst; - - uint m_nBlockSize; - uint m_nBlockArea; - uint m_nBlockSamples; - uint m_nChannelCount; - uint m_nWidthBlocks; - uint m_nHeightBlocks; - - int m_dwBytesPerLine; - uint m_dwClippedPixel; - - int m_ptrDstBlock; - int m_nDstLineBytes; - int m_nDstPixelBytes; - uint m_nDstWidth; - uint m_nDstHeight; - uint m_fdwDecFlags; - - // buffers for lossless encoding - byte[] m_ptrOperations; - sbyte[] m_ptrColumnBuf; - sbyte[] m_ptrLineBuf; - sbyte[] m_ptrDecodeBuf; - sbyte[] m_ptrArrangeBuf; - int[] m_pArrangeTable = new int[4]; - - HuffmanTree m_pHuffmanTree; - - PtrProcedure[] m_pfnColorOperation; - - public byte[] Data { get { return m_output; } } - public PixelFormat Format { get; private set; } - public int Stride { get { return Math.Abs (m_dwBytesPerLine); } } - public BitmapPalette Palette { get; private set; } - - public EriReader (Stream stream, EriMetaData info, Color[] palette) - { - m_info = info; - if (CvType.Lossless_ERI == m_info.Transformation) - InitializeLossless(); - else if (CvType.LOT_ERI == m_info.Transformation - || CvType.DCT_ERI == m_info.Transformation) - InitializeLossy(); - else - throw new NotSupportedException ("Not supported ERI compression"); - if (null != palette) - Palette = new BitmapPalette (palette); - CreateImageBuffer(); - m_context.AttachInputFile (stream); - - m_pfnColorOperation = new PtrProcedure[0x10] - { - ColorOperation0000, - ColorOperation0000, - ColorOperation0000, - ColorOperation0000, - ColorOperation0000, - ColorOperation0101, - ColorOperation0110, - ColorOperation0111, - ColorOperation0000, - ColorOperation1001, - ColorOperation1010, - ColorOperation1011, - ColorOperation0000, - ColorOperation1101, - ColorOperation1110, - ColorOperation1111 - }; - } - - private void InitializeLossless () - { - switch (m_info.Architecture) - { - case EriCode.Nemesis: - throw new NotSupportedException ("Not supported ERI compression"); - case EriCode.RunlengthHuffman: - case EriCode.RunlengthGamma: - break; - default: - throw new InvalidFormatException(); - } - if (0 == m_info.BlockingDegree) - throw new InvalidFormatException(); - - switch (m_info.FormatType & (int)EriImage.TypeMask) - { - case (int)EriImage.RGB: - if (m_info.BPP <= 8) - m_nChannelCount = 1; - else if (0 == (m_info.FormatType & (int)EriImage.WithAlpha)) - m_nChannelCount = 3; - else - m_nChannelCount = 4; - break; - - case (int)EriImage.Gray: - m_nChannelCount = 1; - break; - - default: - throw new InvalidFormatException(); - } - - m_nBlockSize = (uint) (1 << m_info.BlockingDegree); - m_nBlockArea = (uint) (1 << (m_info.BlockingDegree * 2)); - m_nBlockSamples = m_nBlockArea * m_nChannelCount; - m_nWidthBlocks = (uint)((m_info.Width + m_nBlockSize - 1) >> m_info.BlockingDegree); - m_nHeightBlocks = (uint)((m_info.Height + m_nBlockSize - 1) >> m_info.BlockingDegree); - - m_ptrOperations = new byte[m_nWidthBlocks * m_nHeightBlocks]; - m_ptrColumnBuf = new sbyte[m_nBlockSize * m_nChannelCount]; - m_ptrLineBuf = new sbyte[m_nChannelCount * (m_nWidthBlocks << m_info.BlockingDegree)]; - m_ptrDecodeBuf = new sbyte[m_nBlockSamples]; - m_ptrArrangeBuf = new sbyte[m_nBlockSamples]; - - InitializeArrangeTable(); - if (0x00020200 == m_info.Version) - { - if (EriCode.RunlengthHuffman == m_info.Architecture) - { - m_pHuffmanTree = new HuffmanTree(); - } - /* - else if (EriCode.Nemesis == m_info.Architecture) - { - m_pProbERISA = new ERISA_PROB_MODEL ; - } - */ - } - if (EriCode.RunlengthHuffman == m_info.Architecture) - m_context = new HuffmanDecodeContext (0x10000); - else - m_context = new RLEDecodeContext (0x10000); - } - - private void InitializeLossy () - { - throw new NotImplementedException ("Lossy ERI compression not implemented"); - } - - int[] m_ptrTable; - - void InitializeArrangeTable () - { - uint i, j, k, l, m; - - m_ptrTable = new int[m_nBlockSamples * 4]; - m_pArrangeTable[0] = 0; - m_pArrangeTable[1] = (int)m_nBlockSamples; - m_pArrangeTable[2] = (int)m_nBlockSamples * 2; - m_pArrangeTable[3] = (int)m_nBlockSamples * 3; - - int ptrNext = m_pArrangeTable[0]; - for (i = 0; i < m_nBlockSamples; ++i) - { - m_ptrTable[ptrNext+i] = (int)i; - } - - ptrNext = m_pArrangeTable[1]; - l = 0; - for (i = 0; i < m_nChannelCount; i++) - { - for (j = 0; j < m_nBlockSize; j++) - { - m = l + j; - for (k = 0; k < m_nBlockSize; k++) - { - m_ptrTable[ptrNext++] = (int)m; - m += m_nBlockSize; - } - } - l += m_nBlockArea; - } - ptrNext = m_pArrangeTable[2]; - for (i = 0; i < m_nBlockArea; i++) - { - k = i; - for (j = 0; j < m_nChannelCount; j++) - { - m_ptrTable[ptrNext++] = (int)k; - k += m_nBlockArea; - } - } - ptrNext = m_pArrangeTable[3]; - for (i = 0; i < m_nBlockSize; i++) - { - l = i; - for (j = 0; j < m_nBlockSize; j++) - { - m = l; - l += m_nBlockSize; - for (k = 0; k < m_nChannelCount; k++) - { - m_ptrTable[ptrNext++] = (int)m; - m += m_nBlockArea; - } - } - } - } - - private void CreateImageBuffer () - { - uint stride = ((m_info.Width * (uint)m_info.BPP / 8u) + 0x03u) & ~0x03u; - uint image_bytes = stride * m_info.Height; - m_output = new byte[image_bytes]; - m_dwBytesPerLine = (int)stride; - m_dwClippedPixel = 0; - if (!m_info.VerticalFlip) - { - m_dst = ((int)m_info.Height - 1) * m_dwBytesPerLine; - m_dwBytesPerLine = -m_dwBytesPerLine; - } - else - { - m_dst = 0; - } - } - - public void DecodeImage () - { - if (CvType.Lossless_ERI == m_info.Transformation) - DecodeLosslessImage (m_context as RLEDecodeContext); - else - DecodeLossyImage (m_context as HuffmanDecodeContext); - } - - private delegate void PtrProcedure (); - - private void DecodeLosslessImage (RLEDecodeContext context) - { - context.FlushBuffer(); - - uint nERIVersion = context.GetNBits (8); - uint fOpTable = context.GetNBits (8); - uint fEncodeType = context.GetNBits (8); - uint nBitCount = context.GetNBits (8); - - if (0 != fOpTable || 0 != (fEncodeType & 0xFE)) - { - throw new InvalidFormatException(); - } - switch (nERIVersion) - { - case 1: - if (nBitCount != 0) - throw new InvalidFormatException(); - break; - case 8: - if (nBitCount != 8) - throw new InvalidFormatException(); - break; - case 16: - if ((nBitCount != 8) || (fEncodeType != 0)) - throw new InvalidFormatException(); - break; - default: - throw new InvalidFormatException(); - } - m_nDstPixelBytes = m_info.BPP >> 3; - m_nDstLineBytes = m_dwBytesPerLine; - var pfnRestoreFunc = GetLLRestoreFunc (m_info.FormatType, m_info.BPP); - if (null == pfnRestoreFunc) - throw new InvalidFormatException(); - /* - if (EriCode.Nemesis == m_info.Architecture) - { - Debug.Assert (m_pProbERISA != null); - m_pProbERISA.Initialize(); - } - */ - int i; - int ptrNextOperation = 0; // index within m_ptrOperations - if ((0 != (fEncodeType & 0x01)) && (m_nChannelCount >= 3)) - { - Debug.Assert (m_info.Architecture != EriCode.Nemesis); - int nAllBlockCount = (int)(m_nWidthBlocks * m_nHeightBlocks); - for (i = 0; i < nAllBlockCount; i++) - { - if (EriCode.RunlengthGamma == m_info.Architecture) - { - m_ptrOperations[i] = (byte)(context.GetNBits(4) | 0xC0); - } - else - { - Debug.Assert (EriCode.RunlengthHuffman == m_info.Architecture); - m_ptrOperations[i] = (byte)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree); - } - } - } - if (context.GetABit() != 0) - throw new InvalidFormatException(); - - if (EriCode.RunlengthGamma == m_info.Architecture) - { - if (0 != (fEncodeType & 0x01)) - { - context.InitGammaContext(); - } - } - else if (EriCode.RunlengthHuffman == m_info.Architecture) - { - (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); - } - /* - else - { - Debug.Assert (EriCode.Nemesis == m_info.Architecture); - context.PrepareToDecodeERISACode(); - } - */ - int nWidthSamples = (int)(m_nChannelCount * m_nWidthBlocks * m_nBlockSize); - for (i = 0; i < nWidthSamples; ++i) - m_ptrLineBuf[i] = 0; - - int nAllBlockLines = (int)(m_nBlockSize * m_nChannelCount); - int nLeftHeight = (int)m_info.Height; - - for (int nPosY = 0; nPosY < (int) m_nHeightBlocks; ++nPosY) - { - int nColumnBufSamples = (int)(m_nBlockSize * m_nChannelCount); - for (i = 0; i < nColumnBufSamples; ++i) - m_ptrColumnBuf[i] = 0; - - m_ptrDstBlock = m_dst + nPosY * m_dwBytesPerLine * (int)m_nBlockSize; - m_nDstHeight = m_nBlockSize; - if ((int)m_nDstHeight > nLeftHeight) - { - m_nDstHeight = (uint)nLeftHeight; - } - int nLeftWidth = (int)m_info.Width; - int ptrNextLineBuf = 0; // m_ptrLineBuf; - - for (int nPosX = 0; nPosX < (int)m_nWidthBlocks; ++nPosX) - { - m_nDstWidth = Math.Min (m_nBlockSize, (uint)nLeftWidth); - - uint dwOperationCode; - if (m_nChannelCount >= 3) - { - if (0 != (fEncodeType & 1)) - { - dwOperationCode = m_ptrOperations[ptrNextOperation++]; - } - else if (m_info.Architecture == EriCode.RunlengthHuffman) - { - dwOperationCode = (uint)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree); - } - /* - else if (m_info.Architecture == EriCode.Nemesis) - { - dwOperationCode = context.DecodeERISACode (m_pProbERISA); - } - */ - else - { - Debug.Assert (EriCode.RunlengthGamma == m_info.Architecture); - dwOperationCode = context.GetNBits (4) | 0xC0; - context.InitGammaContext(); - } - } - else - { - if ((int)EriImage.Gray == m_info.FormatType) - { - dwOperationCode = 0xC0; - } - else - { - dwOperationCode = 0x00; - } - if (0 == (fEncodeType & 0x01) && m_info.Architecture == EriCode.RunlengthGamma) - { - context.InitGammaContext(); - } - } - if (context.DecodeBytes (m_ptrArrangeBuf, m_nBlockSamples) < m_nBlockSamples) - { - throw new InvalidFormatException(); - } - PerformOperation (dwOperationCode, nAllBlockLines, m_ptrLineBuf, ptrNextLineBuf); - ptrNextLineBuf += nColumnBufSamples; - - pfnRestoreFunc(); - - m_ptrDstBlock += (int)(m_nDstPixelBytes * m_nBlockSize); - nLeftWidth -= (int) m_nBlockSize; - } - nLeftHeight -= (int)m_nBlockSize; - } - } - - private void DecodeLossyImage (HuffmanDecodeContext context) - { - throw new NotImplementedException ("Lossy ERI compression not implemented"); - } - - void PerformOperation (uint dwOpCode, int nAllBlockLines, sbyte[] pNextLineBuf, int iNextLineIdx ) - { - int i, j, k; - uint nArrangeCode, nColorOperation, nDiffOperation; - nColorOperation = dwOpCode & 0x0F; - nArrangeCode = (dwOpCode >> 4) & 0x03; - nDiffOperation = (dwOpCode >> 6) & 0x03; - - if (0 == nArrangeCode) - { - Buffer.BlockCopy (m_ptrArrangeBuf, 0, m_ptrDecodeBuf, 0, (int)m_nBlockSamples); - if (0 == dwOpCode) - { - return; - } - } - else - { - int pArrange = m_pArrangeTable[nArrangeCode]; - for (i = 0; i < (int)m_nBlockSamples; i++) - { - m_ptrDecodeBuf[m_ptrTable[pArrange + i]] = m_ptrArrangeBuf[i]; - } - } - m_pfnColorOperation[nColorOperation](); - - int ptrNextBuf = 0; // m_ptrDecodeBuf - int ptrNextColBuf = 0; // m_ptrColumnBuf - if (0 != (nDiffOperation & 0x01)) - { - for (i = 0; i < nAllBlockLines; i++) - { - sbyte nLastVal = m_ptrColumnBuf[ptrNextColBuf]; - for (j = 0; j < (int)m_nBlockSize; j++) - { - nLastVal += m_ptrDecodeBuf[ptrNextBuf]; - m_ptrDecodeBuf[ptrNextBuf++] = nLastVal; - } - m_ptrColumnBuf[ptrNextColBuf++] = nLastVal; - } - } - else - { - for (i = 0; i < nAllBlockLines; i ++) - { - m_ptrColumnBuf[ptrNextColBuf++] = m_ptrDecodeBuf[ptrNextBuf + m_nBlockSize - 1]; - ptrNextBuf += (int)m_nBlockSize; - } - } - int iNextDst = 0; - for (k = 0; k < (int)m_nChannelCount; k++) - { - sbyte[] ptrLastLine = pNextLineBuf; - int idxLastLine = iNextLineIdx; - for (i = 0; i < (int)m_nBlockSize; i++) - { - for (j = 0; j < (int)m_nBlockSize; j++) - { - m_ptrDecodeBuf[iNextDst+j] += ptrLastLine[idxLastLine+j]; - } - ptrLastLine = m_ptrDecodeBuf; - idxLastLine = iNextDst; - iNextDst += (int)m_nBlockSize; - } - Buffer.BlockCopy (ptrLastLine, idxLastLine, pNextLineBuf, iNextLineIdx, (int)m_nBlockSize); - iNextLineIdx += (int)m_nBlockSize; - } - } - - PtrProcedure GetLLRestoreFunc (int fdwFormatType, int dwBitsPerPixel) - { - switch (dwBitsPerPixel) - { - case 32: - if ((int)EriImage.RGBA == fdwFormatType) - { - Format = PixelFormats.Bgra32; - return RestoreRGBA32; - } - Format = PixelFormats.Bgr32; - return RestoreRGB24; - case 24: - Format = PixelFormats.Bgr24; - return RestoreRGB24; - case 16: - Format = PixelFormats.Bgr555; - return RestoreRGB16; - case 8: - if (null == Palette) - Format = PixelFormats.Gray8; - else - Format = PixelFormats.Indexed8; - return RestoreGray8; - } - return null; - } - - void RestoreRGBA32 () - { - int ptrDstLine = m_ptrDstBlock; - int ptrSrcLine = 0; //m_ptrDecodeBuf; - int nBlockSamples = (int)m_nBlockArea; - int nBlockSamplesX3 = nBlockSamples * 3; - - for (uint y = 0; y < m_nDstHeight; y++) - { - int ptrDstNext = ptrDstLine; - int ptrSrcNext = ptrSrcLine; - - for (uint x = 0; x < m_nDstWidth; x++) - { - m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext]; - m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples]; - m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2]; - m_output[ptrDstNext++] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamplesX3]; - ptrSrcNext ++; - } - ptrSrcLine += (int)m_nBlockSize; - ptrDstLine += m_nDstLineBytes; - } - } - - void RestoreRGB24() - { - int ptrDstLine = m_ptrDstBlock; - int ptrSrcLine = 0; //m_ptrDecodeBuf; - int nBytesPerPixel = m_nDstPixelBytes; - int nBlockSamples = (int)m_nBlockArea; - - for (uint y = 0; y < m_nDstHeight; y++) - { - int ptrDstNext = ptrDstLine; - int ptrSrcNext = ptrSrcLine; - - for (uint x = 0; x < m_nDstWidth; x++) - { - m_output[ptrDstNext] = (byte)m_ptrDecodeBuf[ptrSrcNext]; - m_output[ptrDstNext+1] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples]; - m_output[ptrDstNext+2] = (byte)m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2]; - ptrSrcNext ++; - ptrDstNext += nBytesPerPixel; - } - ptrSrcLine += (int)m_nBlockSize; - ptrDstLine += m_nDstLineBytes; - } - } - - void RestoreRGB16() - { - int ptrDstLine = m_ptrDstBlock; - int ptrSrcLine = 0; //m_ptrDecodeBuf; - int nBlockSamples = (int)m_nBlockArea; - - for (uint y = 0; y < m_nDstHeight; y++) - { - int ptrDstNext = ptrDstLine; - int ptrSrcNext = ptrSrcLine; - - for (uint x = 0; x < m_nDstWidth; x++) - { - int word = (m_ptrDecodeBuf[ptrSrcNext] & 0x1F) | - ((m_ptrDecodeBuf[ptrSrcNext + nBlockSamples] & 0x1F) << 5) | - ((m_ptrDecodeBuf[ptrSrcNext + nBlockSamples * 2] & 0x1F) << 10); - m_output[ptrDstNext++] = (byte)word; - m_output[ptrDstNext++] = (byte)(word >> 8); - ptrSrcNext ++; - } - ptrSrcLine += (int)m_nBlockSize; - ptrDstLine += m_nDstLineBytes; - } - } - - void RestoreGray8() - { - int ptrDstLine = m_ptrDstBlock; - int ptrSrcLine = 0; //m_ptrDecodeBuf; - - for (uint y = 0; y < m_nDstHeight; y++) - { - Buffer.BlockCopy (m_ptrDecodeBuf, ptrSrcLine, m_output, ptrDstLine, (int)m_nDstWidth); - ptrSrcLine += (int)m_nBlockSize; - ptrDstLine += m_nDstLineBytes; - } - } - - void ColorOperation0000 () - { - } - - void ColorOperation0101 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext]; - m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation0110 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea * 2; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext]; - m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation0111 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext]; - m_ptrDecodeBuf[ptrNext + nChSamples] += nBase; - m_ptrDecodeBuf[ptrNext + nChSamples * 2] += nBase; - ptrNext ++; - } - while (0 != --nRepCount); - } - - void ColorOperation1001 () - { - int ptrNext = 0; //m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; - m_ptrDecodeBuf[ptrNext++] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation1010 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; - m_ptrDecodeBuf[ptrNext++ + nChSamples * 2] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation1011 () - { - int ptrNext = 0; //m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; - m_ptrDecodeBuf[ptrNext] += nBase; - m_ptrDecodeBuf[ptrNext + nChSamples * 2] += nBase; - ptrNext ++; - } - while (0 != --nRepCount); - } - - void ColorOperation1101 () - { - int ptrNext = 0; //m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea * 2; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples]; - m_ptrDecodeBuf[ptrNext++] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation1110 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples * 2]; - m_ptrDecodeBuf[ptrNext++ + nChSamples] += nBase; - } - while (0 != --nRepCount); - } - - void ColorOperation1111 () - { - int ptrNext = 0; // m_ptrDecodeBuf; - uint nChSamples = m_nBlockArea; - uint nRepCount = m_nBlockArea; - do - { - sbyte nBase = m_ptrDecodeBuf[ptrNext + nChSamples * 2]; - m_ptrDecodeBuf[ptrNext] += nBase; - m_ptrDecodeBuf[ptrNext + nChSamples] += nBase; - ptrNext ++; - } - while (0 != --nRepCount); - } - } - - internal static class Erina - { - public const int CodeFlag = int.MinValue; - public const int HuffmanEscape = 0x7FFFFFFF; - public const int HuffmanNull = 0x8000; - public const int HuffmanMax = 0x4000; - public const int HuffmanRoot = 0x200; - }; - - internal class HuffmanNode - { - public ushort Weight; - public ushort Parent; - public int ChildCode; - - public void CopyFrom (HuffmanNode other) - { - this.Weight = other.Weight; - this.Parent = other.Parent; - this.ChildCode = other.ChildCode; - } - } - - internal class HuffmanTree - { - public HuffmanNode[] m_hnTree = new HuffmanNode[0x201]; - public int[] m_iSymLookup = new int[0x100]; - public int m_iEscape; - public int m_iTreePointer; - - public HuffmanTree () - { - Initialize(); - } - - public void Initialize () - { - for (int i = 0; i < 0x201; i++) - { - m_hnTree[i] = new HuffmanNode(); - } - for (int i = 0; i < 0x100; i++) - { - m_iSymLookup[i] = (int)Erina.HuffmanNull; - } - m_iEscape = (int)Erina.HuffmanNull; - m_iTreePointer = (int)Erina.HuffmanRoot; - m_hnTree[Erina.HuffmanRoot].Weight = 0; - m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull; - m_hnTree[Erina.HuffmanRoot].ChildCode = Erina.HuffmanNull; - } - - public void IncreaseOccuredCount (int iEntry) - { - m_hnTree[iEntry].Weight++; - Normalize (iEntry); - if (m_hnTree[Erina.HuffmanRoot].Weight >= Erina.HuffmanMax) - { - HalfAndRebuild(); - } - } - - private void RecountOccuredCount (int iParent) - { - int iChild = m_hnTree[iParent].ChildCode; - m_hnTree[iParent].Weight = (ushort)(m_hnTree[iChild].Weight + m_hnTree[iChild + 1].Weight); - } - - private void Normalize (int iEntry) - { - while (iEntry < Erina.HuffmanRoot) - { - int iSwap = iEntry + 1; - ushort weight = m_hnTree[iEntry].Weight; - while (iSwap < Erina.HuffmanRoot) - { - if (m_hnTree[iSwap].Weight >= weight) - break; - ++iSwap; - } - if (iEntry == --iSwap) - { - iEntry = m_hnTree[iEntry].Parent; - RecountOccuredCount (iEntry); - continue; - } - int iChild, nCode; - if (0 == (m_hnTree[iEntry].ChildCode & Erina.CodeFlag)) - { - iChild = m_hnTree[iEntry].ChildCode; - m_hnTree[iChild].Parent = (ushort)iSwap; - m_hnTree[iChild + 1].Parent = (ushort)iSwap; - } - else - { - nCode = m_hnTree[iEntry].ChildCode & ~Erina.CodeFlag; - if (nCode != Erina.HuffmanEscape) - m_iSymLookup[nCode & 0xFF] = iSwap; - else - m_iEscape = iSwap; - } - if (0 == (m_hnTree[iSwap].ChildCode & Erina.CodeFlag)) - { - iChild = m_hnTree[iSwap].ChildCode; - m_hnTree[iChild].Parent = (ushort)iEntry; - m_hnTree[iChild+1].Parent = (ushort)iEntry; - } - else - { - nCode = m_hnTree[iSwap].ChildCode & ~Erina.CodeFlag; - if (nCode != Erina.HuffmanEscape) - m_iSymLookup[nCode & 0xFF] = iEntry; - else - m_iEscape = iEntry; - } - var node = m_hnTree[iSwap]; // XXX - ushort iEntryParent = m_hnTree[iEntry].Parent; - ushort iSwapParent = m_hnTree[iSwap].Parent; - - m_hnTree[iSwap] = m_hnTree[iEntry]; - m_hnTree[iEntry] = node; - m_hnTree[iSwap].Parent = iSwapParent; - m_hnTree[iEntry].Parent = iEntryParent; - - RecountOccuredCount (iSwapParent); - iEntry = iSwapParent; - } - } - - public void AddNewEntry (int nNewCode) - { - if (m_iTreePointer > 0) - { - m_iTreePointer -= 2; - int i = m_iTreePointer; - var phnNew = m_hnTree[i]; - phnNew.Weight = 1; - phnNew.ChildCode = Erina.CodeFlag | nNewCode; - m_iSymLookup[nNewCode & 0xFF] = i ; - - var phnRoot = m_hnTree[Erina.HuffmanRoot]; - if (phnRoot.ChildCode != Erina.HuffmanNull) - { - var phnParent = m_hnTree[i + 2]; - var phnChild = m_hnTree[i + 1]; - phnChild.CopyFrom (phnParent); // m_hnTree[i + 1] = m_hnTree[i + 2]; - - if (0 != (phnChild.ChildCode & Erina.CodeFlag)) - { - int nCode = phnChild.ChildCode & ~Erina.CodeFlag; - if (nCode != Erina.HuffmanEscape) - m_iSymLookup[nCode & 0xFF] = i + 1; - else - m_iEscape = i + 1; - } - phnParent.Weight = (ushort)(phnNew.Weight + phnChild.Weight); - phnParent.Parent = phnChild.Parent; - phnParent.ChildCode = i; - - phnNew.Parent = phnChild.Parent = (ushort)(i + 2); - Normalize (i + 2); - } - else - { - phnNew.Parent = Erina.HuffmanRoot; - m_iEscape = i + 1; - var phnEscape = m_hnTree[m_iEscape]; - phnEscape.Weight = 1; - phnEscape.Parent = Erina.HuffmanRoot; - phnEscape.ChildCode = Erina.CodeFlag | Erina.HuffmanEscape; - - phnRoot.Weight = 2; - phnRoot.ChildCode = i; - } - } - else - { - int i = m_iTreePointer; - var phnEntry = m_hnTree[i]; - if (phnEntry.ChildCode == (Erina.CodeFlag | Erina.HuffmanEscape)) - { - phnEntry = m_hnTree[i + 1]; - } - phnEntry.ChildCode = Erina.CodeFlag | nNewCode; - } - } - - private void HalfAndRebuild () - { - int i; - int iNextEntry = Erina.HuffmanRoot; - for (i = Erina.HuffmanRoot - 1; i >= m_iTreePointer; i--) - { - if (0 != (m_hnTree[i].ChildCode & Erina.CodeFlag)) - { - m_hnTree[i].Weight = (ushort)((m_hnTree[i].Weight + 1) >> 1); - m_hnTree[iNextEntry--].CopyFrom (m_hnTree[i]); - } - } - ++iNextEntry; - - int iChild, nCode; - i = m_iTreePointer; - for (;;) - { - m_hnTree[i].CopyFrom (m_hnTree[iNextEntry]); - m_hnTree[i + 1].CopyFrom (m_hnTree[iNextEntry + 1]); - iNextEntry += 2; - var phnChild1 = m_hnTree[i]; - var phnChild2 = m_hnTree[i + 1]; - - if (0 == (phnChild1.ChildCode & Erina.CodeFlag)) - { - iChild = phnChild1.ChildCode; - m_hnTree[iChild].Parent = (ushort)i; - m_hnTree[iChild + 1].Parent = (ushort)i; - } - else - { - nCode = phnChild1.ChildCode & ~Erina.CodeFlag; - if (Erina.HuffmanEscape == nCode) - m_iEscape = i; - else - m_iSymLookup[nCode & 0xFF] = i; - } - if (0 == (phnChild2.ChildCode & Erina.CodeFlag)) - { - iChild = phnChild2.ChildCode; - m_hnTree[iChild].Parent = (ushort)(i + 1); - m_hnTree[iChild + 1].Parent = (ushort)(i + 1); - } - else - { - nCode = phnChild2.ChildCode & ~Erina.CodeFlag; - if (Erina.HuffmanEscape == nCode) - m_iEscape = i + 1; - else - m_iSymLookup[nCode & 0xFF] = i + 1; - } - ushort weight = (ushort)(phnChild1.Weight + phnChild2.Weight); - - if (iNextEntry <= Erina.HuffmanRoot) - { - int j = iNextEntry; - for (;;) - { - if (weight <= m_hnTree[j].Weight) - { - m_hnTree[j - 1].Weight = weight; - m_hnTree[j - 1].ChildCode = i; - break; - } - m_hnTree[j - 1].CopyFrom (m_hnTree[j]); - if (++j > Erina.HuffmanRoot) - { - m_hnTree[Erina.HuffmanRoot].Weight = weight; - m_hnTree[Erina.HuffmanRoot].ChildCode = i; - break; - } - } - --iNextEntry; - } - else - { - m_hnTree[Erina.HuffmanRoot].Weight = weight; - m_hnTree[Erina.HuffmanRoot].Parent = Erina.HuffmanNull; - m_hnTree[Erina.HuffmanRoot].ChildCode = i; - phnChild1.Parent = Erina.HuffmanRoot; - phnChild2.Parent = Erina.HuffmanRoot; - break; - } - i += 2; - } - } - } - - internal class RLEDecodeContext : ERISADecodeContext - { - protected int m_flgZero; - protected uint m_nLength; - - public RLEDecodeContext (uint nBufferingSize) : base (nBufferingSize) - { - } - - public void InitGammaContext () - { - m_flgZero = GetABit(); - m_nLength = 0; - } - - public override uint DecodeBytes (Array ptrDst, uint nCount) - { - return DecodeGammaCodeBytes (ptrDst as sbyte[], nCount); - } - - public uint DecodeGammaCodeBytes (sbyte[] ptrDst, uint nCount) - { - int dst = 0; - uint nDecoded = 0; - - if (m_nLength == 0) - { - m_nLength = (uint)GetGammaCode(); - if (0 == m_nLength) - { - return nDecoded; - } - } - for (;;) - { - uint nRepeat = Math.Min (m_nLength, nCount); - Debug.Assert (nRepeat > 0); - m_nLength -= nRepeat; - nCount -= nRepeat; - - if (0 == m_flgZero) - { - nDecoded += nRepeat; - do - { - ptrDst[dst++] = 0; - } - while (0 != --nRepeat); - } - else - { - do - { - sbyte nSign = (sbyte)GetABit(); - sbyte nCode = (sbyte)GetGammaCode(); - if (0 == nCode) - { - return nDecoded; - } - nDecoded ++; - ptrDst[dst++] = (sbyte)((nCode ^ nSign) - nSign); - } - while (0 != --nRepeat); - } - if (0 == nCount) - { - if (0 == m_nLength) - { - m_flgZero = ~m_flgZero; - } - return nDecoded; - } - m_flgZero = ~m_flgZero; - m_nLength = (uint) GetGammaCode(); - if (0 == m_nLength) - { - return nDecoded; - } - } - } - - protected int GetGammaCode() - { - if (!PrefetchBuffer()) - { - return 0; - } - m_nIntBufCount--; - uint dwIntBuf = m_dwIntBuffer; - m_dwIntBuffer <<= 1; - if (0 == (dwIntBuf & 0x80000000)) - { - return 1; - } - if (!PrefetchBuffer()) - { - return 0; - } - int nCode = 0; - if ((0 != (~m_dwIntBuffer & 0x55000000)) && (m_nIntBufCount >= 8)) - { - uint i = (m_dwIntBuffer >> 24) << 1; - nCode = nGammaCodeLookup[i]; - int nBitCount = nGammaCodeLookup[i + 1]; - Debug.Assert (nBitCount <= m_nIntBufCount); - Debug.Assert (nCode > 0); - m_nIntBufCount -= nBitCount; - m_dwIntBuffer <<= nBitCount; - return nCode; - } - int nBase = 2; - for (;;) - { - if (m_nIntBufCount >= 2) - { - dwIntBuf = m_dwIntBuffer; - m_dwIntBuffer <<= 2; - nCode = (int)(((uint)nCode << 1) | (dwIntBuf >> 31)); - m_nIntBufCount -= 2; - if (0 == (dwIntBuf & 0x40000000)) - { - return nCode + nBase; - } - nBase <<= 1; - } - else - { - if (!PrefetchBuffer()) - { - return 0; - } - nCode = (int)(((uint)nCode << 1) | (m_dwIntBuffer >> 31)); - m_nIntBufCount --; - m_dwIntBuffer <<= 1; - - if (!PrefetchBuffer()) - { - return 0; - } - dwIntBuf = m_dwIntBuffer; - m_nIntBufCount --; - m_dwIntBuffer <<= 1; - if (0 == (dwIntBuf & 0x80000000)) - { - return nCode + nBase; - } - nBase <<= 1; - } - } - } - - static readonly byte[] nGammaCodeLookup = new byte[0x200] - { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 8, 6, 8, 6, 8, 6, 8, 6, 16, 8, 0xff, 0xff, 17, 8, 0xff, 0xff, - 9, 6, 9, 6, 9, 6, 9, 6, 18, 8, 0xff, 0xff, 19, 8, 0xff, 0xff, - 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, - 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, - 10, 6, 10, 6, 10, 6, 10, 6, 20, 8, 0xff, 0xff, 21, 8, 0xff, 0xff, - 11, 6, 11, 6, 11, 6, 11, 6, 22, 8, 0xff, 0xff, 23, 8, 0xff, 0xff, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, - 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, - 12, 6, 12, 6, 12, 6, 12, 6, 24, 8, 0xff, 0xff, 25, 8, 0xff, 0xff, - 13, 6, 13, 6, 13, 6, 13, 6, 26, 8, 0xff, 0xff, 27, 8, 0xff, 0xff, - 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, - 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, - 14, 6, 14, 6, 14, 6, 14, 6, 28, 8, 0xff, 0xff, 29, 8, 0xff, 0xff, - 15, 6, 15, 6, 15, 6, 15, 6, 30, 8, 0xff, 0xff, 31, 8, 0xff, 0xff - }; - } - - internal class HuffmanDecodeContext : RLEDecodeContext - { - int m_dwERINAFlags; - HuffmanTree m_pLastHuffmanTree; - HuffmanTree[] m_ppHuffmanTree; - - // ERINAEncodingFlag - public const int efERINAOrder0 = 0x0000; - public const int efERINAOrder1 = 0x0001; - - public HuffmanDecodeContext (uint nBufferingSize) : base (nBufferingSize) - { - } - - public void PrepareToDecodeERINACode (int flags = efERINAOrder1) - { - int i; - if (null == m_ppHuffmanTree) - { - m_ppHuffmanTree = new HuffmanTree[0x101]; - } - m_dwERINAFlags = flags; - m_nLength = 0; - if (efERINAOrder0 == flags) - { - m_ppHuffmanTree[0] = new HuffmanTree(); - m_ppHuffmanTree[0x100] = new HuffmanTree(); - for (i = 1; i < 0x100; i++) - { - m_ppHuffmanTree[i] = m_ppHuffmanTree[0]; - } - } - else - { - for (i = 0; i < 0x101; i++) - { - m_ppHuffmanTree[i] = new HuffmanTree(); - } - } - m_pLastHuffmanTree = m_ppHuffmanTree[0]; - } - - public override uint DecodeBytes (Array ptrDst, uint nCount) - { - return DecodeErinaCodeBytes (ptrDst as sbyte[], nCount); - } - - public uint DecodeErinaCodeBytes (sbyte[] ptrDst, uint nCount) - { - var tree = m_pLastHuffmanTree; - int symbol, length; - uint i = 0; - if (m_nLength > 0) - { - length = (int)Math.Min (m_nLength, nCount); - m_nLength -= (uint)length; - do - { - ptrDst[i++] = 0; - } - while (0 != --length); - } - while (i < nCount) - { - symbol = GetHuffmanCode (tree); - if (Erina.HuffmanEscape == symbol) - { - break; - } - ptrDst[i++] = (sbyte)symbol; - - if (0 == symbol) - { - length = GetLengthHuffman (m_ppHuffmanTree[0x100]); - if (Erina.HuffmanEscape == length) - { - break; - } - if (0 != --length) - { - m_nLength = (uint)length; - if (i + length > nCount) - { - length = (int)(nCount - i); - } - m_nLength -= (uint)length; - while (length > 0) - { - ptrDst[i++] = 0; - --length; - } - } - } - tree = m_ppHuffmanTree[symbol & 0xFF]; - } - m_pLastHuffmanTree = tree; - return i; - } - - private int GetLengthHuffman (HuffmanTree tree) - { - int nCode; - if (tree.m_iEscape != Erina.HuffmanNull) - { - int iEntry = Erina.HuffmanRoot; - int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode; - do - { - if (!PrefetchBuffer()) - { - return Erina.HuffmanEscape; - } - iEntry = iChild + (int)(m_dwIntBuffer >> 31); - iChild = tree.m_hnTree[iEntry].ChildCode; - m_dwIntBuffer <<= 1; - --m_nIntBufCount; - } - while (0 == (iChild & Erina.CodeFlag)); - - if ((m_dwERINAFlags != efERINAOrder0) || - (tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1)) - { - tree.IncreaseOccuredCount (iEntry); - } - nCode = iChild & ~Erina.CodeFlag; - if (nCode != Erina.HuffmanEscape) - { - return nCode ; - } - } - nCode = GetGammaCode(); - if (-1 == nCode) - { - return Erina.HuffmanEscape; - } - tree.AddNewEntry (nCode); - return nCode; - } - - public int GetHuffmanCode (HuffmanTree tree) - { - int nCode; - if (tree.m_iEscape != Erina.HuffmanNull) - { - int iEntry = Erina.HuffmanRoot; - int iChild = tree.m_hnTree[Erina.HuffmanRoot].ChildCode; - do - { - if (!PrefetchBuffer()) - { - return Erina.HuffmanEscape; - } - iEntry = iChild + (int)(m_dwIntBuffer >> 31); - iChild = tree.m_hnTree[iEntry].ChildCode; - m_dwIntBuffer <<= 1; - --m_nIntBufCount; - } - while (0 == (iChild & Erina.CodeFlag)); - - if ((m_dwERINAFlags != efERINAOrder0) || - (tree.m_hnTree[Erina.HuffmanRoot].Weight < Erina.HuffmanMax-1)) - { - tree.IncreaseOccuredCount (iEntry); - } - nCode = iChild & ~Erina.CodeFlag; - if (nCode != Erina.HuffmanEscape) - { - return nCode; - } - } - nCode = (int)GetNBits (8); - tree.AddNewEntry (nCode); - - return nCode; - } - } } diff --git a/ArcFormats/MioDecoder.cs b/ArcFormats/MioDecoder.cs new file mode 100644 index 00000000..336ba883 --- /dev/null +++ b/ArcFormats/MioDecoder.cs @@ -0,0 +1,1307 @@ +// ***************************************************************************** +// E R I S A - L i b r a r y +// ----------------------------------------------------------------------------- +// Copyright (C) 2002-2007 Leshade Entis, Entis-soft. All rights reserved. +// ***************************************************************************** +// +// C# port by morkt +// + +using System; +using System.Diagnostics; +using GameRes.Utility; + +namespace GameRes.Formats.Entis +{ + internal class MioInfoHeader + { + public int Version; + public CvType Transformation; + public EriCode Architecture; + public int ChannelCount; + public uint SamplesPerSec; + public uint BlocksetCount; + public int SubbandDegree; + public uint AllSampleCount; + public uint LappedDegree; + public uint BitsPerSample; + } + + internal class MioDataHeader + { + public byte Version; + public byte Flags; + public uint SampleCount; + } + + internal struct EriSinCos + { + public float rSin; + public float rCos; + } + + internal class MioDecoder + { + MioInfoHeader m_mioih; + + uint m_nBufLength = 0; + int[] m_ptrBuffer1; + int[] m_ptrBuffer2; + sbyte[] m_ptrBuffer3; + byte[] m_ptrBuffer4; + byte[] m_ptrDivisionTable; + byte[] m_ptrRevolveCode; + int[] m_ptrWeightCode; + int[] m_ptrCoefficient; + + float[] m_ptrMatrixBuf; + float[] m_ptrInternalBuf; + float[] m_ptrWorkBuf; + float[] m_ptrWeightTable; + float[] m_ptrLastDCT; + + int m_ptrNextDivision; + int m_ptrNextRevCode; + int m_ptrNextWeight; + int m_ptrNextCoefficient; + int m_ptrNextSource; + int m_ptrLastDCTBuf; + int m_nSubbandDegree; + int m_nDegreeNum; + EriSinCos[] m_pRevolveParam; + readonly int[] m_nFrequencyPoint = new int[7]; + + const int MIN_DCT_DEGREE = 2; + const int MAX_DCT_DEGREE = 12; + + static MioDecoder () + { + eriInitializeMatrix(); + } + + public MioDecoder (MioInfoHeader info) + { + m_nBufLength = 0; + m_mioih = info; + + if (!Initialize()) + throw new InvalidFormatException(); + } + + bool Initialize () + { + if ((m_mioih.ChannelCount != 1) && (m_mioih.ChannelCount != 2)) + { + return false; + } + + if (m_mioih.Transformation == CvType.Lossless_ERI) + { + if (m_mioih.Architecture != EriCode.RunlengthHuffman) + { + return false; + } + if ((m_mioih.BitsPerSample != 8) && (m_mioih.BitsPerSample != 16)) + { + return false; + } + } + else if ((m_mioih.Transformation == CvType.LOT_ERI) + || (m_mioih.Transformation == CvType.LOT_ERI_MSS)) + { + if ((m_mioih.Architecture != EriCode.RunlengthGamma) + && (m_mioih.Architecture != EriCode.RunlengthHuffman) + && (m_mioih.Architecture != EriCode.Nemesis)) + { + return false; + } + if (m_mioih.BitsPerSample != 16) + { + return false; + } + if ((m_mioih.SubbandDegree < 8) || (m_mioih.SubbandDegree > MAX_DCT_DEGREE)) + { + return false; + } + if (m_mioih.LappedDegree != 1) + { + return false; + } + int subband = (sizeof(float) << m_mioih.SubbandDegree) / sizeof(float); + int block_size = m_mioih.ChannelCount * subband; + m_ptrBuffer1 = new int[block_size]; + m_ptrMatrixBuf = new float[block_size]; + m_ptrInternalBuf = new float[block_size]; + m_ptrWorkBuf = new float[subband]; + + m_ptrWeightTable = new float[subband]; + + uint nBlocksetSamples = (uint)(m_mioih.ChannelCount << m_mioih.SubbandDegree); + uint nLappedSamples = nBlocksetSamples * m_mioih.LappedDegree; + if (nLappedSamples > 0) + { + m_ptrLastDCT = new float[nLappedSamples]; + } + InitializeWithDegree (m_mioih.SubbandDegree); + } + else + { + return false; + } + return true; + } + + public bool DecodeSound (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) + { + context.FlushBuffer(); + + if (m_mioih.Transformation == CvType.Lossless_ERI) + { + if (m_mioih.BitsPerSample == 8) + { + return DecodeSoundPCM8 (context, datahdr, ptrWaveBuf, wave_pos); + } + else if (m_mioih.BitsPerSample == 16) + { + return DecodeSoundPCM16 (context, datahdr, ptrWaveBuf, wave_pos); + } + } + else if ((m_mioih.Transformation == CvType.LOT_ERI) + || (m_mioih.Transformation == CvType.LOT_ERI_MSS)) + { + if ((m_mioih.ChannelCount != 2) || (m_mioih.Transformation == CvType.LOT_ERI)) + { + return DecodeSoundDCT (context, datahdr, ptrWaveBuf, wave_pos); + } + else + { + return DecodeSoundDCT_MSS (context, datahdr, ptrWaveBuf, wave_pos); + } + } + return false; + } + + bool DecodeSoundPCM8 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) + { + uint nSampleCount = datahdr.SampleCount; + if (nSampleCount > m_nBufLength) + { + m_ptrBuffer3 = new sbyte [nSampleCount * m_mioih.ChannelCount]; + m_nBufLength = nSampleCount; + } + if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) + { + (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); + } + uint nBytes = nSampleCount * (uint)m_mioih.ChannelCount; + if (context.DecodeBytes (m_ptrBuffer3, nBytes) < nBytes) + { + return false; + } + int ptrSrcBuf = 0; // (PBYTE) m_ptrBuffer3; + int nStep = m_mioih.ChannelCount; + for (int i = 0; i < m_mioih.ChannelCount; i ++ ) + { + int ptrDstBuf = wave_pos + i; + sbyte bytValue = 0; + for (uint j = 0; j < nSampleCount; j++) + { + bytValue += m_ptrBuffer3[ptrSrcBuf++]; + ptrWaveBuf[ptrDstBuf] = (byte)bytValue; + ptrDstBuf += nStep; + } + } + return true; + } + + bool DecodeSoundPCM16 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) + { + uint nSampleCount = datahdr.SampleCount; + uint nChannelCount = (uint)m_mioih.ChannelCount; + uint nAllSampleCount = nSampleCount * nChannelCount; + + if (nSampleCount > m_nBufLength) + { + m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; + m_ptrBuffer4 = new byte[nAllSampleCount * sizeof(short)]; + m_nBufLength = nSampleCount; + } + if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) + { + (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); + } + uint nBytes = nAllSampleCount * sizeof(short); + if (context.DecodeBytes (m_ptrBuffer3, nBytes) < nBytes) + { + return false; + } + int pbytSrcBuf1, pbytSrcBuf2, pbytDstBuf; + for (int i = 0; i < m_mioih.ChannelCount; i++) + { + int nOffset = i * (int)nSampleCount * sizeof(short); + pbytSrcBuf1 = nOffset; // ((PBYTE) m_ptrBuffer3) + nOffset; + pbytSrcBuf2 = pbytSrcBuf1 + (int)nSampleCount; // pbytSrcBuf1 + nSampleCount; + pbytDstBuf = nOffset; // ((PBYTE) m_ptrBuffer4) + nOffset; + + for (uint j = 0; j < nSampleCount; j ++) + { + sbyte bytLow = m_ptrBuffer3[pbytSrcBuf2 + j]; + sbyte bytHigh = m_ptrBuffer3[pbytSrcBuf1 + j]; + m_ptrBuffer4[pbytDstBuf + j * sizeof(short) + 0] = (byte)bytLow; + m_ptrBuffer4[pbytDstBuf + j * sizeof(short) + 1] = (byte)(bytHigh ^ (bytLow >> 7)); + } + } + int ptrSrcBuf = 0; // (SWORD*) m_ptrBuffer4; + int nStep = m_mioih.ChannelCount; + for (int i = 0; i < m_mioih.ChannelCount; i++) + { + int ptrDstBuf = wave_pos + i*sizeof(short); // (SWORD*) ptrWaveBuf; + short wValue = 0; + short wDelta = 0; + for (uint j = 0; j < nSampleCount; j++) + { + wDelta += LittleEndian.ToInt16 (m_ptrBuffer4, ptrSrcBuf); + wValue += wDelta; + LittleEndian.Pack (wValue, ptrWaveBuf, ptrDstBuf); // *ptrDstBuf = wValue; + ptrSrcBuf += sizeof(short); + ptrDstBuf += nStep; + } + } + return true; + } + + static readonly int[] FreqWidth = new int[7] { -6, -6, -5, -4, -3, -2, -1 }; + + void InitializeWithDegree (int nSubbandDegree) + { + m_pRevolveParam = eriCreateRevolveParameter (nSubbandDegree); + for (int i = 0, j = 0; i < 7; i ++) + { + int nFrequencyWidth = 1 << (nSubbandDegree + FreqWidth[i]); + m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2); + j += nFrequencyWidth; + } + m_nSubbandDegree = nSubbandDegree; + m_nDegreeNum = 1 << nSubbandDegree; + } + + const uint MIO_LEAD_BLOCK = 0x01; + + bool DecodeSoundDCT (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) + { + uint i, j, k; + uint nDegreeWidth = 1u << m_mioih.SubbandDegree; + uint nSampleCount = (datahdr.SampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); + uint nSubbandCount = (nSampleCount >> m_mioih.SubbandDegree); + uint nChannelCount = (uint)m_mioih.ChannelCount; + uint nAllSampleCount = nSampleCount * nChannelCount; + uint nAllSubbandCount = nSubbandCount * nChannelCount; + + if (nSampleCount > m_nBufLength) + { + m_ptrBuffer2 = new int[nAllSampleCount]; + m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; + m_ptrDivisionTable = new byte[nAllSubbandCount]; + m_ptrWeightCode = new int[nAllSubbandCount * 5]; + m_ptrCoefficient = new int[nAllSubbandCount * 5]; + m_nBufLength = nSampleCount; + } + if (context.GetABit() != 0) + { + return false; + } + int[] pLastDivision = new int [nChannelCount]; + m_ptrNextDivision = 0; // within m_ptrDivisionTable; + m_ptrNextWeight = 0; // within m_ptrWeightCode; + m_ptrNextCoefficient = 0; // within m_ptrCoefficient; + + for (i = 0; i < nChannelCount; i++) + { + pLastDivision[i] = -1; + } + for (i = 0; i < nSubbandCount; i++) + { + for (j = 0; j < nChannelCount; j++) + { + int nDivisionCode = (int)context.GetNBits(2); + m_ptrDivisionTable[m_ptrNextDivision++] = (byte)nDivisionCode; + + if (nDivisionCode != pLastDivision[j]) + { + if (i != 0) + { + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + pLastDivision[j] = nDivisionCode; + } + + uint nDivisionCount = 1u << nDivisionCode; + for (k = 0; k < nDivisionCount; k ++) + { + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + } + } + if (nSubbandCount > 0) + { + for (i = 0; i < nChannelCount; i++) + { + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + } + + if (context.GetABit() != 0) + { + return false; + } + if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) + { + if (m_mioih.Architecture != EriCode.Nemesis) + { + (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); + } + else + { + throw new NotImplementedException ("Nemesis encoding not implemented"); +// context.PrepareToDecodeERISACode(); + } + } + else if (m_mioih.Architecture == EriCode.Nemesis) + { + throw new NotImplementedException ("Nemesis encoding not implemented"); +// context.InitializeERISACode(); + } + if (m_mioih.Architecture != EriCode.Nemesis) + { + if (context.DecodeBytes (m_ptrBuffer3, nAllSampleCount * 2 ) < nAllSampleCount * 2) + { + return false; + } + int ptrHBuf = 0; // within m_ptrBuffer3; + int ptrLBuf = (int)nAllSampleCount; // within m_ptrBuffer3 + + for (i = 0; i < nDegreeWidth; i++) + { + int ptrQuantumized = (int)i; // within (PINT) m_ptrBuffer2 + for (j = 0; j < nAllSubbandCount; j++) + { + int nLow = m_ptrBuffer3[ptrLBuf++]; + int nHigh = m_ptrBuffer3[ptrHBuf++] ^ (nLow >> 8); + m_ptrBuffer2[ptrQuantumized] = (nLow & 0xFF) | (nHigh << 8); + ptrQuantumized += (int)nDegreeWidth; + } + } + } + else + { + throw new NotImplementedException ("Nemesis encoding not implemented"); + /* + if (context.DecodeERISACodeWords (m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) + { + return false; + } + for (i = 0; i < nAllSampleCount; i++) + { + ((PINT)m_ptrBuffer2)[i] = ((SWORD*)m_ptrBuffer3)[i]; + } + */ + } + uint nSamples; + uint[] pRestSamples = new uint [nChannelCount]; + int[] ptrDstBuf = new int [nChannelCount]; // indices within ptrWaveBuf + + m_ptrNextDivision = 0; // within m_ptrDivisionTable; + m_ptrNextWeight = 0; // within m_ptrWeightCode; + m_ptrNextCoefficient = 0; // within m_ptrCoefficient; + m_ptrNextSource = 0; // within (PINT) m_ptrBuffer2; + + for (i = 0; i < nChannelCount; i++) + { + pLastDivision[i] = -1; + pRestSamples[i] = datahdr.SampleCount; + ptrDstBuf[i] = wave_pos + (int)i*sizeof(short); + } + int nCurrentDivision = -1; + + for (i = 0; i < nSubbandCount; i++) + { + for (j = 0; j < nChannelCount; j++) + { + int nDivisionCode = m_ptrDivisionTable[m_ptrNextDivision++]; + int nDivisionCount = 1 << nDivisionCode; + int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * j); + m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT + + bool fLeadBlock = false; + if (pLastDivision[j] != nDivisionCode) + { + if (i != 0) + { + if (nCurrentDivision != pLastDivision[j]) + { + InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[j]); + nCurrentDivision = pLastDivision[j]; + } + nSamples = pRestSamples[j]; + if (nSamples > m_nDegreeNum) + { + nSamples = (uint)m_nDegreeNum; + } + DecodePostBlock (ptrWaveBuf, ptrDstBuf[j], nSamples); + pRestSamples[j] -= nSamples; + ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short)); + } + pLastDivision[j] = (int)nDivisionCode; + fLeadBlock = true; + } + if (nCurrentDivision != nDivisionCode) + { + InitializeWithDegree (m_mioih.SubbandDegree - nDivisionCode); + nCurrentDivision = nDivisionCode; + } + for (k = 0; k < nDivisionCount; k++) + { + if (fLeadBlock) + { + DecodeLeadBlock(); + fLeadBlock = false; + } + else + { + nSamples = pRestSamples[j]; + if (nSamples > m_nDegreeNum) + { + nSamples = (uint)m_nDegreeNum; + } + DecodeInternalBlock (ptrWaveBuf, ptrDstBuf[j], nSamples); + pRestSamples[j] -= nSamples; + ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short)); + } + } + } + } + if (nSubbandCount > 0) + { + for (i = 0; i < nChannelCount; i ++) + { + int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * i); + m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT + + if (nCurrentDivision != pLastDivision[i]) + { + InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[i]); + nCurrentDivision = pLastDivision[i]; + } + nSamples = pRestSamples[i]; + if (nSamples > m_nDegreeNum) + { + nSamples = (uint)m_nDegreeNum; + } + DecodePostBlock (ptrWaveBuf, ptrDstBuf[i], nSamples); + pRestSamples[i] -= nSamples; + ptrDstBuf[i] += (int)(nSamples * nChannelCount * sizeof(short)); + } + } + return true; + } + + void DecodeInternalBlock (byte[] ptrDst, int iDst, uint nSamples) + { + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer2, m_ptrNextSource, m_nDegreeNum, nWeightCode, nCoefficient); + m_ptrNextSource += (int)m_nDegreeNum; + + eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree); + eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree); + eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, 0, m_nSubbandDegree); + + Array.Copy (m_ptrMatrixBuf, 0, m_ptrLastDCT, m_ptrLastDCTBuf, m_nDegreeNum); + Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, 0, m_nDegreeNum); + + eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 0, 1, m_ptrWorkBuf, m_nSubbandDegree); + if (nSamples != 0) + { + eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples); + } + } + + void DecodeLeadBlock () + { + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + uint i; + uint nHalfDegree = (uint)m_nDegreeNum / 2; + for (i = 0; i < nHalfDegree; i++) + { + m_ptrBuffer1[i * 2] = 0; + m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; + } + IQuantumize (m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); + eriOddGivensInverseMatrix (m_ptrLastDCT, m_ptrLastDCTBuf, m_pRevolveParam, m_nSubbandDegree); + for (i = 0; i < m_nDegreeNum; i += 2) + { + m_ptrLastDCT[m_ptrLastDCTBuf + i] = m_ptrLastDCT[m_ptrLastDCTBuf + i + 1]; + } + eriFastIPLOT (m_ptrLastDCT, m_ptrLastDCTBuf, m_nSubbandDegree); + } + + void DecodePostBlock (byte[] ptrDst, int iDst, uint nSamples) + { + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + uint i; + uint nHalfDegree = (uint)m_nDegreeNum / 2; + for (i = 0; i < nHalfDegree; i++) + { + m_ptrBuffer1[i * 2] = 0; + m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; + } + IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); + eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree); + + for (i = 0; i < m_nDegreeNum; i += 2) + { + m_ptrMatrixBuf[i] = - m_ptrMatrixBuf[i + 1]; + } + + eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree); + eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, 0, m_nSubbandDegree); + + Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, 0, m_nDegreeNum); + + eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 0, 1, m_ptrWorkBuf, m_nSubbandDegree); + if (nSamples != 0) + { + eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples); + } + } + + bool DecodeSoundDCT_MSS (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos) + { + uint nDegreeWidth = 1u << m_mioih.SubbandDegree; + uint nSampleCount = (datahdr.SampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); + uint nSubbandCount = (nSampleCount >> m_mioih.SubbandDegree); + uint nChannelCount = (uint)m_mioih.ChannelCount; + uint nAllSampleCount = nSampleCount * nChannelCount; + uint nAllSubbandCount = nSubbandCount; + + if (nSampleCount > m_nBufLength) + { + m_ptrBuffer2 = new int[nAllSampleCount]; + m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)]; + m_ptrDivisionTable = new byte[nAllSubbandCount]; + m_ptrRevolveCode = new byte[nAllSubbandCount * 10]; + m_ptrWeightCode = new int[nAllSubbandCount * 10]; + m_ptrCoefficient = new int[nAllSubbandCount * 10]; + m_nBufLength = nSampleCount; + } + if (context.GetABit() != 0) + { + return false; + } + + int nLastDivision = -1; + m_ptrNextDivision = 0; // within m_ptrDivisionTable; + m_ptrNextRevCode = 0; // within m_ptrRevolveCode; + m_ptrNextWeight = 0; // within m_ptrWeightCode; + m_ptrNextCoefficient = 0; // within m_ptrCoefficient; + + uint i, j, k; + for (i = 0; i < nSubbandCount; i ++) + { + int nDivisionCode = (int)context.GetNBits (2); + m_ptrDivisionTable[m_ptrNextDivision++] = (byte)nDivisionCode; + + bool fLeadBlock = false; + if (nDivisionCode != nLastDivision) + { + if (i != 0) + { + m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + fLeadBlock = true; + nLastDivision = nDivisionCode; + } + uint nDivisionCount = 1u << nDivisionCode; + for (k = 0; k < nDivisionCount; k++) + { + if (fLeadBlock) + { + m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); + fLeadBlock = false; + } + else + { + m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (4); + } + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + } + if (nSubbandCount > 0) + { + m_ptrRevolveCode[m_ptrNextRevCode++] = (byte)context.GetNBits (2); + m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32); + m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16); + } + if (context.GetABit() != 0) + { + return false; + } + if (0 != (datahdr.Flags & MIO_LEAD_BLOCK)) + { + if (m_mioih.Architecture != EriCode.Nemesis) + { + (context as HuffmanDecodeContext).PrepareToDecodeERINACode(); + } + else + { + throw new NotImplementedException ("Nemesis encoding not implemented"); +// context.PrepareToDecodeERISACode( ); + } + } + else if (m_mioih.Architecture == EriCode.Nemesis) + { + throw new NotImplementedException ("Nemesis encoding not implemented"); +// context.InitializeERISACode( ); + } + if (m_mioih.Architecture != EriCode.Nemesis) + { + if (context.DecodeBytes (m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) + { + return false; + } + int ptrHBuf = 0; // within m_ptrBuffer3; + int ptrLBuf = (int)nAllSampleCount; // within m_ptrBuffer3 + + for (i = 0; i < nDegreeWidth * 2; i++) + { + int ptrQuantumized = (int)i; // within (PINT) m_ptrBuffer2 + for (j = 0; j < nAllSubbandCount; j++) + { + int nLow = m_ptrBuffer3[ptrLBuf++]; + int nHigh = m_ptrBuffer3[ptrHBuf++] ^ (nLow >> 8); + m_ptrBuffer2[ptrQuantumized] = (nLow & 0xFF) | (nHigh << 8); + ptrQuantumized += (int)nDegreeWidth * 2; + } + } + } + else + { + throw new NotImplementedException ("Nemesis encoding not implemented"); + /* + if ( context.DecodeERISACodeWords + ( (SWORD*) m_ptrBuffer3, nAllSampleCount ) < nAllSampleCount ) + { + return false; + } + for ( i = 0; i < nAllSampleCount; i ++ ) + { + ((PINT)m_ptrBuffer2)[i] = ((SWORD*)m_ptrBuffer3)[i]; + } + */ + } + uint nSamples; + uint nRestSamples = datahdr.SampleCount; +// int ptrDstBuf = wave_pos; // within (SWORD*) ptrWaveBuf; + + nLastDivision = -1; + m_ptrNextDivision = 0; // m_ptrDivisionTable; + m_ptrNextRevCode = 0; // m_ptrRevolveCode; + m_ptrNextWeight = 0; // m_ptrWeightCode; + m_ptrNextCoefficient = 0; // m_ptrCoefficient; + m_ptrNextSource = 0; // (PINT) m_ptrBuffer2; + + for (i = 0; i < nSubbandCount; i++) + { + int nDivisionCode = m_ptrDivisionTable[m_ptrNextDivision++]; + uint nDivisionCount = 1u << nDivisionCode; + + bool fLeadBlock = false; + if (nLastDivision != nDivisionCode) + { + if (i != 0) + { + nSamples = Math.Min (nRestSamples, (uint)m_nDegreeNum); + DecodePostBlock_MSS (ptrWaveBuf, wave_pos, nSamples); + nRestSamples -= nSamples; + wave_pos += (int)(nSamples * nChannelCount * sizeof(short)); + } + InitializeWithDegree (m_mioih.SubbandDegree - nDivisionCode); + nLastDivision = nDivisionCode; + fLeadBlock = true; + } + for (k = 0; k < nDivisionCount; k++) + { + if (fLeadBlock) + { + DecodeLeadBlock_MSS(); + fLeadBlock = false; + } + else + { + nSamples = nRestSamples; + if (nSamples > m_nDegreeNum) + { + nSamples = (uint)m_nDegreeNum; + } + DecodeInternalBlock_MSS (ptrWaveBuf, wave_pos, nSamples); + nRestSamples -= nSamples; + wave_pos += (int)(nSamples * nChannelCount * sizeof(short)); + } + } + } + if (nSubbandCount > 0) + { + nSamples = nRestSamples; + if (nSamples > m_nDegreeNum) + { + nSamples = (uint)m_nDegreeNum; + } + DecodePostBlock_MSS (ptrWaveBuf, wave_pos, nSamples); + nRestSamples -= nSamples; + wave_pos += (int)(nSamples * nChannelCount) * sizeof(short); + } + return true; + } + + void DecodeLeadBlock_MSS () + { + uint i, j; + uint nHalfDegree = (uint)m_nDegreeNum / 2; + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + int ptrLapBuf = 0; // within m_ptrLastDCT; + + for (i = 0; i < 2; i++) + { + int ptrSrcBuf = 0; // within (PINT) m_ptrBuffer1; + for (j = 0; j < nHalfDegree; j++) + { + m_ptrBuffer1[ptrSrcBuf + j * 2] = 0; + m_ptrBuffer1[ptrSrcBuf + j * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; + } + IQuantumize (m_ptrLastDCT, ptrLapBuf, m_ptrBuffer1, ptrSrcBuf, m_nDegreeNum, nWeightCode, nCoefficient); + ptrLapBuf += (int)m_nDegreeNum; + } + int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; + + int ptrLapBuf1 = 0; // m_ptrLastDCT; + int ptrLapBuf2 = (int)m_nDegreeNum; // m_ptrLastDCT + + float rSin = (float)Math.Sin (nRevCode * Math.PI / 8); + float rCos = (float)Math.Cos (nRevCode * Math.PI / 8); + eriRevolve2x2 (m_ptrLastDCT, ptrLapBuf1, m_ptrLastDCT, ptrLapBuf2, rSin, rCos, 1, m_nDegreeNum); + + ptrLapBuf = 0; //m_ptrLastDCT; + for (i = 0; i < 2; i++) + { + eriOddGivensInverseMatrix (m_ptrLastDCT, ptrLapBuf, m_pRevolveParam, m_nSubbandDegree); + + for (j = 0; j < m_nDegreeNum; j += 2) + { + m_ptrLastDCT[ptrLapBuf + j] = m_ptrLastDCT[ptrLapBuf + j + 1]; + } + eriFastIPLOT (m_ptrLastDCT, ptrLapBuf, m_nSubbandDegree); + ptrLapBuf += (int)m_nDegreeNum; + } + } + + void DecodeInternalBlock_MSS (byte[] ptrDst, int iDst, uint nSamples) + { + int ptrSrcBuf = 0; // m_ptrMatrixBuf; + int ptrLapBuf = 0; // m_ptrLastDCT; + + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + + for (int i = 0; i < 2; i++) + { + IQuantumize (m_ptrMatrixBuf, ptrSrcBuf, m_ptrBuffer2, m_ptrNextSource, m_nDegreeNum, nWeightCode, nCoefficient); + m_ptrNextSource += m_nDegreeNum; + ptrSrcBuf += m_nDegreeNum; + } + int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; + int nRevCode1 = (nRevCode >> 2) & 0x03; + int nRevCode2 = (nRevCode & 0x03); + + int ptrSrcBuf1 = 0; // m_ptrMatrixBuf; + int ptrSrcBuf2 = m_nDegreeNum; // m_ptrMatrixBuf + m_nDegreeNum; + + float rSin = (float) Math.Sin (nRevCode1 * Math.PI / 8); + float rCos = (float) Math.Cos (nRevCode1 * Math.PI / 8); + eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1, m_ptrMatrixBuf, ptrSrcBuf2, rSin, rCos, 2, m_nDegreeNum / 2); + + rSin = (float) Math.Sin (nRevCode2 * Math.PI / 8); + rCos = (float) Math.Cos (nRevCode2 * Math.PI / 8); + eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1 + 1, m_ptrMatrixBuf, ptrSrcBuf2 + 1, rSin, rCos, 2, m_nDegreeNum / 2); + + ptrSrcBuf = 0; // m_ptrMatrixBuf; + + for (int i = 0; i < 2; i++) + { + eriOddGivensInverseMatrix (m_ptrMatrixBuf, ptrSrcBuf, m_pRevolveParam, m_nSubbandDegree); + eriFastIPLOT (m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); + eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, ptrLapBuf, m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); + + Array.Copy (m_ptrMatrixBuf, ptrSrcBuf, m_ptrLastDCT, ptrLapBuf, m_nDegreeNum); + Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, ptrSrcBuf, m_nDegreeNum); + + eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, ptrSrcBuf, 1, m_ptrWorkBuf, m_nSubbandDegree); + if (nSamples != 0) + { + eriRoundR32ToWordArray (ptrDst, iDst + (int)i*2, 2, m_ptrInternalBuf, (int)nSamples); + } + ptrSrcBuf += m_nDegreeNum; + ptrLapBuf += m_nDegreeNum; + } + } + + void DecodePostBlock_MSS (byte[] ptrDst, int iDst, uint nSamples) + { + int ptrLapBuf = 0; // m_ptrLastDCT; + int ptrSrcBuf = 0; // m_ptrMatrixBuf; + + int i, j; + uint nHalfDegree = (uint)m_nDegreeNum / 2u; + int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++]; + int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++]; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < nHalfDegree; j++) + { + m_ptrBuffer1[j * 2] = 0; + m_ptrBuffer1[j * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++]; + } + IQuantumize (m_ptrMatrixBuf, ptrSrcBuf, m_ptrBuffer1, 0, m_nDegreeNum, nWeightCode, nCoefficient); + ptrSrcBuf += m_nDegreeNum; + } + float rSin, rCos; + int nRevCode = m_ptrRevolveCode[m_ptrNextRevCode++]; + + int ptrSrcBuf1 = 0; // m_ptrMatrixBuf; + int ptrSrcBuf2 = m_nDegreeNum; // m_ptrMatrixBuf + m_nDegreeNum; + + rSin = (float) Math.Sin (nRevCode * Math.PI / 8); + rCos = (float) Math.Cos (nRevCode * Math.PI / 8); + eriRevolve2x2 (m_ptrMatrixBuf, ptrSrcBuf1, m_ptrMatrixBuf, ptrSrcBuf2, rSin, rCos, 1, m_nDegreeNum); + + ptrSrcBuf = 0; // m_ptrMatrixBuf; + + for (i = 0; i < 2; i ++) + { + eriOddGivensInverseMatrix (m_ptrMatrixBuf, ptrSrcBuf, m_pRevolveParam, m_nSubbandDegree); + + for (j = 0; j < m_nDegreeNum; j += 2) + { + m_ptrMatrixBuf[ptrSrcBuf + j] = -m_ptrMatrixBuf[ptrSrcBuf + j + 1]; + } + eriFastIPLOT (m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); + eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, ptrLapBuf, m_ptrMatrixBuf, ptrSrcBuf, m_nSubbandDegree); + + Array.Copy (m_ptrWorkBuf, 0, m_ptrMatrixBuf, ptrSrcBuf, m_nDegreeNum); + + eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, ptrSrcBuf, 1, m_ptrWorkBuf, m_nSubbandDegree); + if (nSamples != 0) + { + eriRoundR32ToWordArray (ptrDst, iDst + (int)i*2, 2, m_ptrInternalBuf, (int)nSamples); + } + ptrLapBuf += m_nDegreeNum; + ptrSrcBuf += m_nDegreeNum; + } + } + + void IQuantumize (float[] ptrDestination, int dst, int[] ptrQuantumized, int qsrc, int nDegreeNum, int nWeightCode, int nCoefficient) + { + int i, j; + double rMatrixScale = Math.Sqrt (2.0 / nDegreeNum); + double rCoefficient = rMatrixScale * nCoefficient; + double[] rAvgRatio = new double[7]; + for (i = 0; i < 6; i++) + { + rAvgRatio[i] = 1.0 / Math.Pow (2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5); + } + rAvgRatio[6] = 1.0; + for (i = 0; i < m_nFrequencyPoint[0]; i++) + { + m_ptrWeightTable[i] = (float) rAvgRatio[0]; + } + for (j = 1; j < 7; j++) + { + double a = rAvgRatio[j - 1]; + double k = (rAvgRatio[j] - a) / (m_nFrequencyPoint[j] - m_nFrequencyPoint[j - 1]); + while (i < m_nFrequencyPoint[j]) + { + m_ptrWeightTable[i] = (float)(k * (i - m_nFrequencyPoint[j - 1]) + a); + i++; + } + } + while (i < nDegreeNum) + { + m_ptrWeightTable[i++] = (float)rAvgRatio[6]; + } + float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0); + for (i = 15; i < nDegreeNum; i += 16) + { + m_ptrWeightTable[i] *= rOddWeight; + } + m_ptrWeightTable[nDegreeNum-1] = (float) nCoefficient; + for (i = 0; i < nDegreeNum; i++) + { + m_ptrWeightTable[i] = 1.0F / m_ptrWeightTable[i]; + } + for (i = 0; i < nDegreeNum; i ++) + { + ptrDestination[dst + i] = (float) (rCoefficient * m_ptrWeightTable[i] * ptrQuantumized[qsrc+i]); + } + } + + static readonly float ERI_rCosPI4 = (float)Math.Cos (Math.PI / 4); + static readonly float ERI_r2CosPI4 = 2 * ERI_rCosPI4; + static readonly float[] ERI_DCTofK2 = new float[2]; // = cos( (2*i+1) / 8 ) + static readonly float[] ERI_DCTofK4 = new float[4]; // = cos( (2*i+1) / 16 ) + static readonly float[] ERI_DCTofK8 = new float[8]; // = cos( (2*i+1) / 32 ) + static readonly float[] ERI_DCTofK16 = new float[16]; // = cos( (2*i+1) / 64 ) + static readonly float[] ERI_DCTofK32 = new float[32]; // = cos( (2*i+1) / 128 ) + static readonly float[] ERI_DCTofK64 = new float[64]; // = cos( (2*i+1) / 256 ) + static readonly float[] ERI_DCTofK128 = new float[128]; // = cos( (2*i+1) / 512 ) + static readonly float[] ERI_DCTofK256 = new float[256]; // = cos( (2*i+1) / 1024 ) + static readonly float[] ERI_DCTofK512 = new float[512]; // = cos( (2*i+1) / 2048 ) + static readonly float[] ERI_DCTofK1024 = new float[1024]; // = cos( (2*i+1) / 4096 ) + static readonly float[] ERI_DCTofK2048 = new float[2048]; // = cos( (2*i+1) / 8192 ) + + static readonly float[][] ERI_pMatrixDCTofK = new float[MAX_DCT_DEGREE][] + { + null, + ERI_DCTofK2, + ERI_DCTofK4, + ERI_DCTofK8, + ERI_DCTofK16, + ERI_DCTofK32, + ERI_DCTofK64, + ERI_DCTofK128, + ERI_DCTofK256, + ERI_DCTofK512, + ERI_DCTofK1024, + ERI_DCTofK2048 + }; + + static void eriInitializeMatrix () + { + for (int i = 1; i < MAX_DCT_DEGREE; i++) + { + int n = (1 << i); + float[] pDCTofK = ERI_pMatrixDCTofK[i]; + double nr = Math.PI / (4.0 * n); + double dr = nr + nr; + double ir = nr; + for (int j = 0; j < n; j++) + { + pDCTofK[j] = (float)Math.Cos (ir); + ir += dr; + } + } + } + + static void eriRoundR32ToWordArray (byte[] ptrDst, int dst, int nStep, float[] ptrSrc, int nCount) + { + nStep *= 2; + for (int i = 0; i < nCount; i++) + { + int nValue = eriRoundR32ToInt (ptrSrc[i]); + if (nValue <= -0x8000) + { + LittleEndian.Pack ((short)-0x8000, ptrDst, dst); + } + else if (nValue >= 0x7FFF) + { + LittleEndian.Pack ((short)0x7FFF, ptrDst, dst); + } + else + { + LittleEndian.Pack ((short)nValue, ptrDst, dst); + } + dst += nStep; + } + } + + static int eriRoundR32ToInt (float r) + { + if (r >= 0.0) + return (int)Math.Floor (r + 0.5); + else + return (int)Math.Ceiling (r - 0.5); + } + + static EriSinCos[] eriCreateRevolveParameter (int nDegreeDCT) + { + int nDegreeNum = 1 << nDegreeDCT; + int lc = 1; + for (int n = nDegreeNum / 2; n >= 8; n /= 8) + { + ++lc; + } + EriSinCos[] ptrRevolve = new EriSinCos[lc*8]; + + double k = Math.PI / (nDegreeNum * 2); + int ptrNextRev = 0; + int nStep = 2; + do + { + for (int i = 0; i < 7; i++) + { + double ws = 1.0; + double a = 0.0; + for (int j = 0; j < i; j++) + { + a += nStep; + ws = ws * ptrRevolve[ptrNextRev+j].rSin + ptrRevolve[ptrNextRev+j].rCos * Math.Cos (a * k); + } + double r = Math.Atan2 (ws, Math.Cos ((a + nStep) * k)); + ptrRevolve[ptrNextRev+i].rSin = (float)Math.Sin (r); + ptrRevolve[ptrNextRev+i].rCos = (float)Math.Cos (r); + } + ptrNextRev += 7; + nStep *= 8; + } + while (nStep < nDegreeNum); + return ptrRevolve; + } + + static void eriOddGivensInverseMatrix (float[] ptrSrc, int src, EriSinCos[] ptrRevolve, int nDegreeDCT) + { + int nDegreeNum = 1 << nDegreeDCT; + int index = 1; + int nStep = 2; + int lc = (nDegreeNum / 2) / 8; + int resolve_idx = 0; + for (;;) + { + resolve_idx += 7; + index += nStep * 7; + nStep *= 8; + if (lc <= 8) + break; + lc /= 8; + } + int k = index + nStep * (lc - 2); + int j; + float r1, r2; + for (j = lc - 2; j >= 0; j--) + { + r1 = ptrSrc[src + k]; + r2 = ptrSrc[src + k + nStep]; + ptrSrc[src + k] = r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin; + ptrSrc[src + k + nStep] = r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin; + k -= nStep; + } + for (; lc <= (nDegreeNum / 2) / 8; lc *= 8) + { + resolve_idx -= 7; + nStep /= 8; + index -= nStep * 7; + for (int i = 0; i < lc; i++) + { + k = i * (nStep * 8) + index + nStep * 6; + for ( j = 6; j >= 0; j -- ) + { + r1 = ptrSrc[src + k]; + r2 = ptrSrc[src + k + nStep]; + ptrSrc[src + k] = + r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin; + ptrSrc[src + k + nStep] = + r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin; + k -= nStep; + } + } + } + } + + static void eriFastIPLOT (float[] ptrSrc, int src, int nDegreeDCT) + { + int nDegreeNum = 1 << nDegreeDCT; + for (int i = 0; i < nDegreeNum; i += 2) + { + float r1 = ptrSrc[src + i]; + float r2 = ptrSrc[src + i + 1]; + ptrSrc[src + i] = 0.5f * (r1 + r2); + ptrSrc[src + i + 1] = 0.5f * (r1 - r2); + } + } + + static void eriFastILOT (float[] ptrDst, float[] ptrSrc1, int src1, float[] ptrSrc2, int src2, int nDegreeDCT) + { + int nDegreeNum = 1 << nDegreeDCT; + for (int i = 0; i < nDegreeNum; i += 2) + { + float r1 = ptrSrc1[src1 + i]; + float r2 = ptrSrc2[src2 + i + 1]; + ptrDst[i] = r1 + r2; + ptrDst[i + 1] = r1 - r2; + } + } + + static void eriFastDCT (float[] ptrDst, int dst, int nDstInterval, float[] ptrSrc, int src, float[] ptrWorkBuf, int work, int nDegreeDCT) + { + Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE)); + + if (nDegreeDCT == MIN_DCT_DEGREE) + { + float[] r32Buf = new float[4]; + r32Buf[0] = ptrSrc[src] + ptrSrc[src+3]; + r32Buf[2] = ptrSrc[src] - ptrSrc[src+3]; + r32Buf[1] = ptrSrc[src+1] + ptrSrc[src+2]; + r32Buf[3] = ptrSrc[src+1] - ptrSrc[src+2]; + + ptrDst[dst] = 0.5f * (r32Buf[0] + r32Buf[1]); + ptrDst[dst+nDstInterval * 2] = ERI_rCosPI4 * (r32Buf[0] - r32Buf[1]); + + r32Buf[2] = ERI_DCTofK2[0] * r32Buf[2]; + r32Buf[3] = ERI_DCTofK2[1] * r32Buf[3]; + + r32Buf[0] = r32Buf[2] + r32Buf[3]; + r32Buf[1] = ERI_r2CosPI4 * (r32Buf[2] - r32Buf[3]); + + r32Buf[1] -= r32Buf[0]; + + ptrDst[dst+nDstInterval] = r32Buf[0]; + ptrDst[dst+nDstInterval * 3] = r32Buf[1]; + } + else + { + uint i; + uint nDegreeNum = 1u << nDegreeDCT; + uint nHalfDegree = nDegreeNum >> 1; + for (i = 0; i < nHalfDegree; i++) + { + ptrWorkBuf[work+i] = ptrSrc[src+i] + ptrSrc[src + nDegreeNum - i - 1]; + ptrWorkBuf[work+i + nHalfDegree] = ptrSrc[src+i] - ptrSrc[src + nDegreeNum - i - 1]; + } + int nDstStep = nDstInterval << 1; + eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, work, ptrSrc, src, nDegreeDCT - 1); + + float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1]; + src = (int)(work+nHalfDegree); // ptrSrc = ptrWorkBuf + nHalfDegree; + dst += nDstInterval; // ptrDst += nDstInterval; + + for (i = 0; i < nHalfDegree; i++) + { + ptrWorkBuf[src + i] *= pDCTofK[i]; + } + + eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, src, ptrWorkBuf, work, nDegreeDCT - 1); + // eriFastDCT (ptrDst, nDstStep, ptrSrc, ptrWorkBuf, nDegreeDCT - 1); + + int ptrNext = dst; // within ptrDst; + for (i = 0; i < nHalfDegree; i++) + { + ptrDst[ptrNext] += ptrDst[ptrNext]; // *ptrNext += *ptrNext; + ptrNext += nDstStep; + } + ptrNext = dst; + for (i = 1; i < nHalfDegree; i ++) + { + ptrDst[ptrNext + nDstStep] -= ptrDst[ptrNext]; + ptrNext += nDstStep; + } + } + } + + static void eriFastIDCT (float[] ptrDst, float[] srcBuf, int ptrSrc, int nSrcInterval, float[] ptrWorkBuf, int nDegreeDCT) + { + Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE)); + + if (nDegreeDCT == MIN_DCT_DEGREE) + { + float[] r32Buf1 = new float[2]; + float[] r32Buf2 = new float[4]; + + r32Buf1[0] = srcBuf[ptrSrc]; + r32Buf1[1] = ERI_rCosPI4 * srcBuf[ptrSrc + nSrcInterval * 2]; + + r32Buf2[0] = r32Buf1[0] + r32Buf1[1]; + r32Buf2[1] = r32Buf1[0] - r32Buf1[1]; + + r32Buf1[0] = ERI_DCTofK2[0] * srcBuf[ptrSrc + nSrcInterval]; + r32Buf1[1] = ERI_DCTofK2[1] * srcBuf[ptrSrc + nSrcInterval * 3]; + + r32Buf2[2] = r32Buf1[0] + r32Buf1[1]; + r32Buf2[3] = ERI_r2CosPI4 * (r32Buf1[0] - r32Buf1[1]); + + r32Buf2[3] -= r32Buf2[2]; + + ptrDst[0] = r32Buf2[0] + r32Buf2[2]; + ptrDst[3] = r32Buf2[0] - r32Buf2[2]; + ptrDst[1] = r32Buf2[1] + r32Buf2[3]; + ptrDst[2] = r32Buf2[1] - r32Buf2[3]; + } + else + { + uint nDegreeNum = 1u << nDegreeDCT; + uint nHalfDegree = nDegreeNum >> 1; + int nSrcStep = nSrcInterval << 1; + eriFastIDCT (ptrDst, srcBuf, ptrSrc, nSrcStep, ptrWorkBuf, nDegreeDCT - 1); + + float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1]; + int pOddDst = (int)nHalfDegree; // within ptrDst + int ptrNext = ptrSrc + nSrcInterval; // within srcBuf + + uint i; + for (i = 0; i < nHalfDegree; i++) + { + ptrWorkBuf[i] = srcBuf[ptrNext] * pDCTofK[i]; + ptrNext += nSrcStep; + } + + eriFastDCT (ptrDst, pOddDst, 1, ptrWorkBuf, 0, ptrWorkBuf, (int)nHalfDegree, nDegreeDCT - 1); + // eriFastDCT(pOddDst, 1, ptrWorkBuf, (ptrWorkBuf + nHalfDegree), nDegreeDCT - 1); + + for (i = 0; i < nHalfDegree; i ++) + { + ptrDst[pOddDst + i] += ptrDst[pOddDst + i]; + } + + for (i = 1; i < nHalfDegree; i++) + { + ptrDst[pOddDst + i] -= ptrDst[pOddDst + i - 1]; + } + float[] r32Buf = new float[4]; + uint nQuadDegree = nHalfDegree >> 1; + for (i = 0; i < nQuadDegree; i++) + { + r32Buf[0] = ptrDst[i] + ptrDst[nHalfDegree + i]; + r32Buf[3] = ptrDst[i] - ptrDst[nHalfDegree + i]; + r32Buf[1] = ptrDst[nHalfDegree - 1 - i] + ptrDst[nDegreeNum - 1 - i]; + r32Buf[2] = ptrDst[nHalfDegree - 1 - i] - ptrDst[nDegreeNum - 1 - i]; + + ptrDst[i] = r32Buf[0]; + ptrDst[nHalfDegree - 1 - i] = r32Buf[1]; + ptrDst[nHalfDegree + i] = r32Buf[2]; + ptrDst[nDegreeNum - 1 - i] = r32Buf[3]; + } + } + } + + void eriRevolve2x2 (float[] buf1, int ptrBuf1, float[] buf2, int ptrBuf2, float rSin, float rCos, int nStep, int nCount) + { + for (int i = 0; i < nCount; i++) + { + float r1 = buf1[ptrBuf1]; + float r2 = buf2[ptrBuf2]; + + buf1[ptrBuf1] = r1 * rCos - r2 * rSin; + buf2[ptrBuf2] = r1 * rSin + r2 * rCos; + + ptrBuf1 += nStep; + ptrBuf2 += nStep; + } + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 6b7ce57a..ad4864e8 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -51,5 +51,5 @@ using System.Windows; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.1.4.23")] -[assembly: AssemblyFileVersion ("1.1.4.23")] +[assembly: AssemblyVersion ("1.1.4.24")] +[assembly: AssemblyFileVersion ("1.1.4.24")]